From dbd3db3393624b85e5abb6cd572fc80f8dbde5e4 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 19 Aug 2015 01:19:05 +0200 Subject: [PATCH] Always use general "send" API and determine internally to encrypt. With that also get rid of the "Api.send2" and "Api.apply" hacks. Now the respective methods take an optional function to call for sending the data as first argument. No more magic object binding, yay! --- static/js/directives/chat.js | 32 ++---- static/js/directives/presentation.js | 19 ++-- static/js/directives/screenshare.js | 11 +- static/js/directives/youtubevideo.js | 19 ++-- static/js/mediastream/api.js | 152 ++++++++++++++------------- 5 files changed, 109 insertions(+), 124 deletions(-) diff --git a/static/js/directives/chat.js b/static/js/directives/chat.js index b9a595f9..a89e1d33 100644 --- a/static/js/directives/chat.js +++ b/static/js/directives/chat.js @@ -291,21 +291,10 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro }); } _.delay(function() { - mediaStream.api.apply("sendChat", { - send: function(type, data, origType, origData) { - // We also send to self, to display our own stuff. - if (!noloop) { - var encrypted = (type !== origType); - mediaStream.api.received({ - Type: origData.Type, - Data: origData, - From: mediaStream.api.id, - To: peercall.id - }, encrypted); - } - return peercall.peerconnection.send(data); - } - })(to, message, status, mid); + mediaStream.api.sendChat(function(type, data) { + data.Type = type; + return peercall.peerconnection.send(data); + }, to, message, status, mid, true); }, 100); return mid; }; @@ -316,17 +305,8 @@ define(['jquery', 'underscore', 'text!partials/chat.html', 'text!partials/chatro }); } _.delay(function() { - mediaStream.api.send2("sendChat", function(type, data, encrypted) { - if (!noloop) { - //console.log("looped to self", type, data); - mediaStream.api.received({ - Type: data.Type, - Data: data, - From: mediaStream.api.id, - To: to - }, encrypted); - } - })(to, message, status, mid); + // Tell API to loop back message internally. + mediaStream.api.sendChat(to, message, status, mid, true); }, 100); return mid; }; diff --git a/static/js/directives/presentation.js b/static/js/directives/presentation.js index bc01604d..44253af4 100644 --- a/static/js/directives/presentation.js +++ b/static/js/directives/presentation.js @@ -415,17 +415,16 @@ define(['jquery', 'underscore', 'text!partials/presentation.html', 'bigscreen'], var tokenHandler = null; var mediaStreamSendPresentation = function(peercall, token, params) { - mediaStream.api.apply("sendPresentation", { - send: function(type, data) { - if (!peercall.peerconnection.datachannelReady) { - return peercall.e.one("dataReady", function() { - peercall.peerconnection.send(data); - }); - } else { - return peercall.peerconnection.send(data); - } + mediaStream.api.sendPresentation(function(type, data) { + data.Type = type; + if (!peercall.peerconnection.datachannelReady) { + return peercall.e.one("dataReady", function() { + peercall.peerconnection.send(data); + }); + } else { + return peercall.peerconnection.send(data); } - })(peercall.id, token, params); + }, peercall.id, token, params); }; var connector = function(token, peercall) { diff --git a/static/js/directives/screenshare.js b/static/js/directives/screenshare.js index 58e73dd7..3e3ee79f 100644 --- a/static/js/directives/screenshare.js +++ b/static/js/directives/screenshare.js @@ -205,12 +205,11 @@ define(['jquery', 'underscore', 'text!partials/screenshare.html', 'text!partials delete peers[currentcall.id]; console.log("Removed closed call from screen sharing.", currentcall.id); }); - mediaStream.api.apply("sendScreenshare", { - send: function(type, data) { - //console.log("sent screenshare", data, peercall); - return peercall.peerconnection.send(data); - } - })(peercall.from, token); + mediaStream.api.sendScreenshare(function(type, data) { + data.Type = type; + //console.log("sent screenshare", data, peercall); + return peercall.peerconnection.send(data); + }, peercall.from, token); }; usermedia.e.one("mediasuccess", function(event, usermedia) { diff --git a/static/js/directives/youtubevideo.js b/static/js/directives/youtubevideo.js index 90d79f03..2c5f4471 100644 --- a/static/js/directives/youtubevideo.js +++ b/static/js/directives/youtubevideo.js @@ -482,17 +482,16 @@ define(['require', 'jquery', 'underscore', 'moment', 'text!partials/youtubevideo var tokenHandler = null; var mediaStreamSendYouTubeVideo = function(peercall, token, params) { - mediaStream.api.apply("sendYouTubeVideo", { - send: function(type, data) { - if (!peercall.peerconnection.datachannelReady) { - return peercall.e.one("dataReady", function() { - peercall.peerconnection.send(data); - }); - } else { - return peercall.peerconnection.send(data); - } + mediaStream.api.sendYouTubeVideo(function(type, data) { + data.Type = type; + if (!peercall.peerconnection.datachannelReady) { + return peercall.e.one("dataReady", function() { + peercall.peerconnection.send(data); + }); + } else { + return peercall.peerconnection.send(data); } - })(peercall.id, token, params); + }, peercall.id, token, params); }; var connector = function(token, peercall) { diff --git a/static/js/mediastream/api.js b/static/js/mediastream/api.js index b8c095bb..a3dcc367 100644 --- a/static/js/mediastream/api.js +++ b/static/js/mediastream/api.js @@ -22,6 +22,21 @@ "use strict"; define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { + // "Decorate" the passed method to make sure the first argument is a + // function to use for sending data. Use the default send function if + // no function is passed. + var addDefaultSendFunc = function(f) { + var func = function(sendFunc) { + if (!_.isFunction(sendFunc)) { + var args = Array.prototype.slice.call(arguments); + args.unshift(_.bind(this.defaultSendFunc, this)); + return func.apply(this, args); + } + return f.apply(this, arguments); + }; + return func; + }; + var Api = function(version, connector, endToEndEncryption) { this.e = $({}); this.version = version; @@ -81,48 +96,64 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { }; - Api.prototype.send = function(type, data, noqueue) { - + Api.prototype.defaultSendFunc = function(type, data, noqueue) { var payload = { Type: type }; payload[type] = data; //console.log("<<<<<<<<<<<<", JSON.stringify(payload, null, 2)); this.connector.send(payload, noqueue); - }; - Api.prototype.send2 = function(name, cb) { - var obj = { - send: _.bind(function(type, data) { - if (cb) { - cb(type, data); - } - this.send(type, data); - }, this), - sendEncrypted: _.bind(function(type, data) { - if (cb) { - var to = data.To; - var encrypted = (to && this.endToEndEncryption); - cb(type, data, encrypted); - } - this.sendEncrypted(type, data); - }, this) + Api.prototype.supportsEncryption = function(peer, type) { + // Broadcast or server messages are never encrypted. + if (!peer) { + return false; + } + + // Need encryption support in the current browser environment. + if (!this.endToEndEncryption) { + return false; + } + + // Messages to setup encryption are never encrypted. + if (type === "EncryptionRegister" || + type === "EncryptionKeyBundle" || + type === "EncryptionRequestKeyBundle") { + return false; } - return this.apply(name, obj); + + // TODO(fancycode): Check if remote peer supports encryption. + return true; }; - Api.prototype.sendEncrypted = function(type, data, noqueue) { + Api.prototype.loopSelf = function(type, data, encrypted) { + this.received({ + Type: data.Type, + Data: data, + From: this.id, + To: data.To + }, encrypted); + }; + + Api.prototype.send = addDefaultSendFunc(function(sendFunc, type, data, noqueue, loopSelf) { var to = data.To; - if (!to || !this.endToEndEncryption) { - return this.send(type, data, noqueue); + if (this.supportsEncryption(to, type)) { + this.endToEndEncryption.encrypt(to, type, data, _.bind(function(encryptedType, encrypted) { + if (loopSelf) { + this.loopSelf(type, data, true); + } + encrypted.To = to; + sendFunc(encryptedType, encrypted, noqueue); + }, this)); + return; } - this.endToEndEncryption.encrypt(to, type, data, _.bind(function(type, encrypted) { - encrypted.To = to - this.send(type, encrypted, noqueue); - }, this)); - }; + if (loopSelf) { + this.loopSelf(type, data, false); + } + sendFunc(type, data, noqueue); + }); Api.prototype.request = function(type, data, cb, noqueue) { @@ -139,29 +170,6 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { } - // Helper hack function to send API requests to other destinations. - // Simply provide an alternative send function on the obj Object. The - // alternative send function will get the type and data to send, together - // with the original type and data (which are potentially unencrypted). - Api.prototype.apply = function(name, obj) { - var f = this[name]; - if (!obj.hasOwnProperty("sendEncrypted")) { - obj.sendEncrypted = _.bind(function(type, data) { - var to = data.To; - if (!to || !this.endToEndEncryption) { - return obj.send(type, data, type, data); - } - - this.endToEndEncryption.encrypt(to, type, data, _.bind(function(encryptedType, encrypted) { - encrypted.To = to - encrypted.Type = encryptedType - obj.send(encryptedType, encrypted, type, data); - }, this)); - }, this); - } - return _.bind(f, obj); - }; - Api.prototype.received = function(d, encrypted) { // Store received timestamp. @@ -331,7 +339,7 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { Offer: payload } - return this.sendEncrypted("Offer", data); + return this.send("Offer", data); }; @@ -343,7 +351,7 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { Candidate: payload } - return this.sendEncrypted("Candidate", data); + return this.send("Candidate", data); } @@ -355,7 +363,7 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { Answer: payload } - return this.sendEncrypted("Answer", data); + return this.send("Answer", data); } @@ -420,11 +428,15 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { } } - return this.sendEncrypted("Bye", data); + return this.send("Bye", data); }; - Api.prototype.sendChat = function(to, message, status, mid) { + Api.prototype.sendChat = addDefaultSendFunc(function(sendFunc, to, message, status, mid, loopSelf) { + if (!loopSelf && this.supportsEncryption(to, "Chat")) { + // We can't let the server loop back the encrypted message. + loopSelf = true; + } var data = { To: to, @@ -433,13 +445,12 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { Mid: mid, Message: message, Status: status, - NoEcho: true // This client shows own messages internally. + NoEcho: !!loopSelf } } - return this.sendEncrypted("Chat", data); - - }; + return this.send(sendFunc, "Chat", data, false, loopSelf); + }); Api.prototype.sendConference = function(id, ids) { @@ -453,8 +464,7 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { }; - Api.prototype.sendScreenshare = function(id, screen_id) { - + Api.prototype.sendScreenshare = addDefaultSendFunc(function(sendFunc, id, screen_id) { var data = { Id: id, Type: "Screenshare", @@ -463,12 +473,11 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { } } - return this.send("Screenshare", data); - - }; + return this.send(sendFunc, "Screenshare", data); - Api.prototype.sendPresentation = function(id, viewer_id, viewer_data) { + }); + Api.prototype.sendPresentation = addDefaultSendFunc(function(sendFunc, id, viewer_id, viewer_data) { var data = { Id: id, Type: "Presentation", @@ -480,12 +489,11 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { data.Presentation = _.extend(data.Presentation, viewer_data); } - return this.send("Presentation", data); - - }; + return this.send(sendFunc, "Presentation", data); - Api.prototype.sendYouTubeVideo = function(id, video_id, video_data) { + }); + Api.prototype.sendYouTubeVideo = addDefaultSendFunc(function(sendFunc, id, video_id, video_data) { var data = { Id: id, Type: "YouTubeVideo", @@ -497,9 +505,9 @@ define(['jquery', 'underscore', 'ua-parser'], function($, _, uaparser) { data.YouTubeVideo = _.extend(data.YouTubeVideo, video_data); } - return this.send("YouTubeVideo", data); + return this.send(sendFunc, "YouTubeVideo", data); - }; + }); Api.prototype.sendAlive = function(timestamp) {