From ddba403ef56a1b867aed2aa857111b1ebd4e3cf1 Mon Sep 17 00:00:00 2001 From: lilia Date: Mon, 19 Sep 2016 16:43:59 -0700 Subject: [PATCH] Move registrationId from session record to session state This was mostly used internally by SessionRecord to flag the lack of an open session, but that can be replaced with an actual check for an open session. --- dist/libsignal-protocol.js | 51 +++++++++++++------------------------- src/SessionBuilder.js | 9 ++++--- src/SessionCipher.js | 10 +++++--- src/SessionRecord.js | 32 ++++-------------------- test/SessionCipherTest.js | 45 ++++++++++++++++++++++++++++----- 5 files changed, 73 insertions(+), 74 deletions(-) diff --git a/dist/libsignal-protocol.js b/dist/libsignal-protocol.js index 5d0f1b6..a430245 100644 --- a/dist/libsignal-protocol.js +++ b/dist/libsignal-protocol.js @@ -35554,37 +35554,28 @@ Internal.SessionRecord = function() { return JSON.stringify(ensureStringed(thing)); //TODO: jquery??? } - var SessionRecord = function(registrationId) { + var SessionRecord = function() { this._sessions = {}; - this.registrationId = registrationId; - - if (this.registrationId === undefined || typeof this.registrationId !== 'number') { - this.registrationId = null; - } }; SessionRecord.deserialize = function(serialized) { var data = JSON.parse(serialized); - var record = new SessionRecord(data.registrationId); + var record = new SessionRecord(); record._sessions = data.sessions; if (record._sessions === undefined || record._sessions === null || typeof record._sessions !== "object" || Array.isArray(record._sessions)) { throw new Error("Error deserializing SessionRecord"); } - if (record.registrationId === undefined) { - throw new Error("Error deserializing SessionRecord"); - } return record; }; SessionRecord.prototype = { serialize: function() { return jsonThing({ - sessions : this._sessions, - registrationId : this.registrationId + sessions : this._sessions }); }, haveOpenSession: function() { - return this.registrationId !== null; + return this.getOpenSession() !== undefined; }, getSessionByBaseKey: function(baseKey) { @@ -35643,7 +35634,7 @@ Internal.SessionRecord = function() { } } }, - updateSessionState: function(session, registrationId) { + updateSessionState: function(session) { var sessions = this._sessions; this.removeOldChains(session); @@ -35652,19 +35643,6 @@ Internal.SessionRecord = function() { this.removeOldSessions(); - var openSessionRemaining = false; - for (var key in sessions) { - if (sessions[key].indexInfo.closed == -1) { - openSessionRemaining = true; - } - } - if (!openSessionRemaining) { // Used as a flag to get new pre keys for the next session - this.registrationId = null; - } else if (this.registrationId === null && registrationId !== undefined) { - this.registrationId = registrationId; - } else if (this.registrationId === null) { - throw new Error("Had open sessions on a record that had no registrationId set"); - } }, getSessions: function() { // return an array of sessions ordered by time closed, @@ -35818,7 +35796,7 @@ SessionBuilder.prototype = { }).then(function(baseKey) { var devicePreKey = (device.preKey.publicKey); return this.initSession(true, baseKey, undefined, device.identityKey, - devicePreKey, device.signedPreKey.publicKey + devicePreKey, device.signedPreKey.publicKey, device.registrationId ).then(function(session) { session.pendingPreKey = { preKeyId : device.preKey.keyId, @@ -35834,7 +35812,7 @@ SessionBuilder.prototype = { if (serialized !== undefined) { record = Internal.SessionRecord.deserialize(serialized); } else { - record = new Internal.SessionRecord(device.registrationId); + record = new Internal.SessionRecord(); } record.archiveCurrentState(); @@ -35892,7 +35870,7 @@ SessionBuilder.prototype = { } return this.initSession(false, preKeyPair, signedPreKeyPair, message.identityKey.toArrayBuffer(), - message.baseKey.toArrayBuffer(), undefined + message.baseKey.toArrayBuffer(), undefined, message.registrationId ).then(function(new_session) { // Note that the session is not actually saved until the very // end of decryptWhisperMessage ... to ensure that the sender @@ -35906,7 +35884,7 @@ SessionBuilder.prototype = { }, initSession: function(isInitiator, ourEphemeralKey, ourSignedKey, theirIdentityPubKey, theirEphemeralPubKey, - theirSignedPubKey) { + theirSignedPubKey, registrationId) { return this.storage.getIdentityKeyPair().then(function(ourIdentityKey) { if (isInitiator) { if (ourSignedKey !== undefined) { @@ -35956,6 +35934,7 @@ SessionBuilder.prototype = { return Internal.HKDF(sharedSecret.buffer, new ArrayBuffer(32), "WhisperText"); }).then(function(masterKey) { var session = { + registrationId: registrationId, currentRatchet: { rootKey : masterKey[0], lastRemoteEphemeralKey : theirSignedPubKey, @@ -36114,14 +36093,14 @@ SessionCipher.prototype = { return { type : 3, body : result, - registrationId : record.registrationId + registrationId : session.registrationId }; } else { return { type : 1, body : util.toString(message), - registrationId : record.registrationId + registrationId : session.registrationId }; } }); @@ -36346,7 +36325,11 @@ SessionCipher.prototype = { if (record === undefined) { return undefined; } - return record.registrationId; + var openSession = record.getOpenSession(); + if (openSession === undefined) { + return null; + } + return openSession.registrationId; }); }.bind(this)); }, diff --git a/src/SessionBuilder.js b/src/SessionBuilder.js index bfe1971..6b8ea5e 100644 --- a/src/SessionBuilder.js +++ b/src/SessionBuilder.js @@ -23,7 +23,7 @@ SessionBuilder.prototype = { }).then(function(baseKey) { var devicePreKey = (device.preKey.publicKey); return this.initSession(true, baseKey, undefined, device.identityKey, - devicePreKey, device.signedPreKey.publicKey + devicePreKey, device.signedPreKey.publicKey, device.registrationId ).then(function(session) { session.pendingPreKey = { preKeyId : device.preKey.keyId, @@ -39,7 +39,7 @@ SessionBuilder.prototype = { if (serialized !== undefined) { record = Internal.SessionRecord.deserialize(serialized); } else { - record = new Internal.SessionRecord(device.registrationId); + record = new Internal.SessionRecord(); } record.archiveCurrentState(); @@ -97,7 +97,7 @@ SessionBuilder.prototype = { } return this.initSession(false, preKeyPair, signedPreKeyPair, message.identityKey.toArrayBuffer(), - message.baseKey.toArrayBuffer(), undefined + message.baseKey.toArrayBuffer(), undefined, message.registrationId ).then(function(new_session) { // Note that the session is not actually saved until the very // end of decryptWhisperMessage ... to ensure that the sender @@ -111,7 +111,7 @@ SessionBuilder.prototype = { }, initSession: function(isInitiator, ourEphemeralKey, ourSignedKey, theirIdentityPubKey, theirEphemeralPubKey, - theirSignedPubKey) { + theirSignedPubKey, registrationId) { return this.storage.getIdentityKeyPair().then(function(ourIdentityKey) { if (isInitiator) { if (ourSignedKey !== undefined) { @@ -161,6 +161,7 @@ SessionBuilder.prototype = { return Internal.HKDF(sharedSecret.buffer, new ArrayBuffer(32), "WhisperText"); }).then(function(masterKey) { var session = { + registrationId: registrationId, currentRatchet: { rootKey : masterKey[0], lastRemoteEphemeralKey : theirSignedPubKey, diff --git a/src/SessionCipher.js b/src/SessionCipher.js index 076e85c..b32aaa4 100644 --- a/src/SessionCipher.js +++ b/src/SessionCipher.js @@ -97,14 +97,14 @@ SessionCipher.prototype = { return { type : 3, body : result, - registrationId : record.registrationId + registrationId : session.registrationId }; } else { return { type : 1, body : util.toString(message), - registrationId : record.registrationId + registrationId : session.registrationId }; } }); @@ -329,7 +329,11 @@ SessionCipher.prototype = { if (record === undefined) { return undefined; } - return record.registrationId; + var openSession = record.getOpenSession(); + if (openSession === undefined) { + return null; + } + return openSession.registrationId; }); }.bind(this)); }, diff --git a/src/SessionRecord.js b/src/SessionRecord.js index 0a6a2e9..d76fdbc 100644 --- a/src/SessionRecord.js +++ b/src/SessionRecord.js @@ -55,37 +55,28 @@ Internal.SessionRecord = function() { return JSON.stringify(ensureStringed(thing)); //TODO: jquery??? } - var SessionRecord = function(registrationId) { + var SessionRecord = function() { this._sessions = {}; - this.registrationId = registrationId; - - if (this.registrationId === undefined || typeof this.registrationId !== 'number') { - this.registrationId = null; - } }; SessionRecord.deserialize = function(serialized) { var data = JSON.parse(serialized); - var record = new SessionRecord(data.registrationId); + var record = new SessionRecord(); record._sessions = data.sessions; if (record._sessions === undefined || record._sessions === null || typeof record._sessions !== "object" || Array.isArray(record._sessions)) { throw new Error("Error deserializing SessionRecord"); } - if (record.registrationId === undefined) { - throw new Error("Error deserializing SessionRecord"); - } return record; }; SessionRecord.prototype = { serialize: function() { return jsonThing({ - sessions : this._sessions, - registrationId : this.registrationId + sessions : this._sessions }); }, haveOpenSession: function() { - return this.registrationId !== null; + return this.getOpenSession() !== undefined; }, getSessionByBaseKey: function(baseKey) { @@ -144,7 +135,7 @@ Internal.SessionRecord = function() { } } }, - updateSessionState: function(session, registrationId) { + updateSessionState: function(session) { var sessions = this._sessions; this.removeOldChains(session); @@ -153,19 +144,6 @@ Internal.SessionRecord = function() { this.removeOldSessions(); - var openSessionRemaining = false; - for (var key in sessions) { - if (sessions[key].indexInfo.closed == -1) { - openSessionRemaining = true; - } - } - if (!openSessionRemaining) { // Used as a flag to get new pre keys for the next session - this.registrationId = null; - } else if (this.registrationId === null && registrationId !== undefined) { - this.registrationId = registrationId; - } else if (this.registrationId === null) { - throw new Error("Had open sessions on a record that had no registrationId set"); - } }, getSessions: function() { // return an array of sessions ordered by time closed, diff --git a/test/SessionCipherTest.js b/test/SessionCipherTest.js index 88bd8fc..0c04ed9 100644 --- a/test/SessionCipherTest.js +++ b/test/SessionCipherTest.js @@ -4,14 +4,31 @@ 'use strict'; describe('SessionCipher', function() { + describe('getRemoteRegistrationId', function() { var store = new SignalProtocolStore(); var registrationId = 1337; var address = new libsignal.SignalProtocolAddress('foo', 1); var sessionCipher = new libsignal.SessionCipher(store, address.toString()); - describe('when a record exists', function() { + describe('when an open record exists', function() { before(function(done) { var record = new Internal.SessionRecord(registrationId); + var session = { + registrationId: registrationId, + currentRatchet: { + rootKey : new ArrayBuffer(32), + lastRemoteEphemeralKey : new ArrayBuffer(32), + previousCounter : 0 + }, + indexInfo: { + baseKey : new ArrayBuffer(32), + baseKeyType : Internal.BaseKeyType.OURS, + remoteIdentityKey : new ArrayBuffer(32), + closed : -1 + }, + oldRatchetList: [] + }; + record.updateSessionState(session); store.storeSession(address.toString(), record.serialize()).then(done); }); it('returns a valid registrationId', function(done) { @@ -34,23 +51,39 @@ describe('SessionCipher', function() { var store = new SignalProtocolStore(); var address = new libsignal.SignalProtocolAddress('foo', 1); var sessionCipher = new libsignal.SessionCipher(store, address.toString()); - describe('registrationId is valid', function() { + describe('open session exists', function() { before(function(done) { - var record = new Internal.SessionRecord( 1); + var record = new Internal.SessionRecord(); + var session = { + registrationId: 1337, + currentRatchet: { + rootKey : new ArrayBuffer(32), + lastRemoteEphemeralKey : new ArrayBuffer(32), + previousCounter : 0 + }, + indexInfo: { + baseKey : new ArrayBuffer(32), + baseKeyType : Internal.BaseKeyType.OURS, + remoteIdentityKey : new ArrayBuffer(32), + closed : -1 + }, + oldRatchetList: [] + }; + record.updateSessionState(session); store.storeSession(address.toString(), record.serialize()).then(done); }); - it('returns true for a session with a valid registrationId', function(done) { + it('returns true', function(done) { sessionCipher.hasOpenSession(address.toString()).then(function(value) { assert.isTrue(value); }).then(done,done); }); }); - describe('registrationId is null', function() { + describe('no open session exists', function() { before(function(done) { var record = new Internal.SessionRecord(); store.storeSession(address.toString(), record.serialize()).then(done); }); - it('returns false for a session with a null registrationId', function(done) { + it('returns false', function(done) { sessionCipher.hasOpenSession(address.toString()).then(function(value) { assert.isFalse(value); }).then(done,done);