From 9aae93fc9961a783b08fe8c9ba4aa156faa04ff6 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Wed, 21 May 2014 15:04:05 -0400 Subject: [PATCH] textsecure.protos --- js/crypto.js | 12 +++--- js/helpers.js | 94 ++++++++++++++++++++++++------------------- js/models/messages.js | 2 +- js/test.js | 8 ++-- 4 files changed, 63 insertions(+), 53 deletions(-) diff --git a/js/crypto.js b/js/crypto.js index a37513f32180..9a33b5721441 100644 --- a/js/crypto.js +++ b/js/crypto.js @@ -523,7 +523,7 @@ window.textsecure.crypto = new function() { var messageProto = messageBytes.substring(1, messageBytes.length - 8); var mac = messageBytes.substring(messageBytes.length - 8, messageBytes.length); - var message = decodeWhisperMessageProtobuf(messageProto); + var message = textsecure.protos.decodeWhisperMessageProtobuf(messageProto); var remoteEphemeralKey = toArrayBuffer(message.ephemeralKey); if (session === undefined) { @@ -547,7 +547,7 @@ window.textsecure.crypto = new function() { removeOldChains(session); delete session['pendingPreKey']; - var finalMessage = decodePushMessageContentProtobuf(getString(plaintext)); + var finalMessage = textsecure.protos.decodePushMessageContentProtobuf(getString(plaintext)); if ((finalMessage.flags & 1) == 1) // END_SESSION closeSession(session); @@ -601,7 +601,7 @@ window.textsecure.crypto = new function() { self.handleIncomingPushMessageProto = function(proto) { switch(proto.type) { case 0: //TYPE_MESSAGE_PLAINTEXT - return Promise.resolve(decodePushMessageContentProtobuf(getString(proto.message))); + return Promise.resolve(textsecure.protos.decodePushMessageContentProtobuf(getString(proto.message))); case 1: //TYPE_MESSAGE_CIPHERTEXT return decryptWhisperMessage(proto.source, getString(proto.message)).then(function(result) { return {message:result, pushMessage: proto}; @@ -609,7 +609,7 @@ window.textsecure.crypto = new function() { case 3: //TYPE_MESSAGE_PREKEY_BUNDLE if (proto.message.readUint8() != (2 << 4 | 2)) throw new Error("Bad version byte"); - var preKeyProto = decodePreKeyWhisperMessageProtobuf(getString(proto.message)); + var preKeyProto = textsecure.protos.decodePreKeyWhisperMessageProtobuf(getString(proto.message)); return initSessionFromPreKeyWhisperMessage(proto.source, preKeyProto).then(function(sessions) { return decryptWhisperMessage(proto.source, getString(preKeyProto.message), sessions[0]).then(function(result) { if (sessions[1] !== undefined) @@ -625,7 +625,7 @@ window.textsecure.crypto = new function() { var session = crypto_storage.getOpenSession(deviceObject.encodedNumber); var doEncryptPushMessageContent = function() { - var msg = new WhisperMessageProtobuf(); + var msg = new textsecure.protos.WhisperMessageProtobuf(); var plaintext = toArrayBuffer(pushMessageContent.encode()); msg.ephemeralKey = toArrayBuffer(session.currentRatchet.ephemeralKeyPair.pubKey); @@ -655,7 +655,7 @@ window.textsecure.crypto = new function() { }); } - var preKeyMsg = new PreKeyWhisperMessageProtobuf(); + var preKeyMsg = new textsecure.protos.PreKeyWhisperMessageProtobuf(); preKeyMsg.identityKey = toArrayBuffer(crypto_storage.getStoredPubKey("identityKey")); preKeyMsg.preKeyId = deviceObject.preKeyId; preKeyMsg.registrationId = textsecure.storage.getUnencrypted("registrationId"); diff --git a/js/helpers.js b/js/helpers.js index 8a93e9967e12..b4d80a930f2a 100644 --- a/js/helpers.js +++ b/js/helpers.js @@ -152,27 +152,6 @@ function toArrayBuffer(thing) { return res; } -function ensureStringed(thing) { - if (getStringable(thing)) - return getString(thing); - else if (thing instanceof Array) { - var res = []; - for (var i = 0; i < thing.length; i++) - res[i] = ensureStringed(thing[i]); - return res; - } else if (thing === Object(thing)) { - var res = {}; - for (key in thing) - res[key] = ensureStringed(thing[key]); - return res; - } - throw new Error("unsure of how to jsonify object of type " + typeof thing); - -} - -function jsonThing(thing) { - return JSON.stringify(ensureStringed(thing)); -} function base64ToArrayBuffer(string) { return base64DecToArr(string); @@ -180,30 +159,36 @@ function base64ToArrayBuffer(string) { // Protobuf decoding //TODO: throw on missing fields everywhere -var IncomingPushMessageProtobuf = dcodeIO.ProtoBuf.loadProtoFile("protos/IncomingPushMessageSignal.proto").build("textsecure.IncomingPushMessageSignal"); -function decodeIncomingPushMessageProtobuf(string) { - return IncomingPushMessageProtobuf.decode(btoa(string)); -} +window.textsecure.protos = function() { + var self = {}; -var PushMessageContentProtobuf = dcodeIO.ProtoBuf.loadProtoFile("protos/IncomingPushMessageSignal.proto").build("textsecure.PushMessageContent"); -function decodePushMessageContentProtobuf(string) { - return PushMessageContentProtobuf.decode(btoa(string)); -} + self.IncomingPushMessageProtobuf = dcodeIO.ProtoBuf.loadProtoFile("protos/IncomingPushMessageSignal.proto").build("textsecure.IncomingPushMessageSignal"); + self.decodeIncomingPushMessageProtobuf = function(string) { + return IncomingPushMessageProtobuf.decode(btoa(string)); + } -var WhisperMessageProtobuf = dcodeIO.ProtoBuf.loadProtoFile("protos/WhisperTextProtocol.proto").build("textsecure.WhisperMessage"); -function decodeWhisperMessageProtobuf(string) { - return WhisperMessageProtobuf.decode(btoa(string)); -} + self.PushMessageContentProtobuf = dcodeIO.ProtoBuf.loadProtoFile("protos/IncomingPushMessageSignal.proto").build("textsecure.PushMessageContent"); + self.decodePushMessageContentProtobuf = function(string) { + return PushMessageContentProtobuf.decode(btoa(string)); + } -var PreKeyWhisperMessageProtobuf = dcodeIO.ProtoBuf.loadProtoFile("protos/WhisperTextProtocol.proto").build("textsecure.PreKeyWhisperMessage"); -function decodePreKeyWhisperMessageProtobuf(string) { - return PreKeyWhisperMessageProtobuf.decode(btoa(string)); -} + self.WhisperMessageProtobuf = dcodeIO.ProtoBuf.loadProtoFile("protos/WhisperTextProtocol.proto").build("textsecure.WhisperMessage"); + self.decodeWhisperMessageProtobuf = function(string) { + return WhisperMessageProtobuf.decode(btoa(string)); + } -var KeyExchangeMessageProtobuf = dcodeIO.ProtoBuf.loadProtoFile("protos/WhisperTextProtocol.proto").build("textsecure.KeyExchangeMessage"); -function decodeKeyExchangeMessageProtobuf(string) { - return KeyExchangeMessageProtobuf.decode(btoa(string)); -} + self.PreKeyWhisperMessageProtobuf = dcodeIO.ProtoBuf.loadProtoFile("protos/WhisperTextProtocol.proto").build("textsecure.PreKeyWhisperMessage"); + self.decodePreKeyWhisperMessageProtobuf = function(string) { + return PreKeyWhisperMessageProtobuf.decode(btoa(string)); + } + + self.KeyExchangeMessageProtobuf = dcodeIO.ProtoBuf.loadProtoFile("protos/WhisperTextProtocol.proto").build("textsecure.KeyExchangeMessage"); + self.decodeKeyExchangeMessageProtobuf = function(string) { + return KeyExchangeMessageProtobuf.decode(btoa(string)); + } + + return self; +}(); // Number formatting function getNumberFromString(string) { @@ -232,6 +217,31 @@ function verifyNumber(string) { window.textsecure.storage = function() { var self = {}; + /**************************** + *** Conversion Utilities *** + ****************************/ + function ensureStringed(thing) { + if (getStringable(thing)) + return getString(thing); + else if (thing instanceof Array) { + var res = []; + for (var i = 0; i < thing.length; i++) + res[i] = ensureStringed(thing[i]); + return res; + } else if (thing === Object(thing)) { + var res = {}; + for (key in thing) + res[key] = ensureStringed(thing[key]); + return res; + } + throw new Error("unsure of how to jsonify object of type " + typeof thing); + + } + + function jsonThing(thing) { + return JSON.stringify(ensureStringed(thing)); + } + /***************************** *** Base Storage Routines *** *****************************/ @@ -426,7 +436,7 @@ window.textsecure.subscribeToPush = function() { console.log("Got pong message"); } else if (message.type === undefined && message.id !== undefined) { textsecure.crypto.decryptWebsocketMessage(message.message).then(function(plaintext) { - var proto = decodeIncomingPushMessageProtobuf(getString(plaintext)); + var proto = textsecure.protos.decodeIncomingPushMessageProtobuf(getString(plaintext)); // After this point, a) decoding errors are not the server's fault, and // b) we should handle them gracefully and tell the user they received an invalid message console.log("Successfully decoded message with id: " + message.id); diff --git a/js/models/messages.js b/js/models/messages.js index 8d1b56402f92..d6c90cdad1ff 100644 --- a/js/models/messages.js +++ b/js/models/messages.js @@ -5,7 +5,7 @@ var Whisper = Whisper || {}; var Message = Backbone.Model.extend({ toProto: function() { - return new PushMessageContentProtobuf({body: this.get('body')}); + return new textsecure.protos.PushMessageContentProtobuf({body: this.get('body')}); } }); diff --git a/js/test.js b/js/test.js index bc7fc501a50d..2a4faff268b9 100644 --- a/js/test.js +++ b/js/test.js @@ -336,11 +336,11 @@ textsecure.registerOnLoadFunction(function() { if (data.newEphemeralKey !== undefined) privKeyQueue.push(data.newEphemeralKey); - var message = new IncomingPushMessageProtobuf(); + var message = new textsecure.protos.IncomingPushMessageProtobuf(); message.type = data.type; message.source = remoteDevice.encodedNumber; message.message = data.message; - return textsecure.crypto.handleIncomingPushMessageProto(decodeIncomingPushMessageProtobuf(getString(message.encode()))).then(function(res) { + return textsecure.crypto.handleIncomingPushMessageProto(textsecure.protos.decodeIncomingPushMessageProtobuf(getString(message.encode()))).then(function(res) { return res.message.body == data.expectedSmsText; }); } @@ -373,11 +373,11 @@ textsecure.registerOnLoadFunction(function() { //XXX: This should be all we do: stepDone(getString(data.expectedCiphertext) == getString(res.body)); if (res.type == 1) { //XXX: This should be used for everything... var expectedString = getString(data.expectedCiphertext); - var decoded = decodeWhisperMessageProtobuf(expectedString.substring(1, expectedString.length - 8)); + var decoded = textsecure.protos.decodeWhisperMessageProtobuf(expectedString.substring(1, expectedString.length - 8)); var result = getString(res.body); return getString(decoded.encode()) == result.substring(1, result.length - 8); } else { - var decoded = decodePreKeyWhisperMessageProtobuf(getString(data.expectedCiphertext).substr(1)); + var decoded = textsecure.protos.decodePreKeyWhisperMessageProtobuf(getString(data.expectedCiphertext).substr(1)); var result = getString(res.body).substring(1); return getString(decoded.encode()) == result; }