From a9617068a2e1a73789cdfef9c6b03f0601aff458 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 15 Jan 2015 14:30:55 -1000 Subject: [PATCH] Move key updating and retry handling to libtextsecure --- Gruntfile.js | 3 ++- libaxolotl/protocol.js | 36 ++++++++++++------------- libtextsecure/axolotl_wrapper.js | 46 ++++++++++++++++++++++++-------- 3 files changed, 54 insertions(+), 31 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 434e2043b..1a4637429 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -85,8 +85,10 @@ module.exports = function(grunt) { ], dest: 'libtextsecure/libaxolotl_concat.js', }, + //TODO: Move errors back down? libtextsecure: { src: [ + 'libtextsecure/errors.js', 'libtextsecure/axolotl_wrapper.js', 'libtextsecure/libaxolotl_concat.js', @@ -96,7 +98,6 @@ module.exports = function(grunt) { 'libtextsecure/websocket.js', 'libtextsecure/websocket-resources.js', 'libtextsecure/helpers.js', - 'libtextsecure/errors.js', 'libtextsecure/stringview.js', 'libtextsecure/api.js', 'libtextsecure/sendmessage.js', diff --git a/libaxolotl/protocol.js b/libaxolotl/protocol.js index f6eacc0d7..a0fe7fe96 100644 --- a/libaxolotl/protocol.js +++ b/libaxolotl/protocol.js @@ -349,25 +349,13 @@ window.textsecure.protocol = function() { crypto_storage.saveSession(encodedNumber, session); } - //TODO: Rewrite this! - /*var wipeIdentityAndTryMessageAgain = function(from, encodedMessage, message_id) { - // Wipe identity key! - textsecure.storage.removeEncrypted("devices" + from.split('.')[0]); - return handlePreKeyWhisperMessage(from, encodedMessage).then( - function(pushMessageContent) { - extension.trigger('message:decrypted', { - message_id : message_id, - data : pushMessageContent - }); - } - ); - } - textsecure.replay.registerFunction(wipeIdentityAndTryMessageAgain, textsecure.replay.Type.INIT_SESSION);*/ - + var refreshPreKeys; var initSessionFromPreKeyWhisperMessage = function(encodedNumber, message) { var preKeyPair = crypto_storage.getStoredKeyPair("preKey" + message.preKeyId); var signedPreKeyPair = crypto_storage.getStoredKeyPair("signedKey" + message.signedPreKeyId); + //TODO: Call refreshPreKeys when it looks like all our prekeys are used up? + var session = crypto_storage.getSessionOrIdentityKeyByBaseKey(encodedNumber, toArrayBuffer(message.baseKey)); var open_session = crypto_storage.getOpenSession(encodedNumber); if (signedPreKeyPair === undefined) { @@ -715,6 +703,7 @@ window.textsecure.protocol = function() { crypto_storage.removeStoredKeyPair("signedKey" + (signedKeyId - 2)); return Promise.all(promises).then(function() { + axolotl.api.storage.put("lastPreKeyUpdate", Date.now()); return keys; }); } @@ -724,12 +713,21 @@ window.textsecure.protocol = function() { return identityKeyCalculated(identityKeyPair); } - //TODO: Dont always update prekeys here - //XXX: This is busted as fuck - if (axolotl.api.storage.get("lastSignedKeyUpdate", Date.now()) < Date.now() - MESSAGE_LOST_THRESHOLD_MS) { - new Promise(function(resolve) { resolve(self.generateKeys()); }); + refreshPreKeys = function() { + self.generateKeys().then(function(keys) { + console.log("Pre Keys updated!"); + return axolotl.api.updateKeys(keys); + }).catch(function(e) { + //TODO: Notify the user somehow??? + console.error(e); + }); } + window.setInterval(function() { + // Note that this will not ever run until generateKeys has been called at least once + if (axolotl.api.storage.get("lastPreKeyUpdate", Date.now()) < Date.now() - MESSAGE_LOST_THRESHOLD_MS) + refreshPreKeys(); + }, 60 * 1000); self.prepareTempWebsocket = function() { var socketInfo = {}; diff --git a/libtextsecure/axolotl_wrapper.js b/libtextsecure/axolotl_wrapper.js index 6ad76c3c9..84fa349aa 100644 --- a/libtextsecure/axolotl_wrapper.js +++ b/libtextsecure/axolotl_wrapper.js @@ -22,33 +22,41 @@ return textsecure.storage.removeEncrypted(key); }, }, + updateKeys: function(keys) { + return textsecure.api.registerKeys(keys).catch(function(e) { + //TODO: Notify the user somehow? + console.error(e); + }); + }, }; + var decodeMessageContents = function(res) { + var finalMessage = textsecure.protobuf.PushMessageContent.decode(res[0]); + + //TODO + /*if ((finalMessage.flags & textsecure.protobuf.PushMessageContent.Flags.END_SESSION) + == textsecure.protobuf.PushMessageContent.Flags.END_SESSION) + textsecure.protocol.closeSession(res[1], true);*/ + + return finalMessage; + } + window.textsecure = window.textsecure || {}; window.textsecure.protocol_wrapper = { handleIncomingPushMessageProto: function(proto) { - var decodeContents = function(res) { - var finalMessage = textsecure.protobuf.PushMessageContent.decode(res[0]); - //TODO - /*if ((finalMessage.flags & textsecure.protobuf.PushMessageContent.Flags.END_SESSION) - == textsecure.protobuf.PushMessageContent.Flags.END_SESSION) - textsecure.protocol.closeSession(res[1], true);*/ - - return finalMessage; - } switch(proto.type) { case textsecure.protobuf.IncomingPushMessageSignal.Type.PLAINTEXT: return Promise.resolve(textsecure.protobuf.PushMessageContent.decode(proto.message)); case textsecure.protobuf.IncomingPushMessageSignal.Type.CIPHERTEXT: var from = proto.source + "." + (proto.sourceDevice == null ? 0 : proto.sourceDevice); - return textsecure.protocol.decryptWhisperMessage(from, getString(proto.message)).then(decodeContents); + return textsecure.protocol.decryptWhisperMessage(from, getString(proto.message)).then(decodeMessageContents); case textsecure.protobuf.IncomingPushMessageSignal.Type.PREKEY_BUNDLE: if (proto.message.readUint8() != ((3 << 4) | 3)) throw new Error("Bad version byte"); var from = proto.source + "." + (proto.sourceDevice == null ? 0 : proto.sourceDevice); - return textsecure.protocol.handlePreKeyWhisperMessage(from, getString(proto.message)).then(decodeContents); + return textsecure.protocol.handlePreKeyWhisperMessage(from, getString(proto.message)).then(decodeMessageContents); case textsecure.protobuf.IncomingPushMessageSignal.Type.RECEIPT: return Promise.resolve(null); case textsecure.protobuf.IncomingPushMessageSignal.Type.PREKEY_BUNDLE_DEVICE_CONTROL: @@ -68,4 +76,20 @@ } } }; + + var wipeIdentityAndTryMessageAgain = function(from, encodedMessage, message_id) { + // Wipe identity key! + //TODO: Encapsuate with the rest of textsecure.storage.devices + textsecure.storage.removeEncrypted("devices" + from.split('.')[0]); + //TODO: Probably breaks with a devicecontrol message + return textsecure.protocol.handlePreKeyWhisperMessage(from, encodedMessage).then(decodeMessageContents).then( + function(pushMessageContent) { + extension.trigger('message:decrypted', { + message_id : message_id, + data : pushMessageContent + }); + } + ); + } + textsecure.replay.registerFunction(wipeIdentityAndTryMessageAgain, textsecure.replay.Type.INIT_SESSION); })();