zxcvbn-ruby 1.2.0 → 1.4.0

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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -2
  3. data/README.md +3 -12
  4. data/lib/zxcvbn/clock.rb +11 -0
  5. data/lib/zxcvbn/crack_time.rb +14 -14
  6. data/lib/zxcvbn/data.rb +42 -9
  7. data/lib/zxcvbn/dictionary_ranker.rb +7 -6
  8. data/lib/zxcvbn/entropy.rb +52 -48
  9. data/lib/zxcvbn/feedback.rb +2 -0
  10. data/lib/zxcvbn/feedback_giver.rb +4 -3
  11. data/lib/zxcvbn/match.rb +18 -4
  12. data/lib/zxcvbn/matchers/date.rb +26 -21
  13. data/lib/zxcvbn/matchers/dictionary.rb +48 -13
  14. data/lib/zxcvbn/matchers/digits.rb +3 -1
  15. data/lib/zxcvbn/matchers/l33t.rb +56 -38
  16. data/lib/zxcvbn/matchers/new_l33t.rb +30 -32
  17. data/lib/zxcvbn/matchers/regex_helpers.rb +6 -4
  18. data/lib/zxcvbn/matchers/repeat.rb +8 -8
  19. data/lib/zxcvbn/matchers/sequences.rb +18 -18
  20. data/lib/zxcvbn/matchers/spatial.rb +26 -24
  21. data/lib/zxcvbn/matchers/year.rb +4 -2
  22. data/lib/zxcvbn/math.rb +12 -8
  23. data/lib/zxcvbn/omnimatch.rb +5 -2
  24. data/lib/zxcvbn/password_strength.rb +6 -4
  25. data/lib/zxcvbn/score.rb +3 -1
  26. data/lib/zxcvbn/scorer.rb +26 -23
  27. data/lib/zxcvbn/tester.rb +2 -2
  28. data/lib/zxcvbn/trie.rb +44 -0
  29. data/lib/zxcvbn/version.rb +1 -1
  30. data/lib/zxcvbn.rb +4 -2
  31. data/sig/README.md +65 -0
  32. data/sig/zxcvbn/crack_time.rbs +13 -0
  33. data/sig/zxcvbn/data.rbs +31 -0
  34. data/sig/zxcvbn/dictionary_ranker.rbs +7 -0
  35. data/sig/zxcvbn/entropy.rbs +33 -0
  36. data/sig/zxcvbn/feedback.rbs +8 -0
  37. data/sig/zxcvbn/feedback_giver.rbs +13 -0
  38. data/sig/zxcvbn/match.rbs +38 -0
  39. data/sig/zxcvbn/math.rbs +13 -0
  40. data/sig/zxcvbn/omnimatch.rbs +16 -0
  41. data/sig/zxcvbn/password_strength.rbs +10 -0
  42. data/sig/zxcvbn/score.rbs +15 -0
  43. data/sig/zxcvbn/scorer.rbs +20 -0
  44. data/sig/zxcvbn/tester.rbs +17 -0
  45. data/sig/zxcvbn/trie.rbs +13 -0
  46. data/sig/zxcvbn.rbs +10 -0
  47. metadata +27 -105
  48. data/.github/workflows/ci.yml +0 -23
  49. data/.gitignore +0 -18
  50. data/.rspec +0 -1
  51. data/CODE_OF_CONDUCT.md +0 -130
  52. data/Gemfile +0 -10
  53. data/Guardfile +0 -26
  54. data/Rakefile +0 -22
  55. data/spec/dictionary_ranker_spec.rb +0 -12
  56. data/spec/feedback_giver_spec.rb +0 -212
  57. data/spec/matchers/date_spec.rb +0 -109
  58. data/spec/matchers/dictionary_spec.rb +0 -30
  59. data/spec/matchers/digits_spec.rb +0 -15
  60. data/spec/matchers/l33t_spec.rb +0 -87
  61. data/spec/matchers/repeat_spec.rb +0 -18
  62. data/spec/matchers/sequences_spec.rb +0 -21
  63. data/spec/matchers/spatial_spec.rb +0 -20
  64. data/spec/matchers/year_spec.rb +0 -15
  65. data/spec/omnimatch_spec.rb +0 -24
  66. data/spec/scorer_spec.rb +0 -5
  67. data/spec/scoring/crack_time_spec.rb +0 -106
  68. data/spec/scoring/entropy_spec.rb +0 -216
  69. data/spec/scoring/math_spec.rb +0 -135
  70. data/spec/spec_helper.rb +0 -54
  71. data/spec/support/js_helpers.rb +0 -34
  72. data/spec/support/js_source/adjacency_graphs.js +0 -8
  73. data/spec/support/js_source/compiled.js +0 -1188
  74. data/spec/support/js_source/frequency_lists.js +0 -10
  75. data/spec/support/js_source/init.coffee +0 -63
  76. data/spec/support/js_source/init.js +0 -95
  77. data/spec/support/js_source/matching.coffee +0 -444
  78. data/spec/support/js_source/matching.js +0 -685
  79. data/spec/support/js_source/scoring.coffee +0 -270
  80. data/spec/support/js_source/scoring.js +0 -390
  81. data/spec/support/matcher.rb +0 -35
  82. data/spec/tester_spec.rb +0 -99
  83. data/spec/zxcvbn_spec.rb +0 -24
  84. data/zxcvbn-ruby.gemspec +0 -33
