strong_password 0.0.6 → 0.0.8

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
  SHA256:
3
- metadata.gz: 0506c07961d8cf54ee30542579493af60a4a508c176f7de7c0131d8082bcdf35
4
- data.tar.gz: 132ea4c4bc8a96f44b687a342f418ef9c183efb696618cf6b6a7f14a3558c590
3
+ metadata.gz: 9a5e366ad0a5a46d9b2dbda6c2b637bfcbc667f4ed8e7b4cd25e64ed75d315bd
4
+ data.tar.gz: 2793f8c780ef37d19a3b5b11ae81adf175fa0f2d6716047830e0d79efbc6891c
5
5
  SHA512:
6
- metadata.gz: 9342ba93d158425cb8623662341f43fda16c33102590c846571767f09aa8def4a34f4d0d03eb150ea468b3f3c2de58a4cdf2f57c29367fbbc402a3e797b4f893
7
- data.tar.gz: 5ba21b3b35527fc07fe5744dc9560e083fe0844a316c88ef22249aeacea0f77ec1b3082a6fb20b4eb6cc7f4cabb63560433023c1c438a73a28e60ec46e64b4aa
6
+ metadata.gz: 6a155d97437572fcaa4b17142f1f0e355128925620dd461525f8480194f6b9c89dc848494d2eb261b9cca15c54cbd452437ad6f2a3f8f4f4ccccbb9bb9955bb9
7
+ data.tar.gz: 63761deb2f831eed7cf7150c17f72e9f64f5d37398ce7ff1a9c253a61404775654fa0f29113af367f43c3cc2471d025f099e15083c06b0ef9c88206fbdd22a42
data/CHANGELOG CHANGED
@@ -1,3 +1,16 @@
1
+ ## v0.0.8
2
+ This release breaks backwards compatibility if you are using the lib components
3
+ directly. If you are using the ActiveModel validations in a Rails project then
4
+ you should be unaffected.
5
+
6
+ The major changes when used directly are that you now initialize the objects
7
+ with the various strength options instead of the password and then provide the
8
+ password to the various methods. The README section on standalone usage has
9
+ been updated to reflect this change.
10
+
11
+ * jacobat - Performance improvements
12
+ * jacksenechal - Updated README
13
+
1
14
  ## v0.0.4
2
15
  * peterkovacs - Increase size of password dictionary
3
16
  * peterkovacs - Swapped in a cleaner, more efficient comparison algorithm
@@ -7,4 +20,4 @@
7
20
 
8
21
  ## v0.0.1
9
22
 
10
- * Initial release
23
+ * Initial release
data/README.md CHANGED
@@ -19,7 +19,7 @@ NOTE: StrongPassword requires the use of Ruby 2.0. Upgrade if you haven't alrea
19
19
 
20
20
  Add this line to your application's Gemfile:
21
21
 
22
- gem 'strong_password', '~> 0.0.6'
22
+ gem 'strong_password', '~> 0.0.8'
23
23
 
24
24
  And then execute:
25
25
 
@@ -82,18 +82,22 @@ StrongPassword can also be used standalone if you need to. There are a few helpe
82
82
  password is strong or not. You can also directly access the entropy calculations if you want.
83
83
 
84
84
  ```text
85
- 2.0.0p0 :001 > checker = StrongPassword::StrengthChecker.new('password')
86
- => #<StrongPassword::StrengthChecker:0x007fcd7c939b48 @base_password="password">
87
- 2.0.0p0 :002 > checker.is_strong?
88
- => false
89
- 2.0.0p0 :003 > checker.is_weak?
90
- => true
91
- 2.0.0p0 :004 > checker.is_strong?(min_entropy: 2)
92
- => true
93
- 2.0.0p0 :005 > checker.calculate_entropy
94
- => 15.5
95
- 2.0.0p0 :006 > checker.calculate_entropy(use_dictionary: true)
96
- => 2
85
+ irb(main):004:0> checker = StrongPassword::StrengthChecker.new
86
+ => #<StrongPassword::StrengthChecker:0x00007f985509db30 @min_entropy=18, @use_dictionary=false, @min_word_length=4, @extra_dictionary_words=[]>
87
+ irb(main):005:0> checker.is_strong?("password")
88
+ => false
89
+ irb(main):006:0> checker.is_weak?("password")
90
+ => true
91
+ irb(main):007:0> checker = StrongPassword::StrengthChecker.new(min_entropy: 2)
92
+ => #<StrongPassword::StrengthChecker:0x00007f9855147bd0 @min_entropy=2, @use_dictionary=false, @min_word_length=4, @extra_dictionary_words=[]>
93
+ irb(main):008:0> checker.calculate_entropy("password")
94
+ => 15.5
95
+ irb(main):009:0> checker.is_strong?("password")
96
+ => true
97
+ irb(main):010:0> checker = StrongPassword::StrengthChecker.new(use_dictionary: true)
98
+ => #<StrongPassword::StrengthChecker:0x00007f98550ee008 @min_entropy=18, @use_dictionary=true, @min_word_length=4, @extra_dictionary_words=[]>
99
+ irb(main):011:0> checker.calculate_entropy("password")
100
+ => 2
97
101
  ```
