2022-03-17 08:11:46 +01:00
|
|
|
import {zxcvbn, zxcvbnOptions} from "@zxcvbn-ts/core";
|
|
|
|
import zxcvbnCommonPackage from "@zxcvbn-ts/language-common";
|
|
|
|
import zxcvbnEnPackage from "@zxcvbn-ts/language-en";
|
2021-04-23 21:27:13 +02:00
|
|
|
|
|
|
|
import {$t} from "./i18n";
|
|
|
|
|
2022-03-17 08:11:46 +01:00
|
|
|
zxcvbnOptions.setOptions({
|
|
|
|
translations: zxcvbnEnPackage.translations,
|
|
|
|
dictionary: {
|
|
|
|
...zxcvbnCommonPackage.dictionary,
|
|
|
|
...zxcvbnEnPackage.dictionary,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2021-04-23 21:27:13 +02:00
|
|
|
// Note: this module is loaded asynchronously from the app with
|
|
|
|
// import() to keep zxcvbn out of the initial page load. Do not
|
|
|
|
// import it synchronously from the app.
|
|
|
|
|
|
|
|
// Return a boolean indicating whether the password is acceptable.
|
|
|
|
// Also updates a Bootstrap progress bar control (a jQuery object)
|
|
|
|
// if provided.
|
2021-07-03 19:51:37 +02:00
|
|
|
export function password_quality(
|
|
|
|
password: string,
|
2022-01-25 11:36:19 +01:00
|
|
|
$bar: JQuery | undefined,
|
|
|
|
$password_field: JQuery,
|
2021-07-03 19:51:37 +02:00
|
|
|
): boolean {
|
2022-01-25 11:36:19 +01:00
|
|
|
const min_length = $password_field.data("minLength");
|
|
|
|
const min_guesses = $password_field.data("minGuesses");
|
2021-04-23 21:27:13 +02:00
|
|
|
|
|
|
|
const result = zxcvbn(password);
|
|
|
|
const acceptable = password.length >= min_length && result.guesses >= min_guesses;
|
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
if ($bar !== undefined) {
|
2022-03-17 08:11:46 +01:00
|
|
|
const t = result.crackTimesSeconds.offlineSlowHashing1e4PerSecond;
|
2021-04-23 21:27:13 +02:00
|
|
|
let bar_progress = Math.min(1, Math.log(1 + t) / 22);
|
|
|
|
|
|
|
|
// Even if zxcvbn loves your short password, the bar should be
|
|
|
|
// filled at most 1/3 of the way, because we won't accept it.
|
|
|
|
if (!acceptable) {
|
|
|
|
bar_progress = Math.min(bar_progress, 0.33);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The bar bottoms out at 10% so there's always something
|
|
|
|
// for the user to see.
|
2022-01-25 11:36:19 +01:00
|
|
|
$bar.width(`${90 * bar_progress + 10}%`)
|
2021-04-23 21:27:13 +02:00
|
|
|
.removeClass("bar-success bar-danger")
|
|
|
|
.addClass(acceptable ? "bar-success" : "bar-danger");
|
|
|
|
}
|
|
|
|
|
|
|
|
return acceptable;
|
|
|
|
}
|
|
|
|
|
2022-01-25 11:36:19 +01:00
|
|
|
export function password_warning(password: string, $password_field: JQuery): string {
|
|
|
|
const min_length = $password_field.data("minLength");
|
2021-04-23 21:27:13 +02:00
|
|
|
|
|
|
|
if (password.length < min_length) {
|
|
|
|
return $t(
|
|
|
|
{defaultMessage: "Password should be at least {length} characters long"},
|
|
|
|
{length: min_length},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return zxcvbn(password).feedback.warning || $t({defaultMessage: "Password is too weak"});
|
|
|
|
}
|