initial pseudocode WIP for e2e online backups

This commit is contained in:
Matthew Hodgson 2018-01-15 02:02:48 +00:00
parent 952f2c6a21
commit a233af67ea
4 changed files with 247 additions and 0 deletions

View file

@ -0,0 +1,96 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import sdk from './index';
import Modal from './Modal';
export default class SuggestKeyRestoreHandler {
constructor(matrixClient) {
this._matrixClient = matrixClient;
}
handleSuggestKeyRestore() {
const onVerifyDevice = () => {
const DeviceVerifyDialog = sdk.getComponent('views.dialogs.DeviceVerifyDialog');
Modal.createTrackedDialog('Key Restore', 'Starting verification', DeviceVerifyDialog, {
// userId: this.props.userId,
// device: this.state.deviceInfo,
onFinished: (verified) => {
if (verified) {
this.props.onFinished();
}
},
});
};
const onRecoverFromBackup = () => {
// XXX: we need this so that you can get at it from UserSettings too
// * prompt for recovery key
// * Download the current backup version info from the server and check the key decrypts it okay.
// * Check that the public key for that backup version matches the recovery key
// * show a spinner
// * Download all the existing keys from the server
// * Decrypt them using the recovery key
// * Add them to the local store (which encrypts them as normal with "DEFAULT KEY"
// * Enable incremental backups for this device.
};
const onIgnoreSuggestion = () => {
};
const onFinished = () => {
this.suggestBackup();
};
// FIXME: need a way to know if an account has ever touched E2E before.
// Perhaps we can extend toDevice to include a flag if it's the first time the
// server has ever sent a room_key to a client or something?
const virginAccount = false;
if (virginAccount) {
this.suggestBackup();
return;
}
const SuggestKeyRestoreDialog = sdk.getComponent("dialogs.SuggestKeyRestoreDialog");
Modal.createTrackedDialog('Key Restore', 'Key Restore', SuggestKeyRestoreDialog, {
matrixClient: this._matrixClient,
isOnlyDevice: false, // FIXME
hasOnlineBackup: false, // FIXME
onVerifyDevice: onVerifyDevice,
onRecoverFromBackup: onRecoverFromBackup,
onIgnoreSuggestion: onIgnoreSuggestion,
onFinished: onFinished,
});
}
suggestBackup() {
if (hasOnlineBackup) return;
const onStartNewBackup = () => {
// XXX: we need this so that you can get at it from UserSettings too
// * Upload all their existing keys from their session store to the backup using the bulk upload API.
// (Having re-encrypted them using the backup keypair rather than the static one used to store them on disk)
};
const SuggestKeyBackupDialog = sdk.getComponent("dialogs.SuggestKeyBackupDialog");
Modal.createTrackedDialog('Key Backup', 'Key Backup', SuggestKeyBackupDialog, {
onStartNewBackup: onStartNewBackup,
});
}
}

View file

@ -1129,6 +1129,12 @@ export default React.createClass({
cli.on("crypto.roomKeyRequestCancellation", (req) => {
krh.handleKeyRequestCancellation(req);
});
const skrh = new SuggestKeyRestoreHandler(cli);
cli.on("crypto.suggestKeyRestore", () => {
skrh.handleSuggestKeyRestore();
});
cli.on("Room", (room) => {
if (MatrixClientPeg.get().isCryptoEnabled()) {
const blacklistEnabled = SettingsStore.getValueAt(

View file

@ -0,0 +1,68 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Modal from '../../../Modal';
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import { _t, _td } from '../../../languageHandler';
/**
* Dialog which asks the user whether they want to restore megolm keys
* from various sources when they first start using E2E on a new device.
*/
export default React.createClass({
propTypes: {
onStartNewBackup: PropTypes.func.isRequired,
},
render: function() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
return (
<BaseDialog className='mx_SuggestKeyRestoreDialog'
onFinished={this.props.onFinished}
title={_t('Backup encryption keys on your server?')}
>
<div>
<p>To avoid ever losing your encrypted message history, you
can save your encryption keys on the server, protected by a recovery key.
</p>
<p>To maximise security, your recovery key is never stored by the app,
so you must store it yourself somewhere safe.</p>
<p>
<p>Warning: storing your encryption keys on the server means that
if someone gains access to your account and also steals your recovery key,
they will be able to read all of your encrypted conversation history.
</p>
<p>Do you wish to generate a recovery key and backup your encryption
keys on the server?
<div className="mx_Dialog_buttons">
<button onClick={this.props.onStartNewBackup}>
{ _t("Generate recovery key and enable online backups") }
</button>
<button onClick={this.props.onFinished}>
{ _t("I'll stick to manual backups") }
</button>
</div>
</div>
</BaseDialog>
);
},
});

View file

@ -0,0 +1,77 @@
/*
Copyright 2018 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Modal from '../../../Modal';
import React from 'react';
import PropTypes from 'prop-types';
import sdk from '../../../index';
import { _t, _td } from '../../../languageHandler';
/**
* Dialog which asks the user whether they want to restore megolm keys
* from various sources when they first start using E2E on a new device.
*/
export default React.createClass({
propTypes: {
matrixClient: PropTypes.object.isRequired,
isOnlyDevice: PropTypes.bool.isRequired,
hasOnlineBackup: PropTypes.bool.isRequired,
onVerifyDevice: PropTypes.func.isRequired,
onImportBackup: PropTypes.func.isRequired,
onRecoverFromBackup: PropTypes.func.isRequired,
onIgnoreSuggestion: PropTypes.func.isRequired,
},
render: function() {
const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog');
return (
<BaseDialog className='mx_SuggestKeyRestoreDialog'
onFinished={this.props.onFinished}
title={_t('Restore encryption keys')}
>
<div>
<p>We don't have a way to decrypt older messages on this device.</p>
<p>Your options are:</p>
<li>
{ !this.props.isOnlyDevice ? <ul>Verify this device from one or more of your other ones to automatically sync keys</ul>: '' }
{ this.props.hasOnlineBackup ? <ul>Enter your recovery key to restore encryption keys from your online backup</ul> : '' }
<ul>Import encryption keys from an offline backup</ul>
<ul>Continue without restoring keys, syncing keys from your other devices on a best effort basis</ul>
</li>
<div className="mx_Dialog_buttons">
<button onClick={this.props.onVerifyDevice}>
{ _t('Verify this device') }
</button>
<button onClick={this.props.onRecoverFromBackup}>
{ _t('Restore from online backup') }
</button>
<button onClick={this.props.onImportBackup}>
{ _t('Restore from offline backup') }
</button>
<button onClick={this.props.onIgnoreClicked}>
{ _t('Ignore request') }
</button>
</div>
</div>
</BaseDialog>
);
},
});