Method: Password.phonemic
- Defined in:
- lib/password.rb
.phonemic(length = 8, flags = nil) ⇒ Object
Generate a memorable password of length characters, using phonemes that a human-being can easily remember. flags is one or more of Password::ONE_DIGIT and Password::ONE_CASE, logically OR’ed together. For example:
pw = Password.phonemic( 8, Password::ONE_DIGIT | Password::ONE_CASE )
This would generate an eight character password, containing a digit and an upper-case letter, such as Ug2shoth.
This method was inspired by the pwgen tool, written by Theodore Ts’o.
Generated passwords may contain any of the characters in Password::PASSWD_CHARS.
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 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/password.rb', line 265 def Password.phonemic(length=8, flags=nil) pw = nil ph_flags = flags loop do pw = "" # Separate the flags integer into an array of individual flags feature_flags = [ flags & ONE_DIGIT, flags & ONE_CASE ] prev = [] first = true desired = Password.get_vowel_or_consonant # Get an Array of all of the phonemes phonemes = PHONEMES.keys.map { |ph| ph.to_s } nr_phonemes = phonemes.size while pw.length < length do # Get a random phoneme and its length phoneme = phonemes[ rand( nr_phonemes ) ] ph_len = phoneme.length # Get its flags as an Array ph_flags = PHONEMES[ phoneme.to_sym ] ph_flags = [ ph_flags & CONSONANT, ph_flags & VOWEL, ph_flags & DIPHTHONG, ph_flags & NOT_FIRST ] # Filter on the basic type of the next phoneme next if ph_flags.include? desired # Handle the NOT_FIRST flag next if first and ph_flags.include? NOT_FIRST # Don't allow a VOWEL followed a vowel/diphthong pair next if prev.include? VOWEL and ph_flags.include? VOWEL and ph_flags.include? DIPHTHONG # Don't allow us to go longer than the desired length next if ph_len > length - pw.length # We've found a phoneme that meets our criteria pw << phoneme # Handle ONE_CASE if feature_flags.include? ONE_CASE if (first or ph_flags.include? CONSONANT) and rand( 10 ) < 3 pw[-ph_len, 1] = pw[-ph_len, 1].upcase feature_flags.delete ONE_CASE end end # Is password already long enough? break if pw.length >= length # Handle ONE_DIGIT if feature_flags.include? ONE_DIGIT if ! first and rand( 10 ) < 3 pw << ( rand( 10 ) + ?0 ).chr feature_flags.delete ONE_DIGIT first = true prev = [] desired = Password.get_vowel_or_consonant next end end if desired == CONSONANT desired = VOWEL elsif prev.include? VOWEL or ph_flags.include? DIPHTHONG or rand(10) > 3 desired = CONSONANT else desired = VOWEL end prev = ph_flags first = false end # Try again break unless feature_flags.include? ONE_CASE or feature_flags.include? ONE_DIGIT end Password.new( pw ) end |