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);