use forms to wrap password fields so Chrome doesn't go wild and prefill all the things

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2020-01-29 13:24:45 +00:00
parent 45735d5ae3
commit cb0392b78d
3 changed files with 57 additions and 64 deletions

View file

@ -295,31 +295,27 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
});
}
_onPassPhraseNextClick = () => {
this.setState({phase: PHASE_PASSPHRASE_CONFIRM});
}
_onPassPhraseKeyPress = async (e) => {
if (e.key === 'Enter') {
// If we're waiting for the timeout before updating the result at this point,
// skip ahead and do it now, otherwise we'll deny the attempt to proceed
// even if the user entered a valid passphrase
if (this._setZxcvbnResultTimeout !== null) {
clearTimeout(this._setZxcvbnResultTimeout);
this._setZxcvbnResultTimeout = null;
await new Promise((resolve) => {
this.setState({
zxcvbnResult: scorePassword(this.state.passPhrase),
}, resolve);
});
}
if (this._passPhraseIsValid()) {
this._onPassPhraseNextClick();
}
_onPassPhraseNextClick = async () => {
// If we're waiting for the timeout before updating the result at this point,
// skip ahead and do it now, otherwise we'll deny the attempt to proceed
// even if the user entered a valid passphrase
if (this._setZxcvbnResultTimeout !== null) {
clearTimeout(this._setZxcvbnResultTimeout);
this._setZxcvbnResultTimeout = null;
await new Promise((resolve) => {
this.setState({
zxcvbnResult: scorePassword(this.state.passPhrase),
}, resolve);
});
}
}
if (this._passPhraseIsValid()) {
this.setState({phase: PHASE_PASSPHRASE_CONFIRM});
}
};
_onPassPhraseConfirmNextClick = async () => {
if (this.state.passPhrase !== this.state.passPhraseConfirm) return;
const [keyInfo, encodedRecoveryKey] =
await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(this.state.passPhrase);
this._keyInfo = keyInfo;
@ -332,12 +328,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
});
}
_onPassPhraseConfirmKeyPress = (e) => {
if (e.key === 'Enter' && this.state.passPhrase === this.state.passPhraseConfirm) {
this._onPassPhraseConfirmNextClick();
}
}
_onSetAgainClick = () => {
this.setState({
passPhrase: '',
@ -407,7 +397,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
} else if (this.state.canUploadKeysWithPasswordOnly) {
authPrompt = <div>
<div>{_t("Enter your account password to confirm the upgrade:")}</div>
<div><Field type="password"
<div><Field
type="password"
id="mx_CreateSecretStorage_accountPassword"
label={_t("Password")}
value={this.state.accountPassword}
@ -469,7 +460,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
</div>;
}
return <div>
return <form>
<p>{_t(
"Set up encryption on this device to allow it to verify other devices, " +
"granting them access to encrypted messages and marking them as trusted for other users.",
@ -480,13 +471,14 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
)}</p>
<div className="mx_CreateSecretStorageDialog_passPhraseContainer">
<Field type="password"
<Field
type="password"
className="mx_CreateSecretStorageDialog_passPhraseField"
onChange={this._onPassPhraseChange}
onKeyPress={this._onPassPhraseKeyPress}
value={this.state.passPhrase}
label={_t("Enter a passphrase")}
autoFocus={true}
autoComplete="new-password"
/>
<div className="mx_CreateSecretStorageDialog_passPhraseHelp">
{strengthMeter}
@ -499,10 +491,12 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
onChange={this._onUseKeyBackupChange} value={this.state.useKeyBackup}
/>
<DialogButtons primaryButton={_t('Continue')}
<DialogButtons
primaryButton={_t('Continue')}
onPrimaryButtonClick={this._onPassPhraseNextClick}
hasCancel={false}
disabled={!this._passPhraseIsValid()}
primaryIsSubmit={true}
>
<button type="button"
onClick={this._onSkipSetupClick}
@ -516,7 +510,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
{_t("Set up with a recovery key")}
</AccessibleButton></p>
</details>
</div>;
</form>;
}
_renderPhasePassPhraseConfirm() {
@ -549,27 +543,30 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
</div>;
}
const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
return <div>
return <form>
<p>{_t(
"Enter your passphrase a second time to confirm it.",
)}</p>
<div className="mx_CreateSecretStorageDialog_passPhraseContainer">
<Field type="password"
<Field
type="password"
id="mx_CreateSecretStorageDialog_passPhraseField"
onChange={this._onPassPhraseConfirmChange}
onKeyPress={this._onPassPhraseConfirmKeyPress}
value={this.state.passPhraseConfirm}
className="mx_CreateSecretStorageDialog_passPhraseField"
label={_t("Confirm your passphrase")}
autoFocus={true}
autoComplete="new-password"
/>
<div className="mx_CreateSecretStorageDialog_passPhraseMatch">
{passPhraseMatch}
</div>
</div>
<DialogButtons primaryButton={_t('Continue')}
<DialogButtons
primaryButton={_t('Continue')}
onPrimaryButtonClick={this._onPassPhraseConfirmNextClick}
hasCancel={false}
primaryIsSubmit={true}
disabled={this.state.passPhrase !== this.state.passPhraseConfirm}
>
<button type="button"
@ -577,7 +574,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
className="danger"
>{_t("Skip")}</button>
</DialogButtons>
</div>;
</form>;
}
_renderPhaseShowKey() {

View file

@ -160,6 +160,7 @@ export default createReactClass({
onKeyDown={ this._onKeyDown }
onBlur={this._onBlur}
placeholder={ placeholder }
autoComplete="off"
/>
{ clearButton }
</div>

View file

@ -1,6 +1,6 @@
/*
Copyright 2018, 2019 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -21,7 +21,6 @@ import * as sdk from '../../../../index';
import {MatrixClientPeg} from '../../../../MatrixClientPeg';
import { _t } from '../../../../languageHandler';
import { Key } from "../../../../Keyboard";
/*
* Access Secure Secret Storage by requesting the user's passphrase.
@ -69,6 +68,8 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
}
_onPassPhraseNext = async () => {
if (this.state.passPhrase.length <= 0) return;
this.setState({ keyMatches: null });
const input = { passphrase: this.state.passPhrase };
const keyMatches = await this.props.checkPrivateKey(input);
@ -80,6 +81,8 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
}
_onRecoveryKeyNext = async () => {
if (!this.state.recoveryKeyValid) return;
this.setState({ keyMatches: null });
const input = { recoveryKey: this.state.recoveryKey };
const keyMatches = await this.props.checkPrivateKey(input);
@ -97,18 +100,6 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
});
}
_onPassPhraseKeyPress = (e) => {
if (e.key === Key.ENTER && this.state.passPhrase.length > 0) {
this._onPassPhraseNext();
}
}
_onRecoveryKeyKeyPress = (e) => {
if (e.key === Key.ENTER && this.state.recoveryKeyValid) {
this._onRecoveryKeyNext();
}
}
render() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
@ -135,7 +126,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
)}
</div>;
} else {
keyStatus = <div className="mx_AccessSecretStorageDialog_keyStatus"></div>;
keyStatus = <div className="mx_AccessSecretStorageDialog_keyStatus" />;
}
content = <div>
@ -149,23 +140,26 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
"identity for verifying other devices by entering your passphrase.",
)}</p>
<div className="mx_AccessSecretStorageDialog_primaryContainer">
<input type="password"
<form className="mx_AccessSecretStorageDialog_primaryContainer">
<input
type="password"
className="mx_AccessSecretStorageDialog_passPhraseInput"
onChange={this._onPassPhraseChange}
onKeyPress={this._onPassPhraseKeyPress}
value={this.state.passPhrase}
autoFocus={true}
autoComplete="new-password"
/>
{keyStatus}
<DialogButtons primaryButton={_t('Next')}
<DialogButtons
primaryButton={_t('Next')}
onPrimaryButtonClick={this._onPassPhraseNext}
hasCancel={true}
onCancel={this._onCancel}
focus={false}
primaryIsSubmit={true}
primaryDisabled={this.state.passPhrase.length === 0}
/>
</div>
</form>
{_t(
"If you've forgotten your passphrase you can "+
"<button1>use your recovery key</button1> or " +
@ -192,7 +186,7 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
let keyStatus;
if (this.state.recoveryKey.length === 0) {
keyStatus = <div className="mx_AccessSecretStorageDialog_keyStatus"></div>;
keyStatus = <div className="mx_AccessSecretStorageDialog_keyStatus" />;
} else if (this.state.recoveryKeyValid) {
keyStatus = <div className="mx_AccessSecretStorageDialog_keyStatus">
{"\uD83D\uDC4D "}{_t("This looks like a valid recovery key!")}
@ -221,22 +215,23 @@ export default class AccessSecretStorageDialog extends React.PureComponent {
"identity for verifying other devices by entering your recovery key.",
)}</p>
<div className="mx_AccessSecretStorageDialog_primaryContainer">
<form className="mx_AccessSecretStorageDialog_primaryContainer">
<input className="mx_AccessSecretStorageDialog_recoveryKeyInput"
onChange={this._onRecoveryKeyChange}
onKeyPress={this._onRecoveryKeyKeyPress}
value={this.state.recoveryKey}
autoFocus={true}
/>
{keyStatus}
<DialogButtons primaryButton={_t('Next')}
<DialogButtons
primaryButton={_t('Next')}
onPrimaryButtonClick={this._onRecoveryKeyNext}
hasCancel={true}
onCancel={this._onCancel}
focus={false}
primaryIsSubmit={true}
primaryDisabled={!this.state.recoveryKeyValid}
/>
</div>
</form>
{_t(
"If you've forgotten your recovery key you can "+
"<button>set up new recovery options</button>."