zxcvbn 0.1.2 → 0.1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d56d0f63e1c4c3aedf3155181de533b58d5dfc342daf383e6fcfffc9e9a4def4
4
- data.tar.gz: 043e9ac637ff1932e204f842d8bd26b2089798ec2a455cfdbe3a4515025cef8f
3
+ metadata.gz: 497a8237437937a17ce899c92181dcc11f32e164ca5515ba2739ac02e59f79b2
4
+ data.tar.gz: 0e0ee12a70d1814db3178c9d925a43b22036c3c5c1444dd2ed38873c5c5686a7
5
5
  SHA512:
6
- metadata.gz: f34c91177043d1f11c5f9a8514234e6ff9ebc1a8320a672debf8a531730ee16f1f1ac9229fc399a55eb0eef250defc08b2e42925ff18f1e00398a8bde13c877c
7
- data.tar.gz: b24c9e9cbe8154befbcc1a818bbdd3b373fc3e33645087a96bd2ff2c58c6be46ff79f514ee27bbe79a4f1c5a5209abf1196c6389ed9bce16fb5388f818ca8851
6
+ metadata.gz: ab0bf4b0709602f08bdb20caae26f124487c3dac8d1f35ef04fb728a0bda822e68ad35db065d28be15745a7c61705ecb402cc7fb463209d8bbc24ca3d8edf379
7
+ data.tar.gz: e03692c3985a020195e1304451dcd3c91b847d9ef2c391ba62ce61b33f08251a73f195877618a649bd847dd4736769de0b31779a5a61e6b7ab2b23ca946cda81
data/.rubocop.yml CHANGED
@@ -1,5 +1,31 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.5
3
+ NewCops: enable
4
+ SuggestExtensions: false
5
+
6
+ Layout/EndAlignment:
7
+ EnforcedStyleAlignWith: start_of_line
8
+
9
+ Layout/LineLength:
10
+ Max: 120
11
+
12
+ Lint/UnderscorePrefixedVariableName:
13
+ Enabled: false
14
+
15
+ Metrics:
16
+ Enabled: false
17
+
18
+ Naming/VariableNumber:
19
+ Enabled: false
20
+
21
+ Style/Documentation:
22
+ Enabled: false
23
+
24
+ Style/Next:
25
+ Enabled: false
26
+
27
+ Style/NumericPredicate:
28
+ Enabled: false
3
29
 
4
30
  Style/StringLiterals:
5
31
  Enabled: true
@@ -9,5 +35,11 @@ Style/StringLiteralsInInterpolation:
9
35
  Enabled: true
10
36
  EnforcedStyle: double_quotes
11
37
 
12
- Layout/LineLength:
13
- Max: 120
38
+ Style/NegatedIf:
39
+ Enabled: false
40
+
41
+ Style/SymbolArray:
42
+ Enabled: false
43
+
44
+ Style/WordArray:
45
+ Enabled: false
data/.travis.yml CHANGED
@@ -2,5 +2,8 @@
2
2
  language: ruby
3
3
  cache: bundler
4
4
  rvm:
5
- - 2.6.6
5
+ - 2.5.9
6
+ - 2.6.7
7
+ - 2.7.3
8
+ - 3.0.1
6
9
  before_install: gem install bundler -v 2.2.15
data/CHANGELOG.md CHANGED
@@ -1,4 +1,18 @@
1
- ## [Unreleased]
1
+ ## [0.1.7] - 2021-06-12
2
+ - Ported original specs
3
+ - Fix difference found on enumerate_l33t_subs
4
+ - Setup to also test against current versions of ruby
5
+
6
+ ## [0.1.6] - 2021-05-28
7
+ - Added test methods for compatibility with zxcvbn-js and zxcvbn-ruby.
8
+
9
+ ## [0.1.5] - 2021-05-27
10
+ - Fix classification of scoring causing differences between js and ruby.
11
+
12
+ ## [0.1.4] - 2021-05-16
13
+
14
+ - Bunch of fixes, all example passwords included have same result as js version.
15
+ - consistent code style applied.
2
16
 
