135 lines
4.6 KiB
Python
135 lines
4.6 KiB
Python
from zxcvbn.scoring import START_UPPER, ALL_UPPER
|
|
from gettext import gettext as _
|
|
|
|
|
|
def get_feedback(score, sequence):
|
|
if len(sequence) == 0:
|
|
return {
|
|
'warning': '',
|
|
'suggestions': [
|
|
_("Use a few words, avoid common phrases."),
|
|
_("No need for symbols, digits, or uppercase letters.")
|
|
]
|
|
}
|
|
|
|
if score > 2:
|
|
return {
|
|
'warning': '',
|
|
'suggestions': [],
|
|
}
|
|
|
|
longest_match = sequence[0]
|
|
for match in sequence[1:]:
|
|
if len(match['token']) > len(longest_match['token']):
|
|
longest_match = match
|
|
|
|
feedback = get_match_feedback(longest_match, len(sequence) == 1)
|
|
extra_feedback = _('Add another word or two. Uncommon words are better.')
|
|
if feedback:
|
|
feedback['suggestions'].insert(0, extra_feedback)
|
|
if not feedback['warning']:
|
|
feedback['warning'] = ''
|
|
else:
|
|
feedback = {
|
|
'warning': '',
|
|
'suggestions': [extra_feedback]
|
|
}
|
|
|
|
return feedback
|
|
|
|
|
|
def get_match_feedback(match, is_sole_match):
|
|
if match['pattern'] == 'dictionary':
|
|
return get_dictionary_match_feedback(match, is_sole_match)
|
|
elif match['pattern'] == 'spatial':
|
|
if match['turns'] == 1:
|
|
warning = _('Straight rows of keys are easy to guess.')
|
|
else:
|
|
warning = _('Short keyboard patterns are easy to guess.')
|
|
|
|
return {
|
|
'warning': warning,
|
|
'suggestions': [
|
|
_('Use a longer keyboard pattern with more turns.')
|
|
]
|
|
}
|
|
elif match['pattern'] == 'repeat':
|
|
if len(match['base_token']) == 1:
|
|
warning = _('Repeats like "aaa" are easy to guess.')
|
|
else:
|
|
warning = _('Repeats like "abcabcabc" are only slightly harder to ' \
|
|
'guess than "abc".')
|
|
return {
|
|
'warning': warning,
|
|
'suggestions': [
|
|
_('Avoid repeated words and characters.')
|
|
]
|
|
}
|
|
elif match['pattern'] == 'sequence':
|
|
return {
|
|
'warning': _('Sequences like "abc" or "6543" are easy to guess.'),
|
|
'suggestions': [
|
|
_('Avoid sequences.')
|
|
]
|
|
}
|
|
elif match['pattern'] == 'regex':
|
|
if match['regex_name'] == 'recent_year':
|
|
return {
|
|
'warning': _("Recent years are easy to guess."),
|
|
'suggestions': [
|
|
_('Avoid recent years.'),
|
|
_('Avoid years that are associated with you.'),
|
|
]
|
|
}
|
|
elif match['pattern'] == 'date':
|
|
return {
|
|
'warning': _("Dates are often easy to guess."),
|
|
'suggestions': [
|
|
_('Avoid dates and years that are associated with you.'),
|
|
],
|
|
}
|
|
|
|
|
|
def get_dictionary_match_feedback(match, is_sole_match):
|
|
warning = ''
|
|
if match['dictionary_name'] == 'passwords':
|
|
if is_sole_match and not match.get('l33t', False) and not \
|
|
match['reversed']:
|
|
if match['rank'] <= 10:
|
|
warning = _('This is a top-10 common password.')
|
|
elif match['rank'] <= 100:
|
|
warning = _('This is a top-100 common password.')
|
|
else:
|
|
warning = _('This is a very common password.')
|
|
elif match['guesses_log10'] <= 4:
|
|
warning = _('This is similar to a commonly used password.')
|
|
elif match['dictionary_name'] == 'english':
|
|
if is_sole_match:
|
|
warning = _('A word by itself is easy to guess.')
|
|
elif match['dictionary_name'] in ['surnames', 'male_names',
|
|
'female_names', ]:
|
|
if is_sole_match:
|
|
warning = _('Names and surnames by themselves are easy to guess.')
|
|
else:
|
|
warning = _('Common names and surnames are easy to guess.')
|
|
else:
|
|
warning = ''
|
|
|
|
suggestions = []
|
|
word = match['token']
|
|
if START_UPPER.search(word):
|
|
suggestions.append(_("Capitalization doesn't help very much."))
|
|
elif ALL_UPPER.search(word) and word.lower() != word:
|
|
suggestions.append(_("All-uppercase is almost as easy to guess as "
|
|
"all-lowercase."))
|
|
|
|
if match['reversed'] and len(match['token']) >= 4:
|
|
suggestions.append(_("Reversed words aren't much harder to guess."))
|
|
if match.get('l33t', False):
|
|
suggestions.append(_("Predictable substitutions like '@' instead of 'a' "
|
|
"don't help very much."))
|
|
|
|
return {
|
|
'warning': warning,
|
|
'suggestions': suggestions,
|
|
}
|