Class: Milia::Password
- Inherits:
-
Object
- Object
- Milia::Password
- Defined in:
- lib/milia/password_generator.rb
Overview
Provides support generating memorable passwords
Class Method Summary collapse
-
.generate(length = 8, flags = nil) ⇒ Object
Generate a memorable password of
length
characters, using phonemes that a human-being can easily remember. -
.get_vowel_or_consonant ⇒ Object
Determine whether the next character should be a vowel or consonant.
Class Method Details
.generate(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:
password = Password.generate(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
.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/milia/password_generator.rb', line 83 def generate(length = 8, flags = nil) password = nil ph_flags = flags loop do password = '' # 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 password.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 && ph_flags.include?(NOT_FIRST) # Don't allow a VOWEL followed a vowel/diphthong pair next if prev.include?(VOWEL) && ph_flags.include?(VOWEL) && ph_flags.include?(DIPHTHONG) # Don't allow us to go longer than the desired length next if ph_len > length - password.length # We've found a phoneme that meets our criteria password << phoneme # Handle ONE_CASE if feature_flags.include?(ONE_CASE) if (first || ph_flags.include?(CONSONANT)) && rand(10) < 3 password[-ph_len, 1] = password[-ph_len, 1].upcase feature_flags.delete(ONE_CASE) end end # Is password already long enough? break if password.length >= length # Handle ONE_DIGIT if feature_flags.include?(ONE_DIGIT) if !first && rand(10) < 3 password << (rand(10) + '0'.ord).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) || ph_flags.include?(DIPHTHONG) || rand(10) > 3 desired = CONSONANT else desired = VOWEL end prev = ph_flags first = false end # Try again break unless feature_flags.include?(ONE_CASE) || feature_flags.include?(ONE_DIGIT) end password end |
.get_vowel_or_consonant ⇒ Object
Determine whether the next character should be a vowel or consonant.
64 65 66 |
# File 'lib/milia/password_generator.rb', line 64 def get_vowel_or_consonant rand( 2 ) == 1 ? VOWEL : CONSONANT end |