@@ -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'
@@ -11,9 +13,9 @@ module Zxcvbn
11
13
  end
12
14
 
13
15
  def test(password, user_inputs = [])
14
- password = password || ''
16
+ 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,19 +18,22 @@ 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.positive? ? 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|
27
31
  match.j == k
28
32
  end.each do |match|
29
- i, j = match.i, match.j
33
+ i = match.i
34
+ j = match.j
30
35
  # 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
36
+ previous_i_entropy = i.positive? ? up_to_k[i - 1] : 0
32
37
  candidate_entropy = previous_i_entropy + calc_entropy(match)
33
38
  if up_to_k[j] && candidate_entropy < up_to_k[j]
34
39
  up_to_k[j] = candidate_entropy
@@ -54,29 +59,26 @@ module Zxcvbn
54
59
  score_for(password, match_sequence, up_to_k)
55
60
  end
56
61
 
57
- 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
+ def score_for(password, match_sequence, up_to_k)
63
+ min_entropy = up_to_k[password.length - 1] || 0 # or 0 corner case is for an empty password ''
59
64
  crack_time = entropy_to_crack_time(min_entropy)
60
65
 
61
66
  # final result object
62
67
  Score.new(
63
- :password => password,
64
- :entropy => min_entropy.round(3),
65
- :match_sequence => match_sequence,
66
- :crack_time => crack_time.round(3),
67
- :crack_time_display => display_time(crack_time),
68
- :score => crack_time_to_score(crack_time)
68
+ password: password,
69
+ entropy: min_entropy.round(3),
70
+ match_sequence: match_sequence,
71
+ crack_time: crack_time.round(3),
72
+ crack_time_display: display_time(crack_time),
73
+ score: crack_time_to_score(crack_time)
69
74
  )
70
75
  end
71
76
 
72
-
73
77
  def pad_with_bruteforce_matches(match_sequence, password, bruteforce_cardinality)
74
78
  k = 0
75
79
  match_sequence_copy = []
76
80
  match_sequence.each do |match|
77
- if match.i > k
78
- match_sequence_copy << make_bruteforce_match(password, k, match.i - 1, bruteforce_cardinality)
79
- end
81
+ match_sequence_copy << make_bruteforce_match(password, k, match.i - 1, bruteforce_cardinality) if match.i > k
80
82
  k = match.j + 1
81
83
  match_sequence_copy << match
