Module: Zxcvbn

Defined in:
lib/zxcvbn.rb,
lib/zxcvbn/data.rb,
lib/zxcvbn/math.rb,
lib/zxcvbn/trie.rb,
lib/zxcvbn/clock.rb,
lib/zxcvbn/match.rb,
lib/zxcvbn/score.rb,
lib/zxcvbn/scorer.rb,
lib/zxcvbn/tester.rb,
lib/zxcvbn/guesses.rb,
lib/zxcvbn/version.rb,
lib/zxcvbn/feedback.rb,
lib/zxcvbn/omnimatch.rb,
lib/zxcvbn/crack_time.rb,
lib/zxcvbn/match_builder.rb,
lib/zxcvbn/matchers/date.rb,
lib/zxcvbn/matchers/l33t.rb,
lib/zxcvbn/matchers/year.rb,
lib/zxcvbn/feedback_giver.rb,
lib/zxcvbn/tester_builder.rb,
lib/zxcvbn/matchers/digits.rb,
lib/zxcvbn/matchers/repeat.rb,
lib/zxcvbn/matchers/spatial.rb,
lib/zxcvbn/dictionary_ranker.rb,
lib/zxcvbn/matchers/sequences.rb,
lib/zxcvbn/matchers/dictionary.rb,
lib/zxcvbn/matchers/regex_helpers.rb

Overview

Ruby port of zxcvbn.js — realistic password strength estimation.

Analyses a password against dictionary lists, keyboard patterns, dates, sequences, and repeats to produce a Score with guess estimates and human-readable crack-time display strings.

Defined Under Namespace

Modules: Clock, CrackTime, Guesses, Matchers, Math Classes: Data, DictionaryRanker, Feedback, FeedbackGiver, Match, MatchBuilder, Omnimatch, PasswordTooLong, Score, Scorer, Tester, TesterBuilder, Trie

Constant Summary collapse

VERSION =
'2.0.0'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#ascendingBoolean? (readonly)

Returns true if the sequence is ascending.

Returns:

  • (Boolean, nil)

    true if the sequence is ascending



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#base_guessesNumeric? (readonly)

Returns guesses for the base token (repeat matches) or rank before variation multipliers (dictionary matches).

