@@ -35679,6 +35679,26 @@ Internal.SessionRecord = function() {
3567935679 throw new Error("Had open sessions on a record that had no registrationId set");
3568035680 }
3568135681 },
35682+ getSessions: function() {
35683+ // return an array of sessions ordered by time closed,
35684+ // followed by the open session
35685+ var list = [];
35686+ var openSession;
35687+ for (var k in this._sessions) {
35688+ if (this._sessions[k].indexInfo.closed === -1) {
35689+ openSession = this._sessions[k];
35690+ } else {
35691+ list.push(this._sessions[k]);
35692+ }
35693+ }
35694+ list = list.sort(function(s1, s2) {
35695+ return s1.indexInfo.closed - s2.indexInfo.closed;
35696+ });
35697+ if (openSession) {
35698+ list.push(openSession);
35699+ }
35700+ return list;
35701+ },
3568235702 archiveCurrentState: function() {
3568335703 var open_session = this.getOpenSession();
3568435704 if (open_session !== undefined) {
@@ -35690,6 +35710,7 @@ Internal.SessionRecord = function() {
3569035710 if (session.indexInfo.closed > -1) {
3569135711 return;
3569235712 }
35713+ console.log('closing session', session.indexInfo.baseKey);
3569335714
3569435715 // After this has run, we can still receive messages on ratchet chains which
3569535716 // were already open (unless we know we dont need them),
@@ -36110,6 +36131,22 @@ SessionCipher.prototype = {
3611036131 });
3611136132 }.bind(this));
3611236133 },
36134+ decryptWithSessionList: function(buffer, sessionList, errors) {
36135+ // Iterate recursively through the list, attempting to decrypt
36136+ // using each one at a time. Stop and return the result if we get
36137+ // a valid result
36138+ if (sessionList.length === 0) {
36139+ return Promise.reject(errors[0]);
36140+ }
36141+
36142+ var session = sessionList.pop();
36143+ return this.doDecryptWhisperMessage(buffer, session).then(function(plaintext) {
36144+ return { plaintext: plaintext, session: session };
36145+ }).catch(function(e) {
36146+ errors.push(e);
36147+ return this.decryptWithSessionList(buffer, sessionList, errors);
36148+ }.bind(this));
36149+ },
3611336150 decryptWhisperMessage: function(buffer, encoding) {
3611436151 buffer = dcodeIO.ByteBuffer.wrap(buffer, encoding).toArrayBuffer();
3611536152 return Internal.SessionLock.queueJobForNumber(this.remoteAddress.toString(), function() {
@@ -36118,15 +36155,14 @@ SessionCipher.prototype = {
3611836155 if (!record) {
3611936156 throw new Error("No record for device " + address);
3612036157 }
36121- var messageProto = buffer.slice(1, buffer.byteLength - 8);
36122- var message = Internal.protobuf.WhisperMessage.decode(messageProto);
36123- var remoteEphemeralKey = message.ephemeralKey.toArrayBuffer();
36124- var session = record.getSessionByRemoteEphemeralKey(remoteEphemeralKey);
36125- return this.doDecryptWhisperMessage(buffer, session).then(function(plaintext) {
36126- record.updateSessionState(session);
36127- return this.storage.storeSession(address, record.serialize()).then(function() {
36128- return plaintext;
36129- });
36158+ var errors = [];
36159+ return this.decryptWithSessionList(buffer, record.getSessions(), errors).then(function(result) {
36160+ return this.getRecord(address).then(function(record) {
36161+ record.updateSessionState(result.session);
36162+ return this.storage.storeSession(address, record.serialize()).then(function() {
36163+ return result.plaintext;
36164+ });
36165+ }.bind(this));
3613036166 }.bind(this));
3613136167 }.bind(this));
3613236168 }.bind(this));
@@ -36184,7 +36220,7 @@ SessionCipher.prototype = {
3618436220 var remoteEphemeralKey = message.ephemeralKey.toArrayBuffer();
3618536221
3618636222 if (session === undefined) {
36187- throw new Error("No session found to decrypt message from " + this.remoteAddress.toString());
36223+ return Promise.reject( new Error("No session found to decrypt message from " + this.remoteAddress.toString() ));
3618836224 }
3618936225 if (session.indexInfo.closed != -1) {
3619036226 console.log('decrypting message for closed session');
0 commit comments