98
102
 
99
103
  ## Details
@@ -145,11 +149,9 @@ disallowed by the strength checker.
145
149
 
146
150
  ## Todo
147
151
 
148
- 1. Allow the dictionary of common words to be specified by the user. This is currently hard-coded to
149
- the 500 most common passwords. That also means it's not a true "dictionary" check...
150
- 2. Add a common password adjuster that basically works like the existing DictionaryAdjuster but does
152
+ 1. Add a common password adjuster that basically works like the existing DictionaryAdjuster but does
151
153
  not stop at the first found word. Stopping at the first word make sense if you have a 300,000 word
152
- dictionary of the English language but not so much when you're only talking about the 500 most
154
+ dictionary of the English language but not so much when you're only talking about the 10,000 most
153
155
  common passwords.
154
156
 
155
157
  ## Running the tests
@@ -4,8 +4,8 @@ module ActiveModel
4
4
  module Validations
5
5
  class PasswordStrengthValidator < ActiveModel::EachValidator
6
6
  def validate_each(object, attribute, value)
7
- ps = ::StrongPassword::StrengthChecker.new(value.to_s)
8
- unless ps.is_strong?(strength_options(options, object))
7
+ ps = ::StrongPassword::StrengthChecker.new(strength_options(options, object))
8
+ unless ps.is_strong?(value.to_s)
9
9
  object.errors.add(attribute, :'password.password_strength', options.merge(:value => value.to_s))
10
10
  end
11
11
  end
@@ -967,20 +967,20 @@ module StrongPassword
967
967
  hounds honeydew hooters1 hoes howie hevnm4 hugohugo eighty epson evangeli
968
968
  eeeee1 eyphed ).sort_by(&:length).reverse
969
969
 
970
- attr_reader :base_password
970
+ attr_reader :min_entropy, :min_word_length, :extra_dictionary_words
971
971
 
972
- def initialize(password)
973
- @base_password = password.downcase
972
+ def initialize(min_entropy: 18, min_word_length: 4, extra_dictionary_words: [])
973
+ @min_entropy = min_entropy
974
+ @min_word_length = min_word_length
975
+ @extra_dictionary_words = extra_dictionary_words
974
976
  end
975
977
 
976
- def is_strong?(min_entropy: 18, min_word_length: 4, extra_dictionary_words: [])
977
- adjusted_entropy(entropy_threshhold: min_entropy,
978
- min_word_length: min_word_length,
979
- extra_dictionary_words: extra_dictionary_words) >= min_entropy
978
+ def is_strong?(password)
979
+ adjusted_entropy(password) >= min_entropy
980
980
  end
981
981
 
982
- def is_weak?(min_entropy: 18, min_word_length: 4, extra_dictionary_words: [])
983
- !is_strong?(min_entropy: min_entropy, min_word_length: min_word_length, extra_dictionary_words: extra_dictionary_words)
982
+ def is_weak?(password)
983
+ !is_strong?(password)
984
984
  end
985
985
 
986
986
  # Returns the minimum entropy for the passwords dictionary adjustments.
@@ -988,13 +988,17 @@ module StrongPassword
988
988
  # processing.
989
989
  # Note that we only check for the first matching word up to the threshhold if set.
990
990
  # Subsequent matching words are not deductd.
991
- def adjusted_entropy(min_word_length: 4, extra_dictionary_words: [], entropy_threshhold: -1)
992
- dictionary_words = Regexp.union( ( extra_dictionary_words + COMMON_PASSWORDS ).compact.reject{ |i| i.length < min_word_length } )
991
+ def adjusted_entropy(password)
992
+ base_password = password.downcase
993
993
  min_entropy = EntropyCalculator.calculate(base_password)
