diff --git a/libaxolotl/protocol.js b/libaxolotl/protocol.js index e0f3617b..e63f5403 100644 --- a/libaxolotl/protocol.js +++ b/libaxolotl/protocol.js @@ -113,6 +113,16 @@ window.axolotl.protocol = function() { openSessionRemaining = true; if (!openSessionRemaining) // Used as a flag to get new pre keys for the next session record.registrationId = null; + else if (record.registrationId === null && registrationId !== undefined) + record.registrationId = registrationId; + else if (record.registrationId === null) + throw new Error("Had open sessions on a record that had no registrationId set"); + + var identityKey = axolotl.api.storage.identityKeys.get(encodedNumber); + if (identityKey === undefined) + axolotl.api.storage.identityKeys.put(encodedNumber, record.identityKey); + else if (getString(identityKey) !== getString(record.identityKey)) + throw new Error("Tried to change identity key at save time"); axolotl.api.storage.sessions.put(encodedNumber, record); } @@ -160,8 +170,12 @@ window.axolotl.protocol = function() { crypto_storage.getSessionOrIdentityKeyByBaseKey = function(encodedNumber, baseKey) { var record = axolotl.api.storage.sessions.get(encodedNumber); - if (record === undefined) - return undefined; + if (record === undefined) { + var identityKey = axolotl.api.storage.identityKeys.get(encodedNumber); + if (identityKey === undefined) + return undefined; + return { indexInfo: { remoteIdentityKey: identityKey } }; + } var sessions = record._sessions; var preferredSession = record._sessions[getString(baseKey)]; diff --git a/libaxolotl/test/fake_api.js b/libaxolotl/test/fake_api.js index 722a33ab..dfbd3c8f 100644 --- a/libaxolotl/test/fake_api.js +++ b/libaxolotl/test/fake_api.js @@ -1,6 +1,7 @@ 'use strict'; var testSessionMap = {}; +var testIdentityKeysMap = {}; ;(function() { window.axolotl = window.axolotl || {}; @@ -24,6 +25,15 @@ var testSessionMap = {}; localStorage.removeItem(key); }, + identityKeys: { + get: function(identifier) { + return testIdentityKeysMap[identifier]; + }, + put: function(identifier, identityKey) { + testIdentityKeysMap[identifier] = identityKey; + }, + }, + sessions: { get: function(identifier) { return testSessionMap[identifier]; diff --git a/libaxolotl/test/protocol_test.js b/libaxolotl/test/protocol_test.js index a554eaf5..4f53ab46 100644 --- a/libaxolotl/test/protocol_test.js +++ b/libaxolotl/test/protocol_test.js @@ -224,6 +224,7 @@ describe('Protocol', function() { it(axolotlTestVectors[i].name, function(done) { localStorage.clear(); testSessionMap = {}; + testIdentityKeysMap = {}; return runAxolotlTest(axolotlTestVectors[i].vectors).then(function(res) { assert(res); }).then(done).catch(done); diff --git a/libtextsecure/axolotl_wrapper.js b/libtextsecure/axolotl_wrapper.js index f6c6e0e3..3c404891 100644 --- a/libtextsecure/axolotl_wrapper.js +++ b/libtextsecure/axolotl_wrapper.js @@ -19,17 +19,22 @@ return textsecure.storage.removeEncrypted(key); }, + identityKeys: { + get: function(identifier) { + return textsecure.storage.devices.getIdentityKeyForNumber(textsecure.utils.unencodeNumber(identifier)[0]); + }, + put: function(identifier, identityKey) { + return textsecure.storage.devices.checkSaveIdentityKeyForNumber(textsecure.utils.unencodeNumber(identifier)[0], identityKey); + }, + }, + sessions: { get: function(identifier) { var device = textsecure.storage.devices.getDeviceObject(identifier, true); - if (device === undefined) + if (device === undefined || device.sessions === undefined) return undefined; var record = new axolotl.sessions.RecipientRecord(); - if (device.sessions !== undefined) - record.deserialize(device.sessions); - else - // TODO: (even for numbers, not devices) We MUST return an identityKey if we have one available - record.identityKey = device.identityKey; + record.deserialize(device.sessions); if (getString(device.identityKey) !== getString(record.identityKey)) throw new Error("Got mismatched identity key on sessions load"); return record; diff --git a/libtextsecure/storage/devices.js b/libtextsecure/storage/devices.js index 382332a7..e21d2f36 100644 --- a/libtextsecure/storage/devices.js +++ b/libtextsecure/storage/devices.js @@ -49,6 +49,19 @@ return map === undefined ? [] : map.devices; }, + getIdentityKeyForNumber: function(number) { + var map = textsecure.storage.getEncrypted("devices" + number); + return map === undefined ? undefined : map.identityKey; + }, + + checkSaveIdentityKeyForNumber: function(number, identityKey) { + var map = textsecure.storage.getEncrypted("devices" + number); + if (map === undefined) + textsecure.storage.putEncrypted("devices" + number, { devices: [], identityKey: identityKey}); + else if (getString(map.identityKey) !== getString(identityKey)) + throw new Error("Attempted to overwrite a different identity key"); + }, + getDeviceObject: function(encodedNumber, returnIdentityKey) { var number = textsecure.utils.unencodeNumber(encodedNumber)[0]; var devices = textsecure.storage.devices.getDeviceObjectsForNumber(number);