Class: Zxcvbn::FeedbackGiver Private

Inherits:
Object
  • Object
show all
Defined in:
lib/zxcvbn/feedback_giver.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Generates human-readable Feedback for a password given its score and match sequence.

Constant Summary collapse

NAME_DICTIONARIES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

%w[surnames male_names female_names].freeze
DEFAULT_FEEDBACK =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Feedback.new(
  suggestions: [
    'Use a few words, avoid common phrases',
    'No need for symbols, digits, or uppercase letters'
  ]
)
EMPTY_FEEDBACK =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Feedback.new

Class Method Summary collapse

Class Method Details

.get_dictionary_match_feedback(match, is_sole_match) ⇒ Feedback

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns feedback specific to a dictionary match.

Parameters:

  • match (Match)

    a dictionary pattern match

  • is_sole_match (Boolean)

    true when this is the only match in the sequence

Returns:



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/zxcvbn/feedback_giver.rb', line 120

def self.get_dictionary_match_feedback(match, is_sole_match)
  warning =
    if match.dictionary_name == 'passwords'
      if is_sole_match && !match.l33t && !match.reversed
        if match.rank <= 10
          'This is a top-10 common password'
        elsif match.rank <= 100
          'This is a top-100 common password'
        else
          'This is a very common password'
        end
      elsif (match.guesses_log10 || 0) <= 4
        'This is similar to a commonly used password'
      end
    elsif match.dictionary_name == 'english_wikipedia'
      'A word by itself is easy to guess' if is_sole_match
    elsif NAME_DICTIONARIES.include? match.dictionary_name
      if is_sole_match
        'Names and surnames by themselves are easy to guess'
      else
        'Common names and surnames are easy to guess'
      end
    end

  suggestions = []
  word = match.token

  if word =~ Zxcvbn::Guesses::START_UPPER
    suggestions.push("Capitalization doesn't help very much")
  elsif word =~ Zxcvbn::Guesses::ALL_UPPER && word.downcase != word
    suggestions.push('All-uppercase is almost as easy to guess as all-lowercase')
  end

  suggestions.push("Reversed words aren't much harder to guess") if match.reversed && match.token.length >= 4
  suggestions.push("Predictable substitutions like '@' instead of 'a' don't help very much") if match.l33t

  Feedback.new(warning:, suggestions:)
end

.get_feedback(score, sequence) ⇒ Feedback

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns feedback appropriate for the given score and match sequence.

Parameters:

  • score (Integer)

    0–4 score from the scorer

  • sequence (Array<Match>)

    optimal match sequence

Returns:



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/zxcvbn/feedback_giver.rb', line 26

def self.get_feedback(score, sequence)
  # starting feedback
  return DEFAULT_FEEDBACK if sequence.empty?

  # no feedback if score is good or great.
  return EMPTY_FEEDBACK if score > 2

  # tie feedback to the longest match for longer sequences
  longest_match = sequence[0]
  sequence[1..].each do |match|
    longest_match = match if match.token.length > longest_match.token.length
  end

  feedback = get_match_feedback(longest_match, sequence.length == 1)
  extra_feedback = 'Add another word or two. Uncommon words are better.'

  if feedback.nil?
    Feedback.new(suggestions: [extra_feedback])
  else
    feedback.with(suggestions: [extra_feedback, *feedback.suggestions])
  end
end

.get_match_feedback(match, is_sole_match) ⇒ Feedback?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns pattern-specific feedback for a single match, or nil if none applies.

Parameters:

  • match (Match)
  • is_sole_match (Boolean)

    true when this is the only match in the sequence

Returns:



54
55
56
57
58
59
60
61
62
63
64
65
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
105
106
107
108
109
110
111
112
113
# File 'lib/zxcvbn/feedback_giver.rb', line 54

def self.get_match_feedback(match, is_sole_match)
  case match.pattern
  when 'dictionary'
    get_dictionary_match_feedback match, is_sole_match

  when 'spatial'
    warning =
      if match.turns == 1
        'Straight rows of keys are easy to guess'
      else
        'Short keyboard patterns are easy to guess'
      end

    Feedback.new(
      warning:,
      suggestions: [
        'Use a longer keyboard pattern with more turns'
      ]
    )

  when 'repeat'
    warning =
      if match.base_token.length == 1
        'Repeats like "aaa" are easy to guess'
      else
        'Repeats like "abcabcabc" are only slightly harder to guess than "abc"'
      end
    Feedback.new(
      warning:,
      suggestions: [
        'Avoid repeated words and characters'
      ]
    )

  when 'sequence'
    Feedback.new(
      warning: 'Sequences like abc or 6543 are easy to guess',
      suggestions: [
        'Avoid sequences'
      ]
    )

  when 'year'
    Feedback.new(
      warning: 'Recent years are easy to guess',
      suggestions: [
        'Avoid recent years',
        'Avoid years that are associated with you'
      ]
    )

  when 'date'
    Feedback.new(
      warning: 'Dates are often easy to guess',
      suggestions: [
        'Avoid dates and years that are associated with you'
      ]
    )
  end
end