From fb1b554b862677848e94dc0e1cf74e6ea184419a Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Mon, 15 Jan 2018 01:50:24 +0000 Subject: [PATCH 1/2] initial pseudocode WIP for e2e online backups --- src/client.js | 1 + src/crypto/OlmDevice.js | 20 ++++++++++++++++++++ src/crypto/index.js | 14 ++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/src/client.js b/src/client.js index 0b00ab36b9e..29357118537 100644 --- a/src/client.js +++ b/src/client.js @@ -393,6 +393,7 @@ MatrixClient.prototype.initCrypto = async function() { "crypto.roomKeyRequest", "crypto.roomKeyRequestCancellation", "crypto.warning", + "crypto.suggestKeyRestore", ]); await crypto.init(); diff --git a/src/crypto/OlmDevice.js b/src/crypto/OlmDevice.js index cda14779c2b..131419ea7e7 100644 --- a/src/crypto/OlmDevice.js +++ b/src/crypto/OlmDevice.js @@ -91,6 +91,21 @@ function OlmDevice(sessionStore, cryptoStore) { this.deviceEd25519Key = null; this._maxOneTimeKeys = null; + // track whether this device's megolm keys are being backed up incrementally + // to the server or not. + // XXX: this should probably have a single source of truth from OlmAccount + this.backupKey = null; + + // track which of our other devices (if any) have cross-signed this device + // XXX: this should probably have a single source of truth in the /devices + // API store or whatever we use to track our self-signed devices. + this.crossSelfSigs = []; + + // track whether we have already suggested to the user that they should + // restore their keys from backup or by cross-signing the device. + // We use this to avoid repeatedly emitting the suggestion event. + this.suggestedKeyRestore = false; + // we don't bother stashing outboundgroupsessions in the sessionstore - // instead we keep them here. this._outboundGroupSessionStore = {}; @@ -921,6 +936,11 @@ OlmDevice.prototype.addInboundGroupSession = async function( this._cryptoStore.addEndToEndInboundGroupSession( senderKey, sessionId, sessionData, txn, ); + + if (this.backupKey) { + // get olm::Account::generate_backup_encryption_secret + // save sessionData (pickled with this secret) to the server + } } finally { session.free(); } diff --git a/src/crypto/index.js b/src/crypto/index.js index 6b1d8f477f6..31dcd76b656 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -1015,6 +1015,13 @@ Crypto.prototype._onRoomKeyEvent = function(event) { return; } + if (!device.suggestedKeyRestore && + !device.backupKey && !device.selfCrossSigs.length) + { + this.emit("crypto.suggestKeyRestore"); + device.suggestKeyRestore = true; + } + const alg = this._getRoomDecryptor(content.room_id, content.algorithm); alg.onRoomKeyEvent(event); }; @@ -1355,6 +1362,13 @@ class IncomingRoomKeyRequestCancellation { * @param {module:crypto~IncomingRoomKeyRequestCancellation} req */ +/** + * Fires when we want to suggest to the user that they restore their megolm keys + * from backup or by cross-signing the device. + * + * @event module:client~MatrixClient#"crypto.suggestKeyRestore" + */ + /** * Fires when the app may wish to warn the user about something related * the end-to-end crypto. From e0c9b990e7db19bed24129b9307b37ed4600c765 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 18 Jan 2018 20:59:08 +0000 Subject: [PATCH 2/2] blindly move crypto.suggestKeyRestore over to /sync --- src/client.js | 7 ++++++- src/crypto/OlmDevice.js | 1 + src/crypto/index.js | 14 -------------- src/sync.js | 10 ++++++++++ 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/client.js b/src/client.js index 29357118537..aa05462ac1c 100644 --- a/src/client.js +++ b/src/client.js @@ -393,7 +393,6 @@ MatrixClient.prototype.initCrypto = async function() { "crypto.roomKeyRequest", "crypto.roomKeyRequestCancellation", "crypto.warning", - "crypto.suggestKeyRestore", ]); await crypto.init(); @@ -3630,6 +3629,12 @@ module.exports.CRYPTO_ENABLED = CRYPTO_ENABLED; * }); */ +/** + * Fires when we want to suggest to the user that they restore their megolm keys + * from backup or by cross-signing the device. + * + * @event module:client~MatrixClient#"crypto.suggestKeyRestore" + */ // EventEmitter JSDocs diff --git a/src/crypto/OlmDevice.js b/src/crypto/OlmDevice.js index 131419ea7e7..656e4fddc05 100644 --- a/src/crypto/OlmDevice.js +++ b/src/crypto/OlmDevice.js @@ -104,6 +104,7 @@ function OlmDevice(sessionStore, cryptoStore) { // track whether we have already suggested to the user that they should // restore their keys from backup or by cross-signing the device. // We use this to avoid repeatedly emitting the suggestion event. + // XXX: persist this somewhere! this.suggestedKeyRestore = false; // we don't bother stashing outboundgroupsessions in the sessionstore - diff --git a/src/crypto/index.js b/src/crypto/index.js index 31dcd76b656..6b1d8f477f6 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -1015,13 +1015,6 @@ Crypto.prototype._onRoomKeyEvent = function(event) { return; } - if (!device.suggestedKeyRestore && - !device.backupKey && !device.selfCrossSigs.length) - { - this.emit("crypto.suggestKeyRestore"); - device.suggestKeyRestore = true; - } - const alg = this._getRoomDecryptor(content.room_id, content.algorithm); alg.onRoomKeyEvent(event); }; @@ -1362,13 +1355,6 @@ class IncomingRoomKeyRequestCancellation { * @param {module:crypto~IncomingRoomKeyRequestCancellation} req */ -/** - * Fires when we want to suggest to the user that they restore their megolm keys - * from backup or by cross-signing the device. - * - * @event module:client~MatrixClient#"crypto.suggestKeyRestore" - */ - /** * Fires when the app may wish to warn the user about something related * the end-to-end crypto. diff --git a/src/sync.js b/src/sync.js index 71fb866d523..74aff54bf08 100644 --- a/src/sync.js +++ b/src/sync.js @@ -1,6 +1,7 @@ /* Copyright 2015, 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd +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. @@ -983,6 +984,15 @@ SyncApi.prototype._processSyncResponse = async function( async function processRoomEvent(e) { client.emit("event", e); if (e.isState() && e.getType() == "m.room.encryption" && self.opts.crypto) { + + // XXX: get device + if (!device.getSuggestedKeyRestore() && + !device.backupKey && !device.selfCrossSigs.length) + { + client.emit("crypto.suggestKeyRestore"); + device.setSuggestedKeyRestore(true); + } + await self.opts.crypto.onCryptoEvent(e); } }