diff --git a/src/client.js b/src/client.js index 561f787e2..e4108aa2a 100644 --- a/src/client.js +++ b/src/client.js @@ -577,11 +577,33 @@ 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, ); }; +/** + * 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 28caaf88d..07bf04131 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) { @@ -104,7 +117,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++) { @@ -116,11 +129,12 @@ 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 { + + /** 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; @@ -258,8 +272,17 @@ export class DehydrationManager { this.timeoutId = global.setTimeout( this.dehydrateDevice.bind(this), oneweek, ); + + return deviceId; } finally { 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(); }; /**