passgen 1.1.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2 -0
- data/lib/passgen.rb +102 -101
- data/lib/passgen/probabilities.rb +52 -52
- data/lib/passgen/strength_analyzer.rb +117 -116
- data/passgen.gemspec +1 -1
- metadata +1 -1
data/CHANGELOG
CHANGED
data/lib/passgen.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#= Passgen
|
2
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.
|
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
6
|
#
|
7
7
|
#== Install
|
8
8
|
#
|
@@ -10,116 +10,116 @@
|
|
10
10
|
#
|
11
11
|
#== Usage
|
12
12
|
#
|
13
|
-
#The usage could not be easier. Just require and call the generate method:
|
13
|
+
# The usage could not be easier. Just require and call the generate method:
|
14
14
|
#
|
15
15
|
# >> require 'rubygems'
|
16
16
|
# >> require 'passgen'
|
17
17
|
# >> Passgen::generate
|
18
18
|
# => "zLWCeS3xC9"
|
19
19
|
#
|
20
|
-
|
20
|
+
# == Examples
|
21
21
|
#
|
22
22
|
# >> Passgen::generate
|
23
23
|
# => "zLWCeS3xC9"
|
24
24
|
#
|
25
|
-
# >> Passgen::generate(:
|
25
|
+
# >> Passgen::generate(length: 20)
|
26
26
|
# => "6lCcHvkuEW6OuzAtkoAs"
|
27
27
|
#
|
28
|
-
# >> Passgen::generate(:
|
28
|
+
# >> Passgen::generate(symbols: true)
|
29
29
|
# => "gr)$6bIym1"
|
30
30
|
#
|
31
|
-
# >> Passgen::generate(:
|
31
|
+
# >> Passgen::generate(lowercase: :only)
|
32
32
|
# => "ysbwuxbcea"
|
33
33
|
#
|
34
|
-
# >> Passgen::generate(:
|
34
|
+
# >> Passgen::generate(number: 3)
|
35
35
|
# => ["REdOigTkdI", "PQu8DsV9WZ", "qptKLbw8YQ"]
|
36
36
|
#
|
37
|
-
# >> Passgen::generate(:
|
37
|
+
# >> Passgen::generate(seed: 5)
|
38
38
|
# => "JoV9M2qjiK"
|
39
|
-
# >> Passgen::generate(:
|
39
|
+
# >> Passgen::generate(seed: 5) # Will generate same password again
|
40
40
|
# => "JoV9M2qjiK"
|
41
41
|
#
|
42
|
-
# >> Passgen::generate(:
|
42
|
+
# >> Passgen::generate(seed: :default) # Will set random seed...
|
43
43
|
# => "SI8QDBdV98"
|
44
|
-
# >> Passgen::generate(:
|
44
|
+
# >> Passgen::generate(seed: :default) # and hence give different password
|
45
45
|
# => "tHHU5HLBAn"
|
46
46
|
#
|
47
|
-
|
47
|
+
# == Options:
|
48
48
|
#
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
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
53
|
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
58
|
#
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
63
|
#
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
69
|
#
|
70
|
-
|
71
|
-
#Not implmented yet.
|
70
|
+
# === :pronounceable => true/false
|
71
|
+
# Not implmented yet.
|
72
72
|
#
|
73
|
-
|
74
|
-
#Number of passwords to generate. If >1 the result is an Array.
|
73
|
+
# === :number => integer
|
74
|
+
# Number of passwords to generate. If >1 the result is an Array.
|
75
75
|
#
|
76
|
-
|
77
|
-
#The number of characters in the generated passwords. A range results in passwords
|
78
|
-
#lengths within the given range.
|
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
79
|
#
|
80
|
-
|
81
|
-
#Set the srand seed to the given integer prior to generating the passwords.
|
80
|
+
# === :seed => integer/:default
|
81
|
+
# Set the srand seed to the given integer prior to generating the passwords.
|
82
82
|
#
|
83
|
-
|
83
|
+
# === Default values:
|
84
84
|
#
|
85
|
-
|
85
|
+
# lowercase: true
|
86
86
|
#
|
87
|
-
|
87
|
+
# uppercase: true
|
88
88
|
#
|
89
|
-
|
89
|
+
# digits: true
|
90
90
|
#
|
91
|
-
|
91
|
+
# symbols: false
|
92
92
|
#
|
93
|
-
|
93
|
+
# pronounceable: Not implemented yet.
|
94
94
|
#
|
95
|
-
|
95
|
+
# number: 1
|
96
96
|
#
|
97
|
-
|
97
|
+
# length: 10
|
98
98
|
#
|
99
|
-
|
99
|
+
# seed: nil
|
100
100
|
#
|
101
|
-
|
101
|
+
# == Copyright and license
|
102
102
|
#
|
103
|
-
#Copyright (c) 2009 Erik Lindblad
|
103
|
+
# Copyright (c) 2009 Erik Lindblad
|
104
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:
|
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
112
|
#
|
113
|
-
#The above copyright notice and this permission notice shall be
|
114
|
-
#included in all copies or substantial portions of the Software.
|
113
|
+
# The above copyright notice and this permission notice shall be
|
114
|
+
# included in all copies or substantial portions of the Software.
|
115
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.
|
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
123
|
|
124
124
|
require 'digest'
|
125
125
|
require 'passgen/probabilities'
|
@@ -128,22 +128,22 @@ require 'passgen/strength_analyzer'
|
|
128
128
|
module Passgen
|
129
129
|
|
130
130
|
VERSION = "1.0.0"
|
131
|
-
|
131
|
+
|
132
132
|
DEFAULT_PARAMS = {
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
133
|
+
number: 1,
|
134
|
+
length: 10,
|
135
|
+
lowercase: true,
|
136
|
+
uppercase: true,
|
137
|
+
digits: true,
|
138
|
+
symbols: false,
|
139
|
+
pronounceable: false
|
140
140
|
}
|
141
141
|
|
142
142
|
def self.default_seed
|
143
143
|
Digest::MD5.hexdigest("#{rand}#{Time.now}#{Process.object_id}").to_i(16)
|
144
144
|
end
|
145
145
|
|
146
|
-
def self.generate(params={})
|
146
|
+
def self.generate(params = {})
|
147
147
|
set_options(params)
|
148
148
|
tokens = valid_tokens
|
149
149
|
set_seed
|
@@ -151,15 +151,16 @@ module Passgen
|
|
151
151
|
if n == 1
|
152
152
|
generate_one(tokens)
|
153
153
|
else
|
154
|
-
Array.new(n) {|i| generate_one(tokens) }
|
154
|
+
Array.new(n) { |i| generate_one(tokens) }
|
155
155
|
end
|
156
156
|
end
|
157
157
|
|
158
158
|
def self.analyze(pw)
|
159
159
|
Passgen::StrengthAnalyzer.analyze(pw)
|
160
160
|
end
|
161
|
-
|
161
|
+
|
162
162
|
private
|
163
|
+
|
163
164
|
def self.alphabet(index)
|
164
165
|
if use_lowercase? && !use_uppercase?
|
165
166
|
LOWERCASE_TOKENS[index]
|
@@ -171,12 +172,12 @@ module Passgen
|
|
171
172
|
tmp
|
172
173
|
end
|
173
174
|
end
|
174
|
-
|
175
|
+
|
175
176
|
def self.generate_one(tokens)
|
176
177
|
if @options[:pronounceable]
|
177
178
|
generate_pronounceable
|
178
179
|
else
|
179
|
-
Array.new(password_length) {tokens[rand(tokens.size)]}.join
|
180
|
+
Array.new(password_length) { tokens[rand(tokens.size)] }.join
|
180
181
|
end
|
181
182
|
end
|
182
183
|
|
@@ -185,24 +186,24 @@ module Passgen
|
|
185
186
|
|
186
187
|
# Append digits in front
|
187
188
|
digits_prefix = if @options[:digits_before]
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
189
|
+
@options[:length] -= @options[:digits_before]
|
190
|
+
Array.new(@options[:digits_before]) { DIGIT_TOKENS[rand(DIGIT_TOKENS.size)] }.join
|
191
|
+
else
|
192
|
+
""
|
193
|
+
end
|
193
194
|
|
194
195
|
# Append digits at the end
|
195
196
|
digits_suffix = if @options[:digits_after]
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
197
|
+
@options[:length] -= @options[:digits_after]
|
198
|
+
Array.new(@options[:digits_after]) { DIGIT_TOKENS[rand(DIGIT_TOKENS.size)] }.join
|
199
|
+
else
|
200
|
+
""
|
201
|
+
end
|
201
202
|
|
202
203
|
# Find a random starting point.
|
203
204
|
found_start = false
|
204
|
-
ranno
|
205
|
-
sum
|
205
|
+
ranno = rand * SIGMA # random number [0,1[ weighed by sum of frequencies
|
206
|
+
sum = 0;
|
206
207
|
N_LETTERS.times do |c1|
|
207
208
|
N_LETTERS.times do |c2|
|
208
209
|
N_LETTERS.times do |c3|
|
@@ -222,13 +223,13 @@ module Passgen
|
|
222
223
|
|
223
224
|
# Do a random walk.
|
224
225
|
(3...@options[:length]).each do |nchar|
|
225
|
-
c1
|
226
|
-
c2
|
226
|
+
c1 = LETTER_INDEXES[password[nchar - 2..nchar - 2]]
|
227
|
+
c2 = LETTER_INDEXES[password[nchar - 1..nchar - 1]]
|
227
228
|
sum = 0
|
228
|
-
N_LETTERS.times {|c3| sum += P[c1][c2][c3]}
|
229
|
+
N_LETTERS.times { |c3| sum += P[c1][c2][c3] }
|
229
230
|
break if sum == 0
|
230
231
|
ranno = rand * sum
|
231
|
-
sum
|
232
|
+
sum = 0
|
232
233
|
N_LETTERS.times do |c3|
|
233
234
|
sum += P[c1][c2][c3]
|
234
235
|
if sum > ranno
|
@@ -239,7 +240,7 @@ module Passgen
|
|
239
240
|
end
|
240
241
|
digits_prefix + password + digits_suffix
|
241
242
|
end
|
242
|
-
|
243
|
+
|
243
244
|
def self.password_length
|
244
245
|
if @options[:length].is_a?(Range)
|
245
246
|
tmp = @options[:length].to_a
|
@@ -256,12 +257,12 @@ module Passgen
|
|
256
257
|
def self.set_options(params)
|
257
258
|
if params[:lowercase] == :only
|
258
259
|
params[:uppercase] = false
|
259
|
-
params[:digits]
|
260
|
+
params[:digits] = false
|
260
261
|
end
|
261
262
|
|
262
263
|
if params[:uppercase] == :only
|
263
264
|
params[:lowercase] = false
|
264
|
-
params[:digits]
|
265
|
+
params[:digits] = false
|
265
266
|
end
|
266
267
|
|
267
268
|
if params[:digits] == :only
|
@@ -272,8 +273,8 @@ module Passgen
|
|
272
273
|
if params[:symbols] == :only
|
273
274
|
params[:lowercase] = false
|
274
275
|
params[:uppercase] = false
|
275
|
-
params[:digits]
|
276
|
-
params[:symbols]
|
276
|
+
params[:digits] = false
|
277
|
+
params[:symbols] = true
|
277
278
|
end
|
278
279
|
|
279
280
|
if params[:digits_before] == true
|
@@ -748,57 +748,57 @@ module Passgen
|
|
748
748
|
DIGIT_TOKENS = %w{0 1 2 3 4 5 6 7 8 9}
|
749
749
|
|
750
750
|
LETTER_INDEXES = {
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
751
|
+
a: 0,
|
752
|
+
b: 1,
|
753
|
+
c: 2,
|
754
|
+
d: 3,
|
755
|
+
e: 4,
|
756
|
+
f: 5,
|
757
|
+
g: 6,
|
758
|
+
h: 7,
|
759
|
+
i: 8,
|
760
|
+
j: 9,
|
761
|
+
k: 10,
|
762
|
+
l: 11,
|
763
|
+
m: 12,
|
764
|
+
n: 13,
|
765
|
+
o: 14,
|
766
|
+
p: 15,
|
767
|
+
q: 16,
|
768
|
+
r: 17,
|
769
|
+
s: 18,
|
770
|
+
t: 19,
|
771
|
+
u: 20,
|
772
|
+
v: 21,
|
773
|
+
w: 22,
|
774
|
+
x: 23,
|
775
|
+
y: 24,
|
776
|
+
z: 25,
|
777
|
+
A: 0,
|
778
|
+
B: 1,
|
779
|
+
C: 2,
|
780
|
+
D: 3,
|
781
|
+
E: 4,
|
782
|
+
F: 5,
|
783
|
+
G: 6,
|
784
|
+
H: 7,
|
785
|
+
I: 8,
|
786
|
+
J: 9,
|
787
|
+
K: 10,
|
788
|
+
L: 11,
|
789
|
+
M: 12,
|
790
|
+
N: 13,
|
791
|
+
O: 14,
|
792
|
+
P: 15,
|
793
|
+
Q: 16,
|
794
|
+
R: 17,
|
795
|
+
S: 18,
|
796
|
+
T: 19,
|
797
|
+
U: 20,
|
798
|
+
V: 21,
|
799
|
+
W: 22,
|
800
|
+
X: 23,
|
801
|
+
Y: 24,
|
802
|
+
Z: 25
|
803
803
|
}
|
804
804
|
end
|
@@ -2,125 +2,125 @@ module Passgen
|
|
2
2
|
class StrengthAnalyzer
|
3
3
|
MIN_LENGTH = 8
|
4
4
|
attr_reader :password, :score, :complexity, :errors
|
5
|
-
|
5
|
+
|
6
6
|
def initialize(pw)
|
7
|
-
@password
|
8
|
-
@score
|
7
|
+
@password = pw
|
8
|
+
@score = 0
|
9
9
|
@complexity = "Invalid"
|
10
|
-
@errors
|
10
|
+
@errors = []
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def self.analyze(pw)
|
14
14
|
sa = StrengthAnalyzer.new(pw)
|
15
15
|
sa.analyze
|
16
16
|
sa
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def analyze
|
20
20
|
return self unless check_minimum_requirements
|
21
|
-
|
22
|
-
nScore
|
23
|
-
nLength
|
24
|
-
nAlphaUC
|
25
|
-
nAlphaLC
|
26
|
-
nNumber
|
27
|
-
nSymbol
|
28
|
-
nMidChar
|
29
|
-
nRequirements
|
30
|
-
nAlphasOnly
|
31
|
-
nNumbersOnly
|
32
|
-
nUnqChar
|
33
|
-
nRepChar
|
34
|
-
nRepInc
|
35
|
-
nConsecAlphaUC
|
36
|
-
nConsecAlphaLC
|
37
|
-
nConsecNumber
|
38
|
-
nConsecSymbol
|
39
|
-
nConsecCharType
|
40
|
-
nSeqAlpha
|
41
|
-
nSeqNumber
|
42
|
-
nSeqSymbol
|
43
|
-
nSeqChar
|
44
|
-
nReqChar
|
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
45
|
nMultConsecCharType = 0
|
46
|
-
nMultRepChar
|
47
|
-
nMultConsecSymbol
|
48
|
-
nMultMidChar
|
49
|
-
nMultRequirements
|
50
|
-
nMultConsecAlphaUC
|
51
|
-
nMultConsecAlphaLC
|
52
|
-
nMultConsecNumber
|
53
|
-
nReqCharType
|
54
|
-
nMultAlphaUC
|
55
|
-
nMultAlphaLC
|
56
|
-
nMultSeqAlpha
|
57
|
-
nMultSeqNumber
|
58
|
-
nMultSeqSymbol
|
59
|
-
nMultLength
|
60
|
-
nMultNumber
|
61
|
-
nMultSymbol
|
62
|
-
nTmpAlphaUC
|
63
|
-
nTmpAlphaLC
|
64
|
-
nTmpNumber
|
65
|
-
nTmpSymbol
|
66
|
-
sAlphas
|
67
|
-
sNumerics
|
68
|
-
sSymbols
|
69
|
-
sComplexity
|
70
|
-
sStandards
|
71
|
-
nMinPwdLen
|
72
|
-
|
73
|
-
nScore
|
74
|
-
nLength
|
75
|
-
arrPwd
|
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
76
|
arrPwdLen = arrPwd.length
|
77
|
-
|
77
|
+
|
78
78
|
# Loop through password to check for Symbol, Numeric, Lowercase and Uppercase pattern matches
|
79
79
|
arrPwdLen.times do |a|
|
80
80
|
if /[A-Z]/.match(arrPwd[a])
|
81
|
-
if
|
81
|
+
if nTmpAlphaUC != ""
|
82
82
|
if (nTmpAlphaUC + 1) == a
|
83
|
-
nConsecAlphaUC
|
83
|
+
nConsecAlphaUC += 1
|
84
84
|
nConsecCharType += 1
|
85
85
|
end
|
86
86
|
end
|
87
87
|
nTmpAlphaUC = a
|
88
|
-
nAlphaUC
|
88
|
+
nAlphaUC += 1
|
89
89
|
elsif /[a-z]/.match(arrPwd[a])
|
90
90
|
if nTmpAlphaLC != ""
|
91
91
|
if (nTmpAlphaLC + 1) == a
|
92
|
-
nConsecAlphaLC
|
92
|
+
nConsecAlphaLC += 1
|
93
93
|
nConsecCharType += 1
|
94
94
|
end
|
95
95
|
end
|
96
96
|
nTmpAlphaLC = a
|
97
|
-
nAlphaLC
|
97
|
+
nAlphaLC += 1
|
98
98
|
elsif /[0-9]/.match(arrPwd[a])
|
99
|
-
if
|
99
|
+
if a > 0 && a < (arrPwdLen - 1)
|
100
100
|
nMidChar += 1
|
101
101
|
end
|
102
102
|
if nTmpNumber != ""
|
103
|
-
if (
|
104
|
-
nConsecNumber
|
103
|
+
if (nTmpNumber + 1) == a
|
104
|
+
nConsecNumber += 1
|
105
105
|
nConsecCharType += 1
|
106
106
|
end
|
107
107
|
end
|
108
108
|
nTmpNumber = a
|
109
|
-
nNumber
|
110
|
-
elsif /[^a-zA-Z0-9_]/.match(arrPwd[a])
|
109
|
+
nNumber += 1
|
110
|
+
elsif /[^a-zA-Z0-9_]/.match(arrPwd[a])
|
111
111
|
if a > 0 && a < (arrPwdLen - 1)
|
112
112
|
nMidChar += 1
|
113
113
|
end
|
114
114
|
if nTmpSymbol != ""
|
115
115
|
if (nTmpSymbol + 1) == a
|
116
|
-
nConsecSymbol
|
116
|
+
nConsecSymbol += 1
|
117
117
|
nConsecCharType += 1
|
118
118
|
end
|
119
119
|
end
|
120
|
-
nTmpSymbol = a
|
121
|
-
nSymbol += 1
|
120
|
+
nTmpSymbol = a
|
121
|
+
nSymbol += 1
|
122
122
|
end
|
123
|
-
|
123
|
+
|
124
124
|
# Internal loop through password to check for repeat characters
|
125
125
|
bCharExists = false
|
126
126
|
arrPwdLen.times do |b|
|
@@ -130,75 +130,75 @@ module Passgen
|
|
130
130
|
# Deduction is incremented each time a new match is discovered
|
131
131
|
# Deduction amount is based on total password length divided by the
|
132
132
|
# difference of distance between currently selected match
|
133
|
-
nRepInc += (arrPwdLen/(b-a)).abs
|
133
|
+
nRepInc += (arrPwdLen / (b - a)).abs
|
134
134
|
end
|
135
135
|
end
|
136
|
-
if bCharExists
|
137
|
-
nRepChar += 1
|
138
|
-
nUnqChar = arrPwdLen - nRepChar
|
139
|
-
nRepInc = (nUnqChar > 0) ? (nRepInc/nUnqChar).ceil : nRepInc.ceil
|
136
|
+
if bCharExists
|
137
|
+
nRepChar += 1
|
138
|
+
nUnqChar = arrPwdLen - nRepChar
|
139
|
+
nRepInc = (nUnqChar > 0) ? (nRepInc / nUnqChar).ceil : nRepInc.ceil
|
140
140
|
end
|
141
141
|
end
|
142
|
-
|
142
|
+
|
143
143
|
# Check for sequential alpha string patterns (forward and reverse)
|
144
144
|
(sAlphas.size - 3).times do |s|
|
145
|
-
sFwd = sAlphas[s...s+3]
|
145
|
+
sFwd = sAlphas[s...s + 3]
|
146
146
|
sRev = sFwd.reverse
|
147
147
|
if @password.downcase.index(sFwd) || @password.downcase.index(sRev)
|
148
148
|
nSeqAlpha += 1
|
149
|
-
nSeqChar
|
149
|
+
nSeqChar += 1
|
150
150
|
end
|
151
151
|
end
|
152
|
-
|
152
|
+
|
153
153
|
# Check for sequential numeric string patterns (forward and reverse)
|
154
154
|
(sNumerics.size - 3).times do |s|
|
155
|
-
sFwd = sNumerics[s...s+3]
|
155
|
+
sFwd = sNumerics[s...s + 3]
|
156
156
|
sRev = sFwd.reverse
|
157
157
|
if @password.downcase.index(sFwd) || @password.downcase.index(sRev)
|
158
158
|
nSeqNumber += 1
|
159
|
-
nSeqChar
|
159
|
+
nSeqChar += 1
|
160
160
|
end
|
161
161
|
end
|
162
|
-
|
162
|
+
|
163
163
|
# Check for sequential symbol string patterns (forward and reverse)
|
164
164
|
(sSymbols.size - 3).times do |s|
|
165
|
-
sFwd = sSymbols[s...s+3]
|
165
|
+
sFwd = sSymbols[s...s + 3]
|
166
166
|
sRev = sFwd.reverse
|
167
167
|
if @password.downcase.index(sFwd) || @password.downcase.index(sRev)
|
168
168
|
nSeqSymbol += 1
|
169
|
-
nSeqChar
|
169
|
+
nSeqChar += 1
|
170
170
|
end
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
# Modify overall score value based on usage vs requirements
|
174
174
|
if nAlphaUC > 0 && nAlphaUC < nLength
|
175
175
|
nScore += (nLength - nAlphaUC) * 2
|
176
176
|
end
|
177
177
|
|
178
|
-
if nAlphaLC > 0 && nAlphaLC < nLength
|
178
|
+
if nAlphaLC > 0 && nAlphaLC < nLength
|
179
179
|
nScore += (nLength - nAlphaLC) * 2
|
180
180
|
end
|
181
181
|
|
182
|
-
if
|
182
|
+
if nNumber > 0 && nNumber < nLength
|
183
183
|
nScore += nNumber * nMultNumber
|
184
184
|
end
|
185
185
|
|
186
|
-
if nSymbol > 0
|
186
|
+
if nSymbol > 0
|
187
187
|
nScore += nSymbol * nMultSymbol
|
188
188
|
end
|
189
189
|
|
190
190
|
if nMidChar > 0
|
191
191
|
nScore += nMidChar * nMultMidChar
|
192
192
|
end
|
193
|
-
|
193
|
+
|
194
194
|
# Point deductions for poor practices
|
195
195
|
if (nAlphaLC > 0 || nAlphaUC > 0) && nSymbol == 0 && nNumber == 0 # Only Letters
|
196
|
-
nScore
|
196
|
+
nScore -= nLength
|
197
197
|
nAlphasOnly = nLength
|
198
198
|
end
|
199
199
|
|
200
200
|
if nAlphaLC === 0 && nAlphaUC === 0 && nSymbol === 0 && nNumber > 0 # Only Numbers
|
201
|
-
nScore
|
201
|
+
nScore -= nLength
|
202
202
|
nNumbersOnly = nLength
|
203
203
|
end
|
204
204
|
|
@@ -231,9 +231,9 @@ module Passgen
|
|
231
231
|
end
|
232
232
|
|
233
233
|
# Determine if mandatory requirements have been met and set image indicators accordingly
|
234
|
-
arrChars
|
234
|
+
arrChars = [nLength, nAlphaUC, nAlphaLC, nNumber, nSymbol]
|
235
235
|
arrCharsIds = ["nLength", "nAlphaUC", "nAlphaLC", "nNumber", "nSymbol"]
|
236
|
-
arrCharsLen = arrChars.length
|
236
|
+
arrCharsLen = arrChars.length
|
237
237
|
arrCharsLen.times do |c|
|
238
238
|
minVal = arrCharsIds[c] == "nLength" ? MIN_LENGTH - 1 : 0
|
239
239
|
if arrChars[c] == (minVal + 1)
|
@@ -243,34 +243,35 @@ module Passgen
|
|
243
243
|
end
|
244
244
|
end
|
245
245
|
nRequirements = nReqChar
|
246
|
-
nMinReqChars
|
246
|
+
nMinReqChars = @password.length >= nMinPwdLen ? 3 : 4
|
247
247
|
if nRequirements > nMinReqChars # One or more required characters exist
|
248
|
-
nScore += (nRequirements * 2)
|
248
|
+
nScore += (nRequirements * 2)
|
249
249
|
end
|
250
|
-
|
250
|
+
|
251
251
|
# Determine complexity based on overall score
|
252
|
-
if
|
252
|
+
if nScore > 100
|
253
253
|
nScore = 100
|
254
|
-
elsif
|
254
|
+
elsif nScore < 0
|
255
255
|
nScore = 0
|
256
256
|
end
|
257
257
|
@complexity = case nScore
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
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
270
|
@score = nScore
|
271
271
|
end
|
272
|
-
|
272
|
+
|
273
273
|
private
|
274
|
+
|
274
275
|
def check_minimum_requirements
|
275
276
|
if @password.length < MIN_LENGTH
|
276
277
|
@errors << "Password must be at least #{MIN_LENGTH} characters long"
|
data/passgen.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{passgen}
|
5
|
-
s.version = "1.
|
5
|
+
s.version = "1.2.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Erik Lindblad (CrypticE)", "Ronald Brachetti(rbecher)", "Ken Spencer (IotaSpencer)"]
|