82
84
  end
@@ -85,17 +87,18 @@ module Zxcvbn
85
87
  end
86
88
  match_sequence_copy
87
89
  end
90
+
88
91
  # fill in the blanks between pattern matches with bruteforce "matches"
89
92
  # that way the match sequence fully covers the password:
90
93
  # match1.j == match2.i - 1 for every adjacent match1, match2.
91
94
  def make_bruteforce_match(password, i, j, bruteforce_cardinality)
92
95
  Match.new(
93
- :pattern => 'bruteforce',
94
- :i => i,
95
- :j => j,
96
- :token => password[i..j],
97
- :entropy => lg(bruteforce_cardinality ** (j - i + 1)),
98
- :cardinality => bruteforce_cardinality
96
+ pattern: 'bruteforce',
97
+ i: i,
98
+ j: j,
99
+ token: password.slice(i, j - i + 1),
100
+ entropy: lg(bruteforce_cardinality**(j - i + 1)),
101
+ cardinality: bruteforce_cardinality
99
102
  )
100
103
  end
101
104
  end
data/lib/zxcvbn/tester.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "zxcvbn/data"
4
- require "zxcvbn/password_strength"
3
+ require 'zxcvbn/data'
4
+ require 'zxcvbn/password_strength'
5
5
 
6
6
  module Zxcvbn
7
7
  # Allows you to test the strength of multiple passwords without reading and
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zxcvbn
4
+ # A trie (prefix tree) data structure for efficient dictionary matching.
5
+ # Provides fast prefix-based lookups to eliminate unnecessary substring checks.
6
+ #
7
+ # @see https://en.wikipedia.org/wiki/Trie
8
+ class Trie
9
+ def initialize
10
+ @root = {}
11
+ end
12
+
13
+ # Insert a word and its rank into the trie
14
+ # @param word [String] the word to insert
15
+ # @param rank [Integer] the rank/frequency of the word
16
+ def insert(word, rank)
17
+ node = @root
18
+ word.each_char do |char|
19
+ node[char] ||= {}
20
+ node = node[char]
21
+ end
22
+ node[:rank] = rank
23
+ end
24
+
25
+ # Search for all words in the text starting from a given position
26
+ # @param text [String] the text to search in
27
+ # @param start_pos [Integer] the starting position
28
+ # @return [Array<Array>] array of [word, rank, start, end] tuples
29
+ def search_prefixes(text, start_pos)
30
+ results = []
31
+ node = @root
32
+
33
+ (start_pos...text.length).each do |i|
34
+ char = text[i]
35
+ break unless node[char]
36
+
37
+ node = node[char]
38
+ results << [text[start_pos..i], node[:rank], start_pos, i] if node[:rank]
39
+ end
40
+
41
+ results
42
+ end
43
+ end
44
+ 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.4.0'
5
5
  end
data/lib/zxcvbn.rb CHANGED
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathname'
2
4
  require 'zxcvbn/version'
3
5
  require 'zxcvbn/tester'
4
6
 
5
7
  module Zxcvbn
6
- extend self
8
+ module_function
7
9
 
8
- DATA_PATH = Pathname(File.expand_path('../../data', __FILE__))
10
+ DATA_PATH = Pathname(File.expand_path('../data', __dir__))
9
11
 
10
12
  # Returns a Zxcvbn::Score for the given password
11
13
  #
