Files
zulip/web/src/password_quality.ts
Anders Kaseorg c1675913a2 web: Move web app to ‘web’ directory.
Ever since we started bundling the app with webpack, there’s been less
and less overlap between our ‘static’ directory (files belonging to
the frontend app) and Django’s interpretation of the ‘static’
directory (files served directly to the web).

Split the app out to its own ‘web’ directory outside of ‘static’, and
remove all the custom collectstatic --ignore rules.  This makes it
much clearer what’s actually being served to the web, and what’s being
bundled by webpack.  It also shrinks the release tarball by 3%.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
2023-02-23 16:04:17 -08:00

64 lines
2.2 KiB
TypeScript

import {zxcvbn, zxcvbnOptions} from "@zxcvbn-ts/core";
import zxcvbnCommonPackage from "@zxcvbn-ts/language-common";
import zxcvbnEnPackage from "@zxcvbn-ts/language-en";
import {$t} from "./i18n";
zxcvbnOptions.setOptions({
translations: zxcvbnEnPackage.translations,
dictionary: {
...zxcvbnCommonPackage.dictionary,
...zxcvbnEnPackage.dictionary,
},
});
// 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.
export function password_quality(
password: string,
$bar: JQuery | undefined,
$password_field: JQuery,
): boolean {
const min_length = $password_field.data("minLength");
const min_guesses = $password_field.data("minGuesses");
const result = zxcvbn(password);
const acceptable = password.length >= min_length && result.guesses >= min_guesses;
if ($bar !== undefined) {
const t = result.crackTimesSeconds.offlineSlowHashing1e4PerSecond;
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.
$bar.width(`${90 * bar_progress + 10}%`)
.removeClass("bar-success bar-danger")
.addClass(acceptable ? "bar-success" : "bar-danger");
}
return acceptable;
}
export function password_warning(password: string, $password_field: JQuery): string {
const min_length = $password_field.data("minLength");
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"});
}