Returns:

  • (Numeric, nil)

    guesses for the base token (repeat matches) or rank before variation multipliers (dictionary matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#base_tokenString? (readonly)

Returns the minimal repeating unit (repeat matches).

Returns:

  • (String, nil)

    the minimal repeating unit (repeat matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#calc_timeFloat? (readonly)

Returns time taken to evaluate, in seconds.

Returns:

  • (Float, nil)

    time taken to evaluate, in seconds



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/zxcvbn/score.rb', line 22

Score = ::Data.define(
  :password, :guesses, :sequence, :crack_times_seconds,
  :crack_times_display, :score, :calc_time, :feedback
) do
  def initialize(calc_time: nil, feedback: nil, **kwargs)
    super(calc_time:, feedback:, **kwargs)
  end

  # @return [String] a human-readable representation omitting nil fields and password
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :password }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @return [Float, nil] log10 of {#guesses}, or nil if guesses is not set
  def guesses_log10
    ::Math.log10(guesses) if guesses
  end
end

#crack_times_displayHash{String => String} (readonly)

Returns human-readable crack times per scenario.

Returns:

  • (Hash{String => String})

    human-readable crack times per scenario



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/zxcvbn/score.rb', line 22

Score = ::Data.define(
  :password, :guesses, :sequence, :crack_times_seconds,
  :crack_times_display, :score, :calc_time, :feedback
) do
  def initialize(calc_time: nil, feedback: nil, **kwargs)
    super(calc_time:, feedback:, **kwargs)
  end

  # @return [String] a human-readable representation omitting nil fields and password
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :password }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @return [Float, nil] log10 of {#guesses}, or nil if guesses is not set
  def guesses_log10
    ::Math.log10(guesses) if guesses
  end
end

#crack_times_secondsHash{String => Float} (readonly)

Returns crack time in seconds per attack scenario.

Returns:

  • (Hash{String => Float})

    crack time in seconds per attack scenario



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/zxcvbn/score.rb', line 22

Score = ::Data.define(
  :password, :guesses, :sequence, :crack_times_seconds,
  :crack_times_display, :score, :calc_time, :feedback
) do
  def initialize(calc_time: nil, feedback: nil, **kwargs)
    super(calc_time:, feedback:, **kwargs)
  end

  # @return [String] a human-readable representation omitting nil fields and password
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :password }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @return [Float, nil] log10 of {#guesses}, or nil if guesses is not set
  def guesses_log10
    ::Math.log10(guesses) if guesses
  end
end

#dayInteger? (readonly)

Returns matched day (date matches).

Returns:

  • (Integer, nil)

    matched day (date matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#dictionary_nameString? (readonly)

Returns source dictionary name (dictionary matches).

Returns:

  • (String, nil)

    source dictionary name (dictionary matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#feedbackFeedback? (readonly)

Returns human-readable feedback for low-scoring passwords.

Returns:

  • (Feedback, nil)

    human-readable feedback for low-scoring passwords



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/zxcvbn/score.rb', line 22

Score = ::Data.define(
  :password, :guesses, :sequence, :crack_times_seconds,
  :crack_times_display, :score, :calc_time, :feedback
) do
  def initialize(calc_time: nil, feedback: nil, **kwargs)
    super(calc_time:, feedback:, **kwargs)
  end

  # @return [String] a human-readable representation omitting nil fields and password
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :password }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @return [Float, nil] log10 of {#guesses}, or nil if guesses is not set
  def guesses_log10
    ::Math.log10(guesses) if guesses
  end
end

#graphString? (readonly)

Returns keyboard graph name (spatial matches).

Returns:

  • (String, nil)

    keyboard graph name (spatial matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#guessesNumeric (readonly)

Returns estimated number of guesses to crack the password.

Returns:

  • (Numeric)

    estimated number of guesses to crack the password



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#guesses_log10Float? (readonly)

Returns log10 of #guesses.

Returns:



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#iInteger? (readonly)

Returns start index in the password (inclusive).

Returns:

  • (Integer, nil)

    start index in the password (inclusive)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#jInteger? (readonly)

Returns end index in the password (inclusive).

Returns:

  • (Integer, nil)

    end index in the password (inclusive)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#l33tBoolean? (readonly)

Returns true when the match required l33t substitution.

Returns:

  • (Boolean, nil)

    true when the match required l33t substitution



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#l33t_variationsNumeric? (readonly)

Returns l33t substitution variant count (dictionary matches).

Returns:

  • (Numeric, nil)

    l33t substitution variant count (dictionary matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#matched_wordString? (readonly)

Returns lowercased dictionary word (dictionary matches).

Returns:

  • (String, nil)

    lowercased dictionary word (dictionary matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#monthInteger? (readonly)

Returns matched month (date matches).

Returns:

  • (Integer, nil)

    matched month (date matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#passwordString (readonly)

Returns the password that was evaluated.

Returns:

  • (String)

    the password that was evaluated



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/zxcvbn/score.rb', line 22

Score = ::Data.define(
  :password, :guesses, :sequence, :crack_times_seconds,
  :crack_times_display, :score, :calc_time, :feedback
) do
  def initialize(calc_time: nil, feedback: nil, **kwargs)
    super(calc_time:, feedback:, **kwargs)
  end

  # @return [String] a human-readable representation omitting nil fields and password
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :password }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @return [Float, nil] log10 of {#guesses}, or nil if guesses is not set
  def guesses_log10
    ::Math.log10(guesses) if guesses
  end
end

#patternString? (readonly)

Returns the matcher that produced this match.

Returns:

  • (String, nil)

    the matcher that produced this match



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#rankInteger? (readonly)

Returns frequency rank of the matched word (dictionary matches).

Returns:

  • (Integer, nil)

    frequency rank of the matched word (dictionary matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#repeat_countInteger? (readonly)

Returns number of repetitions (repeat matches).

Returns:

  • (Integer, nil)

    number of repetitions (repeat matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#reversedBoolean? (readonly)

Returns true when matched in the reversed password.

Returns:

  • (Boolean, nil)

    true when matched in the reversed password



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#scoreInteger (readonly)

Returns 0–4 score (0 = very weak, 4 = very strong).

Returns:

  • (Integer)

    0–4 score (0 = very weak, 4 = very strong)



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/zxcvbn/score.rb', line 22

Score = ::Data.define(
  :password, :guesses, :sequence, :crack_times_seconds,
  :crack_times_display, :score, :calc_time, :feedback
) do
  def initialize(calc_time: nil, feedback: nil, **kwargs)
    super(calc_time:, feedback:, **kwargs)
  end

  # @return [String] a human-readable representation omitting nil fields and password
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :password }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @return [Float, nil] log10 of {#guesses}, or nil if guesses is not set
  def guesses_log10
    ::Math.log10(guesses) if guesses
  end
end

#separatorString? (readonly)

Returns date separator character (date matches).

Returns:

  • (String, nil)

    date separator character (date matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#sequenceArray<Match> (readonly)

Returns the optimal match sequence.

Returns:

  • (Array<Match>)

    the optimal match sequence



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/zxcvbn/score.rb', line 22

Score = ::Data.define(
  :password, :guesses, :sequence, :crack_times_seconds,
  :crack_times_display, :score, :calc_time, :feedback
) do
  def initialize(calc_time: nil, feedback: nil, **kwargs)
    super(calc_time:, feedback:, **kwargs)
  end

  # @return [String] a human-readable representation omitting nil fields and password
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :password }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @return [Float, nil] log10 of {#guesses}, or nil if guesses is not set
  def guesses_log10
    ::Math.log10(guesses) if guesses
  end
end

#sequence_nameString? (readonly)

Returns sequence type: “lower”, “upper”, “digits”, or “unicode”.

Returns:

  • (String, nil)

    sequence type: “lower”, “upper”, “digits”, or “unicode”



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#sequence_spaceInteger? (readonly)

Returns size of the character set for the sequence.

Returns:

  • (Integer, nil)

    size of the character set for the sequence



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#shifted_countInteger? (readonly)

Returns number of shifted characters (spatial matches).

Returns:

  • (Integer, nil)

    number of shifted characters (spatial matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#subHash? (readonly)

Returns map of l33t characters to their substituted letters.

Returns:

  • (Hash, nil)

    map of l33t characters to their substituted letters



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#sub_displayString? (readonly)

Returns human-readable substitution summary.

Returns:

  • (String, nil)

    human-readable substitution summary



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#suggestionsArray<String> (readonly)

Returns ordered list of improvement tips.

Returns:

  • (Array<String>)

    ordered list of improvement tips



10
11
12
13
14
15
16
# File 'lib/zxcvbn/feedback.rb', line 10

Feedback = ::Data.define(:warning, :suggestions) do
  # @param warning [String] warning message (default: empty string)
  # @param suggestions [Array<String>] improvement tips (default: [])
  def initialize(warning: nil, suggestions: [])
    super(warning: warning || '', suggestions: suggestions.freeze)
  end
end

#tokenString? (readonly)

Returns the matched substring.

Returns:

  • (String, nil)

    the matched substring



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#turnsInteger? (readonly)

Returns number of direction changes (spatial matches).

Returns:

  • (Integer, nil)

    number of direction changes (spatial matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#uppercase_variationsNumeric? (readonly)

Returns capitalisation variant count (dictionary matches).

Returns:

  • (Numeric, nil)

    capitalisation variant count (dictionary matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

#warningString (readonly)

Returns a single warning message, or empty string.

Returns:

  • (String)

    a single warning message, or empty string



10
11
12
13
14
15
16
# File 'lib/zxcvbn/feedback.rb', line 10

Feedback = ::Data.define(:warning, :suggestions) do
  # @param warning [String] warning message (default: empty string)
  # @param suggestions [Array<String>] improvement tips (default: [])
  def initialize(warning: nil, suggestions: [])
    super(warning: warning || '', suggestions: suggestions.freeze)
  end
end

#yearInteger? (readonly)

Returns matched year (date/year matches).

Returns:

  • (Integer, nil)

    matched year (date/year matches)



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/zxcvbn/match.rb', line 66

Match = ::Data.define(
  :pattern, :i, :j, :token, :matched_word, :rank, :dictionary_name, :reversed,
  :l33t, :sub, :sub_display, :guesses, :guesses_log10, :base_guesses,
  :uppercase_variations, :l33t_variations, :base_token, :repeat_count,
  :sequence_name, :sequence_space, :ascending, :graph, :turns, :shifted_count,
  :year, :month, :day, :separator
) do
  def initialize(
    pattern: nil, i: nil, j: nil, token: nil, matched_word: nil, rank: nil,
    dictionary_name: nil, reversed: nil, l33t: nil, sub: nil,
    sub_display: nil, guesses: nil, guesses_log10: nil, base_guesses: nil,
    uppercase_variations: nil, l33t_variations: nil, base_token: nil,
    repeat_count: nil, sequence_name: nil, sequence_space: nil,
    ascending: nil, graph: nil, turns: nil, shifted_count: nil,
    year: nil, month: nil, day: nil, separator: nil
  )
    super
  end

  # @return [String] a human-readable representation omitting nil fields and token
  def inspect
    fields = to_h.reject { |k, v| v.nil? || k == :token }.map { |k, v| "#{k}=#{v.inspect}" }.join(', ')
    "#<data #{self.class} #{fields}>"
  end

  # @param pp [PP] the pretty-printer instance
  # @return [void]
  def pretty_print(pp)
    fields = to_h.reject { |_, v| v.nil? }
    pp.group(1, "#<data #{self.class}", '>') do
      fields.each_with_index do |(k, v), i|
        pp.text(',') if i.positive?
        pp.breakable ' '
        pp.text("#{k}=")
        v.pretty_print(pp)
      end
    end
  end
end

Class Method Details

.test(password, user_inputs = []) ⇒ Score

Returns a Zxcvbn::Score for the given password.

Reuses a shared Tester instance across calls. For custom word lists or options, use tester_builder to build a dedicated Tester.

Raises PasswordTooLong (a subclass of ArgumentError) if the password exceeds the configured limit (default: 256 characters). Override process-wide via the ZXCVBN_MAX_PASSWORD_LENGTH environment variable; for per-call limits, use tester_builder with Zxcvbn::TesterBuilder#max_password_length.

Example:

Zxcvbn.test("password").score #=> 0

Parameters:

  • password (String)

    the password to evaluate

  • user_inputs (Array<String>) (defaults to: [])

    caller-supplied words to treat as known

Returns:

Raises:



37
38
39
# File 'lib/zxcvbn.rb', line 37

def test(password, user_inputs = [])
  default_tester.test(password, user_inputs)
end

.tester_builderTesterBuilder

Returns a new TesterBuilder for constructing a Tester with custom word lists and options.

Example:

tester = Zxcvbn
  .tester_builder
  .add_word_list('company', %w[acme corp])
  .max_password_length(75)
  .build

Returns:



53
54
55
# File 'lib/zxcvbn.rb', line 53

def tester_builder
  TesterBuilder.new
end