Merge pull request #3974 from matrix-org/t3chguy/password_completion

Use forms to wrap password fields so Chrome doesn't go wild
pull/21833/head
Michael Telatynski 2020-02-10 11:55:51 +00:00 committed by GitHub
commit ffb40d90da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 119 additions and 126 deletions

View File

@ -85,3 +85,9 @@ limitations under the License.
flex: 1; flex: 1;
white-space: nowrap; white-space: nowrap;
} }
.mx_CreateKeyBackupDialog {
details .mx_AccessibleButton {
margin: 1em 0; // emulate paragraph spacing because we can't put this button in a paragraph due to HTML rules
}
}

View File

@ -24,6 +24,7 @@ import { scorePassword } from '../../../../utils/PasswordScorer';
import { _t } from '../../../../languageHandler'; import { _t } from '../../../../languageHandler';
import { accessSecretStorage } from '../../../../CrossSigningManager'; import { accessSecretStorage } from '../../../../CrossSigningManager';
import SettingsStore from '../../../../settings/SettingsStore'; import SettingsStore from '../../../../settings/SettingsStore';
import AccessibleButton from "../../../../components/views/elements/AccessibleButton";
const PHASE_PASSPHRASE = 0; const PHASE_PASSPHRASE = 0;
const PHASE_PASSPHRASE_CONFIRM = 1; const PHASE_PASSPHRASE_CONFIRM = 1;
@ -191,12 +192,9 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
}); });
} }
_onPassPhraseNextClick = () => { _onPassPhraseNextClick = async (e) => {
this.setState({phase: PHASE_PASSPHRASE_CONFIRM}); e.preventDefault();
}
_onPassPhraseKeyPress = async (e) => {
if (e.key === 'Enter') {
// If we're waiting for the timeout before updating the result at this point, // 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 // skip ahead and do it now, otherwise we'll deny the attempt to proceed
// even if the user entered a valid passphrase // even if the user entered a valid passphrase
@ -210,25 +208,22 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
}); });
} }
if (this._passPhraseIsValid()) { if (this._passPhraseIsValid()) {
this._onPassPhraseNextClick(); this.setState({phase: PHASE_PASSPHRASE_CONFIRM});
}
}
} }
};
_onPassPhraseConfirmNextClick = async (e) => {
e.preventDefault();
if (this.state.passPhrase !== this.state.passPhraseConfirm) return;
_onPassPhraseConfirmNextClick = async () => {
this._keyBackupInfo = await MatrixClientPeg.get().prepareKeyBackupVersion(this.state.passPhrase); this._keyBackupInfo = await MatrixClientPeg.get().prepareKeyBackupVersion(this.state.passPhrase);
this.setState({ this.setState({
copied: false, copied: false,
downloaded: false, downloaded: false,
phase: PHASE_SHOWKEY, phase: PHASE_SHOWKEY,
}); });
} };
_onPassPhraseConfirmKeyPress = (e) => {
if (e.key === 'Enter' && this.state.passPhrase === this.state.passPhraseConfirm) {
this._onPassPhraseConfirmNextClick();
}
}
_onSetAgainClick = () => { _onSetAgainClick = () => {
this.setState({ this.setState({
@ -299,7 +294,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
</div>; </div>;
} }
return <div> return <form onSubmit={this._onPassPhraseNextClick}>
<p>{_t( <p>{_t(
"<b>Warning</b>: You should only set up key backup from a trusted computer.", {}, "<b>Warning</b>: You should only set up key backup from a trusted computer.", {},
{ b: sub => <b>{sub}</b> }, { b: sub => <b>{sub}</b> },
@ -314,7 +309,6 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
<div className="mx_CreateKeyBackupDialog_passPhraseContainer"> <div className="mx_CreateKeyBackupDialog_passPhraseContainer">
<input type="password" <input type="password"
onChange={this._onPassPhraseChange} onChange={this._onPassPhraseChange}
onKeyPress={this._onPassPhraseKeyPress}
value={this.state.passPhrase} value={this.state.passPhrase}
className="mx_CreateKeyBackupDialog_passPhraseInput" className="mx_CreateKeyBackupDialog_passPhraseInput"
placeholder={_t("Enter a passphrase...")} placeholder={_t("Enter a passphrase...")}
@ -327,7 +321,8 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
</div> </div>
</div> </div>
<DialogButtons primaryButton={_t('Next')} <DialogButtons
primaryButton={_t('Next')}
onPrimaryButtonClick={this._onPassPhraseNextClick} onPrimaryButtonClick={this._onPassPhraseNextClick}
hasCancel={false} hasCancel={false}
disabled={!this._passPhraseIsValid()} disabled={!this._passPhraseIsValid()}
@ -335,11 +330,11 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
<details> <details>
<summary>{_t("Advanced")}</summary> <summary>{_t("Advanced")}</summary>
<p><button onClick={this._onSkipPassPhraseClick} > <AccessibleButton kind='primary' onClick={this._onSkipPassPhraseClick} >
{_t("Set up with a recovery key")} {_t("Set up with a recovery key")}
</button></p> </AccessibleButton>
</details> </details>
</div>; </form>;
} }
_renderPhasePassPhraseConfirm() { _renderPhasePassPhraseConfirm() {
@ -371,7 +366,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
</div>; </div>;
} }
const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
return <div> return <form onSubmit={this._onPassPhraseConfirmNextClick}>
<p>{_t( <p>{_t(
"Please enter your passphrase a second time to confirm.", "Please enter your passphrase a second time to confirm.",
)}</p> )}</p>
@ -380,7 +375,6 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
<div> <div>
<input type="password" <input type="password"
onChange={this._onPassPhraseConfirmChange} onChange={this._onPassPhraseConfirmChange}
onKeyPress={this._onPassPhraseConfirmKeyPress}
value={this.state.passPhraseConfirm} value={this.state.passPhraseConfirm}
className="mx_CreateKeyBackupDialog_passPhraseInput" className="mx_CreateKeyBackupDialog_passPhraseInput"
placeholder={_t("Repeat your passphrase...")} placeholder={_t("Repeat your passphrase...")}
@ -390,12 +384,13 @@ export default class CreateKeyBackupDialog extends React.PureComponent {
{passPhraseMatch} {passPhraseMatch}
</div> </div>
</div> </div>
<DialogButtons primaryButton={_t('Next')} <DialogButtons
primaryButton={_t('Next')}
onPrimaryButtonClick={this._onPassPhraseConfirmNextClick} onPrimaryButtonClick={this._onPassPhraseConfirmNextClick}
hasCancel={false} hasCancel={false}
disabled={this.state.passPhrase !== this.state.passPhraseConfirm} disabled={this.state.passPhrase !== this.state.passPhraseConfirm}
/> />
</div>; </form>;
} }
_renderPhaseShowKey() { _renderPhaseShowKey() {

View File

@ -289,12 +289,9 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
}); });
} }
_onPassPhraseNextClick = () => { _onPassPhraseNextClick = async (e) => {
this.setState({phase: PHASE_PASSPHRASE_CONFIRM}); e.preventDefault();
}
_onPassPhraseKeyPress = async (e) => {
if (e.key === 'Enter') {
// If we're waiting for the timeout before updating the result at this point, // 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 // skip ahead and do it now, otherwise we'll deny the attempt to proceed
// even if the user entered a valid passphrase // even if the user entered a valid passphrase
@ -308,12 +305,15 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
}); });
} }
if (this._passPhraseIsValid()) { if (this._passPhraseIsValid()) {
this._onPassPhraseNextClick(); this.setState({phase: PHASE_PASSPHRASE_CONFIRM});
}
}
} }
};
_onPassPhraseConfirmNextClick = async (e) => {
e.preventDefault();
if (this.state.passPhrase !== this.state.passPhraseConfirm) return;
_onPassPhraseConfirmNextClick = async () => {
const [keyInfo, encodedRecoveryKey] = const [keyInfo, encodedRecoveryKey] =
await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(this.state.passPhrase); await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(this.state.passPhrase);
this._keyInfo = keyInfo; this._keyInfo = keyInfo;
@ -325,12 +325,6 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
}); });
} }
_onPassPhraseConfirmKeyPress = (e) => {
if (e.key === 'Enter' && this.state.passPhrase === this.state.passPhraseConfirm) {
this._onPassPhraseConfirmNextClick();
}
}
_onSetAgainClick = () => { _onSetAgainClick = () => {
this.setState({ this.setState({
passPhrase: '', passPhrase: '',
@ -400,7 +394,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
} else if (this.state.canUploadKeysWithPasswordOnly) { } else if (this.state.canUploadKeysWithPasswordOnly) {
authPrompt = <div> authPrompt = <div>
<div>{_t("Enter your account password to confirm the upgrade:")}</div> <div>{_t("Enter your account password to confirm the upgrade:")}</div>
<div><Field type="password" <div><Field
type="password"
id="mx_CreateSecretStorage_accountPassword" id="mx_CreateSecretStorage_accountPassword"
label={_t("Password")} label={_t("Password")}
value={this.state.accountPassword} value={this.state.accountPassword}
@ -422,8 +417,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
"as trusted for other users.", "as trusted for other users.",
)}</p> )}</p>
<div>{authPrompt}</div> <div>{authPrompt}</div>
<DialogButtons primaryButton={nextCaption} <DialogButtons
primaryIsSubmit={true} primaryButton={nextCaption}
hasCancel={false} hasCancel={false}
primaryDisabled={this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword} primaryDisabled={this.state.canUploadKeysWithPasswordOnly && !this.state.accountPassword}
> >
@ -467,7 +462,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
</div>; </div>;
} }
return <div> return <form onSubmit={this._onPassPhraseNextClick}>
<p>{_t( <p>{_t(
"Set up encryption on this session to allow it to verify other sessions, " + "Set up encryption on this session to allow it to verify other sessions, " +
"granting them access to encrypted messages and marking them as trusted for other users.", "granting them access to encrypted messages and marking them as trusted for other users.",
@ -483,10 +478,10 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
id="mx_CreateSecretStorageDialog_passPhraseField" id="mx_CreateSecretStorageDialog_passPhraseField"
className="mx_CreateSecretStorageDialog_passPhraseField" className="mx_CreateSecretStorageDialog_passPhraseField"
onChange={this._onPassPhraseChange} onChange={this._onPassPhraseChange}
onKeyPress={this._onPassPhraseKeyPress}
value={this.state.passPhrase} value={this.state.passPhrase}
label={_t("Enter a passphrase")} label={_t("Enter a passphrase")}
autoFocus={true} autoFocus={true}
autoComplete="new-password"
/> />
<div className="mx_CreateSecretStorageDialog_passPhraseHelp"> <div className="mx_CreateSecretStorageDialog_passPhraseHelp">
{strengthMeter} {strengthMeter}
@ -499,7 +494,8 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
onChange={this._onUseKeyBackupChange} value={this.state.useKeyBackup} onChange={this._onUseKeyBackupChange} value={this.state.useKeyBackup}
/> />
<DialogButtons primaryButton={_t('Continue')} <DialogButtons
primaryButton={_t('Continue')}
onPrimaryButtonClick={this._onPassPhraseNextClick} onPrimaryButtonClick={this._onPassPhraseNextClick}
hasCancel={false} hasCancel={false}
disabled={!this._passPhraseIsValid()} disabled={!this._passPhraseIsValid()}
@ -516,7 +512,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
{_t("Set up with a recovery key")} {_t("Set up with a recovery key")}
</AccessibleButton> </AccessibleButton>
</details> </details>
</div>; </form>;
} }
_renderPhasePassPhraseConfirm() { _renderPhasePassPhraseConfirm() {
@ -549,25 +545,27 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
</div>; </div>;
} }
const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); const DialogButtons = sdk.getComponent('views.elements.DialogButtons');
return <div> return <form onSubmit={this._onPassPhraseConfirmNextClick}>
<p>{_t( <p>{_t(
"Enter your passphrase a second time to confirm it.", "Enter your passphrase a second time to confirm it.",
)}</p> )}</p>
<div className="mx_CreateSecretStorageDialog_passPhraseContainer"> <div className="mx_CreateSecretStorageDialog_passPhraseContainer">
<Field type="password" <Field
type="password"
id="mx_CreateSecretStorageDialog_passPhraseField" id="mx_CreateSecretStorageDialog_passPhraseField"
onChange={this._onPassPhraseConfirmChange} onChange={this._onPassPhraseConfirmChange}
onKeyPress={this._onPassPhraseConfirmKeyPress}
value={this.state.passPhraseConfirm} value={this.state.passPhraseConfirm}
className="mx_CreateSecretStorageDialog_passPhraseField" className="mx_CreateSecretStorageDialog_passPhraseField"
label={_t("Confirm your passphrase")} label={_t("Confirm your passphrase")}
autoFocus={true} autoFocus={true}
autoComplete="new-password"
/> />
<div className="mx_CreateSecretStorageDialog_passPhraseMatch"> <div className="mx_CreateSecretStorageDialog_passPhraseMatch">
{passPhraseMatch} {passPhraseMatch}
</div> </div>
</div> </div>
<DialogButtons primaryButton={_t('Continue')} <DialogButtons
primaryButton={_t('Continue')}
onPrimaryButtonClick={this._onPassPhraseConfirmNextClick} onPrimaryButtonClick={this._onPassPhraseConfirmNextClick}
hasCancel={false} hasCancel={false}
disabled={this.state.passPhrase !== this.state.passPhraseConfirm} disabled={this.state.passPhrase !== this.state.passPhraseConfirm}
@ -577,7 +575,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent {
className="danger" className="danger"
>{_t("Skip")}</button> >{_t("Skip")}</button>
</DialogButtons> </DialogButtons>
</div>; </form>;
} }
_renderPhaseShowKey() { _renderPhaseShowKey() {

View File

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

View File

@ -486,6 +486,7 @@ export default createReactClass({
id="mx_RegistrationForm_password" id="mx_RegistrationForm_password"
ref={field => this[FIELD_PASSWORD] = field} ref={field => this[FIELD_PASSWORD] = field}
type="password" type="password"
autoComplete="new-password"
label={_t("Password")} label={_t("Password")}
value={this.state.password} value={this.state.password}
onChange={this.onPasswordChange} onChange={this.onPasswordChange}
@ -499,6 +500,7 @@ export default createReactClass({
id="mx_RegistrationForm_passwordConfirm" id="mx_RegistrationForm_passwordConfirm"
ref={field => this[FIELD_PASSWORD_CONFIRM] = field} ref={field => this[FIELD_PASSWORD_CONFIRM] = field}
type="password" type="password"
autoComplete="new-password"
label={_t("Confirm")} label={_t("Confirm")}
value={this.state.passwordConfirm} value={this.state.passwordConfirm}
onChange={this.onPasswordConfirmChange} onChange={this.onPasswordConfirmChange}

View File

@ -118,6 +118,7 @@ export default class DeactivateAccountDialog extends React.Component {
const Field = sdk.getComponent('elements.Field'); const Field = sdk.getComponent('elements.Field');
// this is on purpose not a <form /> to prevent Enter triggering submission, to further prevent accidents
return ( return (
<BaseDialog className="mx_DeactivateAccountDialog" <BaseDialog className="mx_DeactivateAccountDialog"
onFinished={this.props.onFinished} onFinished={this.props.onFinished}

View File

@ -22,7 +22,6 @@ import {MatrixClientPeg} from '../../../../MatrixClientPeg';
import { MatrixClient } from 'matrix-js-sdk'; import { MatrixClient } from 'matrix-js-sdk';
import Modal from '../../../../Modal'; import Modal from '../../../../Modal';
import { _t } from '../../../../languageHandler'; import { _t } from '../../../../languageHandler';
import {Key} from "../../../../Keyboard";
import { accessSecretStorage } from '../../../../CrossSigningManager'; import { accessSecretStorage } from '../../../../CrossSigningManager';
const RESTORE_TYPE_PASSPHRASE = 0; const RESTORE_TYPE_PASSPHRASE = 0;
@ -125,6 +124,8 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
} }
_onRecoveryKeyNext = async () => { _onRecoveryKeyNext = async () => {
if (!this.state.recoveryKeyValid) return;
this.setState({ this.setState({
loading: true, loading: true,
restoreError: null, restoreError: null,
@ -157,18 +158,6 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
}); });
} }
_onPassPhraseKeyPress = (e) => {
if (e.key === Key.ENTER) {
this._onPassPhraseNext();
}
}
_onRecoveryKeyKeyPress = (e) => {
if (e.key === Key.ENTER && this.state.recoveryKeyValid) {
this._onRecoveryKeyNext();
}
}
async _restoreWithSecretStorage() { async _restoreWithSecretStorage() {
this.setState({ this.setState({
loading: true, loading: true,
@ -305,21 +294,22 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
"messaging by entering your recovery passphrase.", "messaging by entering your recovery passphrase.",
)}</p> )}</p>
<div className="mx_RestoreKeyBackupDialog_primaryContainer"> <form className="mx_RestoreKeyBackupDialog_primaryContainer">
<input type="password" <input type="password"
className="mx_RestoreKeyBackupDialog_passPhraseInput" className="mx_RestoreKeyBackupDialog_passPhraseInput"
onChange={this._onPassPhraseChange} onChange={this._onPassPhraseChange}
onKeyPress={this._onPassPhraseKeyPress}
value={this.state.passPhrase} value={this.state.passPhrase}
autoFocus={true} autoFocus={true}
/> />
<DialogButtons primaryButton={_t('Next')} <DialogButtons
primaryButton={_t('Next')}
onPrimaryButtonClick={this._onPassPhraseNext} onPrimaryButtonClick={this._onPassPhraseNext}
primaryIsSubmit={true}
hasCancel={true} hasCancel={true}
onCancel={this._onCancel} onCancel={this._onCancel}
focus={false} focus={false}
/> />
</div> </form>
{_t( {_t(
"If you've forgotten your recovery passphrase you can "+ "If you've forgotten your recovery passphrase you can "+
"<button1>use your recovery key</button1> or " + "<button1>use your recovery key</button1> or " +
@ -371,7 +361,6 @@ export default class RestoreKeyBackupDialog extends React.PureComponent {
<div className="mx_RestoreKeyBackupDialog_primaryContainer"> <div className="mx_RestoreKeyBackupDialog_primaryContainer">
<input className="mx_RestoreKeyBackupDialog_recoveryKeyInput" <input className="mx_RestoreKeyBackupDialog_recoveryKeyInput"
onChange={this._onRecoveryKeyChange} onChange={this._onRecoveryKeyChange}
onKeyPress={this._onRecoveryKeyKeyPress}
value={this.state.recoveryKey} value={this.state.recoveryKey}
autoFocus={true} autoFocus={true}
/> />

View File

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

View File

@ -253,20 +253,24 @@ export default createReactClass({
<form className={this.props.className} onSubmit={this.onClickChange}> <form className={this.props.className} onSubmit={this.onClickChange}>
{ currentPassword } { currentPassword }
<div className={rowClassName}> <div className={rowClassName}>
<Field id="mx_ChangePassword_newPassword" <Field
id="mx_ChangePassword_newPassword"
type="password" type="password"
label={passwordLabel} label={passwordLabel}
value={this.state.newPassword} value={this.state.newPassword}
autoFocus={this.props.autoFocusNewPasswordInput} autoFocus={this.props.autoFocusNewPasswordInput}
onChange={this.onChangeNewPassword} onChange={this.onChangeNewPassword}
autoComplete="new-password"
/> />
</div> </div>
<div className={rowClassName}> <div className={rowClassName}>
<Field id="mx_ChangePassword_newPasswordConfirm" <Field
id="mx_ChangePassword_newPasswordConfirm"
type="password" type="password"
label={_t("Confirm password")} label={_t("Confirm password")}
value={this.state.newPasswordConfirm} value={this.state.newPasswordConfirm}
onChange={this.onChangeNewPasswordConfirm} onChange={this.onChangeNewPasswordConfirm}
autoComplete="new-password"
/> />
</div> </div>
<AccessibleButton className={buttonClassName} kind={this.props.buttonKind} onClick={this.onClickChange}> <AccessibleButton className={buttonClassName} kind={this.props.buttonKind} onClick={this.onClickChange}>