Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Consider more user inputs when calculating zxcvbn score (#11180)
Browse files Browse the repository at this point in the history
* Consider more user inputs when calculating zxcvbn score

* MatrixClientPeg.getHomeserverName may throw
  • Loading branch information
t3chguy committed Jul 5, 2023
1 parent 90e65e8 commit 4044c2a
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 6 deletions.
4 changes: 3 additions & 1 deletion src/components/views/auth/PassphraseField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ interface IProps extends Omit<IInputProps, "onValidate" | "element"> {
minScore: 0 | 1 | 2 | 3 | 4;
value: string;
fieldRef?: RefCallback<Field> | RefObject<Field>;
// Additional strings such as a username used to catch bad passwords
userInputs?: string[];

label: string;
labelEnterPassword: string;
Expand All @@ -57,7 +59,7 @@ class PassphraseField extends PureComponent<IProps> {
deriveData: async ({ value }): Promise<zxcvbn.ZXCVBNResult | null> => {
if (!value) return null;
const { scorePassword } = await import("../../../utils/PasswordScorer");
return scorePassword(MatrixClientPeg.get(), value);
return scorePassword(MatrixClientPeg.get(), value, this.props.userInputs);
},
rules: [
{
Expand Down
1 change: 1 addition & 0 deletions src/components/views/auth/RegistrationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ export default class RegistrationForm extends React.PureComponent<IProps, IState
value={this.state.password}
onChange={this.onPasswordChange}
onValidate={this.onPasswordValidate}
userInputs={[this.state.username]}
/>
);
}
Expand Down
23 changes: 18 additions & 5 deletions src/utils/PasswordScorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import zxcvbn, { ZXCVBNFeedbackWarning } from "zxcvbn";
import { MatrixClient } from "matrix-js-sdk/src/matrix";

import { _t, _td } from "../languageHandler";
import { MatrixClientPeg } from "../MatrixClientPeg";

const ZXCVBN_USER_INPUTS = ["riot", "matrix"];

Expand Down Expand Up @@ -59,20 +60,32 @@ _td("Short keyboard patterns are easy to guess");
*
* @param {string} password Password to score
* @param matrixClient the client of the logged in user, if any
* @param userInputs additional strings such as the user's name which should be considered a bad password component
* @returns {object} Score result with `score` and `feedback` properties
*/
export function scorePassword(matrixClient: MatrixClient | null, password: string): zxcvbn.ZXCVBNResult | null {
export function scorePassword(
matrixClient: MatrixClient | null,
password: string,
userInputs: string[] = [],
): zxcvbn.ZXCVBNResult | null {
if (password.length === 0) return null;

const userInputs = ZXCVBN_USER_INPUTS.slice();
const inputs = [...userInputs, ...ZXCVBN_USER_INPUTS];
if (matrixClient) {
userInputs.push(matrixClient.getUserIdLocalpart()!);
inputs.push(matrixClient.getUserIdLocalpart()!);
}

let zxcvbnResult = zxcvbn(password, userInputs);
try {
const domain = MatrixClientPeg.getHomeserverName();
inputs.push(domain);
} catch {
// This is fine
}

let zxcvbnResult = zxcvbn(password, inputs);
// Work around https://github.com/dropbox/zxcvbn/issues/216
if (password.includes(" ")) {
const resultNoSpaces = zxcvbn(password.replace(/ /g, ""), userInputs);
const resultNoSpaces = zxcvbn(password.replace(/ /g, ""), inputs);
if (resultNoSpaces.score < zxcvbnResult.score) zxcvbnResult = resultNoSpaces;
}

Expand Down

0 comments on commit 4044c2a

Please sign in to comment.