data/sig/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # RBS Type Signatures
2
+
3
+ This directory contains [RBS](https://github.com/ruby/rbs) type signatures for the zxcvbn-ruby gem.
4
+
5
+ ## What is RBS?
6
+
7
+ RBS is Ruby's type signature language. It provides a way to describe the structure of Ruby programs with:
8
+ - Class and module definitions
9
+ - Method signatures with parameter and return types
10
+ - Instance variables and constants
11
+ - Duck typing and union types
12
+
13
+ ## Usage
14
+
15
+ ### Validating Type Signatures
16
+
17
+ To validate that the RBS files are syntactically correct:
18
+
19
+ ```bash
20
+ bundle exec rake rbs:validate
21
+ ```
22
+
23
+ ### Runtime Type Checking
24
+
25
+ To run runtime type checking against the actual Ruby code during tests:
26
+
27
+ ```bash
28
+ bundle exec rake rbs:test
29
+ ```
30
+
31
+ This runs the RSpec test suite with RBS type checking enabled, verifying that method calls match their type signatures at runtime. Note: This takes about 2 minutes to run.
32
+
33
+ ### Other Useful Commands
34
+
35
+ List all Zxcvbn types:
36
+ ```bash
37
+ bundle exec rake rbs:list
38
+ ```
39
+
40
+ Check syntax of RBS files:
41
+ ```bash
42
+ bundle exec rake rbs:parse
43
+ ```
44
+
45
+ ## File Structure
46
+
47
+ The signatures mirror the structure of the `lib/` directory:
48
+
49
+ - `sig/zxcvbn.rbs` - Main Zxcvbn module
50
+ - `sig/zxcvbn/*.rbs` - Core classes (Tester, Score, Match, etc.)
51
+ - `sig/zxcvbn/matchers/*.rbs` - Pattern matcher classes
52
+
53
+ ## Adding New Signatures
54
+
55
+ When adding new classes or methods to the codebase, remember to:
56
+
57
+ 1. Create or update the corresponding `.rbs` file in the `sig/` directory
58
+ 2. Run `bundle exec rake rbs_validate` to ensure the syntax is correct
59
+ 3. Keep type signatures in sync with the actual implementation
60
+
61
+ ## Resources
62
+
63
+ - [RBS Documentation](https://github.com/ruby/rbs)
64
+ - [RBS Syntax Guide](https://github.com/ruby/rbs/blob/master/docs/syntax.md)
65
+ - [Ruby Signature Collection](https://github.com/ruby/gem_rbs_collection)
@@ -0,0 +1,13 @@
1
+ module Zxcvbn
2
+ module CrackTime
3
+ SINGLE_GUESS: Float
4
+ NUM_ATTACKERS: Integer
5
+ SECONDS_PER_GUESS: Float
6
+
7
+ def entropy_to_crack_time: (Numeric entropy) -> Float
8
+
9
+ def crack_time_to_score: (Numeric seconds) -> Integer
10
+
11
+ def display_time: (Numeric seconds) -> String
12
+ end
13
+ end
@@ -0,0 +1,31 @@
1
+ module Zxcvbn
2
+ class Data
3
+ type ranked_dictionary = Hash[String, Integer]
4
+ type adjacency_graph = Hash[String, Array[String?]]
5
+ type graph_stats = Hash[String, { average_degree: Float, starting_positions: Integer }]
6
+
7
+ @ranked_dictionaries: Hash[String, ranked_dictionary]
8
+ @adjacency_graphs: Hash[String, adjacency_graph]
9
+ @dictionary_tries: Hash[String, Trie]
10
+ @graph_stats: graph_stats
11
+
12
+ attr_reader ranked_dictionaries: Hash[String, ranked_dictionary]
13
+ attr_reader adjacency_graphs: Hash[String, adjacency_graph]
14
+ attr_reader dictionary_tries: Hash[String, Trie]
15
+ attr_reader graph_stats: graph_stats
16
+
17
+ def initialize: () -> void
18
+
19
+ def add_word_list: (String name, Array[String] list) -> void
20
+
21
+ private
22
+
23
+ def read_word_list: (String file) -> Array[String]
24
+
25
+ def build_tries: () -> Hash[String, Trie]
26
+
27
+ def build_trie: (ranked_dictionary ranked_dictionary) -> Trie
28
+
29
+ def compute_graph_stats: () -> graph_stats
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ module Zxcvbn
2
+ class DictionaryRanker
3
+ def self.rank_dictionaries: (Hash[String | Symbol, Array[String]] lists) -> Hash[String | Symbol, Hash[String, Integer]]
4
+
5
+ def self.rank_dictionary: (Array[String] words) -> Hash[String, Integer]
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ module Zxcvbn
2
+ module Entropy
3
+ include Zxcvbn::Math
4
+
5
+ def calc_entropy: (Match match) -> Float
6
+
7
+ def repeat_entropy: (Match match) -> Float
8
+
9
+ def sequence_entropy: (Match match) -> Float
10
+
11
+ def digits_entropy: (Match match) -> Float
12
+
13
+ def year_entropy: (Match? match) -> Float
14
+
15
+ def date_entropy: (Match match) -> Float
16
+
17
+ def dictionary_entropy: (Match match) -> Float
18
+
19
+ def extra_uppercase_entropy: (Match match) -> Numeric
20
+
21
+ def extra_l33t_entropy: (Match match) -> Numeric
22
+
23
+ def spatial_entropy: (Match match) -> Float
24
+
25
+ NUM_YEARS: Integer
26
+ NUM_MONTHS: Integer
27
+ NUM_DAYS: Integer
28
+ START_UPPER: Regexp
29
+ END_UPPER: Regexp
30
+ ALL_UPPER: Regexp
31
+ ALL_LOWER: Regexp
32
+ end
33
+ end
@@ -0,0 +1,8 @@
1
+ module Zxcvbn
2
+ class Feedback
3
+ attr_accessor warning: String?
4
+ attr_accessor suggestions: Array[String]
5
+
6
+ def initialize: (?warning: String?, ?suggestions: Array[String]) -> void
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ module Zxcvbn
2
+ class FeedbackGiver
3
+ NAME_DICTIONARIES: Array[String]
4
+ DEFAULT_FEEDBACK: Feedback
5
+ EMPTY_FEEDBACK: Feedback
6
+
7
+ def self.get_feedback: (Integer? score, Array[Match] sequence) -> Feedback
8
+
9
+ def self.get_match_feedback: (Match match, bool is_sole_match) -> Feedback?
10
+
11
+ def self.get_dictionary_match_feedback: (Match match, bool is_sole_match) -> Feedback
12
+ end
13
+ end
@@ -0,0 +1,38 @@
1
+ module Zxcvbn
2
+ class Match
3
+ attr_accessor pattern: String?
4
+ attr_accessor i: Integer?
5
+ attr_accessor j: Integer?
6
+ attr_accessor token: String?
7
+ attr_accessor matched_word: String?
8
+ attr_accessor rank: Integer?
9
+ attr_accessor dictionary_name: String?
10
+ attr_accessor reversed: bool?
11
+ attr_accessor l33t: bool?
12
+ attr_accessor sub: Hash[String, String]?
13
+ attr_accessor sub_display: String?
14
+ attr_accessor l: Integer?
15
+ attr_accessor entropy: Numeric?
16
+ attr_accessor base_entropy: Numeric?
17
+ attr_accessor uppercase_entropy: Numeric?
18
+ attr_accessor l33t_entropy: Numeric?
19
+ attr_accessor repeated_char: String?
20
+ attr_accessor sequence_name: String?
21
+ attr_accessor sequence_space: Integer?
22
+ attr_accessor ascending: bool?
23
+ attr_accessor graph: String?
24
+ attr_accessor turns: Integer?
25
+ attr_accessor shifted_count: Integer?
26
+ attr_accessor shiffted_count: Integer?
27
+ attr_accessor year: Integer?
28
+ attr_accessor month: Integer?
29
+ attr_accessor day: Integer?
30
+ attr_accessor separator: String?
31
+ attr_accessor cardinality: Integer?
32
+ attr_accessor offset: Integer?
33
+
34
+ def initialize: (**untyped attributes) -> void
35
+
36
+ def to_hash: () -> Hash[String, untyped]
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ module Zxcvbn
2
+ module Math
3
+ def bruteforce_cardinality: (String password) -> Integer
4
+
5
+ def lg: (Numeric n) -> Float
6
+
7
+ def nCk: (Integer n, Integer k) -> Integer
8
+
9
+ def average_degree_for_graph: (String graph_name) -> Float
10
+
11
+ def starting_positions_for_graph: (String graph_name) -> Integer
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ module Zxcvbn
2
+ class Omnimatch
3
+ @data: Data
4
+ @matchers: Array[untyped]
5
+
6
+ def initialize: (Data data) -> void
7
+
8
+ def matches: (String password, ?Array[String] user_inputs) -> Array[Match]
9
+
10
+ private
11
+
12
+ def user_input_matchers: (Array[String] user_inputs) -> Array[untyped]
13
+
14
+ def build_matchers: () -> Array[untyped]
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ module Zxcvbn
2
+ class PasswordStrength
3
+ @omnimatch: Omnimatch
4
+ @scorer: Scorer
5
+
6
+ def initialize: (Data data) -> void
7
+
8
+ def test: (String? password, ?Array[untyped] user_inputs) -> Score
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module Zxcvbn
2
+ class Score
3
+ attr_accessor entropy: Numeric?
4
+ attr_accessor crack_time: Numeric?
5
+ attr_accessor crack_time_display: String?
6
+ attr_accessor score: Integer?
7
+ attr_accessor pattern: String?
8
+ attr_accessor match_sequence: Array[Match]?
9
+ attr_accessor password: String?
10
+ attr_accessor calc_time: Float?
11
+ attr_accessor feedback: Feedback?
12
+
13
+ def initialize: (?entropy: Numeric?, ?crack_time: Numeric?, ?crack_time_display: String?, ?score: Integer?, ?match_sequence: Array[Match]?, ?password: String?) -> void
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ module Zxcvbn
2
+ class Scorer
3
+ include Entropy
4
+ include CrackTime
5
+
6
+ @data: Data
7
+
8
+ attr_reader data: Data
9
+
10
+ def initialize: (Data data) -> void
11
+
12
+ def minimum_entropy_match_sequence: (String password, Array[Match] matches) -> Score
13
+
14
+ def score_for: (String password, Array[Match] match_sequence, Array[Float] up_to_k) -> Score
15
+
16
+ def pad_with_bruteforce_matches: (Array[Match] match_sequence, String password, Integer bruteforce_cardinality) -> Array[Match]
17
+
18
+ def make_bruteforce_match: (String password, Integer i, Integer j, Integer bruteforce_cardinality) -> Match
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module Zxcvbn
2
+ class Tester
3
+ @data: Data
4
+
5
+ def initialize: () -> void
6
+
7
+ def test: (String? password, ?Array[untyped] user_inputs) -> Score
8
+
9
+ def add_word_lists: (Hash[String, Array[untyped]] lists) -> void
10
+
11
+ def inspect: () -> String
12
+
13
+ private
14
+
15
+ def sanitize: (Array[untyped] user_inputs) -> Array[String]
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module Zxcvbn
2
+ class Trie
3
+ type node = Hash[untyped, untyped]
4
+
5
+ @root: node
6
+
7
+ def initialize: () -> void
8
+
9
+ def insert: (String word, Integer rank) -> void
10
+
11
+ def search_prefixes: (String text, Integer start_pos) -> Array[[String, Integer?, Integer, Integer]]
12
+ end
13
+ end
data/sig/zxcvbn.rbs ADDED
@@ -0,0 +1,10 @@
1
+ module Zxcvbn
2
+ VERSION: String
3
+
4
+ DATA_PATH: Pathname
5
+
6
+ type word_list = Hash[String, Array[String]]
7
+ type user_inputs = Array[String]
8
+
9
+ def self.test: (String? password, ?user_inputs user_inputs, ?word_list word_lists) -> Score
10
+ end