diff --git a/js/axolotl_store.js b/js/axolotl_store.js index 6f74a664..971ad288 100644 --- a/js/axolotl_store.js +++ b/js/axolotl_store.js @@ -198,19 +198,7 @@ contact.fetch().always(function() { var sessions = contact.get('sessions') || {}; sessions[deviceId] = record; - contact.save({sessions: sessions}).always(function() { - resolve(textsecure.storage.devices.getDeviceObject(encodedNumber).then(function(device) { - if (device === undefined) { - return textsecure.storage.axolotl.getIdentityKey(number).then(function(identityKey) { - device = { encodedNumber: encodedNumber, - //TODO: Remove this duplication - identityKey: identityKey - }; - return textsecure.storage.devices.saveDeviceObject(device); - }); - } - })); - }); + contact.save({sessions: sessions}).always(resolve); }); }); }, diff --git a/js/libtextsecure.js b/js/libtextsecure.js index a5af2980..d4866ef2 100644 --- a/js/libtextsecure.js +++ b/js/libtextsecure.js @@ -38094,122 +38094,64 @@ axolotlInternal.RecipientRecord = function() { window.textsecure = window.textsecure || {}; window.textsecure.storage = window.textsecure.storage || {}; - window.textsecure.storage.devices = { - saveDeviceObject: function(deviceObject) { - return internalSaveDeviceObject(deviceObject, false); - }, + var tempKeys = {}; + window.textsecure.storage.devices = { saveKeysToDeviceObject: function(deviceObject) { - return internalSaveDeviceObject(deviceObject, true); + var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0]; + return textsecure.storage.axolotl.putIdentityKey(number, deviceObject.identityKey).then(function() { + tempKeys[deviceObject.encodedNumber] = { + preKey: deviceObject.preKey, + preKeyId: deviceObject.preKeyId, + signedKey: deviceObject.signedKey, + signedKeyId: deviceObject.signedKeyId, + signedKeySignature: deviceObject.signedKeySignature, + registrationId: deviceObject.registrationId + }; + }); }, removeTempKeysFromDevice: function(encodedNumber) { - return textsecure.storage.devices.getDeviceObject(encodedNumber).then(function(deviceObject) { - try { - delete deviceObject['signedKey']; - delete deviceObject['signedKeyId']; - delete deviceObject['signedKeySignature']; - delete deviceObject['preKey']; - delete deviceObject['preKeyId']; - delete deviceObject['registrationId']; - } catch(_) {} - return internalSaveDeviceObject(deviceObject, false); - }); + delete tempKeys[encodedNumber]; + return Promise.resolve(); }, getDeviceObjectsForNumber: function(number) { return textsecure.storage.axolotl.getIdentityKey(number).then(function(identityKey) { - var map = textsecure.storage.get("devices" + number); - if (map === undefined) + if (identityKey === undefined) { return []; - return map.devices.map(function(device) { - device.identityKey = identityKey; - return device; + } + return textsecure.storage.axolotl.getDeviceIds(number).then(function(deviceIds) { + // Add pending devices from tempKeys + for (var encodedNumber in tempKeys) { + var deviceNumber = textsecure.utils.unencodeNumber(encodedNumber)[0]; + var deviceId = textsecure.utils.unencodeNumber(encodedNumber)[1]; + if (deviceNumber === number && deviceIds.indexOf(deviceId) < 0) { + deviceIds.push(deviceId); + } + } + return deviceIds.map(function(deviceId) { + var encodedNumber = number + '.' + deviceId; + var deviceObject = tempKeys[encodedNumber] || {}; + deviceObject.encodedNumber = encodedNumber; + deviceObject.identityKey = identityKey; + return deviceObject; + }); }); }); }, - getDeviceObject: function(encodedNumber) { - var number = textsecure.utils.unencodeNumber(encodedNumber)[0]; - return textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devices) { - for (var i in devices) - if (devices[i].encodedNumber == encodedNumber) - return devices[i]; - - return undefined; - }); - }, - removeDeviceIdsForNumber: function(number, deviceIdsToRemove) { - return Promise.resolve((function() { - var map = textsecure.storage.get("devices" + number); - if (map === undefined) - throw new Error("Tried to remove device for unknown number"); - - var newDevices = []; - var devicesRemoved = 0; - for (var i in map.devices) { - var keep = true; - for (var j in deviceIdsToRemove) - if (map.devices[i].encodedNumber == number + "." + deviceIdsToRemove[j]) - keep = false; - - if (keep) - newDevices.push(map.devices[i]); - else - devicesRemoved++; - } - - if (devicesRemoved != deviceIdsToRemove.length) - throw new Error("Tried to remove unknown device"); - - if (newDevices.length === 0) - textsecure.storage.remove("devices" + number); - else { - map.devices = newDevices; - textsecure.storage.put("devices" + number, map); - } - })()); - } - }; - - var internalSaveDeviceObject = function(deviceObject, onlyKeys) { - if (deviceObject.encodedNumber === undefined) - throw new Error("Tried to store invalid deviceObject"); - - var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0]; - var map = textsecure.storage.get("devices" + number); - - return textsecure.storage.axolotl.getIdentityKey(number).then(function(identityKey) { - if (identityKey !== undefined && deviceObject.identityKey !== undefined && getString(identityKey) != getString(deviceObject.identityKey)) - throw new Error("Identity key changed"); - - if (map === undefined) - map = { devices: [deviceObject] }; - else { - var updated = false; - for (var i in map.devices) { - if (map.devices[i].encodedNumber == deviceObject.encodedNumber) { - if (!onlyKeys) - map.devices[i] = deviceObject; - else { - map.devices[i].preKey = deviceObject.preKey; - map.devices[i].preKeyId = deviceObject.preKeyId; - map.devices[i].signedKey = deviceObject.signedKey; - map.devices[i].signedKeyId = deviceObject.signedKeyId; - map.devices[i].signedKeySignature = deviceObject.signedKeySignature; - map.devices[i].registrationId = deviceObject.registrationId; - } - updated = true; - } - } - - if (!updated) - map.devices.push(deviceObject); + var promise = Promise.resolve(); + for (var j in deviceIdsToRemove) { + promise = promise.then(function() { + var encodedNumber = number + "." + deviceIdsToRemove[j]; + delete tempKeys[encodedNumber]; + return textsecure.storage.axolotl.removeSession(encodedNumber); + }); } - - textsecure.storage.put("devices" + number, map); - }); + return promise; + } }; })(); diff --git a/libtextsecure/storage/devices.js b/libtextsecure/storage/devices.js index d594cf48..0cd713fd 100644 --- a/libtextsecure/storage/devices.js +++ b/libtextsecure/storage/devices.js @@ -23,121 +23,63 @@ window.textsecure = window.textsecure || {}; window.textsecure.storage = window.textsecure.storage || {}; - window.textsecure.storage.devices = { - saveDeviceObject: function(deviceObject) { - return internalSaveDeviceObject(deviceObject, false); - }, + var tempKeys = {}; + window.textsecure.storage.devices = { saveKeysToDeviceObject: function(deviceObject) { - return internalSaveDeviceObject(deviceObject, true); + var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0]; + return textsecure.storage.axolotl.putIdentityKey(number, deviceObject.identityKey).then(function() { + tempKeys[deviceObject.encodedNumber] = { + preKey: deviceObject.preKey, + preKeyId: deviceObject.preKeyId, + signedKey: deviceObject.signedKey, + signedKeyId: deviceObject.signedKeyId, + signedKeySignature: deviceObject.signedKeySignature, + registrationId: deviceObject.registrationId + }; + }); }, removeTempKeysFromDevice: function(encodedNumber) { - return textsecure.storage.devices.getDeviceObject(encodedNumber).then(function(deviceObject) { - try { - delete deviceObject['signedKey']; - delete deviceObject['signedKeyId']; - delete deviceObject['signedKeySignature']; - delete deviceObject['preKey']; - delete deviceObject['preKeyId']; - delete deviceObject['registrationId']; - } catch(_) {} - return internalSaveDeviceObject(deviceObject, false); - }); + delete tempKeys[encodedNumber]; + return Promise.resolve(); }, getDeviceObjectsForNumber: function(number) { return textsecure.storage.axolotl.getIdentityKey(number).then(function(identityKey) { - var map = textsecure.storage.get("devices" + number); - if (map === undefined) + if (identityKey === undefined) { return []; - return map.devices.map(function(device) { - device.identityKey = identityKey; - return device; + } + return textsecure.storage.axolotl.getDeviceIds(number).then(function(deviceIds) { + // Add pending devices from tempKeys + for (var encodedNumber in tempKeys) { + var deviceNumber = textsecure.utils.unencodeNumber(encodedNumber)[0]; + var deviceId = textsecure.utils.unencodeNumber(encodedNumber)[1]; + if (deviceNumber === number && deviceIds.indexOf(deviceId) < 0) { + deviceIds.push(deviceId); + } + } + return deviceIds.map(function(deviceId) { + var encodedNumber = number + '.' + deviceId; + var deviceObject = tempKeys[encodedNumber] || {}; + deviceObject.encodedNumber = encodedNumber; + deviceObject.identityKey = identityKey; + return deviceObject; + }); }); }); }, - getDeviceObject: function(encodedNumber) { - var number = textsecure.utils.unencodeNumber(encodedNumber)[0]; - return textsecure.storage.devices.getDeviceObjectsForNumber(number).then(function(devices) { - for (var i in devices) - if (devices[i].encodedNumber == encodedNumber) - return devices[i]; - - return undefined; - }); - }, - removeDeviceIdsForNumber: function(number, deviceIdsToRemove) { - return Promise.resolve((function() { - var map = textsecure.storage.get("devices" + number); - if (map === undefined) - throw new Error("Tried to remove device for unknown number"); - - var newDevices = []; - var devicesRemoved = 0; - for (var i in map.devices) { - var keep = true; - for (var j in deviceIdsToRemove) - if (map.devices[i].encodedNumber == number + "." + deviceIdsToRemove[j]) - keep = false; - - if (keep) - newDevices.push(map.devices[i]); - else - devicesRemoved++; - } - - if (devicesRemoved != deviceIdsToRemove.length) - throw new Error("Tried to remove unknown device"); - - if (newDevices.length === 0) - textsecure.storage.remove("devices" + number); - else { - map.devices = newDevices; - textsecure.storage.put("devices" + number, map); - } - })()); + var promise = Promise.resolve(); + for (var j in deviceIdsToRemove) { + promise = promise.then(function() { + var encodedNumber = number + "." + deviceIdsToRemove[j]; + delete tempKeys[encodedNumber]; + return textsecure.storage.axolotl.removeSession(encodedNumber); + }); + } + return promise; } }; - - var internalSaveDeviceObject = function(deviceObject, onlyKeys) { - if (deviceObject.encodedNumber === undefined) - throw new Error("Tried to store invalid deviceObject"); - - var number = textsecure.utils.unencodeNumber(deviceObject.encodedNumber)[0]; - var map = textsecure.storage.get("devices" + number); - - return textsecure.storage.axolotl.getIdentityKey(number).then(function(identityKey) { - if (identityKey !== undefined && deviceObject.identityKey !== undefined && getString(identityKey) != getString(deviceObject.identityKey)) - throw new Error("Identity key changed"); - - if (map === undefined) - map = { devices: [deviceObject] }; - else { - var updated = false; - for (var i in map.devices) { - if (map.devices[i].encodedNumber == deviceObject.encodedNumber) { - if (!onlyKeys) - map.devices[i] = deviceObject; - else { - map.devices[i].preKey = deviceObject.preKey; - map.devices[i].preKeyId = deviceObject.preKeyId; - map.devices[i].signedKey = deviceObject.signedKey; - map.devices[i].signedKeyId = deviceObject.signedKeyId; - map.devices[i].signedKeySignature = deviceObject.signedKeySignature; - map.devices[i].registrationId = deviceObject.registrationId; - } - updated = true; - } - } - - if (!updated) - map.devices.push(deviceObject); - } - - textsecure.storage.put("devices" + number, map); - }); - }; })();