strong_password 0.0.4 → 0.0.5
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 +4 -4
- data/.travis.yml +17 -0
- data/Gemfile +3 -2
- data/README.md +17 -7
- data/Rakefile +5 -0
- data/lib/strong_password.rb +2 -2
- data/lib/strong_password/locale/en.yml +1 -1
- data/lib/strong_password/password_variants.rb +18 -55
- data/lib/strong_password/railtie.rb +1 -1
- data/lib/strong_password/version.rb +1 -1
- data/spec/spec_helper.rb +5 -2
- data/spec/strong_password/dictionary_adjuster_spec.rb +6 -6
- data/spec/strong_password/qwerty_adjuster_spec.rb +7 -7
- data/spec/validation/strength_validator_spec.rb +12 -8
- data/strong_password.gemspec +1 -0
- metadata +28 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21042c15094f1a9a0f960b16435fee882ac7e517
|
4
|
+
data.tar.gz: f4e9cf9c311aa13a7cf591b866d1f43a91c91290
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5be352df9e03643ab21a4c10ba1bdc9561607776faa8974ea59563b43432cfc62a6824d86365811875672a57028c99887df4aee172618f5c0c407d2312ed974
|
7
|
+
data.tar.gz: 67032a9ff38562e8893a9dbd581d55a79531a9b83165029bdbcf05fcf883ab4effd8a8021996c79167fc3d8fc1193d25bfda9b71b2e894c4a31a4a264d244806
|
data/.travis.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.2.3
|
4
|
+
- 2.1.7
|
5
|
+
- ruby-head
|
6
|
+
env:
|
7
|
+
- "RAILS_VERSION=4.2"
|
8
|
+
- "RAILS_VERSION=4.1"
|
9
|
+
- "RAILS_VERSION=4.0"
|
10
|
+
- "RAILS_VERSION=3.2"
|
11
|
+
- "RAILS_VERSION=3.1"
|
12
|
+
- "RAILS_VERSION=3.0"
|
13
|
+
- "RAILS_VERSION=master"
|
14
|
+
matrix:
|
15
|
+
allow_failures:
|
16
|
+
- rvm: ruby-head
|
17
|
+
- env: "RAILS_VERSION=master"
|
data/Gemfile
CHANGED
@@ -2,7 +2,7 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
version = ENV["RAILS_VERSION"] || "
|
5
|
+
version = ENV["RAILS_VERSION"] || "4.2"
|
6
6
|
|
7
7
|
rails = case version
|
8
8
|
when "master"
|
@@ -11,4 +11,5 @@ else
|
|
11
11
|
"~> #{version}.0"
|
12
12
|
end
|
13
13
|
|
14
|
-
gem "rails", rails
|
14
|
+
gem "rails", rails
|
15
|
+
gem "codeclimate-test-reporter", group: :test, require: nil
|
data/README.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
[](https://travis-ci.org/bdmac/strong_password)
|
2
|
+
[](https://codeclimate.com/github/bdmac/strong_password)
|
3
|
+
[](https://codeclimate.com/github/bdmac/strong_password/coverage)
|
4
|
+
|
1
5
|
# StrongPassword
|
2
6
|
|
3
7
|
StrongPassword provides entropy-based password strength checking for your apps.
|
@@ -15,7 +19,7 @@ NOTE: StrongPassword requires the use of Ruby 2.0. Upgrade if you haven't alrea
|
|
15
19
|
|
16
20
|
Add this line to your application's Gemfile:
|
17
21
|
|
18
|
-
gem 'strong_password', '~> 0.0.
|
22
|
+
gem 'strong_password', '~> 0.0.5'
|
19
23
|
|
20
24
|
And then execute:
|
21
25
|
|
@@ -61,15 +65,15 @@ class User
|
|
61
65
|
end
|
62
66
|
```
|
63
67
|
|
64
|
-
The default validation message is "
|
65
|
-
|
68
|
+
The default validation message is "is too weak". Rails will display a field of `:password` having too weak of a password with `full_error_messages` as "Password is too weak". If you would like to customize the error message, you can override it in your locale file by setting a value for this key:
|
69
|
+
|
66
70
|
|
67
71
|
```yml
|
68
72
|
en:
|
69
73
|
errors:
|
70
74
|
messages:
|
71
75
|
password:
|
72
|
-
password_strength: "
|
76
|
+
password_strength: "is a terrible password, try again!"
|
73
77
|
```
|
74
78
|
|
75
79
|
### Standalone
|
@@ -148,10 +152,16 @@ disallowed by the strength checker.
|
|
148
152
|
dictionary of the English language but not so much when you're only talking about the 500 most
|
149
153
|
common passwords.
|
150
154
|
|
155
|
+
## Running the tests
|
156
|
+
|
157
|
+
To run the tests, install the gems with `bundle install`. Then run `rake`.
|
158
|
+
|
151
159
|
## Contributing
|
152
160
|
|
153
161
|
1. Fork it
|
154
162
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
155
|
-
3.
|
156
|
-
4.
|
157
|
-
5.
|
163
|
+
3. Make your changes
|
164
|
+
4. Test the changes and make sure existing tests pass
|
165
|
+
5. Commit your changes (`git commit -am 'Add some feature'`)
|
166
|
+
6. Push to the branch (`git push origin my-new-feature`)
|
167
|
+
7. Create new Pull Request
|
data/Rakefile
CHANGED
data/lib/strong_password.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'active_model/validations'
|
1
|
+
require 'active_model/validations' if defined?(ActiveModel)
|
2
2
|
|
3
3
|
require 'strong_password/version'
|
4
4
|
require 'strong_password/nist_bonus_bits'
|
@@ -12,4 +12,4 @@ require 'active_model/validations/password_strength_validator' if defined?(Activ
|
|
12
12
|
module StrongPassword
|
13
13
|
end
|
14
14
|
|
15
|
-
I18n.load_path << File.dirname(__FILE__) + '/strong_password/locale/en.yml' if defined?(I18n)
|
15
|
+
I18n.load_path << File.dirname(__FILE__) + '/strong_password/locale/en.yml' if defined?(I18n)
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module StrongPassword
|
2
2
|
module PasswordVariants
|
3
|
-
|
3
|
+
LEET_SPEAK_REGEXP = /[\@\!\$1234567890]/
|
4
|
+
|
5
|
+
LEET_SPEAK = {
|
4
6
|
"@" => "a",
|
5
7
|
"!" => "i",
|
6
8
|
"$" => "s",
|
@@ -16,37 +18,9 @@ module StrongPassword
|
|
16
18
|
"0" => "o"
|
17
19
|
}
|
18
20
|
|
19
|
-
|
20
|
-
"@" => "a",
|
21
|
-
"!" => "i",
|
22
|
-
"$" => "s",
|
23
|
-
"1" => "l",
|
24
|
-
"2" => "z",
|
25
|
-
"3" => "e",
|
26
|
-
"4" => "a",
|
27
|
-
"5" => "s",
|
28
|
-
"6" => "g",
|
29
|
-
"7" => "t",
|
30
|
-
"8" => "b",
|
31
|
-
"9" => "g",
|
32
|
-
"0" => "o"
|
33
|
-
}
|
21
|
+
LEET_SPEAK_ALT = LEET_SPEAK.dup.merge!("1" => "l")
|
34
22
|
|
35
|
-
|
36
|
-
"z" => "",
|
37
|
-
"x" => "",
|
38
|
-
"c" => "",
|
39
|
-
"v" => "",
|
40
|
-
"b" => "",
|
41
|
-
"n" => "",
|
42
|
-
"m" => "",
|
43
|
-
"," => "",
|
44
|
-
"." => "",
|
45
|
-
"/" => "",
|
46
|
-
"<" => "",
|
47
|
-
">" => "",
|
48
|
-
"?" => ""
|
49
|
-
}
|
23
|
+
BOTTOM_ROW_REGEXP = /[zxcvbnm,\.\/\<\>\?]/
|
50
24
|
|
51
25
|
KEYBOARDMAP_DOWNRIGHT = {
|
52
26
|
"a" => "z",
|
@@ -105,7 +79,7 @@ module StrongPassword
|
|
105
79
|
"p" => "l",
|
106
80
|
"-" => "p"
|
107
81
|
}
|
108
|
-
|
82
|
+
|
109
83
|
# Returns all variants of a given password including the password itself
|
110
84
|
def self.all_variants(password)
|
111
85
|
passwords = [password.downcase]
|
@@ -117,37 +91,26 @@ module StrongPassword
|
|
117
91
|
# Returns all keyboard shifted variants of a given password
|
118
92
|
def self.keyboard_shift_variants(password)
|
119
93
|
password = password.downcase
|
120
|
-
variants = []
|
121
|
-
|
122
|
-
if (password == password.tr(KEYBOARDMAP_DOWN_NOSHIFT.keys.join, KEYBOARDMAP_DOWN_NOSHIFT.values.join))
|
123
|
-
variant = password.tr(KEYBOARDMAP_DOWNRIGHT.keys.join, KEYBOARDMAP_DOWNRIGHT.values.join)
|
124
|
-
variants << variant
|
125
|
-
variants << variant.reverse
|
126
94
|
|
127
|
-
|
128
|
-
|
129
|
-
variants << variant.reverse
|
130
|
-
end
|
131
|
-
variants
|
95
|
+
return [] if password.match(BOTTOM_ROW_REGEXP)
|
96
|
+
variants(password, KEYBOARDMAP_DOWNRIGHT, KEYBOARDMAP_DOWNLEFT)
|
132
97
|
end
|
133
98
|
|
134
99
|
# Returns all leet speak variants of a given password
|
135
100
|
def self.leet_speak_variants(password)
|
136
101
|
password = password.downcase
|
137
|
-
variants = []
|
138
102
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
103
|
+
return [] if !password.match(LEET_SPEAK_REGEXP)
|
104
|
+
variants(password, LEET_SPEAK, LEET_SPEAK_ALT)
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
144
108
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
109
|
+
def self.variants(password, *mappings)
|
110
|
+
mappings.flat_map do |map|
|
111
|
+
variant = password.tr(map.keys.join, map.values.join)
|
112
|
+
[variant, variant.reverse]
|
149
113
|
end
|
150
|
-
variants
|
151
114
|
end
|
152
115
|
end
|
153
|
-
end
|
116
|
+
end
|
@@ -1 +1 @@
|
|
1
|
-
require 'rails/railtie'
|
1
|
+
require 'rails/railtie' if defined?(Rails)
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
require "codeclimate-test-reporter"
|
2
|
+
CodeClimate::TestReporter.start
|
1
3
|
require 'bundler/setup'
|
2
|
-
require '
|
4
|
+
require 'pry'
|
3
5
|
require 'active_model'
|
6
|
+
require 'strong_password'
|
4
7
|
|
5
8
|
RSpec.configure do |config|
|
6
9
|
config.expect_with(:rspec) {|c| c.syntax = :expect}
|
7
10
|
config.order = :random
|
8
|
-
end
|
11
|
+
end
|
@@ -7,12 +7,12 @@ module StrongPassword
|
|
7
7
|
|
8
8
|
it 'returns true if the calculated entropy is >= the minimum' do
|
9
9
|
subject.stub(adjusted_entropy: 18)
|
10
|
-
expect(subject.is_strong?).to
|
10
|
+
expect(subject.is_strong?).to be_truthy
|
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
|
-
expect(subject.is_strong?).to
|
15
|
+
expect(subject.is_strong?).to be_falsey
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -21,7 +21,7 @@ module StrongPassword
|
|
21
21
|
|
22
22
|
it 'returns the opposite of is_strong?' do
|
23
23
|
subject.stub(is_strong?: true)
|
24
|
-
expect(subject.is_weak?).to
|
24
|
+
expect(subject.is_weak?).to be_falsey
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -52,9 +52,9 @@ module StrongPassword
|
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'allows extra words to be provided as an array' do
|
55
|
-
password = '
|
55
|
+
password = 'administratorWEQ@123'
|
56
56
|
base_entropy = EntropyCalculator.calculate(password)
|
57
|
-
expect(DictionaryAdjuster.new(password).adjusted_entropy(extra_dictionary_words: ['
|
57
|
+
expect(DictionaryAdjuster.new(password).adjusted_entropy(extra_dictionary_words: ['administrator'])).not_to eq(base_entropy)
|
58
58
|
end
|
59
59
|
|
60
60
|
it 'allows minimum word length to be adjusted' do
|
@@ -65,4 +65,4 @@ module StrongPassword
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
|
-
end
|
68
|
+
end
|
@@ -7,24 +7,24 @@ module StrongPassword
|
|
7
7
|
|
8
8
|
it 'returns true if the calculated entropy is >= the minimum' do
|
9
9
|
subject.stub(adjusted_entropy: 18)
|
10
|
-
expect(subject.is_strong?).to
|
10
|
+
expect(subject.is_strong?).to be_truthy
|
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
|
-
expect(subject.is_strong?).to
|
15
|
+
expect(subject.is_strong?).to be_falsey
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
describe '#is_weak?' do
|
20
20
|
let(:subject) { QwertyAdjuster.new('password') }
|
21
21
|
|
22
22
|
it 'returns the opposite of is_strong?' do
|
23
23
|
subject.stub(is_strong?: true)
|
24
|
-
expect(subject.is_weak?).to
|
24
|
+
expect(subject.is_weak?).to be_falsey
|
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
|
{
|
@@ -42,4 +42,4 @@ module StrongPassword
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
45
|
-
end
|
45
|
+
end
|
@@ -18,7 +18,7 @@ class TestStrengthStrongEntropy < User
|
|
18
18
|
end
|
19
19
|
|
20
20
|
class TestStrengthExtraWords < User
|
21
|
-
validates :password, password_strength: {extra_dictionary_words: ['
|
21
|
+
validates :password, password_strength: {extra_dictionary_words: ['administrator'], use_dictionary: true}
|
22
22
|
end
|
23
23
|
|
24
24
|
class TestBaseStrengthAlternative < User
|
@@ -47,7 +47,7 @@ module ActiveModel
|
|
47
47
|
it "adds errors when password is '#{password}'" do
|
48
48
|
base_strength.password = password
|
49
49
|
base_strength.valid?
|
50
|
-
expect(base_strength.errors[:password]).to eq(["
|
50
|
+
expect(base_strength.errors[:password]).to eq(["is too weak"])
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -79,7 +79,7 @@ module ActiveModel
|
|
79
79
|
it "adds errors when password is '#{password}'" do
|
80
80
|
alternative_usage.password = password
|
81
81
|
alternative_usage.valid?
|
82
|
-
expect(alternative_usage.errors[:password]).to eq(["
|
82
|
+
expect(alternative_usage.errors[:password]).to eq(["is too weak"])
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
@@ -129,7 +129,7 @@ module ActiveModel
|
|
129
129
|
it "'#{password}' should be invalid with increased entropy requirement" do
|
130
130
|
strong_entropy.password = password
|
131
131
|
strong_entropy.valid?
|
132
|
-
expect(strong_entropy.errors[:password]).to eq(["
|
132
|
+
expect(strong_entropy.errors[:password]).to eq(["is too weak"])
|
133
133
|
end
|
134
134
|
end
|
135
135
|
end
|
@@ -138,14 +138,18 @@ module ActiveModel
|
|
138
138
|
|
139
139
|
describe 'extra words' do
|
140
140
|
it 'allows extra words to be specified as an option to the validation' do
|
141
|
-
password = '
|
141
|
+
password = 'administratorWEQ@123'
|
142
|
+
# Validate that without 'administrator' added to extra_dictionary_words
|
143
|
+
# this password is considered strong
|
142
144
|
weak_entropy.password = password
|
143
|
-
expect(weak_entropy.valid?).to
|
145
|
+
expect(weak_entropy.valid?).to be_truthy
|
146
|
+
# Now check that with 'administrator' added to extra_dictionary_words
|
147
|
+
# in our model, the same password is considered weak.
|
144
148
|
extra_words.password = password
|
145
|
-
expect(extra_words.valid?).to
|
149
|
+
expect(extra_words.valid?).to be_falsey
|
146
150
|
end
|
147
151
|
end
|
148
152
|
end
|
149
153
|
end
|
150
154
|
end
|
151
|
-
end
|
155
|
+
end
|
data/strong_password.gemspec
CHANGED
metadata
CHANGED
@@ -1,57 +1,71 @@
|
|
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.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian McManus
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.3'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '2.12'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '2.12'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
description: Entropy-based password strength checking for Ruby and ActiveModel
|
56
70
|
email:
|
57
71
|
- bdmac97@gmail.com
|
@@ -59,7 +73,8 @@ executables: []
|
|
59
73
|
extensions: []
|
60
74
|
extra_rdoc_files: []
|
61
75
|
files:
|
62
|
-
- .gitignore
|
76
|
+
- ".gitignore"
|
77
|
+
- ".travis.yml"
|
63
78
|
- CHANGELOG
|
64
79
|
- Gemfile
|
65
80
|
- LICENSE.txt
|
@@ -95,17 +110,17 @@ require_paths:
|
|
95
110
|
- lib
|
96
111
|
required_ruby_version: !ruby/object:Gem::Requirement
|
97
112
|
requirements:
|
98
|
-
- -
|
113
|
+
- - ">="
|
99
114
|
- !ruby/object:Gem::Version
|
100
115
|
version: '0'
|
101
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
117
|
requirements:
|
103
|
-
- -
|
118
|
+
- - ">="
|
104
119
|
- !ruby/object:Gem::Version
|
105
120
|
version: '0'
|
106
121
|
requirements: []
|
107
122
|
rubyforge_project:
|
108
|
-
rubygems_version: 2.
|
123
|
+
rubygems_version: 2.4.5
|
109
124
|
signing_key:
|
110
125
|
specification_version: 4
|
111
126
|
summary: StrongPassword adds a class to check password strength and a validator for
|
@@ -119,3 +134,4 @@ test_files:
|
|
119
134
|
- spec/strong_password/qwerty_adjuster_spec.rb
|
120
135
|
- spec/strong_password/strength_checker_spec.rb
|
121
136
|
- spec/validation/strength_validator_spec.rb
|
137
|
+
has_rdoc:
|