From 4cc6b1ff9ab6d136e1f84e05923f134a853288aa Mon Sep 17 00:00:00 2001 From: lilia Date: Tue, 24 Nov 2015 12:40:00 -0800 Subject: [PATCH] Validate attachment urls // FREEBIE --- Gruntfile.js | 4 ++- js/background.js | 5 +-- js/libtextsecure.js | 51 ++++++++++++++++++++----------- libtextsecure/api.js | 35 +++++++++++++++------ libtextsecure/message_receiver.js | 8 ++--- libtextsecure/sendmessage.js | 8 ++--- 6 files changed, 74 insertions(+), 37 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 39613197..2205646d 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -127,7 +127,9 @@ module.exports = function(grunt) { if (srcpath.match('background.js')) { return content.replace( /textsecure-service-staging.whispersystems.org/g, - 'textsecure-service-ca.whispersystems.org:4433'); + 'textsecure-service-ca.whispersystems.org:4433').replace( + /whispersystems-textsecure-attachments-staging.s3.amazonaws.com/g, + 'whispersystems-textsecure-attachments.s3.amazonaws.com'); } else { return content; } diff --git a/js/background.js b/js/background.js index f5015fe1..57de8aee 100644 --- a/js/background.js +++ b/js/background.js @@ -54,6 +54,7 @@ }); var SERVER_URL = 'https://textsecure-service-staging.whispersystems.org'; + var ATTACHMENT_SERVER_URL = 'https://whispersystems-textsecure-attachments-staging.s3.amazonaws.com'; var messageReceiver; window.getSocketStatus = function() { if (messageReceiver) { @@ -96,7 +97,7 @@ var mySignalingKey = storage.get('signaling_key'); // initialize the socket and start listening for messages - messageReceiver = new textsecure.MessageReceiver(SERVER_URL, USERNAME, PASSWORD, mySignalingKey); + messageReceiver = new textsecure.MessageReceiver(SERVER_URL, USERNAME, PASSWORD, mySignalingKey, ATTACHMENT_SERVER_URL); messageReceiver.addEventListener('message', onMessageReceived); messageReceiver.addEventListener('receipt', onDeliveryReceipt); messageReceiver.addEventListener('contact', onContactReceived); @@ -106,7 +107,7 @@ messageReceiver.addEventListener('contactsync', onContactSyncComplete); - window.textsecure.messaging = new textsecure.MessageSender(SERVER_URL, USERNAME, PASSWORD); + window.textsecure.messaging = new textsecure.MessageSender(SERVER_URL, USERNAME, PASSWORD, ATTACHMENT_SERVER_URL); if (firstRun === true && textsecure.storage.user.getDeviceId() != '1') { textsecure.messaging.sendRequestContactSyncMessage().then(function() { textsecure.messaging.sendRequestGroupSyncMessage(); diff --git a/js/libtextsecure.js b/js/libtextsecure.js index 0f919c9e..8b85e8c9 100644 --- a/js/libtextsecure.js +++ b/js/libtextsecure.js @@ -36241,15 +36241,24 @@ var TextSecureServer = (function() { attachment : "/v1/attachments" }; - var attachment_id_regex = RegExp( "^https:\/\/.*\/(\\d+)\?"); - - function TextSecureServer(url, username, password) { + function TextSecureServer(url, username, password, attachment_server_url) { if (typeof url !== 'string') { throw new Error('Invalid server url'); } this.url = url; this.username = username; this.password = password; + + this.attachment_id_regex = RegExp("^https:\/\/.*\/(\\d+)\?"); + if (attachment_server_url) { + // strip trailing / + attachment_server_url = attachment_server_url.replace(/\/$/,''); + // and escape + attachment_server_url = attachment_server_url.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + this.attachment_id_regex = RegExp( "^" + attachment_server_url + "\/(\\d+)\?"); + } + + } TextSecureServer.prototype = { @@ -36415,29 +36424,37 @@ var TextSecureServer = (function() { httpType : 'GET', urlParameters : '/' + id, }).then(function(response) { + var match = response.location.match(this.attachment_id_regex); + if (!match) { + throw new Error('Received invalid attachment url'); + } return ajax(response.location, { type : "GET", responseType: "arraybuffer", contentType : "application/octet-stream" }); - }); + }.bind(this)); }, putAttachment: function(encryptedBin) { return this.ajax({ call : 'attachment', httpType : 'GET', }).then(function(response) { + // Extract the id as a string from the location url + // (workaround for ids too large for Javascript numbers) + var match = response.location.match(this.attachment_id_regex); + if (!match) { + throw new Error('Received invalid attachment url'); + } return ajax(response.location, { type : "PUT", contentType : "application/octet-stream", data : encryptedBin, processData : false, }).then(function() { - // Parse the id as a string from the location url - // (workaround for ids too large for Javascript numbers) - return response.location.match(attachment_id_regex)[1]; - }); - }); + return match[1]; + }.bind(this)); + }.bind(this)); }, getMessageSocket: function() { return new WebSocket( @@ -36639,12 +36656,12 @@ var TextSecureServer = (function() { * vim: ts=4:sw=4:expandtab */ -function MessageReceiver(url, username, password, signalingKey) { +function MessageReceiver(url, username, password, signalingKey, attachment_server_url) { this.url = url; this.signalingKey = signalingKey; this.username = username; this.password = password; - this.server = new TextSecureServer(url, username, password); + this.server = new TextSecureServer(url, username, password, attachment_server_url); var unencoded = textsecure.utils.unencodeNumber(username); this.number = unencoded[0]; @@ -37048,8 +37065,8 @@ MessageReceiver.prototype = { window.textsecure = window.textsecure || {}; -textsecure.MessageReceiver = function(url, username, password, signalingKey) { - var messageReceiver = new MessageReceiver(url, username, password, signalingKey); +textsecure.MessageReceiver = function(url, username, password, signalingKey, attachment_server_url) { + var messageReceiver = new MessageReceiver(url, username, password, signalingKey, attachment_server_url); this.addEventListener = messageReceiver.addEventListener.bind(messageReceiver); this.removeEventListener = messageReceiver.removeEventListener.bind(messageReceiver); this.getStatus = messageReceiver.getStatus.bind(messageReceiver); @@ -37209,8 +37226,8 @@ OutgoingMessage.prototype = { /* * vim: ts=4:sw=4:expandtab */ -function MessageSender(url, username, password) { - this.server = new TextSecureServer(url, username, password); +function MessageSender(url, username, password, attachment_server_url) { + this.server = new TextSecureServer(url, username, password, attachment_server_url); this.pendingMessages = {}; } @@ -37527,8 +37544,8 @@ MessageSender.prototype = { window.textsecure = window.textsecure || {}; -textsecure.MessageSender = function(url, username, password) { - var sender = new MessageSender(url, username, password); +textsecure.MessageSender = function(url, username, password, attachment_server_url) { + var sender = new MessageSender(url, username, password, attachment_server_url); textsecure.replay.registerFunction(sender.tryMessageAgain.bind(sender), textsecure.replay.Type.ENCRYPT_MESSAGE); textsecure.replay.registerFunction(sender.transmitMessage.bind(sender), textsecure.replay.Type.TRANSMIT_MESSAGE); diff --git a/libtextsecure/api.js b/libtextsecure/api.js index ecae776c..7de6ebba 100644 --- a/libtextsecure/api.js +++ b/libtextsecure/api.js @@ -89,15 +89,24 @@ var TextSecureServer = (function() { attachment : "/v1/attachments" }; - var attachment_id_regex = RegExp( "^https:\/\/.*\/(\\d+)\?"); - - function TextSecureServer(url, username, password) { + function TextSecureServer(url, username, password, attachment_server_url) { if (typeof url !== 'string') { throw new Error('Invalid server url'); } this.url = url; this.username = username; this.password = password; + + this.attachment_id_regex = RegExp("^https:\/\/.*\/(\\d+)\?"); + if (attachment_server_url) { + // strip trailing / + attachment_server_url = attachment_server_url.replace(/\/$/,''); + // and escape + attachment_server_url = attachment_server_url.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + this.attachment_id_regex = RegExp( "^" + attachment_server_url + "\/(\\d+)\?"); + } + + } TextSecureServer.prototype = { @@ -263,29 +272,37 @@ var TextSecureServer = (function() { httpType : 'GET', urlParameters : '/' + id, }).then(function(response) { + var match = response.location.match(this.attachment_id_regex); + if (!match) { + throw new Error('Received invalid attachment url'); + } return ajax(response.location, { type : "GET", responseType: "arraybuffer", contentType : "application/octet-stream" }); - }); + }.bind(this)); }, putAttachment: function(encryptedBin) { return this.ajax({ call : 'attachment', httpType : 'GET', }).then(function(response) { + // Extract the id as a string from the location url + // (workaround for ids too large for Javascript numbers) + var match = response.location.match(this.attachment_id_regex); + if (!match) { + throw new Error('Received invalid attachment url'); + } return ajax(response.location, { type : "PUT", contentType : "application/octet-stream", data : encryptedBin, processData : false, }).then(function() { - // Parse the id as a string from the location url - // (workaround for ids too large for Javascript numbers) - return response.location.match(attachment_id_regex)[1]; - }); - }); + return match[1]; + }.bind(this)); + }.bind(this)); }, getMessageSocket: function() { return new WebSocket( diff --git a/libtextsecure/message_receiver.js b/libtextsecure/message_receiver.js index c9419c88..f2ca08f7 100644 --- a/libtextsecure/message_receiver.js +++ b/libtextsecure/message_receiver.js @@ -2,12 +2,12 @@ * vim: ts=4:sw=4:expandtab */ -function MessageReceiver(url, username, password, signalingKey) { +function MessageReceiver(url, username, password, signalingKey, attachment_server_url) { this.url = url; this.signalingKey = signalingKey; this.username = username; this.password = password; - this.server = new TextSecureServer(url, username, password); + this.server = new TextSecureServer(url, username, password, attachment_server_url); var unencoded = textsecure.utils.unencodeNumber(username); this.number = unencoded[0]; @@ -411,8 +411,8 @@ MessageReceiver.prototype = { window.textsecure = window.textsecure || {}; -textsecure.MessageReceiver = function(url, username, password, signalingKey) { - var messageReceiver = new MessageReceiver(url, username, password, signalingKey); +textsecure.MessageReceiver = function(url, username, password, signalingKey, attachment_server_url) { + var messageReceiver = new MessageReceiver(url, username, password, signalingKey, attachment_server_url); this.addEventListener = messageReceiver.addEventListener.bind(messageReceiver); this.removeEventListener = messageReceiver.removeEventListener.bind(messageReceiver); this.getStatus = messageReceiver.getStatus.bind(messageReceiver); diff --git a/libtextsecure/sendmessage.js b/libtextsecure/sendmessage.js index 528e1526..b5c491d2 100644 --- a/libtextsecure/sendmessage.js +++ b/libtextsecure/sendmessage.js @@ -1,8 +1,8 @@ /* * vim: ts=4:sw=4:expandtab */ -function MessageSender(url, username, password) { - this.server = new TextSecureServer(url, username, password); +function MessageSender(url, username, password, attachment_server_url) { + this.server = new TextSecureServer(url, username, password, attachment_server_url); this.pendingMessages = {}; } @@ -319,8 +319,8 @@ MessageSender.prototype = { window.textsecure = window.textsecure || {}; -textsecure.MessageSender = function(url, username, password) { - var sender = new MessageSender(url, username, password); +textsecure.MessageSender = function(url, username, password, attachment_server_url) { + var sender = new MessageSender(url, username, password, attachment_server_url); textsecure.replay.registerFunction(sender.tryMessageAgain.bind(sender), textsecure.replay.Type.ENCRYPT_MESSAGE); textsecure.replay.registerFunction(sender.transmitMessage.bind(sender), textsecure.replay.Type.TRANSMIT_MESSAGE);