994
994
  # Process the passwords, while looking for possible matching words in the dictionary.
995
995
  PasswordVariants.all_variants(base_password).inject( min_entropy ) do |min_entropy, variant|
996
996
  [ min_entropy, EntropyCalculator.calculate( variant.sub( dictionary_words, '*' ) ) ].min
997
997
  end
998
998
  end
999
+
1000
+ def dictionary_words
1001
+ @dictionary_words ||= Regexp.union( ( extra_dictionary_words + COMMON_PASSWORDS ).compact.reject{ |i| i.length < min_word_length } )
1002
+ end
999
1003
  end
1000
1004
  end
@@ -17,57 +17,61 @@ module StrongPassword
17
17
  "abcdefghijklmnopqrstuvwxyz"
18
18
  ]
19
19
 
20
- attr_reader :base_password
20
+ attr_reader :min_entropy, :entropy_threshhold
21
21
 
22
- def initialize(password)
23
- @base_password = password.downcase
22
+ def initialize(min_entropy: 18, entropy_threshhold: 0)
23
+ @min_entropy = min_entropy
24
+ @entropy_threshhold = entropy_threshhold
24
25
  end
25
26
 
26
- def is_strong?(min_entropy: 18)
27
- adjusted_entropy(entropy_threshhold: min_entropy) >= min_entropy
27
+ def is_strong?(base_password)
28
+ adjusted_entropy(base_password) >= min_entropy
28
29
  end
29
30
 
30
- def is_weak?(min_entropy: 18)
31
- !is_strong?(min_entropy: min_entropy)
31
+ def is_weak?(base_password)
32
+ !is_strong?(base_password)
32
33
  end
33
34
 
34
35
  # Returns the minimum entropy for the password's qwerty locality
35
36
  # adjustments. If a threshhold is specified we will bail
36
37
  # early to avoid unnecessary processing.
37
- def adjusted_entropy(entropy_threshhold: 0)
38
+ def adjusted_entropy(base_password)
38
39
  revpassword = base_password.reverse
39
40
  min_entropy = [EntropyCalculator.calculate(base_password), EntropyCalculator.calculate(revpassword)].min
40
- QWERTY_STRINGS.each do |qwertystr|
41
- qpassword = mask_qwerty_strings(base_password, qwertystr)
42
- qrevpassword = mask_qwerty_strings(revpassword, qwertystr)
43
- if qpassword != base_password
44
- numbits = EntropyCalculator.calculate(qpassword)
45
- min_entropy = [min_entropy, numbits].min
46
- return min_entropy if min_entropy < entropy_threshhold
47
- end
48
- if qrevpassword != revpassword
49
- numbits = EntropyCalculator.calculate(qrevpassword)
50
- min_entropy = [min_entropy, numbits].min
51
- return min_entropy if min_entropy < entropy_threshhold
52
- end
41
+ qpassword = mask_qwerty_strings(base_password)
42
+ qrevpassword = mask_qwerty_strings(revpassword)
43
+ if qpassword != base_password
44
+ numbits = EntropyCalculator.calculate(qpassword)
45
+ min_entropy = [min_entropy, numbits].min
46
+ return min_entropy if min_entropy < entropy_threshhold
47
+ end
48
+ if qrevpassword != revpassword
49
+ numbits = EntropyCalculator.calculate(qrevpassword)
50
+ min_entropy = [min_entropy, numbits].min
51
+ return min_entropy if min_entropy < entropy_threshhold
53
52
  end
54
53
  min_entropy
55
54
  end
56
55
 
57
56
  private
58
57
 
59
- def mask_qwerty_strings(password, qwerty_string)
60
- masked_password = password
61
- z = 6
62
- begin
58
+ def all_qwerty_strings
59
+ @all_qwerty_strings ||= Regexp.union(QWERTY_STRINGS.flat_map do |qwerty_string|
60
+ gen_qw_strings(qwerty_string)
61
+ end)
62
+ end
63
+
64
+ def gen_qw_strings(qwerty_string)
65
+ 6.downto(3).flat_map do |z|
63
66
  y = qwerty_string.length - z
