Support accounts with cross signing but no SSSS
Port https://github.com/matrix-org/matrix-react-sdk/pull/4717 to release
This commit is contained in:
parent
5256a86545
commit
518db90b69
5 changed files with 79 additions and 41 deletions
|
@ -1870,42 +1870,35 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
this.accountPasswordTimer = null;
|
||||
}, 60 * 5 * 1000);
|
||||
|
||||
// Wait for the client to be logged in (but not started)
|
||||
// which is enough to ask the server about account data.
|
||||
const loggedIn = new Promise(resolve => {
|
||||
const actionHandlerRef = dis.register(payload => {
|
||||
if (payload.action !== "on_logged_in") {
|
||||
return;
|
||||
}
|
||||
dis.unregister(actionHandlerRef);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// Create and start the client in the background
|
||||
const setLoggedInPromise = Lifecycle.setLoggedIn(credentials);
|
||||
await loggedIn;
|
||||
// Create and start the client
|
||||
await Lifecycle.setLoggedIn(credentials);
|
||||
|
||||
const cli = MatrixClientPeg.get();
|
||||
// We're checking `isCryptoAvailable` here instead of `isCryptoEnabled`
|
||||
// because the client hasn't been started yet.
|
||||
const cryptoAvailable = isCryptoAvailable();
|
||||
if (!cryptoAvailable) {
|
||||
const cryptoEnabled = cli.isCryptoEnabled();
|
||||
if (!cryptoEnabled) {
|
||||
this.onLoggedIn();
|
||||
}
|
||||
|
||||
this.setState({ pendingInitialSync: true });
|
||||
await this.firstSyncPromise.promise;
|
||||
|
||||
if (!cryptoAvailable) {
|
||||
this.setState({ pendingInitialSync: false });
|
||||
return setLoggedInPromise;
|
||||
const promisesList = [this.firstSyncPromise.promise];
|
||||
if (cryptoEnabled) {
|
||||
// wait for the client to finish downloading cross-signing keys for us so we
|
||||
// know whether or not we have keys set up on this account
|
||||
promisesList.push(cli.downloadKeys([cli.getUserId()]));
|
||||
}
|
||||
|
||||
// Test for the master cross-signing key in SSSS as a quick proxy for
|
||||
// whether cross-signing has been set up on the account.
|
||||
const masterKeyInStorage = !!cli.getAccountData("m.cross_signing.master");
|
||||
if (masterKeyInStorage) {
|
||||
// Now update the state to say we're waiting for the first sync to complete rather
|
||||
// than for the login to finish.
|
||||
this.setState({ pendingInitialSync: true });
|
||||
|
||||
await Promise.all(promisesList);
|
||||
|
||||
if (!cryptoEnabled) {
|
||||
this.setState({ pendingInitialSync: false });
|
||||
return;
|
||||
}
|
||||
|
||||
const crossSigningIsSetUp = cli.getStoredCrossSigningForUser(cli.getUserId());
|
||||
if (crossSigningIsSetUp) {
|
||||
this.setStateForNewView({ view: Views.COMPLETE_SECURITY });
|
||||
} else if (await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) {
|
||||
this.setStateForNewView({ view: Views.E2E_SETUP });
|
||||
|
@ -1913,8 +1906,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||
this.onLoggedIn();
|
||||
}
|
||||
this.setState({ pendingInitialSync: false });
|
||||
|
||||
return setLoggedInPromise;
|
||||
};
|
||||
|
||||
// complete security / e2e setup has finished
|
||||
|
|
|
@ -378,7 +378,7 @@ export default createReactClass({
|
|||
}
|
||||
|
||||
if (response.access_token) {
|
||||
const cli = await this.props.onLoggedIn({
|
||||
await this.props.onLoggedIn({
|
||||
userId: response.user_id,
|
||||
deviceId: response.device_id,
|
||||
homeserverUrl: this.state.matrixClient.getHomeserverUrl(),
|
||||
|
@ -386,7 +386,7 @@ export default createReactClass({
|
|||
accessToken: response.access_token,
|
||||
}, this.state.formVals.password);
|
||||
|
||||
this._setupPushers(cli);
|
||||
this._setupPushers();
|
||||
// we're still busy until we get unmounted: don't show the registration form again
|
||||
newState.busy = true;
|
||||
} else {
|
||||
|
@ -397,10 +397,11 @@ export default createReactClass({
|
|||
this.setState(newState);
|
||||
},
|
||||
|
||||
_setupPushers: function(matrixClient) {
|
||||
_setupPushers: function() {
|
||||
if (!this.props.brand) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const matrixClient = MatrixClientPeg.get();
|
||||
return matrixClient.getPushers().then((resp)=>{
|
||||
const pushers = resp.pushers;
|
||||
for (let i = 0; i < pushers.length; ++i) {
|
||||
|
|
|
@ -28,6 +28,14 @@ import {
|
|||
PHASE_FINISHED,
|
||||
} from '../../../stores/SetupEncryptionStore';
|
||||
|
||||
function keyHasPassphrase(keyInfo) {
|
||||
return (
|
||||
keyInfo.passphrase &&
|
||||
keyInfo.passphrase.salt &&
|
||||
keyInfo.passphrase.iterations
|
||||
);
|
||||
}
|
||||
|
||||
export default class SetupEncryptionBody extends React.Component {
|
||||
static propTypes = {
|
||||
onFinished: PropTypes.func.isRequired,
|
||||
|
@ -108,6 +116,21 @@ export default class SetupEncryptionBody extends React.Component {
|
|||
member={MatrixClientPeg.get().getUser(this.state.verificationRequest.otherUserId)}
|
||||
/>;
|
||||
} else if (phase === PHASE_INTRO) {
|
||||
const store = SetupEncryptionStore.sharedInstance();
|
||||
let recoveryKeyPrompt;
|
||||
if (store.keyInfo && keyHasPassphrase(store.keyInfo)) {
|
||||
recoveryKeyPrompt = _t("Use Recovery Key or Passphrase");
|
||||
} else if (store.keyInfo) {
|
||||
recoveryKeyPrompt = _t("Use Recovery Key");
|
||||
}
|
||||
|
||||
let useRecoveryKeyButton;
|
||||
if (recoveryKeyPrompt) {
|
||||
useRecoveryKeyButton = <AccessibleButton kind="link" onClick={this._onUsePassphraseClick}>
|
||||
{recoveryKeyPrompt}
|
||||
</AccessibleButton>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>{_t(
|
||||
|
@ -131,9 +154,7 @@ export default class SetupEncryptionBody extends React.Component {
|
|||
</div>
|
||||
|
||||
<div className="mx_CompleteSecurity_actionRow">
|
||||
<AccessibleButton kind="link" onClick={this._onUsePassphraseClick}>
|
||||
{_t("Use Recovery Passphrase or Key")}
|
||||
</AccessibleButton>
|
||||
{useRecoveryKeyButton}
|
||||
<AccessibleButton kind="danger" onClick={this.onSkipClick}>
|
||||
{_t("Skip")}
|
||||
</AccessibleButton>
|
||||
|
|
|
@ -2121,10 +2121,11 @@
|
|||
"You can now close this window or <a>log in</a> to your new account.": "You can now close this window or <a>log in</a> to your new account.",
|
||||
"Registration Successful": "Registration Successful",
|
||||
"Create your account": "Create your account",
|
||||
"Use Recovery Key or Passphrase": "Use Recovery Key or Passphrase",
|
||||
"Use Recovery Key": "Use Recovery Key",
|
||||
"Confirm your identity by verifying this login from one of your other sessions, granting it access to encrypted messages.": "Confirm your identity by verifying this login from one of your other sessions, granting it access to encrypted messages.",
|
||||
"This requires the latest Riot on your other devices:": "This requires the latest Riot on your other devices:",
|
||||
"or another cross-signing capable Matrix client": "or another cross-signing capable Matrix client",
|
||||
"Use Recovery Passphrase or Key": "Use Recovery Passphrase or Key",
|
||||
"Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.": "Your new session is now verified. It has access to your encrypted messages, and other users will see it as trusted.",
|
||||
"Your new session is now verified. Other users will see it as trusted.": "Your new session is now verified. Other users will see it as trusted.",
|
||||
"Without completing security on this session, it won’t have access to encrypted messages.": "Without completing security on this session, it won’t have access to encrypted messages.",
|
||||
|
|
|
@ -36,11 +36,20 @@ export class SetupEncryptionStore extends EventEmitter {
|
|||
return;
|
||||
}
|
||||
this._started = true;
|
||||
this.phase = PHASE_INTRO;
|
||||
this.phase = PHASE_BUSY;
|
||||
this.verificationRequest = null;
|
||||
this.backupInfo = null;
|
||||
MatrixClientPeg.get().on("crypto.verification.request", this.onVerificationRequest);
|
||||
MatrixClientPeg.get().on('userTrustStatusChanged', this._onUserTrustStatusChanged);
|
||||
|
||||
// ID of the key that the secrets we want are encrypted with
|
||||
this.keyId = null;
|
||||
// Descriptor of the key that the secrets we want are encrypted with
|
||||
this.keyInfo = null;
|
||||
|
||||
const cli = MatrixClientPeg.get();
|
||||
cli.on("crypto.verification.request", this.onVerificationRequest);
|
||||
cli.on('userTrustStatusChanged', this._onUserTrustStatusChanged);
|
||||
|
||||
this.fetchKeyInfo();
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
@ -57,6 +66,21 @@ export class SetupEncryptionStore extends EventEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
async fetchKeyInfo() {
|
||||
const keys = await MatrixClientPeg.get().isSecretStored('m.cross_signing.master', false);
|
||||
if (keys === null || Object.keys(keys).length === 0) {
|
||||
this.keyId = null;
|
||||
this.keyInfo = null;
|
||||
} else {
|
||||
// If the secret is stored under more than one key, we just pick an arbitrary one
|
||||
this.keyId = Object.keys(keys)[0];
|
||||
this.keyInfo = keys[this.keyId];
|
||||
}
|
||||
|
||||
this.phase = PHASE_INTRO;
|
||||
this.emit("update");
|
||||
}
|
||||
|
||||
async usePassPhrase() {
|
||||
this.phase = PHASE_BUSY;
|
||||
this.emit("update");
|
||||
|
|
Loading…
Reference in a new issue