zxcvbn-ruby 1.2.0 → 1.2.2

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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -1
  3. data/README.md +1 -1
  4. data/lib/zxcvbn/clock.rb +11 -0
  5. data/lib/zxcvbn/crack_time.rb +4 -2
  6. data/lib/zxcvbn/data.rb +6 -4
  7. data/lib/zxcvbn/dictionary_ranker.rb +2 -0
  8. data/lib/zxcvbn/entropy.rb +38 -33
  9. data/lib/zxcvbn/feedback.rb +2 -0
  10. data/lib/zxcvbn/feedback_giver.rb +2 -0
  11. data/lib/zxcvbn/match.rb +2 -0
  12. data/lib/zxcvbn/matchers/date.rb +11 -8
  13. data/lib/zxcvbn/matchers/dictionary.rb +3 -1
  14. data/lib/zxcvbn/matchers/digits.rb +2 -0
  15. data/lib/zxcvbn/matchers/l33t.rb +6 -2
  16. data/lib/zxcvbn/matchers/new_l33t.rb +7 -4
  17. data/lib/zxcvbn/matchers/regex_helpers.rb +2 -0
  18. data/lib/zxcvbn/matchers/repeat.rb +3 -1
  19. data/lib/zxcvbn/matchers/sequences.rb +4 -2
  20. data/lib/zxcvbn/matchers/spatial.rb +5 -3
  21. data/lib/zxcvbn/matchers/year.rb +3 -1
  22. data/lib/zxcvbn/math.rb +3 -0
  23. data/lib/zxcvbn/omnimatch.rb +3 -1
  24. data/lib/zxcvbn/password_strength.rb +5 -3
  25. data/lib/zxcvbn/score.rb +3 -1
  26. data/lib/zxcvbn/scorer.rb +11 -7
  27. data/lib/zxcvbn/version.rb +1 -1
  28. data/lib/zxcvbn.rb +2 -0
  29. metadata +6 -102
  30. data/.github/workflows/ci.yml +0 -23
  31. data/.gitignore +0 -18
  32. data/.rspec +0 -1
  33. data/CODE_OF_CONDUCT.md +0 -130
  34. data/Gemfile +0 -10
  35. data/Guardfile +0 -26
  36. data/Rakefile +0 -22
  37. data/spec/dictionary_ranker_spec.rb +0 -12
  38. data/spec/feedback_giver_spec.rb +0 -212
  39. data/spec/matchers/date_spec.rb +0 -109
  40. data/spec/matchers/dictionary_spec.rb +0 -30
  41. data/spec/matchers/digits_spec.rb +0 -15
  42. data/spec/matchers/l33t_spec.rb +0 -87
  43. data/spec/matchers/repeat_spec.rb +0 -18
  44. data/spec/matchers/sequences_spec.rb +0 -21
  45. data/spec/matchers/spatial_spec.rb +0 -20
  46. data/spec/matchers/year_spec.rb +0 -15
  47. data/spec/omnimatch_spec.rb +0 -24
  48. data/spec/scorer_spec.rb +0 -5
  49. data/spec/scoring/crack_time_spec.rb +0 -106
  50. data/spec/scoring/entropy_spec.rb +0 -216
  51. data/spec/scoring/math_spec.rb +0 -135
  52. data/spec/spec_helper.rb +0 -54
  53. data/spec/support/js_helpers.rb +0 -34
  54. data/spec/support/js_source/adjacency_graphs.js +0 -8
  55. data/spec/support/js_source/compiled.js +0 -1188
  56. data/spec/support/js_source/frequency_lists.js +0 -10
  57. data/spec/support/js_source/init.coffee +0 -63
  58. data/spec/support/js_source/init.js +0 -95
  59. data/spec/support/js_source/matching.coffee +0 -444
  60. data/spec/support/js_source/matching.js +0 -685
  61. data/spec/support/js_source/scoring.coffee +0 -270
  62. data/spec/support/js_source/scoring.js +0 -390
  63. data/spec/support/matcher.rb +0 -35
  64. data/spec/tester_spec.rb +0 -99
  65. data/spec/zxcvbn_spec.rb +0 -24
  66. data/zxcvbn-ruby.gemspec +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa14ec0484793f1034f5dda8b84c6265e2fc8b161e47fa323be7e78dc3223cc4
