is_passgen 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG +17 -0
- data/Manifest +11 -0
- data/README.rdoc +158 -0
- data/Rakefile +15 -0
- data/lib/passgen.rb +329 -0
- data/lib/passgen/probabilities.rb +804 -0
- data/lib/passgen/strength_analyzer.rb +283 -0
- data/passgen.gemspec +29 -0
- data/rails/init.rb +2 -0
- data/spec/passgen/strength_analyzer_spec.rb +75 -0
- data/spec/passgen_spec.rb +150 -0
- metadata +66 -0
@@ -0,0 +1,283 @@
|
|
1
|
+
module Passgen
|
2
|
+
class StrengthAnalyzer
|
3
|
+
MIN_LENGTH = 8
|
4
|
+
attr_reader :password, :score, :complexity, :errors
|
5
|
+
|
6
|
+
def initialize(pw)
|
7
|
+
@password = pw
|
8
|
+
@score = 0
|
9
|
+
@complexity = "Invalid"
|
10
|
+
@errors = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.analyze(pw)
|
14
|
+
sa = StrengthAnalyzer.new(pw)
|
15
|
+
sa.analyze
|
16
|
+
sa
|
17
|
+
end
|
18
|
+
|
19
|
+
def analyze
|
20
|
+
return self unless check_minimum_requirements
|
21
|
+
|
22
|
+
nScore = 0
|
23
|
+
nLength = 0
|
24
|
+
nAlphaUC = 0
|
25
|
+
nAlphaLC = 0
|
26
|
+
nNumber = 0
|
27
|
+
nSymbol = 0
|
28
|
+
nMidChar = 0
|
29
|
+
nRequirements = 0
|
30
|
+
nAlphasOnly = 0
|
31
|
+
nNumbersOnly = 0
|
32
|
+
nUnqChar = 0
|
33
|
+
nRepChar = 0
|
34
|
+
nRepInc = 0
|
35
|
+
nConsecAlphaUC = 0
|
36
|
+
nConsecAlphaLC = 0
|
37
|
+
nConsecNumber = 0
|
38
|
+
nConsecSymbol = 0
|
39
|
+
nConsecCharType = 0
|
40
|
+
nSeqAlpha = 0
|
41
|
+
nSeqNumber = 0
|
42
|
+
nSeqSymbol = 0
|
43
|
+
nSeqChar = 0
|
44
|
+
nReqChar = 0
|
45
|
+
nMultConsecCharType = 0
|
46
|
+
nMultRepChar = 1
|
47
|
+
nMultConsecSymbol = 1
|
48
|
+
nMultMidChar = 2
|
49
|
+
nMultRequirements = 2
|
50
|
+
nMultConsecAlphaUC = 2
|
51
|
+
nMultConsecAlphaLC = 2
|
52
|
+
nMultConsecNumber = 2
|
53
|
+
nReqCharType = 3
|
54
|
+
nMultAlphaUC = 3
|
55
|
+
nMultAlphaLC = 3
|
56
|
+
nMultSeqAlpha = 3
|
57
|
+
nMultSeqNumber = 3
|
58
|
+
nMultSeqSymbol = 3
|
59
|
+
nMultLength = 4
|
60
|
+
nMultNumber = 4
|
61
|
+
nMultSymbol = 6
|
62
|
+
nTmpAlphaUC = ""
|
63
|
+
nTmpAlphaLC = ""
|
64
|
+
nTmpNumber = ""
|
65
|
+
nTmpSymbol = ""
|
66
|
+
sAlphas = 'abcdefghijklmnopqrstuvwxyz'
|
67
|
+
sNumerics = '01234567890'
|
68
|
+
sSymbols = '!@#$%&/()+?*'
|
69
|
+
sComplexity = 'Invalid'
|
70
|
+
sStandards = 'Below'
|
71
|
+
nMinPwdLen = MIN_LENGTH
|
72
|
+
|
73
|
+
nScore = @password.length * nMultLength
|
74
|
+
nLength = @password.length
|
75
|
+
arrPwd = @password.gsub(/\s+/, "").split(/\s*/)
|
76
|
+
arrPwdLen = arrPwd.length
|
77
|
+
|
78
|
+
# Loop through password to check for Symbol, Numeric, Lowercase and Uppercase pattern matches
|
79
|
+
arrPwdLen.times do |a|
|
80
|
+
if /[A-Z]/.match(arrPwd[a])
|
81
|
+
if nTmpAlphaUC != ""
|
82
|
+
if (nTmpAlphaUC + 1) == a
|
83
|
+
nConsecAlphaUC += 1
|
84
|
+
nConsecCharType += 1
|
85
|
+
end
|
86
|
+
end
|
87
|
+
nTmpAlphaUC = a
|
88
|
+
nAlphaUC += 1
|
89
|
+
elsif /[a-z]/.match(arrPwd[a])
|
90
|
+
if nTmpAlphaLC != ""
|
91
|
+
if (nTmpAlphaLC + 1) == a
|
92
|
+
nConsecAlphaLC += 1
|
93
|
+
nConsecCharType += 1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
nTmpAlphaLC = a
|
97
|
+
nAlphaLC += 1
|
98
|
+
elsif /[0-9]/.match(arrPwd[a])
|
99
|
+
if a > 0 && a < (arrPwdLen - 1)
|
100
|
+
nMidChar += 1
|
101
|
+
end
|
102
|
+
if nTmpNumber != ""
|
103
|
+
if (nTmpNumber + 1) == a
|
104
|
+
nConsecNumber += 1
|
105
|
+
nConsecCharType += 1
|
106
|
+
end
|
107
|
+
end
|
108
|
+
nTmpNumber = a
|
109
|
+
nNumber += 1
|
110
|
+
elsif /[^a-zA-Z0-9_]/.match(arrPwd[a])
|
111
|
+
if a > 0 && a < (arrPwdLen - 1)
|
112
|
+
nMidChar += 1
|
113
|
+
end
|
114
|
+
if nTmpSymbol != ""
|
115
|
+
if (nTmpSymbol + 1) == a
|
116
|
+
nConsecSymbol += 1
|
117
|
+
nConsecCharType += 1
|
118
|
+
end
|
119
|
+
end
|
120
|
+
nTmpSymbol = a
|
121
|
+
nSymbol += 1
|
122
|
+
end
|
123
|
+
|
124
|
+
# Internal loop through password to check for repeat characters
|
125
|
+
bCharExists = false
|
126
|
+
arrPwdLen.times do |b|
|
127
|
+
if arrPwd[a] == arrPwd[b] && a != b # repeat character exists
|
128
|
+
bCharExists = true
|
129
|
+
# Calculate increment deduction based on proximity to identical characters
|
130
|
+
# Deduction is incremented each time a new match is discovered
|
131
|
+
# Deduction amount is based on total password length divided by the
|
132
|
+
# difference of distance between currently selected match
|
133
|
+
nRepInc += (arrPwdLen / (b - a)).abs
|
134
|
+
end
|
135
|
+
end
|
136
|
+
if bCharExists
|
137
|
+
nRepChar += 1
|
138
|
+
nUnqChar = arrPwdLen - nRepChar
|
139
|
+
nRepInc = (nUnqChar > 0) ? (nRepInc / nUnqChar).ceil : nRepInc.ceil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Check for sequential alpha string patterns (forward and reverse)
|
144
|
+
(sAlphas.size - 3).times do |s|
|
145
|
+
sFwd = sAlphas[s...s + 3]
|
146
|
+
sRev = sFwd.reverse
|
147
|
+
if @password.downcase.index(sFwd) || @password.downcase.index(sRev)
|
148
|
+
nSeqAlpha += 1
|
149
|
+
nSeqChar += 1
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Check for sequential numeric string patterns (forward and reverse)
|
154
|
+
(sNumerics.size - 3).times do |s|
|
155
|
+
sFwd = sNumerics[s...s + 3]
|
156
|
+
sRev = sFwd.reverse
|
157
|
+
if @password.downcase.index(sFwd) || @password.downcase.index(sRev)
|
158
|
+
nSeqNumber += 1
|
159
|
+
nSeqChar += 1
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# Check for sequential symbol string patterns (forward and reverse)
|
164
|
+
(sSymbols.size - 3).times do |s|
|
165
|
+
sFwd = sSymbols[s...s + 3]
|
166
|
+
sRev = sFwd.reverse
|
167
|
+
if @password.downcase.index(sFwd) || @password.downcase.index(sRev)
|
168
|
+
nSeqSymbol += 1
|
169
|
+
nSeqChar += 1
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Modify overall score value based on usage vs requirements
|
174
|
+
if nAlphaUC > 0 && nAlphaUC < nLength
|
175
|
+
nScore += (nLength - nAlphaUC) * 2
|
176
|
+
end
|
177
|
+
|
178
|
+
if nAlphaLC > 0 && nAlphaLC < nLength
|
179
|
+
nScore += (nLength - nAlphaLC) * 2
|
180
|
+
end
|
181
|
+
|
182
|
+
if nNumber > 0 && nNumber < nLength
|
183
|
+
nScore += nNumber * nMultNumber
|
184
|
+
end
|
185
|
+
|
186
|
+
if nSymbol > 0
|
187
|
+
nScore += nSymbol * nMultSymbol
|
188
|
+
end
|
189
|
+
|
190
|
+
if nMidChar > 0
|
191
|
+
nScore += nMidChar * nMultMidChar
|
192
|
+
end
|
193
|
+
|
194
|
+
# Point deductions for poor practices
|
195
|
+
if (nAlphaLC > 0 || nAlphaUC > 0) && nSymbol == 0 && nNumber == 0 # Only Letters
|
196
|
+
nScore -= nLength
|
197
|
+
nAlphasOnly = nLength
|
198
|
+
end
|
199
|
+
|
200
|
+
if nAlphaLC === 0 && nAlphaUC === 0 && nSymbol === 0 && nNumber > 0 # Only Numbers
|
201
|
+
nScore -= nLength
|
202
|
+
nNumbersOnly = nLength
|
203
|
+
end
|
204
|
+
|
205
|
+
if nRepChar > 0 # Same character exists more than once
|
206
|
+
nScore -= nRepInc
|
207
|
+
end
|
208
|
+
|
209
|
+
if nConsecAlphaUC > 0 # Consecutive Uppercase Letters exist
|
210
|
+
nScore -= nConsecAlphaUC * nMultConsecAlphaUC
|
211
|
+
end
|
212
|
+
|
213
|
+
if nConsecAlphaLC > 0 # Consecutive Lowercase Letters exist
|
214
|
+
nScore -= nConsecAlphaLC * nMultConsecAlphaLC
|
215
|
+
end
|
216
|
+
|
217
|
+
if nConsecNumber > 0 # Consecutive Numbers exist
|
218
|
+
nScore -= nConsecNumber * nMultConsecNumber
|
219
|
+
end
|
220
|
+
|
221
|
+
if nSeqAlpha > 0 # Sequential alpha strings exist (3 characters or more)
|
222
|
+
nScore -= nSeqAlpha * nMultSeqAlpha
|
223
|
+
end
|
224
|
+
|
225
|
+
if nSeqNumber > 0 # Sequential numeric strings exist (3 character or more)
|
226
|
+
nScore -= nSeqNumber * nMultSeqNumber
|
227
|
+
end
|
228
|
+
|
229
|
+
if nSeqSymbol > 0 # Sequential symbol strings exist (3 character or more)
|
230
|
+
nScore -= nSeqSymbol * nMultSeqSymbol
|
231
|
+
end
|
232
|
+
|
233
|
+
# Determine if mandatory requirements have been met and set image indicators accordingly
|
234
|
+
arrChars = [nLength, nAlphaUC, nAlphaLC, nNumber, nSymbol]
|
235
|
+
arrCharsIds = ["nLength", "nAlphaUC", "nAlphaLC", "nNumber", "nSymbol"]
|
236
|
+
arrCharsLen = arrChars.length
|
237
|
+
arrCharsLen.times do |c|
|
238
|
+
minVal = arrCharsIds[c] == "nLength" ? MIN_LENGTH - 1 : 0
|
239
|
+
if arrChars[c] == (minVal + 1)
|
240
|
+
nReqChar += 1
|
241
|
+
elsif arrChars[c] > (minVal + 1)
|
242
|
+
nReqChar += 1
|
243
|
+
end
|
244
|
+
end
|
245
|
+
nRequirements = nReqChar
|
246
|
+
nMinReqChars = @password.length >= nMinPwdLen ? 3 : 4
|
247
|
+
if nRequirements > nMinReqChars # One or more required characters exist
|
248
|
+
nScore += (nRequirements * 2)
|
249
|
+
end
|
250
|
+
|
251
|
+
# Determine complexity based on overall score
|
252
|
+
if nScore > 100
|
253
|
+
nScore = 100
|
254
|
+
elsif nScore < 0
|
255
|
+
nScore = 0
|
256
|
+
end
|
257
|
+
@complexity = case nScore
|
258
|
+
when 0...20
|
259
|
+
"Trivial"
|
260
|
+
when 20...40
|
261
|
+
"Weak"
|
262
|
+
when 40...60
|
263
|
+
"Good"
|
264
|
+
when 60...80
|
265
|
+
"Strong"
|
266
|
+
else
|
267
|
+
"Very Strong"
|
268
|
+
end
|
269
|
+
|
270
|
+
@score = nScore
|
271
|
+
end
|
272
|
+
|
273
|
+
private
|
274
|
+
|
275
|
+
def check_minimum_requirements
|
276
|
+
if @password.length < MIN_LENGTH
|
277
|
+
@errors << "Password must be at least #{MIN_LENGTH} characters long"
|
278
|
+
return false
|
279
|
+
end
|
280
|
+
true
|
281
|
+
end
|
282
|
+
end
|
283
|
+
end
|
data/passgen.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{passgen}
|
5
|
+
s.version = "1.1.2"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Erik Lindblad (CrypticE)", "Ronald Brachetti(rbecher)", "Ken Spencer (IotaSpencer)"]
|
9
|
+
s.date = %q{2020-03-31}
|
10
|
+
s.description = %q{A password generation gem for Ruby and Rails applications.}
|
11
|
+
s.email = %q{erik@l2c.se}
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "README.rdoc", "lib/passgen.rb", "lib/passgen/probabilities.rb", "lib/passgen/strength_analyzer.rb"]
|
13
|
+
s.files = ["CHANGELOG", "Manifest", "README.rdoc", "Rakefile", "rails/init.rb", "lib/passgen.rb", "lib/passgen/probabilities.rb", "lib/passgen/strength_analyzer.rb", "passgen.gemspec", "spec/passgen/strength_analyzer_spec.rb", "spec/passgen_spec.rb"]
|
14
|
+
s.homepage = %q{http://github.com/cryptice/passgen}
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Passgen", "--main", "README.rdoc"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubygems_version = %q{1.3.7}
|
18
|
+
s.summary = %q{A password generation gem for Ruby and Rails applications.}
|
19
|
+
|
20
|
+
if s.respond_to? :specification_version then
|
21
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
22
|
+
s.specification_version = 3
|
23
|
+
|
24
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
25
|
+
else
|
26
|
+
end
|
27
|
+
else
|
28
|
+
end
|
29
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require "./lib/passgen"
|
2
|
+
|
3
|
+
describe "Using strength analyzer" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
srand(2)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return a StrengthAnalyzer instance" do
|
10
|
+
Passgen.analyze("abcdefg").should be_a(Passgen::StrengthAnalyzer)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should require minimum of 8 characters" do
|
14
|
+
sa = Passgen.analyze("abcdefg")
|
15
|
+
sa.score.should == 0
|
16
|
+
sa.complexity.should == "Invalid"
|
17
|
+
sa.errors.should == ["Password must be at least 8 characters long"]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should analyze aaaaaaaa correctly" do
|
21
|
+
sa = Passgen.analyze("aaaaaaaa")
|
22
|
+
sa.score.should == 0
|
23
|
+
sa.complexity.should == "Trivial"
|
24
|
+
sa.errors.should == []
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should analyze aaaaAAAA correctly" do
|
28
|
+
sa = Passgen.analyze("aaaaAAAA")
|
29
|
+
sa.score.should == 0
|
30
|
+
sa.complexity.should == "Trivial"
|
31
|
+
sa.errors.should == []
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should analyze aaaAAA11 correctly" do
|
35
|
+
sa = Passgen.analyze("aaaAAA11")
|
36
|
+
sa.score.should == 35
|
37
|
+
sa.complexity.should == "Weak"
|
38
|
+
sa.errors.should == []
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should analyze aaa1AAA1 correctly" do
|
42
|
+
sa = Passgen.analyze("aaa1AAA1")
|
43
|
+
sa.score.should == 38
|
44
|
+
sa.complexity.should == "Weak"
|
45
|
+
sa.errors.should == []
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should analyze hht14AAA correctly" do
|
49
|
+
sa = Passgen.analyze("hht14AAA")
|
50
|
+
sa.score.should == 57
|
51
|
+
sa.complexity.should == "Good"
|
52
|
+
sa.errors.should == []
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should analyze hie14KOL correctly" do
|
56
|
+
sa = Passgen.analyze("hie14KOL")
|
57
|
+
sa.score.should == 62
|
58
|
+
sa.complexity.should == "Strong"
|
59
|
+
sa.errors.should == []
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should analyze hI&14KoL correctly" do
|
63
|
+
sa = Passgen.analyze("hI&14KoL")
|
64
|
+
sa.score.should == 82
|
65
|
+
sa.complexity.should == "Very Strong"
|
66
|
+
sa.errors.should == []
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should analyze hI&1#4KoL correctly" do
|
70
|
+
sa = Passgen.analyze("hI&1#4KoL")
|
71
|
+
sa.score.should == 100
|
72
|
+
sa.complexity.should == "Very Strong"
|
73
|
+
sa.errors.should == []
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require "./lib/passgen"
|
2
|
+
|
3
|
+
describe "Using passgen" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
srand(2)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return password with default settings." do
|
10
|
+
Passgen::generate.should eql("OpTiwRslOh")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should return password with uppercase chars only" do
|
14
|
+
Passgen::generate(:uppercase => :only).should eql("IPNIWLSLIH")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return password with lowercase chars only" do
|
18
|
+
Passgen::generate(:lowercase => :only).should eql("ipniwlslih")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return password with digits only" do
|
22
|
+
Passgen::generate(:digits => :only).should eql("8862872154")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return password with symbols only" do
|
26
|
+
Passgen::generate(:symbols => :only).should eql("))/*#*)(\#@")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return password with lowercase and uppercase chars only" do
|
30
|
+
Passgen::generate(:digits => false).should eql("OpTiwRslOh")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return password with lowercase and digit chars only" do
|
34
|
+
Passgen::generate(:uppercase => false).should eql("piwslh85lv")
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should return password with lowercase and symbol chars only" do
|
38
|
+
Passgen::generate(:uppercase => false, :digits => false, :symbols => true).should eql("piwslh)&lv")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should return password with uppercase and digit chars only" do
|
42
|
+
Passgen::generate(:lowercase => false).should eql("PIWSLH85LV")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should return password with uppercase and symbol chars only" do
|
46
|
+
Passgen::generate(:lowercase => false, :digits => false, :symbols => true).should eql("PIWSLH)&LV")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return password with digit and symbol chars only" do
|
50
|
+
Passgen::generate(:lowercase => false, :uppercase => false, :symbols => true).should eql("8&$8@)@872")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should return password with lowercase, uppercase and digit chars only" do
|
54
|
+
Passgen::generate.should eql("OpTiwRslOh")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return password with lowercase, uppercase and symbol chars only" do
|
58
|
+
srand(3)
|
59
|
+
Passgen::generate(:digits => false, :symbols => true).should eql("Qy&d%iav+t")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should return password with lowercase, digit and symbol chars only" do
|
63
|
+
srand(4)
|
64
|
+
Passgen::generate(:uppercase => false, :symbols => true).should eql("?fb%xij$+4")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return password with uppercase, digit and symbol chars only" do
|
68
|
+
srand(4)
|
69
|
+
Passgen::generate(:lowercase => false, :symbols => true).should eql("?FB%XIJ$+4")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return given number of passwords in an Array" do
|
73
|
+
Passgen::generate(:number => 3).should eql(["OpTiwRslOh", "IXFlvVFAu8", "0LNdMeQRZN"])
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should return a password with given length" do
|
77
|
+
Passgen::generate(:length => 8).should eql("OpTiwRsl")
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return several passwords of variable length" do
|
81
|
+
Passgen::generate(:length => 3..12, :number => 2).should eql(["pTiwRslOhIX", "VFAu80LN"])
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should use given seed" do
|
85
|
+
pass1 = Passgen::generate(:seed => 5)
|
86
|
+
pass2 = Passgen::generate(:seed => 5)
|
87
|
+
pass1.should eql(pass2)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should set seed to Time.now + Process.id" do
|
91
|
+
pass1 = Passgen::generate(:seed => :default)
|
92
|
+
pass2 = Passgen::generate(:seed => :default)
|
93
|
+
pass1.should_not eql(pass2)
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "handling tokens" do
|
97
|
+
|
98
|
+
it "should return a-z" do
|
99
|
+
Passgen::LOWERCASE_TOKENS.should eql(("a".."z").to_a)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return A-Z" do
|
103
|
+
Passgen::UPPERCASE_TOKENS.should eql(("A".."Z").to_a)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should return 0-9" do
|
107
|
+
Passgen::DIGIT_TOKENS.should eql(("0".."9").to_a)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should return default symbols" do
|
111
|
+
Passgen::symbol_tokens.should eql(%w{! @ # $ % & / ( ) + ? *})
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "pronounceable" do
|
117
|
+
it "should return a pronounceable lower case password" do
|
118
|
+
Passgen::generate(:pronounceable => true, :lowercase => :only).should == "ishanghter"
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should return a pronounceable upper case password" do
|
122
|
+
Passgen::generate(:pronounceable => true, :uppercase => :only).should == "ISHANGHTER"
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should return a pronounceable mixed case password" do
|
126
|
+
Passgen::generate(:pronounceable => true).should == "iShfIeRBAt"
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should return a pronounceable mixed case password of length 7" do
|
130
|
+
Passgen::generate(:pronounceable => true, :length => 7).should == "IShfIeR"
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should return a pronounceable password with 3 digits in front" do
|
134
|
+
Passgen::generate(:pronounceable => true, :digits_before => 3).should == "886uRApLIN"
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should return a pronounceable password with default 2 digits in front" do
|
138
|
+
Passgen::generate(:pronounceable => true, :digits_before => true).should == "88mpICePED"
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should return a pronounceable password with 3 digits at the end" do
|
142
|
+
Passgen::generate(:pronounceable => true, :digits_after => 3).should == "uRAPLIN886"
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should return a pronounceable password with default 2 digits at the end" do
|
146
|
+
Passgen::generate(:pronounceable => true, :digits_after => true).should == "mPICEPED88"
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|