diff --git a/js/axolotl_store.js b/js/axolotl_store.js index ad2f05a6..f8fdf270 100644 --- a/js/axolotl_store.js +++ b/js/axolotl_store.js @@ -214,6 +214,19 @@ }); }); }, + getDeviceIds: function(number) { + if (number === null || number === undefined) + throw new Error("Tried to put session for undefined/null key"); + return new Promise(function(resolve) { + var contact = new Contact({id: number}); + contact.fetch().always(function() { + var sessions = contact.get('sessions') || {}; + resolve(_.keys(sessions).map(function(n) { + return parseInt(n); + })); + }); + }); + }, removeAllSessions: function(number) { if (number === null || number === undefined) throw new Error("Tried to put session for undefined/null key"); diff --git a/libtextsecure/test/in_memory_axolotl_store.js b/libtextsecure/test/in_memory_axolotl_store.js index 37ed6f21..4e00367b 100644 --- a/libtextsecure/test/in_memory_axolotl_store.js +++ b/libtextsecure/test/in_memory_axolotl_store.js @@ -89,5 +89,26 @@ AxolotlStore.prototype = { return new Promise(function(resolve) { resolve(this.put('session' + identifier, record)); }.bind(this)); - } + }, + removeAllSessions: function(identifier) { + return new Promise(function(resolve) { + for (key in this.store) { + if (key.match(RegExp('^session' + identifier.replace('\+','\\\+') + '.+'))) { + delete this.store[key]; + } + } + resolve(); + }.bind(this)); + }, + getDeviceIds: function(identifier) { + return new Promise(function(resolve) { + var deviceIds = []; + for (key in this.store) { + if (key.match(RegExp('^session' + identifier.replace('\+','\\\+') + '.+'))) { + deviceIds.push(parseInt(key.split('.')[1])); + } + } + resolve(deviceIds); + }.bind(this)); + } }; diff --git a/libtextsecure/test/storage_test.js b/libtextsecure/test/storage_test.js index 5933e91a..bc4609c7 100644 --- a/libtextsecure/test/storage_test.js +++ b/libtextsecure/test/storage_test.js @@ -95,7 +95,7 @@ describe("AxolotlStore", function() { }); }); promise.then(function() { - return Promise.all(devices.map(store.getSession)).then(function(records) { + return Promise.all(devices.map(store.getSession.bind(store))).then(function(records) { for (var i in records) { assert.strictEqual(records[i], testRecord + devices[i]); }; @@ -115,7 +115,7 @@ describe("AxolotlStore", function() { }); promise.then(function() { return store.removeAllSessions(identifier).then(function(record) { - return Promise.all(devices.map(store.getSession)).then(function(records) { + return Promise.all(devices.map(store.getSession.bind(store))).then(function(records) { for (var i in records) { assert.isUndefined(records[i]); }; @@ -123,4 +123,26 @@ describe("AxolotlStore", function() { }); }).then(done,done); }); + it('returns deviceIds for a number', function(done) { + var testRecord = "an opaque string"; + var devices = [1, 2, 3].map(function(deviceId) { + return [identifier, deviceId].join('.'); + }); + var promise = Promise.resolve(); + devices.forEach(function(encodedNumber) { + promise = promise.then(function() { + return store.putSession(encodedNumber, testRecord + encodedNumber) + }); + }); + promise.then(function() { + return store.getDeviceIds(identifier).then(function(deviceIds) { + assert.sameMembers(deviceIds, [1, 2, 3]); + }); + }).then(done,done); + }); + it('returns empty array for a number with no device ids', function(done) { + return store.getDeviceIds('foo').then(function(deviceIds) { + assert.sameMembers(deviceIds,[]); + }).then(done,done); + }); }); diff --git a/test/storage_test.js b/test/storage_test.js index 6b199cb3..739e3fd6 100644 --- a/test/storage_test.js +++ b/test/storage_test.js @@ -90,4 +90,47 @@ describe("AxolotlStore", function() { }); }).then(done,done); }); + it('removes all sessions for a number', function(done) { + var testRecord = "an opaque string"; + var devices = [1, 2, 3].map(function(deviceId) { + return [identifier, deviceId].join('.'); + }); + var promise = Promise.resolve(); + devices.forEach(function(encodedNumber) { + promise = promise.then(function() { + return store.putSession(encodedNumber, testRecord + encodedNumber) + }); + }); + promise.then(function() { + return store.removeAllSessions(identifier).then(function(record) { + return Promise.all(devices.map(store.getSession.bind(store))).then(function(records) { + for (var i in records) { + assert.isUndefined(records[i]); + }; + }); + }); + }).then(done,done); + }); + it('returns deviceIds for a number', function(done) { + var testRecord = "an opaque string"; + var devices = [1, 2, 3].map(function(deviceId) { + return [identifier, deviceId].join('.'); + }); + var promise = Promise.resolve(); + devices.forEach(function(encodedNumber) { + promise = promise.then(function() { + return store.putSession(encodedNumber, testRecord + encodedNumber) + }); + }); + promise.then(function() { + return store.getDeviceIds(identifier).then(function(deviceIds) { + assert.sameMembers(deviceIds, [1, 2, 3]); + }); + }).then(done,done); + }); + it('returns empty array for a number with no device ids', function(done) { + return store.getDeviceIds('foo').then(function(deviceIds) { + assert.sameMembers(deviceIds,[]); + }).then(done,done); + }); });