64
- (0..y).each do |x|
65
- str = qwerty_string[x, z].sub('-', '\\-')
66
- masked_password = masked_password.sub(str, '*')
67
+ (0..y).map do |x|
68
+ qwerty_string[x, z].sub('-', '\\-')
67
69
  end
68
- z = z - 1
69
- end while z > 2
70
- masked_password
70
+ end
71
+ end
72
+
73
+ def mask_qwerty_strings(password)
74
+ password.gsub(all_qwerty_strings, '*')
71
75
  end
72
76
  end
73
77
  end
@@ -4,37 +4,55 @@ module StrongPassword
4
4
  PASSWORD_LIMIT = 1_000
5
5
  EXTRA_WORDS_LIMIT = 1_000
6
6
 
7
- attr_reader :base_password
7
+ attr_reader :min_entropy, :use_dictionary, :min_word_length, :extra_dictionary_words
8
8
 
9
- def initialize(password)
10
- @base_password = password.dup[0...PASSWORD_LIMIT]
9
+ def initialize(min_entropy: BASE_ENTROPY, use_dictionary: false, min_word_length: 4, extra_dictionary_words: [])
10
+ @min_entropy = min_entropy
11
+ @use_dictionary = use_dictionary
12
+ @min_word_length = min_word_length
13
+ @extra_dictionary_words = extra_dictionary_words
11
14
  end
12
15
 
13
- def is_weak?(min_entropy: BASE_ENTROPY, use_dictionary: false, min_word_length: 4, extra_dictionary_words: [])
14
- !is_strong?(min_entropy: min_entropy,
15
- use_dictionary: use_dictionary,
16
- min_word_length: min_word_length,
17
- extra_dictionary_words: extra_dictionary_words)
16
+ def is_weak?(password)
17
+ !is_strong?(password)
18
18
  end
19
19
 
20
- def is_strong?(min_entropy: BASE_ENTROPY, use_dictionary: false, min_word_length: 4, extra_dictionary_words: [])
20
+ def is_strong?(password)
21
+ base_password = password.dup[0...PASSWORD_LIMIT]
21
22
  weak = (EntropyCalculator.calculate(base_password) < min_entropy) ||
22
23
  (EntropyCalculator.calculate(base_password.downcase) < min_entropy) ||
23
- (QwertyAdjuster.new(base_password).is_weak?(min_entropy: min_entropy))
24
+ (qwerty_adjuster.is_weak?(base_password))
24
25
  if !weak && use_dictionary
25
- return DictionaryAdjuster.new(base_password).is_strong?(min_entropy: min_entropy,
26
- min_word_length: min_word_length,
27
- extra_dictionary_words: extra_dictionary_words)
26
+ return dictionary_adjuster.is_strong?(base_password)
28
27
  else
29
28
  return !weak
30
29
  end
31
30
  end
32
31
 
33
- def calculate_entropy(use_dictionary: false, min_word_length: 4, extra_dictionary_words: [])
32
+ def calculate_entropy(password)
33
+ base_password = password.dup[0...PASSWORD_LIMIT]
34
34
  extra_dictionary_words.collect! { |w| w[0...EXTRA_WORDS_LIMIT] }
35
- entropies = [EntropyCalculator.calculate(base_password), EntropyCalculator.calculate(base_password.downcase), QwertyAdjuster.new(base_password).adjusted_entropy]
36
- entropies << DictionaryAdjuster.new(base_password).adjusted_entropy(min_word_length: min_word_length, extra_dictionary_words: extra_dictionary_words) if use_dictionary
35
+ entropies = [
36
+ EntropyCalculator.calculate(base_password),
37
+ EntropyCalculator.calculate(base_password.downcase),
38
+ qwerty_adjuster.adjusted_entropy(base_password)
39
+ ]
40
+ entropies << dictionary_adjuster.adjusted_entropy(base_password) if use_dictionary
37
41
  entropies.min
38
42
  end
43
+
44
+ private
45
+
46
+ def qwerty_adjuster
47
+ @qwerty_adjuster ||= QwertyAdjuster.new(min_entropy: min_entropy)
48
+ end
49
+
50
+ def dictionary_adjuster
51
+ @dictionary_adjuster ||= DictionaryAdjuster.new(
52
+ min_word_length: min_word_length,
53
+ extra_dictionary_words: extra_dictionary_words,
54
+ min_entropy: min_entropy
55
+ )
56
+ end
39
57
  end
40
58
  end
@@ -1,3 +1,3 @@
1
1
  module StrongPassword
