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

Tweaks for Cross Signing Support #2556

Closed
wants to merge 12 commits into from
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ import FileSaver from 'file-saver';

import { _t } from '../../../../languageHandler';

const PHASE_PASSPHRASE = 0;
const PHASE_PASSPHRASE_CONFIRM = 1;
const PHASE_SHOWKEY = 2;
const PHASE_KEEPITSAFE = 3;
const PHASE_BACKINGUP = 4;
const PHASE_DONE = 5;
const PHASE_OPTOUT_CONFIRM = 6;
const PHASE_FETCHMYKEYS = 0;
const PHASE_PASSPHRASE = 1;
const PHASE_PASSPHRASE_CONFIRM = 2;
const PHASE_SHOWKEY = 3;
const PHASE_KEEPITSAFE = 4;
const PHASE_INTERACTIVEAUTH = 5;
const PHASE_BACKINGUP = 6;
const PHASE_DONE = 7;
const PHASE_OPTOUT_CONFIRM = 8;

const PASSWORD_MIN_SCORE = 4; // So secure, many characters, much complex, wow, etc, etc.
const PASSPHRASE_FEEDBACK_DELAY = 500; // How long after keystroke to offer passphrase feedback, ms.
Expand All @@ -51,7 +53,7 @@ function selectText(target) {
export default React.createClass({
getInitialState: function() {
return {
phase: PHASE_PASSPHRASE,
phase: PHASE_FETCHMYKEYS,
passPhrase: '',
passPhraseConfirm: '',
copied: false,
Expand All @@ -61,10 +63,22 @@ export default React.createClass({
};
},

componentWillMount: function() {
componentWillMount: async function() {
this._recoveryKeyNode = null;
this._keyBackupInfo = null;
this._setZxcvbnResultTimeout = null;
this._myKeys = null;

try {
this._myKeys = await MatrixClientPeg.get().downloadKeysForUsers([
MatrixClientPeg.get().credentials.userId,
]);
} catch (e) {
// don't die if we can't get our own keys - it's not necessarily critical
}
this.setState({
phase: PHASE_PASSPHRASE,
});
},

componentWillUnmount: function() {
Expand Down Expand Up @@ -102,14 +116,41 @@ export default React.createClass({

_createBackup: async function() {
this.setState({
phase: PHASE_BACKINGUP,
phase: PHASE_INTERACTIVEAUTH,
error: null,
});
let info;
},

_makeCreateBackupRequest: function(auth) {
// XXX: We'll have to think about this 'replaces' flag: replacing your SSK with a new
// one is obviously a big deal, but we're storing the private part in a key backup, so
// if we delete that key backup version it's useless anyway: we really need to warn at
// the point of backup deletion. For now, we always replace any self-signing key that
// exists (which is obviously terrible).
let replacesSsk;
if (
this._myKeys &&
this._myKeys.self_signing_keys &&
this._myKeys.self_signing_keys[MatrixClientPeg.get().credentials.userId]
) {
const mySsks = this._myKeys.self_signing_keys[MatrixClientPeg.get().credentials.userId];
replacesSsk = Object.values(mySsks.keys)[0];
}

return MatrixClientPeg.get().createKeyBackupVersion(
this._keyBackupInfo, auth, replacesSsk,
);
},

_onCreateBackupAuthFinished: async function(success, result) {
if (!success) {
this.setState({
error: result,
});
return;
}

try {
info = await MatrixClientPeg.get().createKeyBackupVersion(
this._keyBackupInfo,
);
await MatrixClientPeg.get().scheduleAllGroupSessionsForBackup();
this.setState({
phase: PHASE_DONE,
Expand All @@ -120,8 +161,8 @@ export default React.createClass({
// delete the version, disable backup, or do nothing? If we just
// disable without deleting, we'll enable on next app reload since
// it is trusted.
if (info) {
MatrixClientPeg.get().deleteKeyBackupVersion(info.version);
if (result) {
MatrixClientPeg.get().deleteKeyBackupVersion(result.version);
}
this.setState({
error: e,
Expand Down Expand Up @@ -444,7 +485,19 @@ export default React.createClass({
</div>;
},

_renderBusyPhase: function(text) {
_renderPhaseInteractiveAuth: function() {
const InteractiveAuth = sdk.getComponent("structures.InteractiveAuth");

return <div>
<InteractiveAuth
matrixClient={MatrixClientPeg.get()}
makeRequest={this._makeCreateBackupRequest}
onAuthFinished={this._onCreateBackupAuthFinished}
/>
</div>;
},

_renderBusyPhase: function() {
const Spinner = sdk.getComponent('views.elements.Spinner');
return <div>
<Spinner />
Expand Down Expand Up @@ -483,6 +536,8 @@ export default React.createClass({

_titleForPhase: function(phase) {
switch (phase) {
case PHASE_FETCHMYKEYS:
return '';
case PHASE_PASSPHRASE:
return _t('Create a Recovery Passphrase');
case PHASE_PASSPHRASE_CONFIRM:
Expand All @@ -493,6 +548,8 @@ export default React.createClass({
return _t('Recovery Key');
case PHASE_KEEPITSAFE:
return _t('Keep it safe');
case PHASE_INTERACTIVEAUTH:
return _t('Authentication Required');
case PHASE_BACKINGUP:
return _t('Starting backup...');
case PHASE_DONE:
Expand Down Expand Up @@ -520,6 +577,9 @@ export default React.createClass({
</div>;
} else {
switch (this.state.phase) {
case PHASE_FETCHMYKEYS:
content = this._renderBusyPhase();
break;
case PHASE_PASSPHRASE:
content = this._renderPhasePassPhrase();
break;
Expand All @@ -532,6 +592,9 @@ export default React.createClass({
case PHASE_KEEPITSAFE:
content = this._renderPhaseKeepItSafe();
break;
case PHASE_INTERACTIVEAUTH:
content = this._renderPhaseInteractiveAuth();
break;
case PHASE_BACKINGUP:
content = this._renderBusyPhase();
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export default React.createClass({
});
try {
const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithPassword(
this.state.passPhrase, undefined, undefined, this.state.backupInfo.version,
this.state.passPhrase, undefined, undefined, this.state.backupInfo,
);
this.setState({
loading: false,
Expand All @@ -105,7 +105,7 @@ export default React.createClass({
});
try {
const recoverInfo = await MatrixClientPeg.get().restoreKeyBackupWithRecoveryKey(
this.state.recoveryKey, undefined, undefined, this.state.backupInfo.version,
this.state.recoveryKey, undefined, undefined, this.state.backupInfo,
);
this.setState({
loading: false,
Expand Down Expand Up @@ -184,7 +184,10 @@ export default React.createClass({
} else if (this.state.backupInfo === null) {
title = _t("Error");
content = _t("No backup found!");
} else if (this.state.recoverInfo && this.state.recoverInfo.imported === 0) {
} else if (this.state.recoverInfo &&
this.state.recoverInfo.imported === 0 &&
this.state.recoverInfo.total > 0
) {
title = _t("Error Restoring Backup");
content = <div>
<p>{_t(
Expand Down
45 changes: 40 additions & 5 deletions src/components/views/settings/KeyBackupPanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,22 +191,57 @@ export default class KeyBackupPanel extends React.PureComponent {
<span className={sig.valid ? 'mx_KeyBackupPanel_sigValid' : 'mx_KeyBackupPanel_sigInvalid'}>
{sub}
</span>;
const verify = sub =>
<span className={sig.device && sig.device.isVerified() ? 'mx_KeyBackupPanel_deviceVerified' : 'mx_KeyBackupPanel_deviceNotVerified'}>
const verify = sub => {
const isVerified = (
(sig.device && sig.device.isVerified()) ||
(sig.self_signing_key && sig.self_signing_key.isVerified())
);
const cls = 'mx_KeyBackupPanel_' + (isVerified ? 'deviceVerified' : 'deviceNotVerified');
return <span className={cls}>
{sub}
</span>;
};
const device = sub => <span className="mx_KeyBackupPanel_deviceName">{deviceName}</span>;
let sigStatus;
if (!sig.device) {
if (sig.self_signing_key && sig.valid && sig.self_signing_key.isVerified()) {
sigStatus = _t(
"Backup has a <validity>valid</validity> signature from your " +
"<verify>verified</verify> Self-Signing Key",
{ }, { validity, verify },
);
} else if (sig.self_signing_key && sig.valid && !sig.self_signing_key.isVerified()) {
sigStatus = _t(
"Backup has a <validity>valid</validity> signature from your " +
"<verify>unverified</verify> Self-Signing Key",
{ }, { validity, verify },
);
} else if (sig.self_signing_key && !sig.valid && sig.self_signing_key.isVerified()) {
sigStatus = _t(
"Backup has an <validity>invalid</validity> signature from your " +
"<verify>verified</verify> Self-Signing Key",
{ }, { validity, verify },
);
} else if (sig.self_signing_key && !sig.valid && !sig.self_signing_key.isVerified()) {
sigStatus = _t(
"Backup has an <validity>invalid</validity> signature from your " +
"<verify>unverified</verify> Self-Signing Key",
{ }, { validity, verify },
);
} else if (!sig.device) {
sigStatus = _t(
"Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.",
{ deviceId: sig.deviceId }, { verify },
);
} else if (sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()) {
} else if (sig.valid && sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()) {
sigStatus = _t(
"Backup has a <validity>valid</validity> signature from this device",
{}, { validity },
);
} else if (!sig.valid && sig.device.getFingerprint() === MatrixClientPeg.get().getDeviceEd25519Key()) {
sigStatus = _t(
"Backup has a <validity>invalid</validity> signature from this device",
{}, { validity },
);
} else if (sig.valid && sig.device.isVerified()) {
sigStatus = _t(
"Backup has a <validity>valid</validity> signature from " +
Expand Down Expand Up @@ -238,7 +273,7 @@ export default class KeyBackupPanel extends React.PureComponent {
verifyButton = <div><br /><AccessibleButton className="mx_UserSettings_button"
onClick={this._verifyDevice} data-sigindex={i}>
{ _t("Verify...") }
</AccessibleButton></div>;
</AccessibleButton><br /><br /></div>;
}

return <div key={i}>
Expand Down
6 changes: 6 additions & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -383,8 +383,13 @@
"This device is <b>not</b> using key backup": "This device is <b>not</b> using key backup",
"Backing up %(sessionsRemaining)s keys...": "Backing up %(sessionsRemaining)s keys...",
"All keys backed up": "All keys backed up",
"Backup has a <validity>valid</validity> signature from your <verify>verified</verify> Self-Signing Key": "Backup has a <validity>valid</validity> signature from your <verify>verified</verify> Self-Signing Key",
"Backup has a <validity>valid</validity> signature from your <verify>unverified</verify> Self-Signing Key": "Backup has a <validity>valid</validity> signature from your <verify>unverified</verify> Self-Signing Key",
"Backup has an <validity>invalid</validity> signature from your <verify>verified</verify> Self-Signing Key": "Backup has an <validity>invalid</validity> signature from your <verify>verified</verify> Self-Signing Key",
"Backup has an <validity>invalid</validity> signature from your <verify>unverified</verify> Self-Signing Key": "Backup has an <validity>invalid</validity> signature from your <verify>unverified</verify> Self-Signing Key",
"Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.": "Backup has a signature from <verify>unknown</verify> device with ID %(deviceId)s.",
"Backup has a <validity>valid</validity> signature from this device": "Backup has a <validity>valid</validity> signature from this device",
"Backup has a <validity>invalid</validity> signature from this device": "Backup has a <validity>invalid</validity> signature from this device",
"Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>": "Backup has a <validity>valid</validity> signature from <verify>verified</verify> device <device></device>",
"Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>": "Backup has a <validity>valid</validity> signature from <verify>unverified</verify> device <device></device>",
"Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>": "Backup has an <validity>invalid</validity> signature from <verify>verified</verify> device <device></device>",
Expand Down Expand Up @@ -1480,6 +1485,7 @@
"<b>Print it</b> and store it somewhere safe": "<b>Print it</b> and store it somewhere safe",
"<b>Save it</b> on a USB key or backup drive": "<b>Save it</b> on a USB key or backup drive",
"<b>Copy it</b> to your personal cloud storage": "<b>Copy it</b> to your personal cloud storage",
"Authentication Required": "Authentication Required",
"Your encryption keys are now being backed up in the background to your Homeserver. The initial backup could take several minutes. You can view key backup upload progress in Settings.": "Your encryption keys are now being backed up in the background to your Homeserver. The initial backup could take several minutes. You can view key backup upload progress in Settings.",
"Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.": "Without setting up Secure Message Recovery, you won't be able to restore your encrypted message history if you log out or use another device.",
"Set up Secure Message Recovery": "Set up Secure Message Recovery",
Expand Down