4
- data.tar.gz: e42207b60f1d6b1c4a198e6e7b466e7dcc68caaaf610bdf6e4d29a85978da58d
3
+ metadata.gz: 7132f3b910a1849c47f1edcb52d2dd2f6f3954472ad912bd20520c942fbc0bda
4
+ data.tar.gz: 45c893886c18c81fcb03627b7dd341eecab816a5fab4e7a9efb9ab5ca0ff9375
5
5
  SHA512:
6
- metadata.gz: d6b789be21697b782a87bc8c946fed85e8f088d8097f75f2e50ae8f9f95954c01dd1df76d8eb58f031b5b6e4ee43bbb14e15264c102371cdbb20696b50e0f3c1
7
- data.tar.gz: a9a0fa505d0896c58cd1e34780ddd07a37d1d5fe34e103c09c86c4b9bdff3d8ddb78c607e2c158ef4d562f93b5a16f20e0f41b0db89dfddc1b7522c4467f1171
6
+ metadata.gz: 259633b2081be2ddd35ae1dfbcf17cf44e50f099e2bff7accbe15ffc6f1faa92217517a6ffdb060540276170f1a12d4cb8fab3ef256ee152efc525b6a902d3c2
7
+ data.tar.gz: 73e728a75b41c46e87074a95a7a8b1849eb6fcb50899e3b3bee6900d77ca0ecacd85f7d2ed539a180420423f0a6d705dc9da377bce107db5e21cb7f661682230
data/CHANGELOG.md CHANGED
@@ -6,7 +6,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- [Unreleased]: https://github.com/envato/zxcvbn-ruby/compare/v1.2.0...HEAD
9
+ [Unreleased]: https://github.com/envato/zxcvbn-ruby/compare/v1.2.2...HEAD
10
+
11
+ ## [1.2.2] - 2025-12-06
12
+
13
+ ### Changed
14
+ - Address layout and frozen string literal issues ([#49])
15
+
16
+ [1.2.2]: https://github.com/envato/zxcvbn-ruby/compare/v1.2.1...v.1.2.2
17
+ [#49]: https://github.com/envato/zxcvbn-ruby/pull/49
18
+
19
+ ## [1.2.1] - 2025-12-05
20
+
21
+ ### Removed
22
+ - Removed the dependency on the Ruby `benchmark` module ([#44]).
23
+ - Tests are no longer included in the gem package ([#45]).
24
+
25
+ [1.2.1]: https://github.com/envato/zxcvbn-ruby/compare/v1.2.0...v.1.2.1
26
+ [#44]: https://github.com/envato/zxcvbn-ruby/pull/44
27
+ [#45]: https://github.com/envato/zxcvbn-ruby/pull/45
10
28
 
11
29
  ## [1.2.0] - 2021-01-05
12
30
 
data/README.md CHANGED
@@ -119,7 +119,7 @@ $ irb
119
119
  **Note**: Storing the entropy of an encrypted or hashed value provides
120
120
  information that can make cracking the value orders of magnitude easier for an
121
121
  attacker. For this reason we advise you not to store the results of
122
- `Zxcvbn::Tester#test`. Further reading: [A Tale of Security Gone Wrong](http://gavinmiller.io/2016/a-tale-of-security-gone-wrong/).
122
+ `Zxcvbn::Tester#test`. Further reading: [A Tale of Security Gone Wrong](https://web.archive.org/web/20240715041147/http://gavinmiller.io/2016/a-tale-of-security-gone-wrong/).
123
123
 
124
124
  ## Contact
125
125
 
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zxcvbn
4
+ module Clock
5
+ def self.realtime
6
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
7
+ yield
8
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zxcvbn
2
4
  module CrackTime
3
5
  SINGLE_GUESS = 0.010
@@ -6,7 +8,7 @@ module Zxcvbn
6
8
  SECONDS_PER_GUESS = SINGLE_GUESS / NUM_ATTACKERS
7
9
 
8
10
  def entropy_to_crack_time(entropy)
9
- 0.5 * (2 ** entropy) * SECONDS_PER_GUESS
11
+ 0.5 * (2**entropy) * SECONDS_PER_GUESS
10
12
  end
11
13
 
12
14
  def crack_time_to_score(seconds)
@@ -50,4 +52,4 @@ module Zxcvbn
50
52
  end
51
53
  end
52
54
  end
53
- end
55
+ end
data/lib/zxcvbn/data.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
  require 'zxcvbn/dictionary_ranker'
3
5
 
@@ -5,11 +7,11 @@ module Zxcvbn
5
7
  class Data
6
8
  def initialize
7
9
  @ranked_dictionaries = DictionaryRanker.rank_dictionaries(
8
- "english" => read_word_list("english.txt"),
10
+ "english" => read_word_list("english.txt"),
9
11
  "female_names" => read_word_list("female_names.txt"),
10
- "male_names" => read_word_list("male_names.txt"),
11
- "passwords" => read_word_list("passwords.txt"),
12
- "surnames" => read_word_list("surnames.txt")
12
+ "male_names" => read_word_list("male_names.txt"),
13
+ "passwords" => read_word_list("passwords.txt"),
14
+ "surnames" => read_word_list("surnames.txt")
13
15
  )
14
16
  @adjacency_graphs = JSON.load(DATA_PATH.join('adjacency_graphs.json').read)
15
17
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zxcvbn
2
4
  class DictionaryRanker
3
5
  def self.rank_dictionaries(lists)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/math'
2
4
 
3
5
  module Zxcvbn::Entropy
@@ -6,24 +8,25 @@ module Zxcvbn::Entropy
6
8
  def calc_entropy(match)
7
9
  return match.entropy unless match.entropy.nil?
8
10
 
9
- match.entropy = case match.pattern
10
- when 'repeat'
11
- repeat_entropy(match)
12
- when 'sequence'
13
- sequence_entropy(match)
14
- when 'digits'
15
- digits_entropy(match)
16
- when 'year'
17
- year_entropy(match)
18
- when 'date'
19
- date_entropy(match)
20
- when 'spatial'
21
- spatial_entropy(match)
22
- when 'dictionary'
23
- dictionary_entropy(match)
24
- else
25
- 0
26
- end
11
+ match.entropy =
12
+ case match.pattern
13
+ when 'repeat'
14
+ repeat_entropy(match)
15
+ when 'sequence'
16
+ sequence_entropy(match)
17
+ when 'digits'
18
+ digits_entropy(match)
19
+ when 'year'
20
+ year_entropy(match)
21
+ when 'date'
22
+ date_entropy(match)
23
+ when 'spatial'
24
+ spatial_entropy(match)
25
+ when 'dictionary'
26
+ dictionary_entropy(match)
27
+ else
28
+ 0
29
+ end
27
30
  end
28
31
 
29
32
  def repeat_entropy(match)
@@ -33,21 +36,22 @@ module Zxcvbn::Entropy
33
36
 
34
37
  def sequence_entropy(match)
35
38
  first_char = match.token[0]
36
- base_entropy = if ['a', '1'].include?(first_char)
37
- 1
38
- elsif first_char.match(/\d/)
39
- lg(10)
40
- elsif first_char.match(/[a-z]/)
41
- lg(26)
42
- else
43
- lg(26) + 1
44
- end
39
+ base_entropy =
40
+ if ['a', '1'].include?(first_char)
41
+ 1
42
+ elsif first_char.match(/\d/)
43
+ lg(10)
44
+ elsif first_char.match(/[a-z]/)
45
+ lg(26)
46
+ else
47
+ lg(26) + 1
48
+ end
45
49
  base_entropy += 1 unless match.ascending
46
50
  base_entropy + lg(match.token.length)
47
51
  end
48
52
 
49
53
  def digits_entropy(match)
50
- lg(10 ** match.token.length)
54
+ lg(10**match.token.length)
51
55
  end
52
56
 
53
57
  NUM_YEARS = 119 # years match against 1900 - 2019
@@ -90,8 +94,8 @@ module Zxcvbn::Entropy
90
94
  [START_UPPER, END_UPPER, ALL_UPPER].each do |regex|
91
95
  return 1 if word.match(regex)
92
96
  end
93
- num_upper = word.chars.count{|c| c.match(/[A-Z]/) }
94
- num_lower = word.chars.count{|c| c.match(/[a-z]/) }
97
+ num_upper = word.chars.count { |c| c.match(/[A-Z]/) }
98
+ num_lower = word.chars.count { |c| c.match(/[a-z]/) }
95
99
  possibilities = 0
96
100
  (0..[num_upper, num_lower].min).each do |i|
97
101
  possibilities += nCk(num_upper + num_lower, i)
@@ -102,10 +106,11 @@ module Zxcvbn::Entropy
102
106
  def extra_l33t_entropy(match)
103
107
  word = match.token
104
108
  return 0 unless match.l33t
109
+
105
110
  possibilities = 0
106
111
  match.sub.each do |subbed, unsubbed|
107
- num_subbed = word.chars.count{|c| c == subbed}
108
- num_unsubbed = word.chars.count{|c| c == unsubbed}
112
+ num_subbed = word.chars.count { |c| c == subbed }
113
+ num_unsubbed = word.chars.count { |c| c == unsubbed }
109
114
  (0..[num_subbed, num_unsubbed].min).each do |i|
110
115
  possibilities += nCk(num_subbed + num_unsubbed, i)
111
116
  end
@@ -131,7 +136,7 @@ module Zxcvbn::Entropy
131
136
  (2..token_length).each do |i|
132
137
  possible_turns = [turns, i - 1].min
133
138
  (1..possible_turns).each do |j|
134
- possibilities += nCk(i - 1, j - 1) * starting_positions * average_degree ** j
139
+ possibilities += nCk(i - 1, j - 1) * starting_positions * average_degree**j
135
140
  end
136
141
  end
137
142
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zxcvbn
2
4
  class Feedback
3
5
  attr_accessor :warning, :suggestions
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/entropy'
2
4
  require 'zxcvbn/feedback'
3
5
 
data/lib/zxcvbn/match.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ostruct'
2
4
 
3
5
  module Zxcvbn
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/matchers/regex_helpers'
2
4
 
3
5
  module Zxcvbn
@@ -71,9 +73,9 @@ module Zxcvbn
71
73
  dates = []
72
74
  date_patterns_for_length(token.length).map do |pattern|
73
75
  candidate = {
74
- :year => '',
75
- :month => '',
76
- :day => ''
76
+ :year => +'',
77
+ :month => +'',
78
+ :day => +''
77
79
  }
78
80
  for i in 0...token.length
79
81
  candidate[PATTERN_CHAR_TO_SYM[pattern[i]]] << token[i]
@@ -92,11 +94,11 @@ module Zxcvbn
92
94
  end
93
95
 
94
96
  DATE_PATTERN_FOR_LENGTH = {
95
- 8 => %w[ yyyymmdd ddmmyyyy mmddyyyy ],
96
- 7 => %w[ yyyymdd yyyymmd ddmyyyy dmmyyyy ],
97
- 6 => %w[ yymmdd ddmmyy mmddyy ],
98
- 5 => %w[ yymdd yymmd ddmyy dmmyy mmdyy mddyy ],
99
- 4 => %w[ yymd dmyy mdyy ]
97
+ 8 => %w[yyyymmdd ddmmyyyy mmddyyyy],
98
+ 7 => %w[yyyymdd yyyymmd ddmyyyy dmmyyyy],
99
+ 6 => %w[yymmdd ddmmyy mmddyy],
100
+ 5 => %w[yymdd yymmd ddmyy dmmyy mmdyy mddyy],
101
+ 4 => %w[yymd dmyy mdyy]
100
102
  }
101
103
 
102
104
  PATTERN_CHAR_TO_SYM = {
@@ -112,6 +114,7 @@ module Zxcvbn
112
114
  def valid_date?(day, month, year)
113
115
  return false if day > 31 || month > 12
114
116
  return false unless year >= 1900 && year <= 2019
117
+
115
118
  true
116
119
  end
117
120
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/match'
2
4
 
3
5
  module Zxcvbn
@@ -33,4 +35,4 @@ module Zxcvbn
33
35
  end
34
36
  end
35
37
  end
36
- end
38
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/matchers/regex_helpers'
2
4
 
3
5
  module Zxcvbn
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zxcvbn
2
4
  module Matchers
3
5
  class L33t
@@ -30,6 +32,7 @@ module Zxcvbn
30
32
  matcher.matches(subbed_password).each do |match|
31
33
  token = password[match.i..match.j]
32
34
  next if token.downcase == match.matched_word.downcase
35
+
33
36
  match_substitutions = {}
34
37
  substitution.each do |s, letter|
35
38
  match_substitutions[s] = letter if token.include?(s)
@@ -79,6 +82,7 @@ module Zxcvbn
79
82
 
80
83
  def find_substitutions(subs, table, keys)
81
84
  return subs if keys.empty?
85
+
82
86
  first_key = keys[0]
83
87
  rest_keys = keys[1..-1]
84
88
  next_subs = []
@@ -114,7 +118,7 @@ module Zxcvbn
114
118
  assoc = sub.dup
115
119
 
116
120
  assoc.sort! rescue debugger
117
- label = assoc.map{|k, v| "#{k},#{v}"}.join('-')
121
+ label = assoc.map { |k, v| "#{k},#{v}" }.join('-')
118
122
  unless members.include?(label)
119
123
  members << label
120
124
  deduped << sub
@@ -124,4 +128,4 @@ module Zxcvbn
124
128
  end
125
129
  end
126
130
  end
127
- end
131
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zxcvbn
2
4
  module Matchers
3
5
  class L33t
@@ -31,6 +33,7 @@ module Zxcvbn
31
33
  matcher.matches(subbed_password).each do |match|
32
34
  token = lowercased_password[match.i..match.j]
33
35
  next if token == match.matched_word.downcase
36
+
34
37
  # debugger if token == '1'
35
38
  match_substitutions = {}
36
39
  substitution.each do |letter, substitution|
@@ -82,7 +85,7 @@ module Zxcvbn
82
85
  expanded_substitutions.each do |substitution_hash|
83
86
  # convert a hash to an array of hashes with 1 key each
84
87
  subs_array = substitution_hash.map do |letter, substitutions|
85
- {letter => substitutions}
88
+ { letter => substitutions }
86
89
  end
87
90
  combinations << subs_array
88
91
 
@@ -110,11 +113,11 @@ module Zxcvbn
110
113
  # [{'a' => '4', 'i' => 1}, {'a' => '@', 'i' => '1'}]
111
114
  def expanded_substitutions(hash)
112
115
  return {} if hash.empty?
116
+
113
117
  values = hash.values
114
118
  product_values = values[0].product(*values[1..-1])
115
- product_values.map{ |p| Hash[hash.keys.zip(p)] }
119
+ product_values.map { |p| Hash[hash.keys.zip(p)] }
116
120
  end
117
-
118
121
  end
119
122
  end
120
- end
123
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/match'
2
4
 
3
5
  module Zxcvbn
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/match'
2
4
 
3
5
  module Zxcvbn
@@ -17,7 +19,7 @@ module Zxcvbn
17
19
  result << Match.new(
18
20
  :pattern => 'repeat',
19
21
  :i => i,
20
- :j => j-1,
22
+ :j => j - 1,
21
23
  :token => password[i...j],
22
24
  :repeated_char => cur_char
23
25
  )
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/match'
2
4
 
3
5
  module Zxcvbn
@@ -14,7 +16,7 @@ module Zxcvbn
14
16
  j = 1
15
17
  while from + j < password.length &&
16
18
  password[from + j] == seq[index_from + direction * j]
17
- j+= 1
19
+ j += 1
18
20
  end
19
21
  j
20
22
  end
@@ -24,7 +26,7 @@ module Zxcvbn
24
26
  def applicable_sequence(password, i)
25
27
  SEQUENCES.each do |name, sequence|
26
28
  index1 = sequence.index(password[i])
27
- index2 = sequence.index(password[i+1])
29
+ index2 = sequence.index(password[i + 1])
28
30
  if index1 and index2
29
31
  seq_direction = index2 - index1
30
32
  if [-1, 1].include?(seq_direction)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/match'
2
4
 
3
5
  module Zxcvbn
@@ -24,7 +26,7 @@ module Zxcvbn
24
26
  turns = 0
25
27
  shifted_count = 0
26
28
  loop do
27
- prev_char = password[j-1]
29
+ prev_char = password[j - 1]
28
30
  found = false
29
31
  found_direction = -1
30
32
  cur_direction = -1
@@ -61,7 +63,7 @@ module Zxcvbn
61
63
  result << Match.new(
62
64
  :pattern => 'spatial',
63
65
  :i => i,
64
- :j => j-1,
66
+ :j => j - 1,
65
67
  :token => password[i...j],
66
68
  :graph => graph_name,
67
69
  :turns => turns,
@@ -78,4 +80,4 @@ module Zxcvbn
78
80
  end
79
81
  end
80
82
  end
81
- end
83
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/matchers/regex_helpers'
2
4
 
3
5
  module Zxcvbn
@@ -17,4 +19,4 @@ module Zxcvbn
17
19
  end
18
20
  end
19
21
  end
20
- end
22
+ end
data/lib/zxcvbn/math.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zxcvbn
2
4
  module Math
3
5
  def bruteforce_cardinality(password)
@@ -31,6 +33,7 @@ module Zxcvbn
31
33
  def nCk(n, k)
32
34
  return 0 if k > n
33
35
  return 1 if k == 0
36
+
34
37
  r = 1
35
38
  (1..k).each do |d|
36
39
  r = r * n
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/dictionary_ranker'
2
4
  require 'zxcvbn/matchers/dictionary'
3
5
  require 'zxcvbn/matchers/l33t'
@@ -26,13 +28,13 @@ module Zxcvbn
26
28
 
27
29
  def user_input_matchers(user_inputs)
28
30
  return [] unless user_inputs.any?
31
+
29
32
  user_ranked_dictionary = DictionaryRanker.rank_dictionary(user_inputs)
30
33
  dictionary_matcher = Matchers::Dictionary.new('user_inputs', user_ranked_dictionary)
31
34
  l33t_matcher = Matchers::L33t.new([dictionary_matcher])
32
35
  [dictionary_matcher, l33t_matcher]
33
36
  end
34
37
 
35
-
36
38
  def build_matchers
37
39
  matchers = []
38
40
  dictionary_matchers = @data.ranked_dictionaries.map do |name, dictionary|
@@ -1,4 +1,6 @@
1
- require 'benchmark'
1
+ # frozen_string_literal: true
2
+
3
+ require 'zxcvbn/clock'
2
4
  require 'zxcvbn/feedback_giver'
3
5
  require 'zxcvbn/omnimatch'
4
6
  require 'zxcvbn/scorer'
@@ -13,7 +15,7 @@ module Zxcvbn
13
15
  def test(password, user_inputs = [])
14
16
  password = password || ''
15
17
  result = nil
16
- calc_time = Benchmark.realtime do
18
+ calc_time = Clock.realtime do
17
19
  matches = @omnimatch.matches(password, user_inputs)
18
20
  result = @scorer.minimum_entropy_match_sequence(password, matches)
19
21
  end
@@ -22,4 +24,4 @@ module Zxcvbn
22
24
  result
23
25
  end
24
26
  end
25
- end
27
+ end
data/lib/zxcvbn/score.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Zxcvbn
2
4
  class Score
3
5
  attr_accessor :entropy, :crack_time, :crack_time_display, :score, :pattern,
@@ -12,4 +14,4 @@ module Zxcvbn
12
14
  @password = options[:password]
13
15
  end
14
16
  end
15
- end
17
+ end
data/lib/zxcvbn/scorer.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'zxcvbn/entropy'
2
4
  require 'zxcvbn/crack_time'
3
5
  require 'zxcvbn/score'
@@ -16,11 +18,13 @@ module Zxcvbn
16
18
 
17
19
  def minimum_entropy_match_sequence(password, matches)
18
20
  bruteforce_cardinality = bruteforce_cardinality(password) # e.g. 26 for lowercase
19
- up_to_k = [] # minimum entropy up to k.
20
- backpointers = [] # for the optimal sequence of matches up to k, holds the final match (match.j == k). null means the sequence ends w/ a brute-force character.
21
+ up_to_k = [] # minimum entropy up to k.
22
+ # for the optimal sequence of matches up to k, holds the final match (match.j == k).
23
+ # null means the sequence ends w/ a brute-force character.
24
+ backpointers = []
21
25
  (0...password.length).each do |k|
22
26
  # starting scenario to try and beat: adding a brute-force character to the minimum entropy sequence at k-1.
23
- previous_k_entropy = k > 0 ? up_to_k[k-1] : 0
27
+ previous_k_entropy = k > 0 ? up_to_k[k - 1] : 0
24
28
  up_to_k[k] = previous_k_entropy + lg(bruteforce_cardinality)
25
29
  backpointers[k] = nil
26
30
  matches.select do |match|
@@ -28,7 +32,7 @@ module Zxcvbn
28
32
  end.each do |match|
29
33
  i, j = match.i, match.j
30
34
  # see if best entropy up to i-1 + entropy of this match is less than the current minimum at j.
31
- previous_i_entropy = i > 0 ? up_to_k[i-1] : 0
35
+ previous_i_entropy = i > 0 ? up_to_k[i - 1] : 0
32
36
  candidate_entropy = previous_i_entropy + calc_entropy(match)
33
37
  if up_to_k[j] && candidate_entropy < up_to_k[j]
34
38
  up_to_k[j] = candidate_entropy
@@ -55,7 +59,7 @@ module Zxcvbn
55
59
  end
56
60
 
57
61
  def score_for password, match_sequence, up_to_k
58
- min_entropy = up_to_k[password.length - 1] || 0 # or 0 corner case is for an empty password ''
62
+ min_entropy = up_to_k[password.length - 1] || 0 # or 0 corner case is for an empty password ''
59
63
  crack_time = entropy_to_crack_time(min_entropy)
60
64
 
61
65
  # final result object
@@ -69,7 +73,6 @@ module Zxcvbn
69
73
  )
70
74
  end
71
75
 
72
-
73
76
  def pad_with_bruteforce_matches(match_sequence, password, bruteforce_cardinality)
74
77
  k = 0
75
78
  match_sequence_copy = []
@@ -85,6 +88,7 @@ module Zxcvbn
85
88
  end
86
89
  match_sequence_copy
87
90
  end
91
+
88
92
  # fill in the blanks between pattern matches with bruteforce "matches"
89
93
  # that way the match sequence fully covers the password:
90
94
  # match1.j == match2.i - 1 for every adjacent match1, match2.
@@ -94,7 +98,7 @@ module Zxcvbn
94
98
  :i => i,
95
99
  :j => j,
96
100
  :token => password[i..j],
97
- :entropy => lg(bruteforce_cardinality ** (j - i + 1)),
101
+ :entropy => lg(bruteforce_cardinality**(j - i + 1)),
98
102
  :cardinality => bruteforce_cardinality
99
103
  )
100
104
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Zxcvbn
4
- VERSION = '1.2.0'
4
+ VERSION = '1.2.2'
5
5
  end
data/lib/zxcvbn.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathname'
2
4
  require 'zxcvbn/version'
3
5
  require 'zxcvbn/tester'