diff --git a/src/client.js b/src/client.js index 8a397bb3f..a737235b1 100644 --- a/src/client.js +++ b/src/client.js @@ -97,6 +97,11 @@ function keyFromRecoverySession(session, decryptionKey) { * @param {string} opts.accessToken The access_token for this user. * * @param {string} opts.userId The user ID for this user. + * + * @param {Object} opts.deviceToImport Device data exported with + * (TODO link to export method) that must be imported to recreate this device. + * Should only be useful for deviced with end-to-end crypto enabled. + * If provided, opts.userId should **not** be provided. * * @param {IdentityServerProvider} [opts.identityServer] * Optional. A provider object with one function `getAccessToken`, which is a @@ -243,6 +248,18 @@ export function MatrixClient(opts) { this.deviceId = opts.deviceId || null; + if (opts.deviceToImport) { + if (this.deviceId) { + logger.warn('not importing device because device ID is provided to constructor independently of exported data'); + } else if (!(opts.deviceToImport.deviceId)){ + logger.warn('not importing device because no device ID in exported data'); + } else { + this.deviceId = opts.deviceToImport.deviceId; + // will be used during async initialization of the crypto + this._exportedOlmDeviceToImport = opts.deviceToImport.olmDevice; + } + } + const userId = (opts.userId || null); this.credentials = { userId: userId, @@ -391,6 +408,17 @@ export function MatrixClient(opts) { utils.inherits(MatrixClient, EventEmitter); utils.extend(MatrixClient.prototype, MatrixBaseApis.prototype); +MatrixClient.prototype.exportDevice = async function() { + if (!(this._crypto)) { + logger.warn('not exporting device if crypto is not enabled'); + return; + } + return { + deviceId: this.deviceId, + olmDevice: await this._crypto._olmDevice.export(), + }; +}; + /** * Clear any data out of the persistent stores used by the client. * @@ -684,7 +712,10 @@ MatrixClient.prototype.initCrypto = async function() { ]); logger.log("Crypto: initialising crypto object..."); - await crypto.init(); + await crypto.init({ + exportedOlmDevice: this._exportedOlmDeviceToImport, + }); + delete this._exportedOlmDeviceToImport; this.olmVersion = Crypto.getOlmVersion(); diff --git a/src/crypto/OlmDevice.js b/src/crypto/OlmDevice.js index ba9f144cc..620cfd7ab 100644 --- a/src/crypto/OlmDevice.js +++ b/src/crypto/OlmDevice.js @@ -225,7 +225,7 @@ OlmDevice.prototype._storeAccount = function(txn, account) { * Export data for re-creating the Olm device later. * TODO export data other than just account and (P2P) sessions. * - * @return {Promise} The export data (see specs for structure) + * @return {Promise} The exported data */ OlmDevice.prototype.export = async function() { const result = { diff --git a/src/crypto/index.js b/src/crypto/index.js index dd5168957..6ef3181c9 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -228,12 +228,24 @@ utils.inherits(Crypto, EventEmitter); * Initialise the crypto module so that it is ready for use * * Returns a promise which resolves once the crypto module is ready for use. + * + * @param {Object} kwargs keyword arguments. + * @param {string} kwargs.exportedOlmDevice (Optional) data from exported device + * that must be re-created. */ -Crypto.prototype.init = async function() { +Crypto.prototype.init = async function(kwargs) { + const { + exportedOlmDevice, + } = kwargs; + logger.log("Crypto: initialising Olm..."); await global.Olm.init(); - logger.log("Crypto: initialising Olm device..."); - await this._olmDevice.init(); + logger.log( + exportedOlmDevice + ? "Crypto: initialising Olm device from exported device..." + : "Crypto: initialising Olm device..." + ); + await this._olmDevice.init(exportedOlmDevice); logger.log("Crypto: loading device list..."); await this._deviceList.load();