xchange-passgen 1.0.1.a

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.
@@ -0,0 +1,282 @@
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
+ def check_minimum_requirements
275
+ if @password.length < MIN_LENGTH
276
+ @errors << "Password must be at least #{MIN_LENGTH} characters long"
277
+ return false
278
+ end
279
+ true
280
+ end
281
+ end
282
+ end
data/lib/passgen.rb ADDED
@@ -0,0 +1,328 @@
1
+ #= Passgen
2
+ #
3
+ #Ruby gem for generating passwords quickly and easily. Although it is
4
+ #suitable for use within Rails it has no Rails dependencies and can be used in
5
+ #non-Rails applications as well.
6
+ #
7
+ #== Install
8
+ #
9
+ # gem install cryptice-passgen --source http://gems.github.com
10
+ #
11
+ #== Usage
12
+ #
13
+ #The usage could not be easier. Just require and call the generate method:
14
+ #
15
+ # >> require 'rubygems'
16
+ # >> require 'passgen'
17
+ # >> Passgen::generate
18
+ # => "zLWCeS3xC9"
19
+ #
20
+ #== Examples
21
+ #
22
+ # >> Passgen::generate
23
+ # => "zLWCeS3xC9"
24
+ #
25
+ # >> Passgen::generate(:length => 20)
26
+ # => "6lCcHvkuEW6OuzAtkoAs"
27
+ #
28
+ # >> Passgen::generate(:symbols => true)
29
+ # => "gr)$6bIym1"
30
+ #
31
+ # >> Passgen::generate(:lowercase => :only)
32
+ # => "ysbwuxbcea"
33
+ #
34
+ # >> Passgen::generate(:number => 3)
35
+ # => ["REdOigTkdI", "PQu8DsV9WZ", "qptKLbw8YQ"]
36
+ #
37
+ # >> Passgen::generate(:seed => 5)
38
+ # => "JoV9M2qjiK"
39
+ # >> Passgen::generate(:seed => 5) # Will generate same password again
40
+ # => "JoV9M2qjiK"
41
+ #
42
+ # >> Passgen::generate(:seed => :default) # Will set random seed...
43
+ # => "SI8QDBdV98"
44
+ # >> Passgen::generate(:seed => :default) # and hence give different password
45
+ # => "tHHU5HLBAn"
46
+ #
47
+ #== Options:
48
+ #
49
+ #=== :lowercase => true/false/:only
50
+ #* true - Use lowercase letters in the generated password.
51
+ #* false - Do not use lowercase letters in the generated password.
52
+ #* :only - Only use lowercase letters in the generated password.
53
+ #
54
+ #=== :uppercase => true/false/:only
55
+ #* true - Use uppercase letters in the generated password.
56
+ #* false - Do not use uppercase letters in the generated password.
57
+ #* :only - Only use uppercase letters in the generated password.
58
+ #
59
+ #=== :digits => true/false/:only
60
+ #* true - Use digits in the generated password.
61
+ #* false - Do not use digits in the generated password.
62
+ #* :only - Only use digits in the generated password.
63
+ #
64
+ #=== :symbols => true/false/:only/:list
65
+ #* true - Use symbols in the generated password.
66
+ #* false - Do not use symbols in the generated password.
67
+ #* :only - Only use symbols in the generated password.
68
+ #* :list - A string with the symbols to use. Not implemented yet.
69
+ #
70
+ #=== :pronounceable => true/false
71
+ #Not implmented yet.
72
+ #
73
+ #=== :number => integer
74
+ #Number of passwords to generate. If >1 the result is an Array.
75
+ #
76
+ #=== :length => integer/range
77
+ #The number of characters in the generated passwords. A range results in passwords
78
+ #lengths within the given range.
79
+ #
80
+ #=== :seed => integer/:default
81
+ #Set the srand seed to the given integer prior to generating the passwords.
82
+ #
83
+ #=== Default values:
84
+ #
85
+ #:lowercase => true
86
+ #
87
+ #:uppercase => true
88
+ #
89
+ #:digits => true
90
+ #
91
+ #:symbols => false
92
+ #
93
+ #:pronounceable => Not implemented yet.
94
+ #
95
+ #:number => 1
96
+ #
97
+ #:length => 10
98
+ #
99
+ #:seed => nil
100
+ #
101
+ #== Copyright and license
102
+ #
103
+ #Copyright (c) 2009 Erik Lindblad
104
+ #
105
+ #Permission is hereby granted, free of charge, to any person obtaining
106
+ #a copy of this software and associated documentation files (the
107
+ #"Software"), to deal in the Software without restriction, including
108
+ #without limitation the rights to use, copy, modify, merge, publish,
109
+ #distribute, sublicense, and/or sell copies of the Software, and to
110
+ #permit persons to whom the Software is furnished to do so, subject to
111
+ #the following conditions:
112
+ #
113
+ #The above copyright notice and this permission notice shall be
114
+ #included in all copies or substantial portions of the Software.
115
+ #
116
+ #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
117
+ #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
118
+ #MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
119
+ #NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
120
+ #LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
121
+ #OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
122
+ #WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
123
+
124
+ require 'digest'
125
+ require 'passgen/probabilities'
126
+ require 'passgen/strength_analyzer'
127
+
128
+ module Passgen
129
+
130
+ VERSION = "1.0.0"
131
+
132
+ DEFAULT_PARAMS = {
133
+ :number => 1,
134
+ :length => 10,
135
+ :lowercase => true,
136
+ :uppercase => true,
137
+ :digits => true,
138
+ :symbols => false,
139
+ :pronounceable => false
140
+ }
141
+
142
+ def self.default_seed
143
+ Digest::MD5.hexdigest("#{rand}#{Time.now}#{Process.object_id}").to_i(16)
144
+ end
145
+
146
+ def self.generate(params={})
147
+ set_options(params)
148
+ tokens = valid_tokens
149
+ set_seed
150
+
151
+ if n == 1
152
+ generate_one(tokens)
153
+ else
154
+ Array.new(n) {|i| generate_one(tokens) }
155
+ end
156
+ end
157
+
158
+ def self.analyze(pw)
159
+ Passgen::StrengthAnalyzer.analyze(pw)
160
+ end
161
+
162
+ private
163
+ def self.alphabet(index)
164
+ if use_lowercase? && !use_uppercase?
165
+ LOWERCASE_TOKENS[index]
166
+ elsif use_uppercase? && !use_lowercase?
167
+ UPPERCASE_TOKENS[index]
168
+ else
169
+ tmp = LOWERCASE_TOKENS[index]
170
+ tmp.upcase! if rand > 0.5
171
+ tmp
172
+ end
173
+ end
174
+
175
+ def self.generate_one(tokens)
176
+ if @options[:pronounceable]
177
+ generate_pronounceable
178
+ else
179
+ Array.new(password_length) {tokens[rand(tokens.size)]}.join
180
+ end
181
+ end
182
+
183
+ def self.generate_pronounceable
184
+ password = ""
185
+
186
+ # Append digits in front
187
+ digits_prefix = if @options[:digits_before]
188
+ @options[:length] -= @options[:digits_before]
189
+ Array.new(@options[:digits_before]) {DIGIT_TOKENS[rand(DIGIT_TOKENS.size)]}.join
190
+ else
191
+ ""
192
+ end
193
+
194
+ # Append digits at the end
195
+ digits_suffix = if @options[:digits_after]
196
+ @options[:length] -= @options[:digits_after]
197
+ Array.new(@options[:digits_after]) {DIGIT_TOKENS[rand(DIGIT_TOKENS.size)]}.join
198
+ else
199
+ ""
200
+ end
201
+
202
+ # Find a random starting point.
203
+ found_start = false
204
+ ranno = rand * SIGMA # random number [0,1[ weighed by sum of frequencies
205
+ sum = 0;
206
+ N_LETTERS.times do |c1|
207
+ N_LETTERS.times do |c2|
208
+ N_LETTERS.times do |c3|
209
+ sum += P[c1][c2][c3]
210
+ if sum > ranno
211
+ password << alphabet(c1)
212
+ password << alphabet(c2)
213
+ password << alphabet(c3)
214
+ found_start = true
215
+ break
216
+ end
217
+ end
218
+ break if found_start
219
+ end
220
+ break if found_start
221
+ end
222
+
223
+ # Do a random walk.
224
+ (3...@options[:length]).each do |nchar|
225
+ c1 = LETTER_INDEXES[password[nchar-2..nchar-2]]
226
+ c2 = LETTER_INDEXES[password[nchar-1..nchar-1]]
227
+ sum = 0
228
+ N_LETTERS.times {|c3| sum += P[c1][c2][c3]}
229
+ break if sum == 0
230
+ ranno = rand * sum
231
+ sum = 0;
232
+ N_LETTERS.times do |c3|
233
+ sum += P[c1][c2][c3]
234
+ if sum > ranno
235
+ password << alphabet(c3)
236
+ break
237
+ end
238
+ end
239
+ end
240
+ digits_prefix + password + digits_suffix
241
+ end
242
+
243
+ def self.password_length
244
+ if @options[:length].is_a?(Range)
245
+ tmp = @options[:length].to_a
246
+ tmp[rand(tmp.size)]
247
+ else
248
+ @options[:length].to_i
249
+ end
250
+ end
251
+
252
+ def self.n
253
+ @options[:number]
254
+ end
255
+
256
+ def self.set_options(params)
257
+ if params[:lowercase] == :only
258
+ params[:uppercase] = false
259
+ params[:digits] = false
260
+ end
261
+
262
+ if params[:uppercase] == :only
263
+ params[:lowercase] = false
264
+ params[:digits] = false
265
+ end
266
+
267
+ if params[:digits] == :only
268
+ params[:lowercase] = false
269
+ params[:uppercase] = false
270
+ end
271
+
272
+ if params[:symbols] == :only
273
+ params[:lowercase] = false
274
+ params[:uppercase] = false
275
+ params[:digits] = false
276
+ params[:symbols] = true
277
+ end
278
+
279
+ if params[:digits_before] == true
280
+ params[:digits_before] = 2
281
+ end
282
+
283
+ if params[:digits_after] == true
284
+ params[:digits_after] = 2
285
+ end
286
+
287
+ @options = DEFAULT_PARAMS.merge(params)
288
+ end
289
+
290
+ def self.set_seed
291
+ if @options[:seed]
292
+ if @options[:seed] == :default
293
+ srand(default_seed)
294
+ else
295
+ srand(@options[:seed])
296
+ end
297
+ end
298
+ end
299
+
300
+ def self.symbol_tokens
301
+ %w{! @ # $ % & / ( ) + ? *}
302
+ end
303
+
304
+ def self.use_lowercase?
305
+ @options[:lowercase]
306
+ end
307
+
308
+ def self.use_uppercase?
309
+ @options[:uppercase]
310
+ end
311
+
312
+ def self.use_digits?
313
+ @options[:digits]
314
+ end
315
+
316
+ def self.use_symbols?
317
+ @options[:symbols]
318
+ end
319
+
320
+ def self.valid_tokens
321
+ tmp = []
322
+ tmp += LOWERCASE_TOKENS if use_lowercase?
323
+ tmp += UPPERCASE_TOKENS if use_uppercase?
324
+ tmp += DIGIT_TOKENS if use_digits?
325
+ tmp += symbol_tokens if use_symbols?
326
+ tmp
327
+ end
328
+ end
data/passgen.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{xchange-passgen}
5
+ s.version = "1.0.1.a"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Erik Lindblad"]
9
+ s.date = %q{2010-12-16}
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", "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.rubyforge_project = %q{passgen}
18
+ s.rubygems_version = %q{1.3.7}
19
+ s.summary = %q{A password generation gem for Ruby and Rails applications.}
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 3
24
+
25
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
26
+ else
27
+ end
28
+ else
29
+ end
30
+ end
@@ -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