strong_password 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21b8b80e1e1a71360c0227964a49eb4157ae65e6
|
4
|
+
data.tar.gz: b5165bce41a88de6ae57ba044c58e09b50059813
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 139743a7ca79896208779198592a532430f3f13aa62c47e6b5e29e62fa1a370d9fb47881aeed74fe29c71979c5b429220668b9e70b6069db9e9c9cb0d7d9029b
|
7
|
+
data.tar.gz: 0aaa1da057d4174f92d0456581d5bc883fca921db535d11a134e6f64ad247f7f9ace21fc91c1fa7ddb94ab661b8410b522aff74f3e5250ea447d55df7ada10cb
|
data/README.md
CHANGED
@@ -15,7 +15,7 @@ NOTE: StrongPassword requires the use of Ruby 2.0. Upgrade if you haven't alrea
|
|
15
15
|
|
16
16
|
Add this line to your application's Gemfile:
|
17
17
|
|
18
|
-
gem 'strong_password'
|
18
|
+
gem 'strong_password', '~> 0.0.2'
|
19
19
|
|
20
20
|
And then execute:
|
21
21
|
|
@@ -38,7 +38,7 @@ model, it simply has to be an object that includes `ActiveModel::Validations`.
|
|
38
38
|
```ruby
|
39
39
|
class User
|
40
40
|
include ActiveModel::Validations
|
41
|
-
|
41
|
+
|
42
42
|
# Basic usage. Defaults to minimum entropy of 18 and no dictionary checking
|
43
43
|
validates :password, password_strength: true
|
44
44
|
# Minimum entropy can be specified as min_entropy
|
@@ -53,7 +53,7 @@ class User
|
|
53
53
|
validates :password, password_strength: {extra_dictionary_words: :my_extra_words, use_dictionary: true}
|
54
54
|
# Alternative way to request password strength validation on a field
|
55
55
|
validates_password_strength :password
|
56
|
-
|
56
|
+
|
57
57
|
# Return an array of words to add to the dictionary we check against.
|
58
58
|
def my_extra_words
|
59
59
|
['extra', 'words', 'here', 'too']
|
@@ -79,15 +79,15 @@ password is strong or not. You can also directly access the entropy calculations
|
|
79
79
|
|
80
80
|
```text
|
81
81
|
2.0.0p0 :001 > checker = StrongPassword::StrengthChecker.new('password')
|
82
|
-
=> #<StrongPassword::StrengthChecker:0x007fcd7c939b48 @base_password="password">
|
82
|
+
=> #<StrongPassword::StrengthChecker:0x007fcd7c939b48 @base_password="password">
|
83
83
|
2.0.0p0 :002 > checker.is_strong?
|
84
|
-
=> false
|
84
|
+
=> false
|
85
85
|
2.0.0p0 :003 > checker.is_weak?
|
86
|
-
=> true
|
86
|
+
=> true
|
87
87
|
2.0.0p0 :004 > checker.is_strong?(min_entropy: 2)
|
88
|
-
=> true
|
88
|
+
=> true
|
89
89
|
2.0.0p0 :005 > checker.calculate_entropy
|
90
|
-
=> 15.5
|
90
|
+
=> 15.5
|
91
91
|
2.0.0p0 :006 > checker.calculate_entropy(use_dictionary: true)
|
92
92
|
=> 2
|
93
93
|
```
|
@@ -145,7 +145,7 @@ disallowed by the strength checker.
|
|
145
145
|
the 500 most common passwords. That also means it's not a true "dictionary" check...
|
146
146
|
2. Add a common password adjuster that basically works like the existing DictionaryAdjuster but does
|
147
147
|
not stop at the first found word. Stopping at the first word make sense if you have a 300,000 word
|
148
|
-
dictionary of the English language but not so much when you're only talking about the 500 most
|
148
|
+
dictionary of the English language but not so much when you're only talking about the 500 most
|
149
149
|
common passwords.
|
150
150
|
|
151
151
|
## Contributing
|
@@ -46,23 +46,23 @@ module StrongPassword
|
|
46
46
|
"blondes","enjoy","girl","apollo","parker","qwert","time","sydney","women","voodoo","magnum",
|
47
47
|
"juice","abgrtyu","777777","dreams","maxwell","music","rush2112","russia","scorpion","rebecca",
|
48
48
|
"tester","mistress","phantom","billy","6666","albert"]
|
49
|
-
|
49
|
+
|
50
50
|
attr_reader :base_password
|
51
|
-
|
51
|
+
|
52
52
|
def initialize(password)
|
53
53
|
@base_password = password.dup.downcase
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
def is_strong?(min_entropy: 18, min_word_length: 4, extra_dictionary_words: [])
|
57
57
|
adjusted_entropy(entropy_threshhold: min_entropy,
|
58
58
|
min_word_length: min_word_length,
|
59
59
|
extra_dictionary_words: extra_dictionary_words) >= min_entropy
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
def is_weak?(min_entropy: 18, min_word_length: 4, extra_dictionary_words: [])
|
63
63
|
!is_strong?(min_entropy: min_entropy, min_word_length: min_word_length, extra_dictionary_words: extra_dictionary_words)
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
# Returns the minimum entropy for the passwords dictionary adjustments.
|
67
67
|
# If a threshhold is specified we will bail early to avoid unnecessary
|
68
68
|
# processing.
|
@@ -82,13 +82,13 @@ module StrongPassword
|
|
82
82
|
x2 = next_non_word ? next_non_word : variant.length + 1
|
83
83
|
found = false
|
84
84
|
while !found && (x2 - x >= min_word_length)
|
85
|
-
word = variant[x, min_word_length]
|
85
|
+
word = Regexp.quote(variant[x, min_word_length])
|
86
86
|
word += variant[(x + min_word_length)..x2].reverse.chars.inject('') {|memo, c| "(#{Regexp.quote(c)}#{memo})?"} if (x + min_word_length) <= y
|
87
87
|
results = dictionary_words.grep(/\b#{word}\b/)
|
88
88
|
if results.empty?
|
89
89
|
x = x + 1
|
90
90
|
numbits = EntropyCalculator.calculate('*' * x)
|
91
|
-
# If we have enough entropy at this length on a fully masked password with
|
91
|
+
# If we have enough entropy at this length on a fully masked password with
|
92
92
|
# duplicates weakened then we can just bail on this variant
|
93
93
|
found = true if entropy_threshhold >= 0 && numbits >= entropy_threshhold
|
94
94
|
else
|
@@ -9,13 +9,13 @@ module StrongPassword
|
|
9
9
|
subject.stub(adjusted_entropy: 18)
|
10
10
|
expect(subject.is_strong?).to be_true
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
it 'returns false if the calculated entropy is < the minimum' do
|
14
14
|
subject.stub(adjusted_entropy: 17)
|
15
15
|
expect(subject.is_strong?).to be_false
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
describe '#is_weak?' do
|
20
20
|
let(:subject) { DictionaryAdjuster.new('password') }
|
21
21
|
|
@@ -24,17 +24,17 @@ module StrongPassword
|
|
24
24
|
expect(subject.is_weak?).to be_false
|
25
25
|
end
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
describe '#adjusted_entropy' do
|
29
29
|
before(:each) { NistBonusBits.stub(bonus_bits: 0)}
|
30
|
-
|
30
|
+
|
31
31
|
it 'checks against all variants of a given password' do
|
32
32
|
password = 'password'
|
33
33
|
adjuster = DictionaryAdjuster.new(password)
|
34
34
|
PasswordVariants.should_receive(:all_variants).with(password).and_return([])
|
35
35
|
adjuster.adjusted_entropy
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
{
|
39
39
|
'bnm,./' => 14, # Qwerty string should not get adjusted by dictionary adjuster
|
40
40
|
'h#e0zbPas' => 19.5, # Random string should not get adjusted by dictionary adjuster
|
@@ -42,19 +42,21 @@ module StrongPassword
|
|
42
42
|
'E_!3password' => 11.5, # Adjusts common dictionary words regardless of placement
|
43
43
|
'h#e0zbPas 32e2i81 password' => 31.3125, # Even if there are multiple words
|
44
44
|
'123456' => 4, # Even if they are also qwerty strings
|
45
|
-
'password123456' => 16 # But only drops the first matched word
|
45
|
+
'password123456' => 16, # But only drops the first matched word
|
46
|
+
'asdf)asdf' => 14, # Doesn't break with parens
|
47
|
+
'asdf[]asdf' => 16 # Doesn't break with []s
|
46
48
|
}.each do |password, bits|
|
47
49
|
it "returns #{bits} for '#{password}'" do
|
48
50
|
expect(DictionaryAdjuster.new(password).adjusted_entropy).to eq(bits)
|
49
51
|
end
|
50
52
|
end
|
51
|
-
|
53
|
+
|
52
54
|
it 'allows extra words to be provided as an array' do
|
53
55
|
password = 'mcmanus'
|
54
56
|
base_entropy = EntropyCalculator.calculate(password)
|
55
57
|
expect(DictionaryAdjuster.new(password).adjusted_entropy(extra_dictionary_words: ['mcmanus'])).not_to eq(base_entropy)
|
56
58
|
end
|
57
|
-
|
59
|
+
|
58
60
|
it 'allows minimum word length to be adjusted' do
|
59
61
|
password = '6969'
|
60
62
|
base_entropy = DictionaryAdjuster.new(password).adjusted_entropy
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: strong_password
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian McManus
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
105
|
version: '0'
|
106
106
|
requirements: []
|
107
107
|
rubyforge_project:
|
108
|
-
rubygems_version: 2.0.
|
108
|
+
rubygems_version: 2.0.3
|
109
109
|
signing_key:
|
110
110
|
specification_version: 4
|
111
111
|
summary: StrongPassword adds a class to check password strength and a validator for
|