3
17
  ## [0.1.0] - 2021-05-16
4
18
 
data/Gemfile CHANGED
@@ -6,10 +6,10 @@ source "https://rubygems.org"
6
6
  gemspec
7
7
 
8
8
  group :development do
9
+ gem "mini_racer"
9
10
  gem "rake", "~> 13.0"
10
11
  gem "rspec", "~> 3.0"
11
12
  gem "rubocop", "~> 1.7"
12
- gem 'mini_racer'
13
13
 
14
14
  gem "pry"
15
15
  gem "pry-byebug"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zxcvbn (0.1.2)
4
+ zxcvbn (0.1.7)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,7 +1,11 @@
1
1
  # Zxcvbn
2
2
 
3
- This is a direct Ruby port of Dropbox's [zxcvbn.js][zxcvbn.js] JavaScript library.
4
- The intention is to provide all the same features and same results as close to the original JS fucntion would do.
3
+ [![Gem Version](https://badge.fury.io/rb/zxcvbn.svg)](https://badge.fury.io/rb/zxcvbn)
4
+ [![Build Status](https://travis-ci.com/formigarafa/zxcvbn-rb.svg?branch=master)](https://travis-ci.com/formigarafa/zxcvbn-rb)
5
+
6
+ Ruby port of Dropbox's [zxcvbn.js](https://github.com/dropbox/zxcvbn) JavaScript library running completely in Ruby (no need to load execjs or libv8).
7
+
8
+ The intention is to provide an option 100% Ruby solution with all the same features and same results (or as close to the original JS function as possible).
5
9
 
6
10
  ## Installation
7
11
 
@@ -24,49 +28,53 @@ Or install it yourself as:
24
28
  ```
25
29
  Zxcvbn.zxcvbn("password")
26
30
  => {
27
- :password => "pasword",
28
- :guesses => 3566,
29
- :guesses_log10 => 3.5521813388393357,
30
- :sequence => [
31
+ "password" => "password",
32
+ "guesses" => 3,
33
+ "guesses_log10" => 0.47712125471966244,
34
+ "sequence" => [
31
35
  {
32
- :pattern => "dictionary",
33
- :i => 0,
34
- :j => 6,
35
- :token => "pasword",
36
- :matched_word => "pasword",
37
- :rank => 3565,
38
- :dictionary_name => "passwords",
39
- :reversed => false,
40
- :l33t => false,
41
- :base_guesses => 3565,
42
- :uppercase_variations => 1,
43
- :l33t_variations => 1,
44
- :guesses => 3565,
45
- :guesses_log10 => 3.5520595341878844
36
+ "pattern" => "dictionary",
37
+ "i" => 0,
38
+ "j" => 7,
39
+ "token" => "password",
40
+ "matched_word" => "password",
41
+ "rank" => 2,
42
+ "dictionary_name" => "passwords",
43
+ "reversed" => false,
44
+ "l33t" => false,
45
+ "base_guesses" => 2,
46
+ "uppercase_variations" => 1,
47
+ "l33t_variations" => 1,
48
+ "guesses" => 2,
49
+ "guesses_log10" => 0.3010299956639812
46
50
  }
47
51
  ],
48
- :calc_time => 0,
49
- :crack_times_seconds => {
50
- :online_throttling_100_per_hour => 128376.0,
51
- :online_no_throttling_10_per_second => 356.6,
52
- :offline_slow_hashing_1e4_per_second => 0.3566,
53
- :offline_fast_hashing_1e10_per_second => 3.566e-07
54
- },
55
- :crack_times_display => {
56
- :online_throttling_100_per_hour => "1 day",
57
- :online_no_throttling_10_per_second => "6 minutes",
58
- :offline_slow_hashing_1e4_per_second => "less than a second",
59
- :offline_fast_hashing_1e10_per_second => "less than a second"
52
+ "calc_time" => 1,
53
+ "crack_times_seconds" => {
54
+ "online_throttling_100_per_hour" => 108.0,
55
+ "online_no_throttling_10_per_second" => 0.3,
56
+ "offline_slow_hashing_1e4_per_second" => 0.0003,
57
+ "offline_fast_hashing_1e10_per_second" => 3.0e-10},
58
+ "crack_times_display" => {
59
+ "online_throttling_100_per_hour" => "2 minutes",
60
+ "online_no_throttling_10_per_second" => "less than a second",
61
+ "offline_slow_hashing_1e4_per_second" => "less than a second",
62
+ "offline_fast_hashing_1e10_per_second" => "less than a second"
60
63
  },
61
- :score => 1,
62
- :feedback =>
63
- {
64
- :warning => "This is a very common password",
65
- :suggestions => ["Add another word or two. Uncommon words are better."]
64
+ "score" => 0,
65
+ "feedback" => {
66
+ "warning" => "This is a top-10 common password",
67
+ "suggestions" => [
68
+ "Add another word or two. Uncommon words are better."
69
+ ]
66
70
  }
67
71
  }
68
72
  ```
69
73
 
74
+ ### Compatible with `zxcvbn-js` and `zxcvbn-ruby`
75
+
76
+ This gem include a compatible interface so it can be used as a drop-in substitution for `zxcvbn-js` or `zxcvbn-ruby`. You can just call `Zxcvbn.test` or use `Zxcvbn::Tester.new` the same way as you would if you were using `zxcvbn-js` or `zxcvbn-ruby`.
77
+
70
78
  ## Development
71
79
 
72
80
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
data/bin/console CHANGED
@@ -14,5 +14,5 @@ require "zxcvbn"
14
14
  # require "irb"
15
15
  # IRB.start(__FILE__)
16
16
 
17
- require 'pry'
17
+ require "pry"
18
18
  Pry.start("main")
data/lib/zxcvbn.rb CHANGED
@@ -14,13 +14,11 @@ module Zxcvbn
14
14
  def self.zxcvbn(password, user_inputs = [])
15
15
  start = (Time.now.to_f * 1000).to_i
16
16
  # reset the user inputs matcher on a per-request basis to keep things stateless
17
- sanitized_inputs = [];
17
+ sanitized_inputs = []
18
18
  user_inputs.each do |arg|
19
- if arg.is_a?(String) || arg.is_a?(Numeric) || arg == true || arg == false
20
- sanitized_inputs << arg.to_s.downcase
21
- end
19
+ sanitized_inputs << arg.to_s.downcase if arg.is_a?(String) || arg.is_a?(Numeric) || arg == true || arg == false
22
20
  end
23
- Matching.set_user_input_dictionary(sanitized_inputs)
21
+ Matching.user_input_dictionary = sanitized_inputs
24
22
  matches = Matching.omnimatch(password)
25
23
  result = Scoring.most_guessable_match_sequence(password, matches)
26
24
  result["calc_time"] = (Time.now.to_f * 1000).to_i - start
@@ -29,6 +27,16 @@ module Zxcvbn
29
27
  result[prop] = val
30
28
  end
31
29
  result["feedback"] = Feedback.get_feedback(result["score"], result["sequence"])
32
- return result
30
+ result
31
+ end
32
+
33
+ def self.test(password, user_inputs = [])
34
+ OpenStruct.new(Zxcvbn.zxcvbn(password, user_inputs))
35
+ end
36
+
37
+ class Tester
38
+ def test(password, user_inputs = [])
39
+ Zxcvbn.test(password, user_inputs)
40
+ end
33
41
  end
34
42
  end
@@ -2,10 +2,12 @@
2
2
 
3
3
  # generated by scripts/build_keyboard_adjacency_graphs.py
4
4
  module Zxcvbn
5
+ # rubocop:disable Layout/SpaceInsideArrayLiteralBrackets
6
+ # rubocop:disable Layout/ExtraSpacing
5
7
  ADJACENCY_GRAPHS = {
6
8
  "qwerty" => {
7
9
  "!" => ["`~", nil, nil, "2@", "qQ", nil],
8
- "\"" => [";:", "[{", "]}", nil, nil, "/?"],
10
+ "\"" => [";:", "[{", "]}", nil, nil, "/?"],
9
11
  "#" => ["2@", nil, nil, "4$", "eE", "wW"],
10
12
  "$" => ["3#", nil, nil, "5%", "rR", "eE"],
11
13
  "%" => ["4$", nil, nil, "6^", "tT", "rR"],
@@ -18,7 +20,7 @@ module Zxcvbn
18
20
  "," => ["mM", "kK", "lL", ".>", nil, nil],
19
21
  "-" => ["0)", nil, nil, "=+", "[{", "pP"],
20
22
  "." => [",<", "lL", ";:", "/?", nil, nil],
21
- "/" => [".>", ";:", "'\"", nil, nil, nil],
23
+ "/" => [".>", ";:", "'\"", nil, nil, nil],
22
24
  "0" => ["9(", nil, nil, "-_", "pP", "oO"],
23
25
  "1" => ["`~", nil, nil, "2@", "qQ", nil],
24
26
  "2" => ["1!", nil, nil, "3#", "wW", "qQ"],
@@ -34,7 +36,7 @@ module Zxcvbn
34
36
  "<" => ["mM", "kK", "lL", ".>", nil, nil],
35
37
  "=" => ["-_", nil, nil, nil, "]}", "[{"],
36
38
  ">" => [",<", "lL", ";:", "/?", nil, nil],
37
- "?" => [".>", ";:", "'\"", nil, nil, nil],
39
+ "?" => [".>", ";:", "'\"", nil, nil, nil],
38
40
  "@" => ["1!", nil, nil, "3#", "wW", "qQ"],
39
41
  "A" => [ nil, "qQ", "wW", "sS", "zZ", nil],
40
42
  "B" => ["vV", "gG", "hH", "nN", nil, nil],
@@ -63,8 +65,8 @@ module Zxcvbn
63
65
  "Y" => ["tT", "6^", "7&", "uU", "hH", "gG"],
64
66
  "Z" => [ nil, "aA", "sS", "xX", nil, nil],
65
67
  "[" => ["pP", "-_", "=+", "]}", "'\"", ";:"],
66
- "\\" => ["]}", nil, nil, nil, nil, nil],
67
- "]" => ["[{", "=+", nil, "\\|", nil, "'\""],
68
+ "\\" => ["]}", nil, nil, nil, nil, nil],
69
+ "]" => ["[{", "=+", nil, "\\|", nil, "'\""],
68
70
  "^" => ["5%", nil, nil, "7&", "yY", "tT"],
69
71
  "_" => ["0)", nil, nil, "=+", "[{", "pP"],
70
72
  "`" => [ nil, nil, nil, "1!", nil, nil],
@@ -96,12 +98,12 @@ module Zxcvbn
96
98
  "z" => [ nil, "aA", "sS", "xX", nil, nil],
97
99
  "{" => ["pP", "-_", "=+", "]}", "'\"", ";:"],
98
100
  "|" => ["]}", nil, nil, nil, nil, nil],
99
- "}" => ["[{", "=+", nil, "\\|", nil, "'\""],
101
+ "}" => ["[{", "=+", nil, "\\|", nil, "'\""],
100
102
  "~" => [ nil, nil, nil, "1!", nil, nil]
101
103
  },
102
104
  "dvorak" => {
103
- "!" => ["`~", nil, nil, "2@", "'\"", nil],
104
- "\"" => [ nil, "1!", "2@", ",<", "aA", nil],
105
+ "!" => ["`~", nil, nil, "2@", "'\"", nil],
106
+ "\"" => [ nil, "1!", "2@", ",<", "aA", nil],
105
107
  "#" => ["2@", nil, nil, "4$", ".>", ",<"],
106
108
  "$" => ["3#", nil, nil, "5%", "pP", ".>"],
107
109
  "%" => ["4$", nil, nil, "6^", "yY", "pP"],
@@ -110,13 +112,13 @@ module Zxcvbn
110
112
  "(" => ["8*", nil, nil, "0)", "rR", "cC"],
111
113
  ")" => ["9(", nil, nil, "[{", "lL", "rR"],
112
114
  "*" => ["7&", nil, nil, "9(", "cC", "gG"],
113
- "+" => ["/?", "]}", nil, "\\|", nil, "-_"],
115
+ "+" => ["/?", "]}", nil, "\\|", nil, "-_"],
114
116
  "," => ["'\"", "2@", "3#", ".>", "oO", "aA"],
115
117
  "-" => ["sS", "/?", "=+", nil, nil, "zZ"],
116
118
  "." => [",<", "3#", "4$", "pP", "eE", "oO"],
117
119
  "/" => ["lL", "[{", "]}", "=+", "-_", "sS"],
118
120
  "0" => ["9(", nil, nil, "[{", "lL", "rR"],
119
- "1" => ["`~", nil, nil, "2@", "'\"", nil],
121
+ "1" => ["`~", nil, nil, "2@", "'\"", nil],
120
122
  "2" => ["1!", nil, nil, "3#", ",<", "'\""],
121
123
  "3" => ["2@", nil, nil, "4$", ".>", ",<"],
122
124
  "4" => ["3#", nil, nil, "5%", "pP", ".>"],
@@ -132,7 +134,7 @@ module Zxcvbn
132
134
  ">" => [",<", "3#", "4$", "pP", "eE", "oO"],
133
135
  "?" => ["lL", "[{", "]}", "=+", "-_", "sS"],
134
136
  "@" => ["1!", nil, nil, "3#", ",<", "'\""],
135
- "A" => [ nil, "'\"", ",<", "oO", ";:", nil],
137
+ "A" => [ nil, "'\"", ",<", "oO", ";:", nil],
136
138
  "B" => ["xX", "dD", "hH", "mM", nil, nil],
137
139
  "C" => ["gG", "8*", "9(", "rR", "tT", "hH"],
138
140
  "D" => ["iI", "fF", "gG", "hH", "bB", "xX"],
@@ -159,12 +161,12 @@ module Zxcvbn
159
161
  "Y" => ["pP", "5%", "6^", "fF", "iI", "uU"],
160
162
  "Z" => ["vV", "sS", "-_", nil, nil, nil],
161
163
  "[" => ["0)", nil, nil, "]}", "/?", "lL"],
162
- "\\" => ["=+", nil, nil, nil, nil, nil],
164
+ "\\" => ["=+", nil, nil, nil, nil, nil],
163
165
  "]" => ["[{", nil, nil, nil, "=+", "/?"],
164
166
  "^" => ["5%", nil, nil, "7&", "fF", "yY"],
165
167
  "_" => ["sS", "/?", "=+", nil, nil, "zZ"],
166
168
  "`" => [ nil, nil, nil, "1!", nil, nil],
167
- "a" => [ nil, "'\"", ",<", "oO", ";:", nil],
169
+ "a" => [ nil, "'\"", ",<", "oO", ";:", nil],
168
170
  "b" => ["xX", "dD", "hH", "mM", nil, nil],
169
171
  "c" => ["gG", "8*", "9(", "rR", "tT", "hH"],
170
172
  "d" => ["iI", "fF", "gG", "hH", "bB", "xX"],
@@ -196,39 +198,41 @@ module Zxcvbn
196
198
  "~" => [ nil, nil, nil, "1!", nil, nil]
197
199
  },
198
200
  "keypad" => {
199
- "*" => ["/", nil, nil, nil, "-", "+", "9", "8"],
200
- "+" => ["9", "*", "-", nil, nil, nil, nil, "6"],
201
- "-" => ["*", nil, nil, nil, nil, nil, "+", "9"],
202
- "." => ["0", "2", "3", nil, nil, nil, nil, nil],
203
- "/" => [ nil, nil, nil, nil, "*", "9", "8", "7"],
204
- "0" => [ nil, "1", "2", "3", ".", nil, nil, nil],
205
- "1" => [ nil, nil, "4", "5", "2", "0", nil, nil],
206
- "2" => ["1", "4", "5", "6", "3", ".", "0", nil],
207
- "3" => ["2", "5", "6", nil, nil, nil, ".", "0"],
208
- "4" => [ nil, nil, "7", "8", "5", "2", "1", nil],
201
+ "*" => ["/", nil, nil, nil, "-", "+", "9", "8"],
202
+ "+" => ["9", "*", "-", nil, nil, nil, nil, "6"],
203
+ "-" => ["*", nil, nil, nil, nil, nil, "+", "9"],
204
+ "." => ["0", "2", "3", nil, nil, nil, nil, nil],
205
+ "/" => [nil, nil, nil, nil, "*", "9", "8", "7"],
206
+ "0" => [nil, "1", "2", "3", ".", nil, nil, nil],
207
+ "1" => [nil, nil, "4", "5", "2", "0", nil, nil],
208
+ "2" => ["1", "4", "5", "6", "3", ".", "0", nil],
209
+ "3" => ["2", "5", "6", nil, nil, nil, ".", "0"],
210
+ "4" => [nil, nil, "7", "8", "5", "2", "1", nil],
209
211
  "5" => ["4", "7", "8", "9", "6", "3", "2", "1"],
210
- "6" => ["5", "8", "9", "+", nil, nil, "3", "2"],
211
- "7" => [ nil, nil, nil, "/", "8", "5", "4", nil],
212
- "8" => ["7", nil, "/", "*", "9", "6", "5", "4"],
213
- "9" => ["8", "/", "*", "-", "+", nil, "6", "5"]
212
+ "6" => ["5", "8", "9", "+", nil, nil, "3", "2"],
213
+ "7" => [nil, nil, nil, "/", "8", "5", "4", nil],
214
+ "8" => ["7", nil, "/", "*", "9", "6", "5", "4"],
215
+ "9" => ["8", "/", "*", "-", "+", nil, "6", "5"]
214
216
  },
215
217
  "mac_keypad" => {
216
- "*" => ["/", nil, nil, nil, nil, nil, "-", "9"],
217
- "+" => ["6", "9", "-", nil, nil, nil, nil, "3"],
218
- "-" => ["9", "/", "*", nil, nil, nil, "+", "6"],
219
- "." => ["0", "2", "3", nil, nil, nil, nil, nil],
220
- "/" => ["=", nil, nil, nil, "*", "-", "9", "8"],
221
- "0" => [ nil, "1", "2", "3", ".", nil, nil, nil],
222
- "1" => [ nil, nil, "4", "5", "2", "0", nil, nil],
223
- "2" => ["1", "4", "5", "6", "3", ".", "0", nil],
224
- "3" => ["2", "5", "6", "+", nil, nil, ".", "0"],
225
- "4" => [ nil, nil, "7", "8", "5", "2", "1", nil],
218
+ "*" => ["/", nil, nil, nil, nil, nil, "-", "9"],
219
+ "+" => ["6", "9", "-", nil, nil, nil, nil, "3"],
220
+ "-" => ["9", "/", "*", nil, nil, nil, "+", "6"],
221
+ "." => ["0", "2", "3", nil, nil, nil, nil, nil],
222
+ "/" => ["=", nil, nil, nil, "*", "-", "9", "8"],
223
+ "0" => [nil, "1", "2", "3", ".", nil, nil, nil],
224
+ "1" => [nil, nil, "4", "5", "2", "0", nil, nil],
225
+ "2" => ["1", "4", "5", "6", "3", ".", "0", nil],
226
+ "3" => ["2", "5", "6", "+", nil, nil, ".", "0"],
227
+ "4" => [nil, nil, "7", "8", "5", "2", "1", nil],
226
228
  "5" => ["4", "7", "8", "9", "6", "3", "2", "1"],
227
- "6" => ["5", "8", "9", "-", "+", nil, "3", "2"],
228
- "7" => [ nil, nil, nil, "=", "8", "5", "4", nil],
229
- "8" => ["7", nil, "=", "/", "9", "6", "5", "4"],
229
+ "6" => ["5", "8", "9", "-", "+", nil, "3", "2"],
230
+ "7" => [nil, nil, nil, "=", "8", "5", "4", nil],
231
+ "8" => ["7", nil, "=", "/", "9", "6", "5", "4"],
230
232
  "9" => ["8", "=", "/", "*", "-", "+", "6", "5"],
231
- "=" => [ nil, nil, nil, nil, "/", "9", "8", "7"]
233
+ "=" => [nil, nil, nil, nil, "/", "9", "8", "7"]
232
234
  }
233
- }
235
+ }.freeze
236
+ # rubocop:enable Layout/ExtraSpacing
237
+ # rubocop:enable Layout/SpaceInsideArrayLiteralBrackets
234
238
  end
@@ -3,9 +3,9 @@
3
3
  module Zxcvbn
4
4
  module Feedback
5
5
  DEFAULT_FEEDBACK = {
6
- "warning" => '',
6
+ "warning" => "",
7
7
  "suggestions" => ["Use a few words, avoid common phrases", "No need for symbols, digits, or uppercase letters"]
8
- }
8
+ }.freeze
9
9
 
10
10
  def self.get_feedback(score, sequence)
11
11
  if sequence.empty?
@@ -16,91 +16,94 @@ module Zxcvbn
16
16
  # no feedback if score is good or great.
17
17
  if score > 2
18
18
  return {
19
- "warning" => '',
19
+ "warning" => "",
20
20
  "suggestions" => []
21
21
  }
22
22
  end
23
23
 
24
- longest_match = sequence.max_by{|match| match["token"].length }
24
+ longest_match = sequence.max_by { |match| match["token"].length }
25
25
  feedback = get_match_feedback(longest_match, sequence.size == 1)
26
- extra_feedback = 'Add another word or two. Uncommon words are better.'
27
- if !feedback.nil?
26
+ extra_feedback = "Add another word or two. Uncommon words are better."
27
+ if feedback
28
28
  feedback["suggestions"].unshift(extra_feedback)
29
- if feedback["warning"].nil?
30
- feedback["warning"] = ''
31
- end
29
+ feedback["warning"] = "" if feedback["warning"].nil?
32
30
  else
33
31
  feedback = {
34
- "warning" => '',
32
+ "warning" => "",
35
33
  "suggestions" => [extra_feedback]
36
34
  }
37
35
  end
38
- return feedback
36
+ feedback
39
37
  end
40
38
 
41
39
  def self.get_match_feedback(match, is_sole_match)
42
40
  case match["pattern"]
43
- when 'dictionary'
44
- return get_dictionary_match_feedback(match, is_sole_match)
45
- when 'spatial'
46
- layout = match["graph.upcase"]
47
- warning = match["turns"] == 1 ? 'Straight rows of keys are easy to guess' : 'Short keyboard patterns are easy to guess'
48
- return {
41
+ when "dictionary"
42
+ get_dictionary_match_feedback(match, is_sole_match)
43
+ when "spatial"
44
+ warning = if match["turns"] == 1
45
+ "Straight rows of keys are easy to guess"
46
+ else
47
+ "Short keyboard patterns are easy to guess"
48
+ end
49
+ {
49
50
  "warning" => warning,
50
- "suggestions" => ['Use a longer keyboard pattern with more turns']
51
+ "suggestions" => ["Use a longer keyboard pattern with more turns"]
51
52
  }
52
- when 'repeat'
53
- warning = match["base_token"].length == 1 ? 'Repeats like "aaa" are easy to guess' : 'Repeats like "abcabcabc" are only slightly harder to guess than "abc"'
54
- return {
53
+ when "repeat"
54
+ warning = if match["base_token"].length == 1
55
+ 'Repeats like "aaa" are easy to guess'
56
+ else
57
+ 'Repeats like "abcabcabc" are only slightly harder to guess than "abc"'
58
+ end
59
+ {
55
60
  "warning" => warning,
56
- "suggestions" => ['Avoid repeated words and characters']
61
+ "suggestions" => ["Avoid repeated words and characters"]
57
62
  }
58
- when 'sequence'
59
- return {
63
+ when "sequence"
64
+ {
60
65
  "warning" => "Sequences like abc or 6543 are easy to guess",
61
- "suggestions" => ['Avoid sequences']
66
+ "suggestions" => ["Avoid sequences"]
62
67
  }
63
- when 'regex'
64
- if match["regex_name"] === 'recent_year'
65
- return {
68
+ when "regex"
69
+ if match["regex_name"] == "recent_year"
70
+ {
66
71
  "warning" => "Recent years are easy to guess",
67
- "suggestions" => ['Avoid recent years', 'Avoid years that are associated with you']
72
+ "suggestions" => ["Avoid recent years", "Avoid years that are associated with you"]
68
73
  }
69
74
  end
70
75
  # break
71
- when 'date'
72
- return {
76
+ when "date"
77
+ {
73
78
  "warning" => "Dates are often easy to guess",
74
- "suggestions" => ['Avoid dates and years that are associated with you']
79
+ "suggestions" => ["Avoid dates and years that are associated with you"]
75
80
  }
76
81
  end
77
82
  end
78
83
 
79
84
  def self.get_dictionary_match_feedback(match, is_sole_match)
80
- warning = if match["dictionary_name"] == 'passwords'
85
+ warning = if match["dictionary_name"] == "passwords"
81
86
  if is_sole_match && !match["l33t"] && !match["reversed"]
82
87
  if match["rank"] <= 10
83
- 'This is a top-10 common password'
88
+ "This is a top-10 common password"
84
89
  elsif match["rank"] <= 100
85
- 'This is a top-100 common password'
90
+ "This is a top-100 common password"
86
91
  else
87
- 'This is a very common password'
92
+ "This is a very common password"
88
93
  end
89
94
  elsif match["guesses_log10"] <= 4
90
- 'This is similar to a commonly used password'
91
- end
92
- elsif match["dictionary_name"] == 'english_wikipedia'
93
- if is_sole_match
94
- 'A word by itself is easy to guess'
95
+ "This is similar to a commonly used password"
95
96
  end
96
- elsif ['surnames', 'male_names', 'female_names'].include?(match["dictionary_name"])
97
+ elsif match["dictionary_name"] == "english_wikipedia"
98
+ "A word by itself is easy to guess" if is_sole_match
99
+ elsif ["surnames", "male_names", "female_names"].include?(match["dictionary_name"])
97
100
  if is_sole_match
98
- 'Names and surnames by themselves are easy to guess'
101
+ "Names and surnames by themselves are easy to guess"
99
102
  else
100
- 'Common names and surnames are easy to guess'
103
+ "Common names and surnames are easy to guess"
101
104
  end
102
105
  else
103
- ''
106
+ ""
104
107
  end
105
108
  suggestions = []
106
109
  word = match["token"]
@@ -109,17 +112,12 @@ module Zxcvbn
109
112
  elsif word.match(Scoring::ALL_UPPER) && word.downcase != word
110
113
  suggestions << "All-uppercase is almost as easy to guess as all-lowercase"
111
114
  end
112
- if match["reversed"] && match["token"].length >= 4
113
- suggestions << "Reversed words aren't much harder to guess"
114
- end
115
- if match["l33t"]
116
- suggestions << "Predictable substitutions like '@' instead of 'a' don't help very much"
117
- end
118
- result = {
115
+ suggestions << "Reversed words aren't much harder to guess" if match["reversed"] && match["token"].length >= 4
116
+ suggestions << "Predictable substitutions like '@' instead of 'a' don't help very much" if match["l33t"]
117
+ {
119
118
  "warning" => warning,
120
119
  "suggestions" => suggestions
121
120
  }
122
- return result
123
121
  end
124
122
  end
125
123
  end