2
- VERSION = "0.0.6"
2
+ VERSION = '0.0.8'.freeze
3
3
  end
@@ -3,36 +3,36 @@ require 'spec_helper'
3
3
  module StrongPassword
4
4
  describe DictionaryAdjuster do
5
5
  describe '#is_strong?' do
6
- let(:subject) { DictionaryAdjuster.new('password') }
6
+ let(:subject) { DictionaryAdjuster.new }
7
7
 
8
8
  it 'returns true if the calculated entropy is >= the minimum' do
9
- subject.stub(adjusted_entropy: 18)
10
- expect(subject.is_strong?).to be_truthy
9
+ allow(subject).to receive_messages(adjusted_entropy: 18)
10
+ expect(subject.is_strong?('password')).to be_truthy
11
11
  end
12
12
 
13
13
  it 'returns false if the calculated entropy is < the minimum' do
14
- subject.stub(adjusted_entropy: 17)
15
- expect(subject.is_strong?).to be_falsey
14
+ allow(subject).to receive_messages(adjusted_entropy: 17)
15
+ expect(subject.is_strong?('password')).to be_falsey
16
16
  end
17
17
  end
18
18
 
19
19
  describe '#is_weak?' do
20
- let(:subject) { DictionaryAdjuster.new('password') }
20
+ let(:subject) { DictionaryAdjuster.new }
21
21
 
22
22
  it 'returns the opposite of is_strong?' do
23
- subject.stub(is_strong?: true)
24
- expect(subject.is_weak?).to be_falsey
23
+ allow(subject).to receive_messages(is_strong?: true)
24
+ expect(subject.is_weak?('password')).to be_falsey
25
25
  end
26
26
  end
27
27
 
28
28
  describe '#adjusted_entropy' do
29
- before(:each) { NistBonusBits.stub(bonus_bits: 0)}
29
+ before(:each) { allow(NistBonusBits).to receive_messages(bonus_bits: 0) }
30
30
 
31
31
  it 'checks against all variants of a given password' do
32
32
  password = 'password'
33
- adjuster = DictionaryAdjuster.new(password)
34
- PasswordVariants.should_receive(:all_variants).with(password).and_return([])
35
- adjuster.adjusted_entropy
33
+ adjuster = DictionaryAdjuster.new
34
+ expect(PasswordVariants).to receive(:all_variants).with(password).and_return([])
35
+ adjuster.adjusted_entropy(password)
36
36
  end
37
37
 
38
38
  {
@@ -47,21 +47,21 @@ module StrongPassword
47
47
  'asdf[]asdf' => 16 # Doesn't break with []s
48
48
  }.each do |password, bits|
49
49
  it "returns #{bits} for '#{password}'" do
50
- expect(DictionaryAdjuster.new(password).adjusted_entropy).to eq(bits)
50
+ expect(DictionaryAdjuster.new.adjusted_entropy(password)).to eq(bits)
51
51
  end
52
52
  end
53
53
 
54
54
  it 'allows extra words to be provided as an array' do
55
55
  password = 'administratorWEQ@123'
56
56
  base_entropy = EntropyCalculator.calculate(password)
57
- expect(DictionaryAdjuster.new(password).adjusted_entropy(extra_dictionary_words: ['administrator'])).not_to eq(base_entropy)
57
+ expect(DictionaryAdjuster.new(extra_dictionary_words: ['administrator']).adjusted_entropy(password)).not_to eq(base_entropy)
58
58
  end
59
59
 
60
60
  it 'allows minimum word length to be adjusted' do
61
61
  password = '6969'
62
- base_entropy = DictionaryAdjuster.new(password).adjusted_entropy
62
+ base_entropy = DictionaryAdjuster.new.adjusted_entropy(password)
63
63
  # If we increase the min_word_length above the length of the password we should get a higher entropy
64
- expect(DictionaryAdjuster.new(password).adjusted_entropy(min_word_length: 6)).not_to be < base_entropy
64
+ expect(DictionaryAdjuster.new(min_word_length: 6).adjusted_entropy(password)).not_to be < base_entropy
65
65
  end
66
66
  end
67
67
  end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  module StrongPassword
4
4
  describe EntropyCalculator do
5
5
  describe '.bits' do
