Class: PawGen
- Inherits:
-
Object
- Object
- PawGen
- Defined in:
- lib/pawgen.rb
Constant Summary collapse
- DIGITS =
'0123456789'.freeze
- UPPERCASE =
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.freeze
- LOWERCASE =
'abcdefghijklmnopqrstuvwxyz'.freeze
- SYMBOLS =
'!"#$%&\'()*+,-./:<=>?@[\\]^_`{|}~'.freeze
- AMBIGUOUS =
'B8G6I1l0OQDS5Z2'.freeze
- VOWELS =
'01aeiouyAEIOUY'.freeze
- PHF_CONSONANT =
Phoneme flags
0x01
- PHF_VOWEL =
0x02
- PHF_DIPTHONG =
0x04
- PHF_NOT_FIRST =
0x08
- ANGLOPHONEMES =
[ ['a', PHF_VOWEL], ['ae', PHF_VOWEL | PHF_DIPTHONG], ['ah', PHF_VOWEL | PHF_DIPTHONG], ['ai', PHF_VOWEL | PHF_DIPTHONG], ['b', PHF_CONSONANT], ['c', PHF_CONSONANT], ['ch', PHF_CONSONANT | PHF_DIPTHONG], ['d', PHF_CONSONANT], ['e', PHF_VOWEL], ['ee', PHF_VOWEL | PHF_DIPTHONG], ['ei', PHF_VOWEL | PHF_DIPTHONG], ['f', PHF_CONSONANT], ['g', PHF_CONSONANT], ['gh', PHF_CONSONANT | PHF_DIPTHONG | PHF_NOT_FIRST], ['h', PHF_CONSONANT], ['i', PHF_VOWEL], ['ie', PHF_VOWEL | PHF_DIPTHONG], ['j', PHF_CONSONANT], ['k', PHF_CONSONANT], ['l', PHF_CONSONANT], ['m', PHF_CONSONANT], ['n', PHF_CONSONANT], ['ng', PHF_CONSONANT | PHF_DIPTHONG | PHF_NOT_FIRST], ['o', PHF_VOWEL], ['oh', PHF_VOWEL | PHF_DIPTHONG], ['oo', PHF_VOWEL | PHF_DIPTHONG], ['p', PHF_CONSONANT], ['ph', PHF_CONSONANT | PHF_DIPTHONG], ['qu', PHF_CONSONANT | PHF_DIPTHONG], ['r', PHF_CONSONANT], ['s', PHF_CONSONANT], ['sh', PHF_CONSONANT | PHF_DIPTHONG], ['t', PHF_CONSONANT], ['th', PHF_CONSONANT | PHF_DIPTHONG], ['u', PHF_VOWEL], ['v', PHF_CONSONANT], ['w', PHF_CONSONANT], ['x', PHF_CONSONANT], ['y', PHF_CONSONANT], ['z', PHF_CONSONANT], ]
- ANGLOVOWELS =
ANGLOPHONEMES. select{|entry| (entry[1] & PHF_VOWEL) != 0}. freeze
- ANGLOCONSONANTS =
ANGLOPHONEMES. select{|entry| (entry[1] & PHF_CONSONANT) != 0}. freeze
- REQ_UPPERCASE =
Requirement flags
0x01
- REQ_DIGITS =
0x02
- REQ_SYMBOLS =
0x04
- KANA_MORAE =
Real kana includes signs to prolongate a preceding vowel or a following consonant. We’re not including these, based on the wild-assed guess that the advantage in memorability is outweighed by the disadvantage in reduced password space.
Similarly, we’re not indicating palatalisation: we’ll use ‘ti’ rather than ‘chi’, ‘tu’ rather than ‘tsu’, and so on.
([''] + %w{k g s z t d n h b p m y r w}). map{|c| %w{a i u e o}.map{|v| c + v}}. flatten + %w{n} - %w{yi ye wu}
Instance Attribute Summary collapse
-
#length ⇒ Object
Returns the value of attribute length.
Class Method Summary collapse
Instance Method Summary collapse
- #anglophonemic ⇒ Object
- #do_not_exclude_ambiguous! ⇒ Object (also: #dont_exclude_ambiguous!)
- #do_not_exclude_vowels! ⇒ Object (also: #dont_exclude_vowels!)
- #exclude_ambiguous! ⇒ Object
- #exclude_ambiguous? ⇒ Boolean
- #exclude_vowels! ⇒ Object
- #exclude_vowels? ⇒ Boolean
- #generate ⇒ Object
- #include_digits! ⇒ Object
- #include_digits? ⇒ Boolean
- #include_symbols! ⇒ Object
- #include_symbols? ⇒ Boolean
- #include_uppercase! ⇒ Object
- #include_uppercase? ⇒ Boolean
-
#initialize ⇒ PawGen
constructor
A new instance of PawGen.
- #kanaphonemic ⇒ Object
- #no_digits! ⇒ Object
- #no_symbols! ⇒ Object
- #no_uppercase! ⇒ Object
- #set_length!(new_length) ⇒ Object
- #structureless ⇒ Object
- #use_anglophonemic_generator! ⇒ Object
- #use_kanaphonemic_generator! ⇒ Object
- #use_structureless_generator! ⇒ Object
Constructor Details
#initialize ⇒ PawGen
Returns a new instance of PawGen.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/pawgen.rb', line 11 def initialize super() # The original defaulted the length to 8, but it's a bit too # short to be the default length these days -- especially # considering that phonemic password construction shrinks # the password space. @length = 12 @include_uppercase = true @include_digits = true @include_symbols = false @exclude_ambiguous = false @exclude_vowels = false @mode = method :anglophonemic return end |
Instance Attribute Details
#length ⇒ Object
Returns the value of attribute length.
102 103 104 |
# File 'lib/pawgen.rb', line 102 def length @length end |
Class Method Details
.random_bool(probability_of_true) ⇒ Object
135 136 137 |
# File 'lib/pawgen.rb', line 135 def self::random_bool probability_of_true return SecureRandom.random_number < probability_of_true end |
.random_item(array) ⇒ Object
139 140 141 |
# File 'lib/pawgen.rb', line 139 def self::random_item array return array[SecureRandom.random_number array.length] end |
Instance Method Details
#anglophonemic ⇒ Object
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'lib/pawgen.rb', line 223 def anglophonemic raise 'unable to generate such a ' + 'short anglophonemic password' \ unless length >= 5 raise 'unable to generate an ' + 'anglophonemic password with no vowels' \ if exclude_vowels? reqs = 0 reqs |= REQ_UPPERCASE if include_uppercase? reqs |= REQ_DIGITS if include_digits? reqs |= REQ_SYMBOLS if include_symbols? result, unmet_reqs = [] # declare local variables begin unmet_reqs = reqs first = true # also re-set after a digit (but not after a symbol) result = '' prev_phoneme_flags = 0 should_be = nil while result.length < length do should_be ||= PawGen.random_item [ANGLOVOWELS, ANGLOCONSONANTS] phoneme, phoneme_flags = PawGen.random_item should_be next if first and (phoneme_flags & PHF_NOT_FIRST) != 0 # block a vowel followed by a vowel-dipthong next if (prev_phoneme_flags & PHF_VOWEL) != 0 and (phoneme_flags & PHF_VOWEL) != 0 and (phoneme_flags & PHF_DIPTHONG) != 0 next if result.length + phoneme.length > length if include_uppercase? and (first or (phoneme_flags & PHF_CONSONANT) != 0) and PawGen.random_bool 0.2 then phoneme = phoneme.capitalize unmet_reqs &= ~REQ_UPPERCASE end # Note that the unambiguous lowercase 'o' can become the # ambiguous 'O' through capitalisation. Contrariwise, # the ambiguous lowercase 'l' can become the unambiguous # uppercase 'L'. next if exclude_ambiguous? and phoneme.split('').any?{|c| AMBIGUOUS.include? c} # All the checks for the phoneme passed. Let's add it. result << phoneme break if result.length == length # Checking against the [[first]] flag here means # requiring at least _two_ phonemes before the digit can # appear, because if we just applied the first phoneme, # [[first]] is still true. if include_digits? and !first and PawGen.random_bool 0.3 then choice = DIGITS.split '' choice -= AMBIGUOUS.split '' if exclude_ambiguous? result << PawGen.random_item(choice) unmet_reqs &= ~REQ_DIGITS first = true prev_phoneme_flags = 0 should_be = nil # pick next [[should_be]] at random next end if include_symbols? and !first and PawGen.random_bool 0.2 then choice = SYMBOLS.split '' # Our [[AMBIGUOUS]] does not actually contain any # symbols in the current version. This may be a # problem, considering [['`]] and [[!/1l|]] and [[&8]] # and [[-_]] and [[^~]] and maybe even [[.,]] and # [[:;]] and [[()l|]] so we're excluding [[AMBIGUOUS]] # anyway in anticipation of a future version # mentioning some of those. choice -= AMBIGUOUS.split '' if exclude_ambiguous? result << PawGen.random_item(choice) unmet_reqs &= ~REQ_SYMBOLS # not resetting [[first]]; not [[next]]ing end if should_be.object_id == ANGLOCONSONANTS.object_id then should_be = ANGLOVOWELS else if (prev_phoneme_flags & PHF_VOWEL) != 0 or (phoneme_flags & PHF_DIPTHONG) != 0 or PawGen.random_bool(0.6) then should_be = ANGLOCONSONANTS else should_be = ANGLOVOWELS end end prev_phoneme_flags = phoneme_flags first = false end end until unmet_reqs.zero? return result end |
#do_not_exclude_ambiguous! ⇒ Object Also known as: dont_exclude_ambiguous!
78 79 80 81 |
# File 'lib/pawgen.rb', line 78 def do_not_exclude_ambiguous! @exclude_ambiguous = false return self end |
#do_not_exclude_vowels! ⇒ Object Also known as: dont_exclude_vowels!
95 96 97 98 |
# File 'lib/pawgen.rb', line 95 def do_not_exclude_vowels! @exclude_vowels = false return self end |
#exclude_ambiguous! ⇒ Object
73 74 75 76 |
# File 'lib/pawgen.rb', line 73 def exclude_ambiguous! @exclude_ambiguous = true return self end |
#exclude_ambiguous? ⇒ Boolean
69 70 71 |
# File 'lib/pawgen.rb', line 69 def exclude_ambiguous? return @exclude_ambiguous end |
#exclude_vowels! ⇒ Object
90 91 92 93 |
# File 'lib/pawgen.rb', line 90 def exclude_vowels! @exclude_vowels = true return self end |
#exclude_vowels? ⇒ Boolean
86 87 88 |
# File 'lib/pawgen.rb', line 86 def exclude_vowels? return @exclude_vowels end |
#generate ⇒ Object
131 132 133 |
# File 'lib/pawgen.rb', line 131 def generate return @mode.call end |
#include_digits! ⇒ Object
45 46 47 48 |
# File 'lib/pawgen.rb', line 45 def include_digits! @include_digits = true return self end |
#include_digits? ⇒ Boolean
41 42 43 |
# File 'lib/pawgen.rb', line 41 def include_digits? return @include_digits end |
#include_symbols! ⇒ Object
59 60 61 62 |
# File 'lib/pawgen.rb', line 59 def include_symbols! @include_symbols = true return self end |
#include_symbols? ⇒ Boolean
55 56 57 |
# File 'lib/pawgen.rb', line 55 def include_symbols? return @include_symbols end |
#include_uppercase! ⇒ Object
31 32 33 34 |
# File 'lib/pawgen.rb', line 31 def include_uppercase! @include_uppercase = true return self end |
#include_uppercase? ⇒ Boolean
27 28 29 |
# File 'lib/pawgen.rb', line 27 def include_uppercase? return @include_uppercase end |
#kanaphonemic ⇒ Object
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/pawgen.rb', line 338 def kanaphonemic raise 'unable to generate such a ' + 'short kanaphonemic password' \ unless length >= 5 raise 'unable to generate an ' + 'kanaphonemic password with no vowels' \ if exclude_vowels? reqs = 0 reqs |= REQ_UPPERCASE if include_uppercase? reqs |= REQ_DIGITS if include_digits? reqs |= REQ_SYMBOLS if include_symbols? result, unmet_reqs = [] # declare local variables begin unmet_reqs = reqs first = true # also re-set after a digit (but not after a symbol) result = '' while result.length < length do phoneme = PawGen.random_item KANA_MORAE next if result.length + phoneme.length > length if include_uppercase? and PawGen.random_bool 0.2 then phoneme = phoneme.capitalize unmet_reqs &= ~REQ_UPPERCASE end # Note that the unambiguous lowercase 'o' can become the # ambiguous 'O' through capitalisation. next if exclude_ambiguous? and phoneme.split('').any?{|c| AMBIGUOUS.include? c} # All the checks for the phoneme passed. Let's add it. result << phoneme break if result.length == length # Checking against the [[first]] flag here means # requiring at least _two_ phonemes before the digit can # appear, because if we just applied the first phoneme, # [[first]] is still true. if include_digits? and !first and PawGen.random_bool 0.3 then choice = DIGITS.split '' choice -= AMBIGUOUS.split '' if exclude_ambiguous? result << PawGen.random_item(choice) unmet_reqs &= ~REQ_DIGITS first = true next end if include_symbols? and !first and PawGen.random_bool 0.2 then choice = SYMBOLS # Our [[AMBIGUOUS]] does not actually contain any # symbols in the current version. This may be a # problem, considering [['`]] and [[!/1l|]] and [[&8]] # and [[-_]] and [[^~]] and maybe even [[.,]] and # [[:;]] and [[()l|]] so we're excluding [[AMBIGUOUS]] # anyway in anticipation of a future version # mentioning some of those. choice -= AMBIGUOUS.split '' if exclude_ambiguous? result << PawGen.random_item(choice) unmet_reqs &= ~REQ_SYMBOLS # not resetting [[first]]; not [[next]]ing end first = false end end until unmet_reqs.zero? return result end |
#no_digits! ⇒ Object
50 51 52 53 |
# File 'lib/pawgen.rb', line 50 def no_digits! @include_digits = false return self end |
#no_symbols! ⇒ Object
64 65 66 67 |
# File 'lib/pawgen.rb', line 64 def no_symbols! @include_symbols = false return self end |
#no_uppercase! ⇒ Object
36 37 38 39 |
# File 'lib/pawgen.rb', line 36 def no_uppercase! @include_uppercase = false return self end |
#set_length!(new_length) ⇒ Object
109 110 111 112 113 114 |
# File 'lib/pawgen.rb', line 109 def set_length! new_length raise 'invalid length' \ unless new_length.is_a? Integer and new_length >= 1 @length = new_length return self end |
#structureless ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/pawgen.rb', line 143 def structureless charset = LOWERCASE charset += UPPERCASE if include_uppercase? charset += DIGITS if include_digits? charset += SYMBOLS if include_symbols? charset = charset.split('') charset -= AMBIGUOUS.split('') if exclude_ambiguous? charset -= VOWELS.split('') if exclude_vowels? return (0 ... @length). map{PawGen.random_item charset}. join '' end |
#use_anglophonemic_generator! ⇒ Object
121 122 123 124 |
# File 'lib/pawgen.rb', line 121 def use_anglophonemic_generator! @mode = method :anglophonemic return end |
#use_kanaphonemic_generator! ⇒ Object
126 127 128 129 |
# File 'lib/pawgen.rb', line 126 def use_kanaphonemic_generator! @mode = method :kanaphonemic return end |
#use_structureless_generator! ⇒ Object
116 117 118 119 |
# File 'lib/pawgen.rb', line 116 def use_structureless_generator! @mode = method :structureless return end |