UNPKG

zxcvbn3

Version:

realistic password strength estimation

161 lines 5.65 kB
import { Scoring } from './scoring'; export function translate(v, options) { if (options.i18n[options.language] && options.i18n[options.language][v]) { return options.i18n[options.language][v]; } if (options.i18n["en"] && options.i18n["en"][v]) { return options.i18n["en"][v]; } console.log("not found", v); return v; } export class Feedback { static get_feedback(score, sequence, options) { // starting feedback if (sequence.length === 0) { return this.default_feedback; } // no feedback if score is good or great. if (score > 2) { return { warning: '', suggestions: [] }; } // tie feedback to the longest match for longer sequences let longest_match = sequence[0]; for (let match of Array.from(sequence.slice(1))) { if (match.token.length > longest_match.token.length) { longest_match = match; } } let feedback = this.get_match_feedback(longest_match, sequence.length === 1, options); const extra_feedback = translate('ADD_MORE_WORDS', options); if (feedback != null) { feedback.suggestions.unshift(extra_feedback); if (feedback.warning == null) { feedback.warning = ''; } } else { feedback = { warning: '', suggestions: [extra_feedback] }; } return feedback; } ; static get_match_feedback(match, is_sole_match, options) { let result = { warning: "", suggestions: [], }; switch (match.pattern) { case 'dictionary': result = this.get_dictionary_match_feedback(match, is_sole_match, options); case 'spatial': var warning = match.turns === 1 ? 'NO_STRAIGHT_ROWS' : 'NO_SHORT_PATTERNS'; result.warning = warning; result.suggestions = [ 'USE_LONGER_PATTERN' ]; break; case 'repeat': warning = match.base_token.length === 1 ? 'NO_REPEATS' : 'NO_REPEATING_REPEATS'; result.warning = warning; result.suggestions = [ 'AVOID_REPEATS' ]; break; case 'sequence': result.warning = "NO_SEQUENCES"; result.suggestions = [ 'AVOID_SEQUENCES' ]; break; case 'regex': if (match.regex_name === 'recent_year') { result.warning = "NO_RECENT_YEARS"; result.suggestions = [ 'AVOID_RECENT_YEARS', 'AVOID_YEARS_ASSOCIATED_WITH_YOU' ]; } break; case 'date': result.warning = "NO_DATES", result.suggestions = [ 'AVOID_DATES' ]; break; } return { warning: translate(result.warning, options), suggestions: result.suggestions.map((s) => translate(s, options)) }; } ; static get_dictionary_match_feedback(match, is_sole_match, options) { const warning = (() => { if (match.dictionary_name === 'passwords') { if (is_sole_match && !match.l33t && !match.reversed) { if (match.rank <= 10) { return 'TOP_10_PASSWORD'; } else if (match.rank <= 100) { return 'TOP_100_PASSWORD'; } else { return 'VERY_COMMON_PASSWORD'; } } else if (match.guesses_log10 <= 4) { return 'NO_SIMILAR_PASSWORDS'; } } else if (match.dictionary_name === 'english_wikipedia') { if (is_sole_match) { return 'NOT_JUST_ONE_WORD'; } } else if (['surnames', 'male_names', 'female_names'].includes(match.dictionary_name)) { if (is_sole_match) { return 'NOT_JUST_NAMES_AND_SURNAMES'; } else { return 'NO_COMMON_NAMES'; } } else { return ''; } })(); const suggestions = []; const word = match.token; if (word.match(Scoring.START_UPPER)) { suggestions.push("CAPITALIZATION_DOESNT_MATTER"); } else if (word.match(Scoring.ALL_UPPER) && (word.toLowerCase() !== word)) { suggestions.push("ALL_UPPERCASE"); } if (match.reversed && (match.token.length >= 4)) { suggestions.push("NO_REVERSED_WORDS"); } if (match.l33t) { suggestions.push("NO_SUBSTITUTIONS"); } const result = { warning, suggestions, }; return result; } } //# sourceMappingURL=feedback.js.map