From 4a401f07f3f24331b69c5a235307bfceedbfb6e0 Mon Sep 17 00:00:00 2001 From: lilia Date: Thu, 18 Dec 2014 17:50:04 -0800 Subject: [PATCH] Rewrite ReplayableErrors ReplayableErrors make it easy for the frontend to handle identity key errors by wrapping the necessary steps into one convenient little replay() callback function. The frontend remains agnostic to what those steps are. It just calls replay() once the user has acknowledged the key change. The protocol layer is responsible for registering the callbacks needed by the IncomingIdentityKeyError and OutgoingIdentityKeyError. --- background.html | 1 + index.html | 1 + js/errors.js | 76 +++++++++++++++++++++++++++++++++++++++++++++++ js/helpers.js | 35 ---------------------- js/protocol.js | 4 +-- js/sendmessage.js | 9 +++--- options.html | 1 + test/index.html | 1 + 8 files changed, 86 insertions(+), 42 deletions(-) create mode 100644 js/errors.js diff --git a/background.html b/background.html index 92379761f..84bfedd20 100644 --- a/background.html +++ b/background.html @@ -24,6 +24,7 @@ + diff --git a/index.html b/index.html index 265ef1c11..46201c21b 100644 --- a/index.html +++ b/index.html @@ -135,6 +135,7 @@ + diff --git a/js/errors.js b/js/errors.js new file mode 100644 index 000000000..9cd5149be --- /dev/null +++ b/js/errors.js @@ -0,0 +1,76 @@ +/* vim: ts=4:sw=4:expandtab + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +;(function() { + 'use strict'; + + var registeredFunctions = {}; + var Type = { + SEND_MESSAGE: 1, + INIT_SESSION: 2, + }; + window.textsecure = window.textsecure || {}; + window.textsecure.replay = { + Type: Type, + registerFunction: function(func, functionCode) { + registeredFunctions[functionCode] = func; + } + }; + + function ReplayableError(options) { + options = options || {}; + this.name = options.name || 'ReplayableError'; + this.functionCode = options.functionCode; + this.args = options.args; + } + ReplayableError.prototype = new Error(); + ReplayableError.prototype.constructor = ReplayableError; + + ReplayableError.prototype.replay = function() { + var args = Array.prototype.slice.call(arguments); + args.shift(); + args = this.args.concat(args); + + registeredFunctions[this.functionCode].apply(window, args); + }; + + function IncomingIdentityKeyError(number, message) { + ReplayableError.call(this, { + functionCode : Type.INIT_SESSION, + args : [number, message] + }); + this.name = 'IncomingIdentityKeyError'; + this.message = "The identity of the sender has changed. This may be malicious, or the sender may have simply reinstalled TextSecure."; + } + IncomingIdentityKeyError.prototype = new ReplayableError(); + IncomingIdentityKeyError.prototype.constructor = IncomingIdentityKeyError; + + function OutgoingIdentityKeyError(number, message) { + ReplayableError.call(this, { + functionCode : Type.SEND_MESSAGE, + args : [number, message] + }); + this.name = 'OutgoingIdentityKeyError'; + this.message = "The identity of the destination has changed. This may be malicious, or the destination may have simply reinstalled TextSecure."; + } + OutgoingIdentityKeyError.prototype = new ReplayableError(); + OutgoingIdentityKeyError.prototype.constructor = OutgoingIdentityKeyError; + + window.textsecure.IncomingIdentityKeyError = IncomingIdentityKeyError; + window.textsecure.OutgoingIdentityKeyError = OutgoingIdentityKeyError; + window.textsecure.ReplayableError = ReplayableError; + +})(); diff --git a/js/helpers.js b/js/helpers.js index ca68abe69..dc1c6a39c 100644 --- a/js/helpers.js +++ b/js/helpers.js @@ -126,41 +126,6 @@ window.textsecure.throwHumanError = function(error, type, humanError) { throw e; } -window.textsecure.replay = function() { - var self = {}; - - self.REPLAY_FUNCS = { - SEND_MESSAGE: 1, - INIT_SESSION: 2, - } - - var functions = {}; - - self.registerReplayFunction = function(func, functionCode) { - functions[functionCode] = func; - } - - self.replayError = function(replayData) { - var args = Array.prototype.slice.call(arguments); - args.shift(); - args = replayData.args.concat(args); - functions[replayData.replayFunction].apply(window, args); - } - - self.createReplayableError = function(shortMsg, longMsg, replayFunction, args) { - var e = new Error(shortMsg); - e.name = "ReplayableError"; - e.humanError = e.longMessage = longMsg; - e.replayData = { replayFunction: replayFunction, args: args }; - e.replay = function() { - self.replayError(e.replayData); - } - return e; - } - - return self; -}(); - // message_callback({message: decryptedMessage, pushMessage: server-providedPushMessage}) window.textsecure.subscribeToPush = function(message_callback) { var socket = textsecure.api.getMessageWebsocket(); diff --git a/js/protocol.js b/js/protocol.js index 53bae4479..8d5d9813f 100644 --- a/js/protocol.js +++ b/js/protocol.js @@ -366,7 +366,7 @@ window.textsecure.protocol = function() { //TODO: Wipe identity key! return handlePreKeyWhisperMessage(from, encodedMessage); } - textsecure.replay.registerReplayFunction(wipeIdentityAndTryMessageAgain, textsecure.replay.REPLAY_FUNCS.INIT_SESSION); + textsecure.replay.registerFunction(wipeIdentityAndTryMessageAgain, textsecure.replay.Type.INIT_SESSION); initSessionFromPreKeyWhisperMessage = function(encodedNumber, message) { var preKeyPair = crypto_storage.getStoredKeyPair("preKey" + message.preKeyId); @@ -394,7 +394,7 @@ window.textsecure.protocol = function() { closeSession(open_session); // To be returned and saved later } else { // ...otherwise create an error that the UI will pick up and ask the user if they want to re-negotiate - throw new Error("Received message with unknown identity key", "The identity of the sender has changed. This may be malicious, or the sender may have simply reinstalled TextSecure.", textsecure.replay.REPLAY_FUNCS.INIT_SESSION, [encodedNumber, getString(message.encode())]); + throw new textsecure.IncomingIdentityKeyError(encodedNumber, getString(message.encode())); } } return initSession(false, preKeyPair, signedPreKeyPair, encodedNumber, toArrayBuffer(message.identityKey), toArrayBuffer(message.baseKey), undefined) diff --git a/js/sendmessage.js b/js/sendmessage.js index abb7db0a3..9db62f6d2 100644 --- a/js/sendmessage.js +++ b/js/sendmessage.js @@ -117,11 +117,11 @@ window.textsecure.messaging = function() { var tryMessageAgain = function(number, encodedMessage, callback) { //TODO: Wipe identity key! refreshGroups(number).then(function() { - var message = textsecure.protobuf.PushMessageContent.decode(encodedMessage, 'binary'); - textsecure.sendMessage([number], message, callback); + var message = textsecure.protobuf.PushMessageContent.decode(encodedMessage); + textsecure.sendMessageProto([number], message, callback); }); }; - textsecure.replay.registerReplayFunction(tryMessageAgain, textsecure.replay.SEND_MESSAGE); + textsecure.replay.registerFunction(tryMessageAgain, textsecure.replay.Type.SEND_MESSAGE); var sendMessageProto = function(numbers, message, callback) { var numbersCompleted = 0; @@ -175,8 +175,7 @@ window.textsecure.messaging = function() { if (error.message !== "Identity key changed") registerError(number, "Failed to reload device keys", error); else { - error = textsecure.replay.createReplayableError("The destination's identity key has changed", "The identity of the destination has changed. This may be malicious, or the destination may have simply reinstalled TextSecure.", - textsecure.replay.SEND_MESSAGE, [number, getString(message.encode())]); + error = new textsecure.OutgoingIdentityKeyError(encodedNumber, message.encode()); registerError(number, "Identity key changed", error); } }); diff --git a/options.html b/options.html index fb53fb46d..a31e7c025 100644 --- a/options.html +++ b/options.html @@ -103,6 +103,7 @@ + diff --git a/test/index.html b/test/index.html index d30d2faad..630e012a8 100644 --- a/test/index.html +++ b/test/index.html @@ -129,6 +129,7 @@ +