6
- before(:each) { NistBonusBits.stub(bonus_bits: 0) }
6
+ before(:each) { allow(NistBonusBits).to receive_messages(bonus_bits: 0) }
7
7
  {
8
8
  '' => 0,
9
9
  '*' => 4,
@@ -5,15 +5,15 @@ module StrongPassword
5
5
  describe '.bonus_bits' do
6
6
  it 'calculates the bonus bits the first time for a given password' do
7
7
  NistBonusBits.reset_bonus_cache!
8
- NistBonusBits.should_receive(:calculate_bonus_bits_for).and_return(1)
8
+ expect(NistBonusBits).to receive(:calculate_bonus_bits_for).and_return(1)
9
9
  expect(NistBonusBits.bonus_bits('password')).to eq(1)
10
10
  end
11
11
 
12
12
  it 'caches the bonus bits for a password for later use' do
13
13
  NistBonusBits.reset_bonus_cache!
14
- NistBonusBits.stub(calculate_bonus_bits_for: 1)
14
+ allow(NistBonusBits).to receive_messages(calculate_bonus_bits_for: 1)
15
15
  NistBonusBits.bonus_bits('password')
16
- NistBonusBits.should_not_receive(:calculate_bonus_bits_for)
16
+ expect(NistBonusBits).not_to receive(:calculate_bonus_bits_for)
17
17
  expect(NistBonusBits.bonus_bits('password')).to eq(1)
18
18
  end
19
19
  end
@@ -8,12 +8,12 @@ module StrongPassword
8
8
  end
9
9
 
10
10
  it 'includes keyboard shift variants' do
11
- subject.stub(keyboard_shift_variants: ['foo', 'bar'])
11
+ allow(subject).to receive_messages(keyboard_shift_variants: ['foo', 'bar'])
12
12
  expect(subject.all_variants("password")).to include('foo', 'bar')
13
13
  end
14
14
 
15
15
  it 'includes leet speak variants' do
16
- subject.stub(leet_speak_variants: ['foo', 'bar'])
16
+ allow(subject).to receive_messages(leet_speak_variants: ['foo', 'bar'])
17
17
  expect(subject.all_variants("password")).to include('foo', 'bar')
18
18
  end
19
19
 
@@ -3,30 +3,30 @@ require 'spec_helper'
3
3
  module StrongPassword
4
4
  describe QwertyAdjuster do
5
5
  describe '#is_strong?' do
6
- let(:subject) { QwertyAdjuster.new('password') }
6
+ let(:subject) { QwertyAdjuster.new }
7
7
 
8
8
  it 'returns true if the calculated entropy is >= the minimum' do
9
- subject.stub(adjusted_entropy: 18)
10
- expect(subject.is_strong?).to be_truthy
9
+ allow(subject).to receive_messages(adjusted_entropy: 18)
10
+ expect(subject.is_strong?("password")).to be_truthy
11
11
  end
12
12
 
13
13
  it 'returns false if the calculated entropy is < the minimum' do
14
- subject.stub(adjusted_entropy: 17)
15
- expect(subject.is_strong?).to be_falsey
14
+ allow(subject).to receive_messages(adjusted_entropy: 17)
15
+ expect(subject.is_strong?("password")).to be_falsey
16
16
  end
17
17
  end
18
18
 
19
19
  describe '#is_weak?' do
20
- let(:subject) { QwertyAdjuster.new('password') }
20
+ let(:subject) { QwertyAdjuster.new }
21
21
 
22
22
  it 'returns the opposite of is_strong?' do
23
- subject.stub(is_strong?: true)
24
- expect(subject.is_weak?).to be_falsey
23
+ allow(subject).to receive_messages(is_strong?: true)
24
+ expect(subject.is_weak?("password")).to be_falsey
25
25
  end
26
26
  end
27
27
 
28
28
  describe '#adjusted_entropy' do
29
- before(:each) { NistBonusBits.stub(bonus_bits: 0)}
29
+ before(:each) { allow(NistBonusBits).to receive_messages(bonus_bits: 0)}
30
30
  {
31
31
  'qwertyuio' => 5.5,
32
32
  '1234567' => 6,
@@ -37,7 +37,7 @@ module StrongPassword
37
37
  'password' => 17.5 # Ensure that we don't qwerty-adjust 'password'
38
38
  }.each do |password, bits|
39
39
  it "returns #{bits} for '#{password}'" do
40
- expect(QwertyAdjuster.new(password).adjusted_entropy).to eq(bits)
40
+ expect(QwertyAdjuster.new.adjusted_entropy(password)).to eq(bits)
41
41
  end
42
42
  end
43
43
  end
@@ -11,7 +11,7 @@ module StrongPassword
11
11
  'aB$1' => false
12
12
  }.each do |password, strength|
