From 67f25214d310a4e88fbaf4f4057a8a458da822b9 Mon Sep 17 00:00:00 2001 From: lilia Date: Tue, 21 Jul 2015 15:51:32 -0700 Subject: [PATCH] Refactor outgoing identity key conflict handling saveKeysToDeviceObject is the detector of outgoing identity key errors. Catch these key errors closer to the source by pulling the getKeysForNumber into the context of sendMessageToDevices, which lets it access registerError and the message protobuf. Previously identity key errors would be uncaught if all existing sessions with a recipient were closed/deleted, since we would preemptively fetch the new identity key. The old error handling only kicked in after a 409/410 response from the server when posting a message encrypted for a stale session. // FREEBIE --- js/libtextsecure.js | 74 ++++++++++++++++++------------------ libtextsecure/sendmessage.js | 74 ++++++++++++++++++------------------ 2 files changed, 72 insertions(+), 76 deletions(-) diff --git a/js/libtextsecure.js b/js/libtextsecure.js index e5a7a43c4..4e0a853dc 100644 --- a/js/libtextsecure.js +++ b/js/libtextsecure.js @@ -39723,34 +39723,6 @@ window.textsecure.messaging = function() { var self = {}; - //TODO: Dont hit disk for any of the key-fetching! - function getKeysForNumber(number, updateDevices) { - var handleResult = function(response) { - return Promise.all(response.devices.map(function(device) { - if (updateDevices === undefined || updateDevices.indexOf(device.deviceId) > -1) - return textsecure.storage.devices.saveKeysToDeviceObject({ - encodedNumber: number + "." + device.deviceId, - identityKey: response.identityKey, - preKey: device.preKey.publicKey, - preKeyId: device.preKey.keyId, - signedKey: device.signedPreKey.publicKey, - signedKeyId: device.signedPreKey.keyId, - signedKeySignature: device.signedPreKey.signature, - registrationId: device.registrationId - }); - })); - }; - - var promises = []; - if (updateDevices !== undefined) - for (var i in updateDevices) - promises[promises.length] = TextSecureServer.getKeysForNumber(number, updateDevices[i]).then(handleResult); - else - return TextSecureServer.getKeysForNumber(number).then(handleResult); - - return Promise.all(promises); - } - // success_callback(server success/failure map), error_callback(error_msg) // message == PushMessageContentProto (NOT STRING) function sendMessageToDevices(timestamp, number, deviceObjectList, message, success_callback, error_callback) { @@ -39882,6 +39854,40 @@ window.textsecure.messaging = function() { } }; + function getKeysForNumber(number, updateDevices) { + var handleResult = function(response) { + return Promise.all(response.devices.map(function(device) { + if (updateDevices === undefined || updateDevices.indexOf(device.deviceId) > -1) + return textsecure.storage.devices.saveKeysToDeviceObject({ + encodedNumber: number + "." + device.deviceId, + identityKey: response.identityKey, + preKey: device.preKey.publicKey, + preKeyId: device.preKey.keyId, + signedKey: device.signedPreKey.publicKey, + signedKeyId: device.signedPreKey.keyId, + signedKeySignature: device.signedPreKey.signature, + registrationId: device.registrationId + }).catch(function(error) { + if (error.message === "Identity key changed") { + error = new textsecure.OutgoingIdentityKeyError(number, message.toArrayBuffer(), timestamp, error.identityKey); + registerError(number, "Identity key changed", error); + } + throw error; + }); + })); + }; + + if (updateDevices === undefined) { + return TextSecureServer.getKeysForNumber(number).then(handleResult); + } else { + var promises = []; + for (var i in updateDevices) + promises[promises.length] = TextSecureServer.getKeysForNumber(number, updateDevices[i]).then(handleResult); + + return Promise.all(promises); + } + } + var doSendMessage = function(number, devicesForNumber, recurse) { var groupUpdate = Promise.resolve(true); if (message.group && message.group.id && message.group.type != textsecure.protobuf.GroupContext.Type.QUIT) @@ -39910,19 +39916,11 @@ window.textsecure.messaging = function() { getKeysForNumber(number, resetDevices) .then(reloadDevicesAndSend(number, false)) .catch(function(error) { - if (error.message !== "Identity key changed at session save time") - registerError(number, "Failed to reload device keys", error); - else { - error = new textsecure.OutgoingIdentityKeyError(number, message.toArrayBuffer(), timestamp, e.identityKey); - registerError(number, "Identity key changed", error); - } + registerError(number, "Failed to reload device keys", error); }); }); - } else if (error.message !== "Identity key changed at session save time") { - registerError(number, "Failed to create or send message", error); } else { - error = new textsecure.OutgoingIdentityKeyError(number, message.toArrayBuffer(), timestamp, e.identityKey); - registerError(number, "Identity key changed", error); + registerError(number, "Failed to create or send message", error); } }); }; diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index d81243909..14db4ce41 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -19,34 +19,6 @@ window.textsecure.messaging = function() { var self = {}; - //TODO: Dont hit disk for any of the key-fetching! - function getKeysForNumber(number, updateDevices) { - var handleResult = function(response) { - return Promise.all(response.devices.map(function(device) { - if (updateDevices === undefined || updateDevices.indexOf(device.deviceId) > -1) - return textsecure.storage.devices.saveKeysToDeviceObject({ - encodedNumber: number + "." + device.deviceId, - identityKey: response.identityKey, - preKey: device.preKey.publicKey, - preKeyId: device.preKey.keyId, - signedKey: device.signedPreKey.publicKey, - signedKeyId: device.signedPreKey.keyId, - signedKeySignature: device.signedPreKey.signature, - registrationId: device.registrationId - }); - })); - }; - - var promises = []; - if (updateDevices !== undefined) - for (var i in updateDevices) - promises[promises.length] = TextSecureServer.getKeysForNumber(number, updateDevices[i]).then(handleResult); - else - return TextSecureServer.getKeysForNumber(number).then(handleResult); - - return Promise.all(promises); - } - // success_callback(server success/failure map), error_callback(error_msg) // message == PushMessageContentProto (NOT STRING) function sendMessageToDevices(timestamp, number, deviceObjectList, message, success_callback, error_callback) { @@ -178,6 +150,40 @@ window.textsecure.messaging = function() { } }; + function getKeysForNumber(number, updateDevices) { + var handleResult = function(response) { + return Promise.all(response.devices.map(function(device) { + if (updateDevices === undefined || updateDevices.indexOf(device.deviceId) > -1) + return textsecure.storage.devices.saveKeysToDeviceObject({ + encodedNumber: number + "." + device.deviceId, + identityKey: response.identityKey, + preKey: device.preKey.publicKey, + preKeyId: device.preKey.keyId, + signedKey: device.signedPreKey.publicKey, + signedKeyId: device.signedPreKey.keyId, + signedKeySignature: device.signedPreKey.signature, + registrationId: device.registrationId + }).catch(function(error) { + if (error.message === "Identity key changed") { + error = new textsecure.OutgoingIdentityKeyError(number, message.toArrayBuffer(), timestamp, error.identityKey); + registerError(number, "Identity key changed", error); + } + throw error; + }); + })); + }; + + if (updateDevices === undefined) { + return TextSecureServer.getKeysForNumber(number).then(handleResult); + } else { + var promises = []; + for (var i in updateDevices) + promises[promises.length] = TextSecureServer.getKeysForNumber(number, updateDevices[i]).then(handleResult); + + return Promise.all(promises); + } + } + var doSendMessage = function(number, devicesForNumber, recurse) { var groupUpdate = Promise.resolve(true); if (message.group && message.group.id && message.group.type != textsecure.protobuf.GroupContext.Type.QUIT) @@ -206,19 +212,11 @@ window.textsecure.messaging = function() { getKeysForNumber(number, resetDevices) .then(reloadDevicesAndSend(number, false)) .catch(function(error) { - if (error.message !== "Identity key changed at session save time") - registerError(number, "Failed to reload device keys", error); - else { - error = new textsecure.OutgoingIdentityKeyError(number, message.toArrayBuffer(), timestamp, e.identityKey); - registerError(number, "Identity key changed", error); - } + registerError(number, "Failed to reload device keys", error); }); }); - } else if (error.message !== "Identity key changed at session save time") { - registerError(number, "Failed to create or send message", error); } else { - error = new textsecure.OutgoingIdentityKeyError(number, message.toArrayBuffer(), timestamp, e.identityKey); - registerError(number, "Identity key changed", error); + registerError(number, "Failed to create or send message", error); } }); };