zxcvbn3
Version:
realistic password strength estimation
161 lines • 5.65 kB
JavaScript
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