From b56936003da8ae45a2625a7e965eff20f2c2916e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 3 Nov 2020 10:13:19 +0100 Subject: [PATCH 1/4] stop dehydration timer when stopping the client --- src/crypto/dehydration.ts | 7 +++++++ src/crypto/index.js | 1 + 2 files changed, 8 insertions(+) diff --git a/src/crypto/dehydration.ts b/src/crypto/dehydration.ts index 28caaf88d..697bf2e48 100644 --- a/src/crypto/dehydration.ts +++ b/src/crypto/dehydration.ts @@ -262,4 +262,11 @@ export class DehydrationManager { this.inProgress = false; } } + + private stop() { + if (this.timeoutId) { + global.clearTimeout(this.timeoutId); + this.timeoutId = undefined; + } + } } diff --git a/src/crypto/index.js b/src/crypto/index.js index 27a6a65d4..332ff7019 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -1752,6 +1752,7 @@ Crypto.prototype.start = function() { Crypto.prototype.stop = function() { this._outgoingRoomKeyRequestManager.stop(); this._deviceList.stop(); + this._dehydrationManager.stop(); }; /** From 4ab675863a3c9ed46455ae39ca53eb07e80106d1 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 4 Nov 2020 16:00:53 +0100 Subject: [PATCH 2/4] fix typo --- src/crypto/dehydration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/dehydration.ts b/src/crypto/dehydration.ts index 697bf2e48..f9996c583 100644 --- a/src/crypto/dehydration.ts +++ b/src/crypto/dehydration.ts @@ -104,7 +104,7 @@ export class DehydrationManager { // Check to see if it's the same key as before. If it's different, // dehydrate a new device. If it's the same, we can keep the same - // device. (Assume that keyInfo and deviceDisplayNamme will be the + // device. (Assume that keyInfo and deviceDisplayName will be the // same if the key is the same.) let matches: boolean = this.key && key.length == this.key.length; for (let i = 0; matches && i < key.length; i++) { From 13c7f55a793974b05a2b343547330e873a89d75a Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 4 Nov 2020 16:01:25 +0100 Subject: [PATCH 3/4] split up setKey and setKeyAndQueue as dehydrating in the background prevents use-cases where you want to await the creation of the dehydrated device --- src/client.js | 2 +- src/crypto/dehydration.ts | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/client.js b/src/client.js index 3f2ac2c66..837122c35 100644 --- a/src/client.js +++ b/src/client.js @@ -577,7 +577,7 @@ MatrixClient.prototype.setDehydrationKey = async function( logger.warn('not dehydrating device if crypto is not enabled'); return; } - return await this._crypto._dehydrationManager.setDehydrationKey( + return await this._crypto._dehydrationManager.setKeyAndQueue( key, keyInfo, deviceDisplayName, ); }; diff --git a/src/crypto/dehydration.ts b/src/crypto/dehydration.ts index f9996c583..e276c140c 100644 --- a/src/crypto/dehydration.ts +++ b/src/crypto/dehydration.ts @@ -77,10 +77,23 @@ export class DehydrationManager { }, ); } - async setDehydrationKey( + + /** set the key, and queue periodic dehydration to the server in the background */ + async setKeyAndQueueDehydration( key: Uint8Array, keyInfo: {[props: string]: any} = {}, deviceDisplayName: string = undefined, ): Promise { + const matches = await this.setKey(key, keyInfo, deviceDisplayName); + if (!matches) { + // start dehydration in the background + this.dehydrateDevice(); + } + } + + async setKey( + key: Uint8Array, keyInfo: {[props: string]: any} = {}, + deviceDisplayName: string = undefined, + ): Promise { if (!key) { // unsetting the key -- cancel any pending dehydration task if (this.timeoutId) { @@ -116,9 +129,8 @@ export class DehydrationManager { this.key = key; this.keyInfo = keyInfo; this.deviceDisplayName = deviceDisplayName; - // start dehydration in the background - this.dehydrateDevice(); } + return matches; } private async dehydrateDevice(): Promise { if (this.inProgress) { From 458164384debb1266cbf88b61953ad35a368f00f Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 4 Nov 2020 16:05:31 +0100 Subject: [PATCH 4/4] add client method for one-time dehydration that can be awaited --- src/client.js | 22 ++++++++++++++++++++++ src/crypto/dehydration.ts | 6 +++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/client.js b/src/client.js index 837122c35..0fc3d64ea 100644 --- a/src/client.js +++ b/src/client.js @@ -582,6 +582,28 @@ MatrixClient.prototype.setDehydrationKey = async function( ); }; +/** + * Creates a new dehydrated device (without queuing periodic dehydration) + * @param {Uint8Array} key the dehydration key + * @param {object} [keyInfo] Information about the key. Primarily for + * information about how to generate the key from a passphrase. + * @param {string} [deviceDisplayName] The device display name for the + * dehydrated device. + * @return {Promise} the device id of the newly created dehydrated device + */ +MatrixClient.prototype.createDehydratedDevice = async function( + key, keyInfo = {}, deviceDisplayName = undefined, +) { + if (!(this._crypto)) { + logger.warn('not dehydrating device if crypto is not enabled'); + return; + } + await this._crypto._dehydrationManager.setKey( + key, keyInfo, deviceDisplayName, + ); + return await this._crypto._dehydrationManager.dehydrateDevice(); +}; + MatrixClient.prototype.exportDevice = async function() { if (!(this._crypto)) { logger.warn('not exporting device if crypto is not enabled'); diff --git a/src/crypto/dehydration.ts b/src/crypto/dehydration.ts index e276c140c..07bf04131 100644 --- a/src/crypto/dehydration.ts +++ b/src/crypto/dehydration.ts @@ -132,7 +132,9 @@ export class DehydrationManager { } return matches; } - private async dehydrateDevice(): Promise { + + /** returns the device id of the newly created dehydrated device */ + async dehydrateDevice(): Promise { if (this.inProgress) { logger.log("Dehydration already in progress -- not starting new dehydration"); return; @@ -270,6 +272,8 @@ export class DehydrationManager { this.timeoutId = global.setTimeout( this.dehydrateDevice.bind(this), oneweek, ); + + return deviceId; } finally { this.inProgress = false; }