13
13
  it "is_strong? returns #{strength} for '#{password}' with 12 bits of entropy" do
14
- expect(StrengthChecker.new(password).is_strong?(min_entropy: 12)).to be(strength)
14
+ expect(StrengthChecker.new(min_entropy: 12).is_strong?(password)).to be(strength)
15
15
  end
16
16
  end
17
17
  end
@@ -26,7 +26,7 @@ module StrongPassword
26
26
  'aB$1' => false
27
27
  }.each do |password, strength|
28
28
  it "is_strong? returns #{strength} for '#{password}' with 12 bits of entropy" do
29
- expect(StrengthChecker.new(password).is_strong?(min_entropy: 12, use_dictionary: true)).to eq(strength)
29
+ expect(StrengthChecker.new(min_entropy: 12, use_dictionary: true).is_strong?(password)).to eq(strength)
30
30
  end
31
31
  end
32
32
  end
@@ -41,7 +41,7 @@ module StrongPassword
41
41
  'correct horse battery staple' => true
42
42
  }.each do |password, strength|
43
43
  it "is_strong? returns #{strength} for '#{password}' with standard bits of entropy" do
44
- expect(StrengthChecker.new(password).is_strong?(use_dictionary: true)).to eq(strength)
44
+ expect(StrengthChecker.new(use_dictionary: true).is_strong?(password)).to eq(strength)
45
45
  end
46
46
  end
47
47
  end
@@ -57,28 +57,31 @@ module StrongPassword
57
57
  'c0rr#ct h0rs3 Batt$ry st@pl3 is Gr34t' => true
58
58
  }.each do |password, strength|
59
59
  it "is_strong? returns #{strength} for '#{password}' with standard bits of entropy" do
60
- expect(StrengthChecker.new(password).is_strong?(min_entropy: 40, use_dictionary: true)).to eq(strength)
60
+ expect(StrengthChecker.new(min_entropy: 40, use_dictionary: true).is_strong?(password)).to eq(strength)
61
61
  end
62
62
  end
63
63
  end
64
64
 
65
65
  context 'with long password' do
66
- let(:strength_checker) { StrengthChecker.new("ba"*500_000) }
66
+ let(:strength_checker) { StrengthChecker.new }
67
+ let(:password) { ("ba"*500_000) }
67
68
  it 'should be truncated' do
68
- expect(strength_checker.instance_variable_get(:@base_password).length).to eq StrengthChecker::PASSWORD_LIMIT
69
+ expect(strength_checker.calculate_entropy(password)).
70
+ to eq(strength_checker.calculate_entropy(password.slice(0, StrengthChecker::PASSWORD_LIMIT)))
69
71
  end
70
72
  end
71
73
 
72
74
  context 'with long extra words' do
73
- let(:strength_checker) { StrengthChecker.new("$tr0NgP4s$w0rd91d£") }
75
+ let(:strength_checker) { StrengthChecker.new(use_dictionary: true, extra_dictionary_words: ["a"*1_000_000, "b"*10_000_000, "c"*10]) }
74
76
  let(:exta_limit) { StrengthChecker::EXTRA_WORDS_LIMIT }
75
77
  it 'should be truncated' do
76
- expect_any_instance_of(DictionaryAdjuster).to receive(:adjusted_entropy).with({
78
+ expect(DictionaryAdjuster).to receive(:new).with({
79
+ min_entropy: 18,
77
80
  min_word_length: 4,
78
81
  extra_dictionary_words:
79
82
  ["a"*StrengthChecker::EXTRA_WORDS_LIMIT, "b"*StrengthChecker::EXTRA_WORDS_LIMIT, "c"*10]
80
83
  }).and_call_original
81
- strength_checker.calculate_entropy(use_dictionary: true, extra_dictionary_words: ["a"*1_000_000, "b"*10_000_000, "c"*10])
84
+ strength_checker.calculate_entropy("$tr0NgP4s$w0rd91d£")
82
85
  end
83
86
  end
84
87
  end
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.6
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian McManus
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-09 00:00:00.000000000 Z
11
+ date: 2019-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler