zxcvbn-ruby 1.3.0 → 2.0.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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +71 -1
  3. data/README.md +322 -75
  4. data/data/frequency_lists/english_wikipedia.txt +30000 -0
  5. data/data/frequency_lists/female_names.txt +11 -114
  6. data/data/frequency_lists/male_names.txt +3 -24
  7. data/data/frequency_lists/passwords.txt +29623 -6764
  8. data/data/frequency_lists/surnames.txt +28 -30611
  9. data/data/frequency_lists/{english.txt → us_tv_and_film.txt} +147 -13532
  10. data/lib/zxcvbn/clock.rb +6 -0
  11. data/lib/zxcvbn/crack_time.rb +52 -18
  12. data/lib/zxcvbn/data.rb +61 -21
  13. data/lib/zxcvbn/dictionary_ranker.rb +10 -0
  14. data/lib/zxcvbn/feedback.rb +11 -6
  15. data/lib/zxcvbn/feedback_giver.rb +75 -50
  16. data/lib/zxcvbn/guesses.rb +208 -0
  17. data/lib/zxcvbn/match.rb +95 -15
  18. data/lib/zxcvbn/match_builder.rb +15 -0
  19. data/lib/zxcvbn/matchers/date.rb +171 -106
  20. data/lib/zxcvbn/matchers/dictionary.rb +15 -8
  21. data/lib/zxcvbn/matchers/digits.rb +6 -1
  22. data/lib/zxcvbn/matchers/l33t.rb +30 -34
  23. data/lib/zxcvbn/matchers/regex_helpers.rb +14 -6
  24. data/lib/zxcvbn/matchers/repeat.rb +47 -16
  25. data/lib/zxcvbn/matchers/sequences.rb +58 -48
  26. data/lib/zxcvbn/matchers/spatial.rb +22 -6
  27. data/lib/zxcvbn/matchers/year.rb +6 -1
  28. data/lib/zxcvbn/math.rb +15 -28
  29. data/lib/zxcvbn/omnimatch.rb +70 -22
  30. data/lib/zxcvbn/ruby.rb +3 -0
  31. data/lib/zxcvbn/score.rb +34 -10
  32. data/lib/zxcvbn/scorer.rb +142 -75
  33. data/lib/zxcvbn/tester.rb +58 -23
  34. data/lib/zxcvbn/tester_builder.rb +83 -0
  35. data/lib/zxcvbn/trie.rb +21 -0
  36. data/lib/zxcvbn/version.rb +1 -1
  37. data/lib/zxcvbn.rb +47 -7
  38. data/sig/README.md +65 -0
  39. data/sig/zxcvbn/clock.rbs +5 -0
  40. data/sig/zxcvbn/crack_time.rbs +11 -0
  41. data/sig/zxcvbn/data.rbs +40 -0
  42. data/sig/zxcvbn/dictionary_ranker.rbs +7 -0
  43. data/sig/zxcvbn/feedback.rbs +10 -0
  44. data/sig/zxcvbn/feedback_giver.rbs +13 -0
  45. data/sig/zxcvbn/guesses.rbs +36 -0
  46. data/sig/zxcvbn/match.rbs +40 -0
  47. data/sig/zxcvbn/match_builder.rbs +36 -0
  48. data/sig/zxcvbn/matchers/date.rbs +23 -0
  49. data/sig/zxcvbn/matchers/dictionary.rbs +21 -0
  50. data/sig/zxcvbn/matchers/digits.rbs +11 -0
  51. data/sig/zxcvbn/matchers/l33t.rbs +27 -0
  52. data/sig/zxcvbn/matchers/regex_helpers.rbs +7 -0
  53. data/sig/zxcvbn/matchers/repeat.rbs +11 -0
  54. data/sig/zxcvbn/matchers/sequences.rbs +16 -0
  55. data/sig/zxcvbn/matchers/spatial.rbs +15 -0
  56. data/sig/zxcvbn/matchers/year.rbs +11 -0
  57. data/sig/zxcvbn/math.rbs +9 -0
  58. data/sig/zxcvbn/omnimatch.rbs +19 -0
  59. data/sig/zxcvbn/score.rbs +26 -0
  60. data/sig/zxcvbn/scorer.rbs +19 -0
  61. data/sig/zxcvbn/tester.rbs +15 -0
  62. data/sig/zxcvbn/tester_builder.rbs +16 -0
  63. data/sig/zxcvbn/trie.rbs +17 -0
  64. data/sig/zxcvbn.rbs +12 -0
  65. metadata +46 -12
  66. data/lib/zxcvbn/entropy.rb +0 -158
  67. data/lib/zxcvbn/matchers/new_l33t.rb +0 -118
  68. data/lib/zxcvbn/password_strength.rb +0 -27
data/lib/zxcvbn.rb CHANGED
@@ -1,22 +1,62 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
4
3
  require 'zxcvbn/version'
5
4
  require 'zxcvbn/tester'
5
+ require 'zxcvbn/tester_builder'
6
6
 
7
+ # Ruby port of zxcvbn.js — realistic password strength estimation.
8
+ #
9
+ # Analyses a password against dictionary lists, keyboard patterns, dates,
10
+ # sequences, and repeats to produce a {Score} with guess estimates and
11
+ # human-readable crack-time display strings.
7
12
  module Zxcvbn
8
13
  module_function
9
14
 
10
- DATA_PATH = Pathname(File.expand_path('../data', __dir__))
15
+ # Mutex protecting lazy initialisation of the shared default {Tester}.
16
+ DEFAULT_TESTER_MUTEX = Mutex.new
17
+ private_constant :DEFAULT_TESTER_MUTEX
11
18
 
12
- # Returns a Zxcvbn::Score for the given password
19
+ # Returns a Zxcvbn::Score for the given password.
20
+ #
21
+ # Reuses a shared {Tester} instance across calls. For custom word lists or
22
+ # options, use {.tester_builder} to build a dedicated {Tester}.
23
+ #
24
+ # Raises {PasswordTooLong} (a subclass of +ArgumentError+) if the password
25
+ # exceeds the configured limit (default: 256 characters). Override process-wide
26
+ # via the +ZXCVBN_MAX_PASSWORD_LENGTH+ environment variable; for per-call limits,
27
+ # use {.tester_builder} with {TesterBuilder#max_password_length}.
13
28
  #
14
29
  # Example:
15
30
  #
16
31
  # Zxcvbn.test("password").score #=> 0
17
- def test(password, user_inputs = [], word_lists = {})
18
- tester = Tester.new
19
- tester.add_word_lists(word_lists)
20
- tester.test(password, user_inputs)
32
+ #
33
+ # @param password [String] the password to evaluate
34
+ # @param user_inputs [Array<String>] caller-supplied words to treat as known
35
+ # @return [Score]
36
+ # @raise [PasswordTooLong] if the password exceeds the maximum length
37
+ def test(password, user_inputs = [])
38
+ default_tester.test(password, user_inputs)
39
+ end
40
+
41
+ # Returns a new {TesterBuilder} for constructing a {Tester} with custom
42
+ # word lists and options.
43
+ #
44
+ # Example:
45
+ #
46
+ # tester = Zxcvbn
47
+ # .tester_builder
48
+ # .add_word_list('company', %w[acme corp])
49
+ # .max_password_length(75)
50
+ # .build
51
+ #
52
+ # @return [TesterBuilder]
53
+ def tester_builder
54
+ TesterBuilder.new
55
+ end
56
+
57
+ # @return [Tester] the shared default tester, constructed on first call
58
+ def default_tester
59
+ DEFAULT_TESTER_MUTEX.synchronize { @default_tester ||= tester_builder.build }
21
60
  end
61
+ private_class_method :default_tester
22
62
  end
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,5 @@
1
+ module Zxcvbn
2
+ module Clock
3
+ def self.realtime: () { () -> void } -> Float
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module Zxcvbn
2
+ module CrackTime
3
+ ATTACK_SCENARIOS: Hash[String, Float]
4
+
5
+ def estimate_attack_times: (Numeric guesses) -> { crack_times_seconds: Hash[String, Float], crack_times_display: Hash[String, String] }
6
+
7
+ def guesses_to_score: (Numeric guesses) -> Integer
8
+
9
+ def display_time: (Numeric seconds) -> String
10
+ end
11
+ end
@@ -0,0 +1,40 @@
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
+ class Dictionaries
8
+ attr_reader ranked: Hash[String, ranked_dictionary]
9
+ attr_reader tries: Hash[String, Trie]
10
+
11
+ def initialize: (ranked: Hash[String, ranked_dictionary], tries: Hash[String, Trie]) -> void
12
+ end
13
+
14
+ RESERVED_NAMES: Array[String]
15
+
16
+ @dictionaries: Dictionaries
17
+ @adjacency_graphs: Hash[String, adjacency_graph]
18
+ @graph_stats: graph_stats
19
+
20
+ attr_reader dictionaries: Dictionaries
21
+ attr_reader adjacency_graphs: Hash[String, adjacency_graph]
22
+ attr_reader graph_stats: graph_stats
23
+
24
+ def ranked_dictionaries: () -> Hash[String, ranked_dictionary]
25
+
26
+ def dictionary_tries: () -> Hash[String, Trie]
27
+
28
+ def initialize: () -> void
29
+
30
+ def add_word_list: (String name, Array[untyped] list) -> void
31
+
32
+ private
33
+
34
+ def read_word_list: (String file) -> Array[String]
35
+
36
+ def build_tries: (Hash[String, ranked_dictionary] ranked) -> Hash[String, Trie]
37
+
38
+ def compute_graph_stats: () -> graph_stats
39
+ end
40
+ 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,10 @@
1
+ module Zxcvbn
2
+ class Feedback < Data
3
+ attr_reader warning: String
4
+ attr_reader suggestions: Array[String]
5
+
6
+ def initialize: (?warning: String, ?suggestions: Array[String]) -> void
7
+
8
+ def with: (?warning: String, ?suggestions: Array[String]) -> Feedback
9
+ end
10
+ 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,36 @@
1
+ module Zxcvbn
2
+ module Guesses
3
+ MIN_GUESSES_BEFORE_GROWING_SEQUENCE: Integer
4
+ MIN_SUBMATCH_GUESSES_SINGLE_CHAR: Integer
5
+ MIN_SUBMATCH_GUESSES_MULTI_CHAR: Integer
6
+ BRUTEFORCE_CARDINALITY: Integer
7
+ MIN_YEAR_SPACE: Integer
8
+
9
+ START_UPPER: Regexp
10
+ END_UPPER: Regexp
11
+ ALL_UPPER: Regexp
12
+ ALL_LOWER: Regexp
13
+
14
+ attr_reader reference_year: Integer
15
+
16
+ def estimate_guesses: (MatchBuilder match, String password) -> Numeric
17
+
18
+ def bruteforce_guesses: (MatchBuilder match) -> Numeric
19
+
20
+ def sequence_guesses: (MatchBuilder match) -> Numeric
21
+
22
+ def digits_guesses: (MatchBuilder match) -> Integer
23
+
24
+ def year_guesses: (MatchBuilder match) -> Integer
25
+
26
+ def date_guesses: (MatchBuilder match) -> Numeric
27
+
28
+ def spatial_guesses: (MatchBuilder match) -> Numeric
29
+
30
+ def dictionary_guesses: (MatchBuilder match) -> Numeric
31
+
32
+ def uppercase_variations: (MatchBuilder match) -> Integer
33
+
34
+ def l33t_variations: (MatchBuilder match) -> Integer
35
+ end
36
+ end
@@ -0,0 +1,40 @@
1
+ module Zxcvbn
2
+ class Match < Data
3
+ attr_reader pattern: String?
4
+ attr_reader i: Integer?
5
+ attr_reader j: Integer?
6
+ attr_reader token: String?
7
+ attr_reader matched_word: String?
8
+ attr_reader rank: Integer?
9
+ attr_reader dictionary_name: String?
10
+ attr_reader reversed: bool?
11
+ attr_reader l33t: bool?
12
+ attr_reader sub: Hash[String, String]?
13
+ attr_reader sub_display: String?
14
+ attr_reader guesses: Numeric?
15
+ attr_reader guesses_log10: Float?
16
+ attr_reader base_guesses: Numeric?
17
+ attr_reader uppercase_variations: Numeric?
18
+ attr_reader l33t_variations: Numeric?
19
+ attr_reader base_token: String?
20
+ attr_reader repeat_count: Integer?
21
+ attr_reader sequence_name: String?
22
+ attr_reader sequence_space: Integer?
23
+ attr_reader ascending: bool?
24
+ attr_reader graph: String?
25
+ attr_reader turns: Integer?
26
+ attr_reader shifted_count: Integer?
27
+ attr_reader year: Integer?
28
+ attr_reader month: Integer?
29
+ attr_reader day: Integer?
30
+ attr_reader separator: String?
31
+
32
+ def initialize: (?pattern: String?, ?i: Integer?, ?j: Integer?, ?token: String?, ?matched_word: String?, ?rank: Integer?, ?dictionary_name: String?, ?reversed: bool?, ?l33t: bool?, ?sub: Hash[String, String]?, ?sub_display: String?, ?guesses: Numeric?, ?guesses_log10: Float?, ?base_guesses: Numeric?, ?uppercase_variations: Numeric?, ?l33t_variations: Numeric?, ?base_token: String?, ?repeat_count: Integer?, ?sequence_name: String?, ?sequence_space: Integer?, ?ascending: bool?, ?graph: String?, ?turns: Integer?, ?shifted_count: Integer?, ?year: Integer?, ?month: Integer?, ?day: Integer?, ?separator: String?) -> void
33
+
34
+ def with: (**untyped) -> Match
35
+
36
+ def inspect: () -> String
37
+
38
+ def pretty_print: (untyped pp) -> void
39
+ end
40
+ end
@@ -0,0 +1,36 @@
1
+ module Zxcvbn
2
+ class MatchBuilder
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 guesses: Numeric?
15
+ attr_accessor guesses_log10: Float?
16
+ attr_accessor base_guesses: Numeric?
17
+ attr_accessor uppercase_variations: Numeric?
18
+ attr_accessor l33t_variations: Numeric?
19
+ attr_accessor base_token: String?
20
+ attr_accessor repeat_count: Integer?
21
+ attr_accessor sequence_name: String?
22
+ attr_accessor sequence_space: Integer?
23
+ attr_accessor ascending: bool?
24
+ attr_accessor graph: String?
25
+ attr_accessor turns: Integer?
26
+ attr_accessor shifted_count: Integer?
27
+ attr_accessor year: Integer?
28
+ attr_accessor month: Integer?
29
+ attr_accessor day: Integer?
30
+ attr_accessor separator: String?
31
+
32
+ def initialize: (?pattern: String?, ?i: Integer?, ?j: Integer?, ?token: String?, ?matched_word: String?, ?rank: Integer?, ?dictionary_name: String?, ?reversed: bool?, ?l33t: bool?, ?sub: Hash[String, String]?, ?sub_display: String?, ?guesses: Numeric?, ?guesses_log10: Float?, ?base_guesses: Numeric?, ?uppercase_variations: Numeric?, ?l33t_variations: Numeric?, ?base_token: String?, ?repeat_count: Integer?, ?sequence_name: String?, ?sequence_space: Integer?, ?ascending: bool?, ?graph: String?, ?turns: Integer?, ?shifted_count: Integer?, ?year: Integer?, ?month: Integer?, ?day: Integer?, ?separator: String?) -> void
33
+
34
+ def build: () -> Match
35
+ end
36
+ end
@@ -0,0 +1,23 @@
1
+ module Zxcvbn
2
+ module Matchers
3
+ class Date
4
+ MAYBE_DATE_WITH_SEP: Regexp
5
+ MAYBE_DATE_WITHOUT_SEP: Regexp
6
+ DATE_SPLITS: Hash[Integer, Array[[Integer, Integer]]]
7
+ DATE_MIN_YEAR: Integer
8
+ DATE_MAX_YEAR: Integer
9
+
10
+ def matches: (String password, ?reference_year: Integer) -> Array[MatchBuilder]
11
+
12
+ def match_with_separator: (String password) -> Array[MatchBuilder]
13
+
14
+ def match_without_separator: (String password, ?reference_year: Integer) -> Array[MatchBuilder]
15
+
16
+ def map_ints_to_dmy: (Integer int1, Integer int2, Integer int3) -> { year: Integer, month: Integer, day: Integer }?
17
+
18
+ def map_ints_to_dm: (Integer day_val, Integer month_val) -> { day: Integer, month: Integer }?
19
+
20
+ def expand_year: (Integer year) -> Integer
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ module Zxcvbn
2
+ module Matchers
3
+ class Dictionary
4
+ @name: String
5
+ @ranked_dictionary: Data::ranked_dictionary
6
+ @trie: Trie?
7
+
8
+ def initialize: (String name, Data::ranked_dictionary ranked_dictionary, ?Trie? trie) -> void
9
+
10
+ def matches: (String password) -> Array[MatchBuilder]
11
+
12
+ private
13
+
14
+ def trie_matches: (String password, String lowercased_password) -> Array[MatchBuilder]
15
+
16
+ def hash_matches: (String password, String lowercased_password) -> Array[MatchBuilder]
17
+
18
+ def build_match: (String matched_word, String token, Integer start_pos, Integer end_pos, Integer rank) -> MatchBuilder
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module Zxcvbn
2
+ module Matchers
3
+ class Digits
4
+ include RegexHelpers
5
+
6
+ DIGITS_REGEX: Regexp
7
+
8
+ def matches: (String password) -> Array[MatchBuilder]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ module Zxcvbn
2
+ module Matchers
3
+ class L33t
4
+ L33T_TABLE: Hash[String, Array[String]]
5
+
6
+ @dictionary_matchers: Array[Dictionary]
7
+
8
+ def initialize: (Array[Dictionary] dictionary_matchers) -> void
9
+
10
+ def matches: (String password) -> Array[MatchBuilder]
11
+
12
+ def translate: (String password, Hash[String, String] sub) -> String
13
+
14
+ def relevent_l33t_subtable: (String password) -> Hash[String, Array[String]]
15
+
16
+ def l33t_subs: (Hash[String, Array[String]] table) -> Array[Hash[String, String]]
17
+
18
+ private
19
+
20
+ def process_match: (MatchBuilder match, String password, Hash[String, String] substitution, Array[MatchBuilder] matches) -> void
21
+
22
+ def find_substitutions: (Array[untyped] subs, Hash[String, Array[String]] table, Array[String] keys) -> Array[untyped]
23
+
24
+ def dedup: (Array[untyped] subs) -> Array[untyped]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ module Zxcvbn
2
+ module Matchers
3
+ module RegexHelpers
4
+ def re_match_all: (Regexp regex, String password) { (MatchBuilder, MatchData) -> void } -> void
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Zxcvbn
2
+ module Matchers
3
+ class Repeat
4
+ GREEDY: Regexp
5
+ LAZY: Regexp
6
+ LAZY_ANCHORED: Regexp
7
+
8
+ def matches: (String password) -> Array[MatchBuilder]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module Zxcvbn
2
+ module Matchers
3
+ class Sequences
4
+ MAX_DELTA: Integer
5
+ ALL_LOWER: Regexp
6
+ ALL_UPPER: Regexp
7
+ ALL_DIGITS: Regexp
8
+
9
+ def matches: (String password) -> Array[MatchBuilder]
10
+
11
+ private
12
+
13
+ def classify: (String token) -> [String, Integer]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module Zxcvbn
2
+ module Matchers
3
+ class Spatial
4
+ SHIFTED_RX: Regexp
5
+
6
+ @graphs: Hash[String, Data::adjacency_graph]
7
+
8
+ def initialize: (Hash[String, Data::adjacency_graph] graphs) -> void
9
+
10
+ def matches: (String password) -> Array[MatchBuilder]
11
+
12
+ def matches_for_graph: (Data::adjacency_graph graph, String graph_name, String password) -> Array[MatchBuilder]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Zxcvbn
2
+ module Matchers
3
+ class Year
4
+ include RegexHelpers
5
+
6
+ YEAR_REGEX: Regexp
7
+
8
+ def matches: (String password) -> Array[MatchBuilder]
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module Zxcvbn
2
+ module Math
3
+ def nCk: (Integer n, Integer k) -> Integer
4
+
5
+ def average_degree_for_graph: (String graph_name) -> Float
6
+
7
+ def starting_positions_for_graph: (String graph_name) -> Integer
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module Zxcvbn
2
+ class Omnimatch
3
+ @data: Data
4
+ @dictionary_matchers: Array[Matchers::Dictionary]
5
+ @matchers: Array[untyped]
6
+
7
+ def initialize: (Data data) -> void
8
+
9
+ def matches: (String password, ?Array[String] user_inputs, ?reference_year: Integer) -> Array[MatchBuilder]
10
+
11
+ private
12
+
13
+ def user_input_matchers: (Array[untyped] user_inputs) -> Array[untyped]
14
+
15
+ def reverse_dictionary_matches: (String password, ?Array[untyped] user_inputs) -> Array[MatchBuilder]
16
+
17
+ def build_matchers: () -> Array[untyped]
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ module Zxcvbn
2
+ class Score < ::Data
3
+ def self.new: (
4
+ password: String,
5
+ guesses: Numeric,
6
+ sequence: Array[Match],
7
+ crack_times_seconds: Hash[String, Float],
8
+ crack_times_display: Hash[String, String],
9
+ score: Integer,
10
+ ?calc_time: Float?,
11
+ ?feedback: Feedback?
12
+ ) -> instance
13
+
14
+ attr_reader password: String?
15
+ attr_reader guesses: Numeric?
16
+ attr_reader sequence: Array[Match]?
17
+ attr_reader crack_times_seconds: Hash[String, Float]?
18
+ attr_reader crack_times_display: Hash[String, String]?
19
+ attr_reader score: Integer?
20
+ attr_reader calc_time: Float?
21
+ attr_reader feedback: Feedback?
22
+
23
+ def guesses_log10: () -> Float?
24
+ def with: (**untyped) -> instance
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ module Zxcvbn
2
+ class Scorer
3
+ include Guesses
4
+ include CrackTime
5
+
6
+ @data: Data
7
+ @omnimatch: Omnimatch
8
+ @reference_year: Integer
9
+ @repeat_cache: Hash[String, Numeric]
10
+
11
+ attr_reader data: Data
12
+
13
+ def initialize: (Data data, Omnimatch omnimatch, Integer reference_year) -> void
14
+
15
+ def most_guessable_match_sequence: (String password, Array[MatchBuilder] matches, ?exclude_additive: bool) -> Score
16
+
17
+ def repeat_guesses: (MatchBuilder match) -> Numeric
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ module Zxcvbn
2
+ class Tester
3
+ @data: Data
4
+ @omnimatch: Omnimatch
5
+ @max_password_length: Integer
6
+
7
+ def initialize: (data: Data, max_password_length: untyped) -> void
8
+
9
+ attr_reader max_password_length: Integer
10
+
11
+ def test: (String? password, ?(Array[untyped] | String)? user_inputs) -> Score
12
+
13
+ def inspect: () -> String
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module Zxcvbn
2
+ class TesterBuilder
3
+ DEFAULT_MAX_PASSWORD_LENGTH: Integer
4
+
5
+ @word_lists: Hash[String, Array[untyped]]
6
+ @max_password_length: Integer?
7
+
8
+ def initialize: () -> void
9
+
10
+ def add_word_list: (String name, ?(Array[untyped] | String)? words) -> TesterBuilder
11
+
12
+ def max_password_length: (Integer length) -> TesterBuilder
13
+
14
+ def build: () -> Tester
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module Zxcvbn
2
+ class Trie
3
+ type node = Hash[untyped, untyped]
4
+
5
+ @root: node
6
+
7
+ def self.from_ranked: (Data::ranked_dictionary ranked_dictionary) -> Trie
8
+
9
+ def initialize: () -> void
10
+
11
+ def insert: (String word, Integer rank) -> void
12
+
13
+ def freeze: () -> self
14
+
15
+ def search_prefixes: (String text, Integer start_pos) -> Array[[String, Integer?, Integer, Integer]]
16
+ end
17
+ end
data/sig/zxcvbn.rbs ADDED
@@ -0,0 +1,12 @@
1
+ module Zxcvbn
2
+ class PasswordTooLong < ArgumentError
3
+ end
4
+
5
+ VERSION: String
6
+
7
+ type user_inputs = Array[String]
8
+
9
+ def self.test: (String? password, ?user_inputs user_inputs) -> Score
10
+
11
+ def self.tester_builder: () -> TesterBuilder
12
+ end