is_passgen 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|