diff --git a/src/crypto/DeviceList.js b/src/crypto/DeviceList.js index 1a213a416..3e7e1a4ff 100644 --- a/src/crypto/DeviceList.js +++ b/src/crypto/DeviceList.js @@ -59,8 +59,9 @@ const TRACKING_STATUS_UP_TO_DATE = 3; * @alias module:crypto/DeviceList */ export default class DeviceList { - constructor(baseApis, cryptoStore, olmDevice) { + constructor(baseApis, cryptoStore, sessionStore, olmDevice) { this._cryptoStore = cryptoStore; + this._sessionStore = sessionStore; // userId -> { // deviceId -> { @@ -96,16 +97,37 @@ export default class DeviceList { * Load the device tracking state from storage */ async load() { + let shouldDeleteSessionStore = false; await this._cryptoStore.doTxn( - 'readonly', [IndexedDBCryptoStore.STORE_DEVICE_DATA], (txn) => { + // migrate from session store if there's data there and not here + 'readwrite', [IndexedDBCryptoStore.STORE_DEVICE_DATA], (txn) => { this._cryptoStore.getEndToEndDeviceData(txn, (deviceData) => { - this._devices = deviceData ? deviceData.devices : {}, - this._deviceTrackingStatus = deviceData ? - deviceData.trackingStatus : {}; - this._syncToken = deviceData ? deviceData.syncToken : null; + if (deviceData === null) { + console.log("Migrating e2e device data..."); + this._devices = this._sessionStore.getAllEndToEndDevices(); + this._deviceTrackingStatus = this._sessionStore.getEndToEndDeviceTrackingStatus(); + this._syncToken = this._sessionStore.getEndToEndDeviceSyncToken(); + this._cryptoStore.storeEndToEndDeviceData({ + devices: this._devices, + trackingStatus: this._deviceTrackingStatus, + syncToken: this._syncToken, + }, txn); + shouldDeleteSessionStore = true; + } else { + this._devices = deviceData ? deviceData.devices : {}, + this._deviceTrackingStatus = deviceData ? + deviceData.trackingStatus : {}; + this._syncToken = deviceData ? deviceData.syncToken : null; + } }); }, ); + + if (shouldDeleteSessionStore) { + // migrated data is now safely persisted: remove from old store + this._sessionStore.removeEndToEndDeviceData(); + } + for (const u of Object.keys(this._deviceTrackingStatus)) { // if a download was in progress when we got shut down, it isn't any more. if (this._deviceTrackingStatus[u] == TRACKING_STATUS_DOWNLOAD_IN_PROGRESS) { diff --git a/src/crypto/index.js b/src/crypto/index.js index 3a8b05d09..d1bee2fd4 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -69,7 +69,7 @@ function Crypto(baseApis, sessionStore, userId, deviceId, this._cryptoStore = cryptoStore; this._olmDevice = new OlmDevice(sessionStore, cryptoStore); - this._deviceList = new DeviceList(baseApis, cryptoStore, this._olmDevice); + this._deviceList = new DeviceList(baseApis, cryptoStore, sessionStore, this._olmDevice); // the last time we did a check for the number of one-time-keys on the // server. diff --git a/src/store/session/webstorage.js b/src/store/session/webstorage.js index 0fa813a27..8ea149beb 100644 --- a/src/store/session/webstorage.js +++ b/src/store/session/webstorage.js @@ -68,43 +68,24 @@ WebStorageSessionStore.prototype = { }, /** - * Stores the known devices for a user. - * @param {string} userId The user's ID. - * @param {object} devices A map from device ID to keys for the device. + * Retrieves the known devices for all users. + * @return {object} A map from user ID to map of device ID to keys for the device. */ - storeEndToEndDevicesForUser: function(userId, devices) { - setJsonItem(this.store, keyEndToEndDevicesForUser(userId), devices); - }, - - /** - * Retrieves the known devices for a user. - * @param {string} userId The user's ID. - * @return {object} A map from device ID to keys for the device. - */ - getEndToEndDevicesForUser: function(userId) { - return getJsonItem(this.store, keyEndToEndDevicesForUser(userId)); - }, - - storeEndToEndDeviceTrackingStatus: function(statusMap) { - setJsonItem(this.store, KEY_END_TO_END_DEVICE_LIST_TRACKING_STATUS, statusMap); + getAllEndToEndDevices: function() { + const prefix = keyEndToEndDevicesForUser(''); + const devices = {}; + for (let i = 0; i < store.length; ++i) { + const key = store.key(i); + const userId = key.substr(prefix.length); + if (key.startsWith(prefix)) devices[userId] = getJsonItem(this.store, key); + } + return devices; }, getEndToEndDeviceTrackingStatus: function() { return getJsonItem(this.store, KEY_END_TO_END_DEVICE_LIST_TRACKING_STATUS); }, - /** - * Store the sync token corresponding to the device list. - * - * This is used when starting the client, to get a list of the users who - * have changed their device list since the list time we were running. - * - * @param {String?} token - */ - storeEndToEndDeviceSyncToken: function(token) { - setJsonItem(this.store, KEY_END_TO_END_DEVICE_SYNC_TOKEN, token); - }, - /** * Get the sync token corresponding to the device list. * @@ -114,6 +95,15 @@ WebStorageSessionStore.prototype = { return getJsonItem(this.store, KEY_END_TO_END_DEVICE_SYNC_TOKEN); }, + /** + * Removes all end to end device data from the store + */ + removeEndToEndDeviceData: function() { + removeByPrefix(this.store, keyEndToEndDevicesForUser('')); + removeByPrefix(this.store, KEY_END_TO_END_DEVICE_LIST_TRACKING_STATUS); + removeByPrefix(this.store, KEY_END_TO_END_DEVICE_SYNC_TOKEN); + }, + /** * Retrieve the end-to-end sessions between the logged-in user and another * device.