zxcvbn 0.1.2 → 0.1.7

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: 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