[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [snowflake/master] Lightly massage some of the generated JavaScript
commit 1867a3f121b5ea032466675f8ea3d00a134acd9a
Author: Arlo Breault <arlolra@xxxxxxxxx>
Date: Sat Jul 6 15:20:07 2019 +0200
Lightly massage some of the generated JavaScript
---
proxy/Cakefile.js | 42 +++--
proxy/broker.js | 188 +++++++++----------
proxy/config.js | 57 +++---
proxy/init-badge.js | 16 +-
proxy/init-node.js | 14 +-
proxy/init-webext.js | 20 +-
proxy/proxypair.js | 432 +++++++++++++++++++++----------------------
proxy/shims.js | 5 +-
proxy/snowflake.js | 298 +++++++++++++++--------------
proxy/spec/broker.spec.js | 58 +++---
proxy/spec/init.spec.js | 19 +-
proxy/spec/proxypair.spec.js | 51 +++--
proxy/spec/snowflake.spec.js | 71 +++----
proxy/spec/ui.spec.js | 26 +--
proxy/spec/util.spec.js | 68 ++++---
proxy/spec/websocket.spec.js | 23 ++-
proxy/ui.js | 299 ++++++++++++++----------------
proxy/util.js | 148 +++++++--------
proxy/websocket.js | 112 ++++++-----
19 files changed, 972 insertions(+), 975 deletions(-)
diff --git a/proxy/Cakefile.js b/proxy/Cakefile.js
index c7bc625..91ceea4 100644
--- a/proxy/Cakefile.js
+++ b/proxy/Cakefile.js
@@ -1,26 +1,44 @@
-// Generated by CoffeeScript 2.4.1
-var FILES, FILES_SPEC, INITS, OUTFILE, STATIC, compileCoffee, copyStaticFiles, exec, execSync, fs, spawn;
-fs = require('fs');
-
-({exec, spawn, execSync} = require('child_process'));
+var fs = require('fs');
+var { exec, spawn, execSync } = require('child_process');
// All coffeescript files required.
-FILES = ['broker.coffee', 'config.coffee', 'proxypair.coffee', 'snowflake.coffee', 'ui.coffee', 'util.coffee', 'websocket.coffee', 'shims.coffee'];
+var FILES = [
+ 'broker.coffee',
+ 'config.coffee',
+ 'proxypair.coffee',
+ 'snowflake.coffee',
+ 'ui.coffee',
+ 'util.coffee',
+ 'websocket.coffee',
+ 'shims.coffee'
+];
-INITS = ['init-badge.coffee', 'init-node.coffee', 'init-webext.coffee'];
+var INITS = [
+ 'init-badge.coffee',
+ 'init-node.coffee',
+ 'init-webext.coffee'
+];
-FILES_SPEC = ['spec/broker.spec.coffee', 'spec/init.spec.coffee', 'spec/proxypair.spec.coffee', 'spec/snowflake.spec.coffee', 'spec/ui.spec.coffee', 'spec/util.spec.coffee', 'spec/websocket.spec.coffee'];
+var FILES_SPEC = [
+ 'spec/broker.spec.coffee',
+ 'spec/init.spec.coffee',
+ 'spec/proxypair.spec.coffee',
+ 'spec/snowflake.spec.coffee',
+ 'spec/ui.spec.coffee',
+ 'spec/util.spec.coffee',
+ 'spec/websocket.spec.coffee'
+];
-OUTFILE = 'snowflake.js';
+var OUTFILE = 'snowflake.js';
-STATIC = 'static';
+var STATIC = 'static';
-copyStaticFiles = function() {
+var copyStaticFiles = function() {
return exec('cp ' + STATIC + '/* build/');
};
-compileCoffee = function(outDir, init) {
+var compileCoffee = function(outDir, init) {
var files;
files = FILES.concat('init-' + init + '.coffee');
return exec('cat ' + files.join(' ') + ' | coffee -cs > ' + outDir + '/' + OUTFILE, function(err, stdout, stderr) {
diff --git a/proxy/broker.js b/proxy/broker.js
index f7af5bb..4e287b4 100644
--- a/proxy/broker.js
+++ b/proxy/broker.js
@@ -1,73 +1,44 @@
-// Generated by CoffeeScript 2.4.1
/*
Communication with the snowflake broker.
Browser snowflakes must register with the broker in order
to get assigned to clients.
*/
-var Broker;
-Broker = (function() {
- // Represents a broker running remotely.
- class Broker {
- // When interacting with the Broker, snowflake must generate a unique session
- // ID so the Broker can keep track of each proxy's signalling channels.
- // On construction, this Broker object does not do anything until
- // |getClientOffer| is called.
- constructor(url) {
- // Promises some client SDP Offer.
- // Registers this Snowflake with the broker using an HTTP POST request, and
- // waits for a response containing some client offer that the Broker chooses
- // for this proxy..
- // TODO: Actually support multiple clients.
- this.getClientOffer = this.getClientOffer.bind(this);
- // urlSuffix for the broker is different depending on what action
- // is desired.
- this._postRequest = this._postRequest.bind(this);
- this.url = url;
- this.clients = 0;
- if (0 === this.url.indexOf('localhost', 0)) {
- // Ensure url has the right protocol + trailing slash.
- this.url = 'http://' + this.url;
- }
- if (0 !== this.url.indexOf('http', 0)) {
- this.url = 'https://' + this.url;
- }
- if ('/' !== this.url.substr(-1)) {
- this.url += '/';
- }
- }
+// Represents a broker running remotely.
+class Broker {
- getClientOffer(id) {
- return new Promise((fulfill, reject) => {
- var xhr;
- xhr = new XMLHttpRequest();
- xhr.onreadystatechange = function() {
- if (xhr.DONE !== xhr.readyState) {
- return;
- }
- switch (xhr.status) {
- case Broker.STATUS.OK:
- return fulfill(xhr.responseText); // Should contain offer.
- case Broker.STATUS.GATEWAY_TIMEOUT:
- return reject(Broker.MESSAGE.TIMEOUT);
- default:
- log('Broker ERROR: Unexpected ' + xhr.status + ' - ' + xhr.statusText);
- snowflake.ui.setStatus(' failure. Please refresh.');
- return reject(Broker.MESSAGE.UNEXPECTED);
- }
- };
- this._xhr = xhr; // Used by spec to fake async Broker interaction
- return this._postRequest(id, xhr, 'proxy', id);
- });
+ // When interacting with the Broker, snowflake must generate a unique session
+ // ID so the Broker can keep track of each proxy's signalling channels.
+ // On construction, this Broker object does not do anything until
+ // |getClientOffer| is called.
+ constructor(url) {
+ // Promises some client SDP Offer.
+ // Registers this Snowflake with the broker using an HTTP POST request, and
+ // waits for a response containing some client offer that the Broker chooses
+ // for this proxy..
+ // TODO: Actually support multiple clients.
+ this.getClientOffer = this.getClientOffer.bind(this);
+ // urlSuffix for the broker is different depending on what action
+ // is desired.
+ this._postRequest = this._postRequest.bind(this);
+ this.url = url;
+ this.clients = 0;
+ if (0 === this.url.indexOf('localhost', 0)) {
+ // Ensure url has the right protocol + trailing slash.
+ this.url = 'http://' + this.url;
+ }
+ if (0 !== this.url.indexOf('http', 0)) {
+ this.url = 'https://' + this.url;
+ }
+ if ('/' !== this.url.substr(-1)) {
+ this.url += '/';
}
+ }
- // Assumes getClientOffer happened, and a WebRTC SDP answer has been generated.
- // Sends it back to the broker, which passes it to back to the original client.
- sendAnswer(id, answer) {
+ getClientOffer(id) {
+ return new Promise((fulfill, reject) => {
var xhr;
- dbg(id + ' - Sending answer back to broker...\n');
- dbg(answer.sdp);
xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.DONE !== xhr.readyState) {
@@ -75,52 +46,75 @@ Broker = (function() {
}
switch (xhr.status) {
case Broker.STATUS.OK:
- dbg('Broker: Successfully replied with answer.');
- return dbg(xhr.responseText);
- case Broker.STATUS.GONE:
- return dbg('Broker: No longer valid to reply with answer.');
+ return fulfill(xhr.responseText); // Should contain offer.
+ case Broker.STATUS.GATEWAY_TIMEOUT:
+ return reject(Broker.MESSAGE.TIMEOUT);
default:
- dbg('Broker ERROR: Unexpected ' + xhr.status + ' - ' + xhr.statusText);
- return snowflake.ui.setStatus(' failure. Please refresh.');
+ log('Broker ERROR: Unexpected ' + xhr.status + ' - ' + xhr.statusText);
+ snowflake.ui.setStatus(' failure. Please refresh.');
+ return reject(Broker.MESSAGE.UNEXPECTED);
}
};
- return this._postRequest(id, xhr, 'answer', JSON.stringify(answer));
- }
+ this._xhr = xhr; // Used by spec to fake async Broker interaction
+ return this._postRequest(id, xhr, 'proxy', id);
+ });
+ }
- _postRequest(id, xhr, urlSuffix, payload) {
- var err;
- try {
- xhr.open('POST', this.url + urlSuffix);
- xhr.setRequestHeader('X-Session-ID', id);
- } catch (error) {
- err = error;
- /*
- An exception happens here when, for example, NoScript allows the domain
- on which the proxy badge runs, but not the domain to which it's trying
- to make the HTTP xhr. The exception message is like "Component
- returned failure code: 0x805e0006 [nsIXMLHttpRequest.open]" on Firefox.
- */
- log('Broker: exception while connecting: ' + err.message);
+ // Assumes getClientOffer happened, and a WebRTC SDP answer has been generated.
+ // Sends it back to the broker, which passes it to back to the original client.
+ sendAnswer(id, answer) {
+ var xhr;
+ dbg(id + ' - Sending answer back to broker...\n');
+ dbg(answer.sdp);
+ xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = function() {
+ if (xhr.DONE !== xhr.readyState) {
return;
}
- return xhr.send(payload);
- }
-
- };
+ switch (xhr.status) {
+ case Broker.STATUS.OK:
+ dbg('Broker: Successfully replied with answer.');
+ return dbg(xhr.responseText);
+ case Broker.STATUS.GONE:
+ return dbg('Broker: No longer valid to reply with answer.');
+ default:
+ dbg('Broker ERROR: Unexpected ' + xhr.status + ' - ' + xhr.statusText);
+ return snowflake.ui.setStatus(' failure. Please refresh.');
+ }
+ };
+ return this._postRequest(id, xhr, 'answer', JSON.stringify(answer));
+ }
- Broker.STATUS = {
- OK: 200,
- GONE: 410,
- GATEWAY_TIMEOUT: 504
- };
+ _postRequest(id, xhr, urlSuffix, payload) {
+ var err;
+ try {
+ xhr.open('POST', this.url + urlSuffix);
+ xhr.setRequestHeader('X-Session-ID', id);
+ } catch (error) {
+ err = error;
+ /*
+ An exception happens here when, for example, NoScript allows the domain
+ on which the proxy badge runs, but not the domain to which it's trying
+ to make the HTTP xhr. The exception message is like "Component
+ returned failure code: 0x805e0006 [nsIXMLHttpRequest.open]" on Firefox.
+ */
+ log('Broker: exception while connecting: ' + err.message);
+ return;
+ }
+ return xhr.send(payload);
+ }
- Broker.MESSAGE = {
- TIMEOUT: 'Timed out waiting for a client offer.',
- UNEXPECTED: 'Unexpected status.'
- };
+};
- Broker.prototype.clients = 0;
+Broker.STATUS = {
+ OK: 200,
+ GONE: 410,
+ GATEWAY_TIMEOUT: 504
+};
- return Broker;
+Broker.MESSAGE = {
+ TIMEOUT: 'Timed out waiting for a client offer.',
+ UNEXPECTED: 'Unexpected status.'
+};
-}).call(this);
+Broker.prototype.clients = 0;
diff --git a/proxy/config.js b/proxy/config.js
index 69d7b75..316f3b0 100644
--- a/proxy/config.js
+++ b/proxy/config.js
@@ -1,43 +1,36 @@
-// Generated by CoffeeScript 2.4.1
-var Config;
-Config = (function() {
- class Config {};
+class Config {};
- Config.prototype.brokerUrl = 'snowflake-broker.bamsoftware.com';
+Config.prototype.brokerUrl = 'snowflake-broker.bamsoftware.com';
- Config.prototype.relayAddr = {
- host: 'snowflake.bamsoftware.com',
- port: '443'
- };
+Config.prototype.relayAddr = {
+ host: 'snowflake.bamsoftware.com',
+ port: '443'
+};
- // Original non-wss relay:
- // host: '192.81.135.242'
- // port: 9902
- Config.prototype.cookieName = "snowflake-allow";
+// Original non-wss relay:
+// host: '192.81.135.242'
+// port: 9902
+Config.prototype.cookieName = "snowflake-allow";
- // Bytes per second. Set to undefined to disable limit.
- Config.prototype.rateLimitBytes = void 0;
+// Bytes per second. Set to undefined to disable limit.
+Config.prototype.rateLimitBytes = void 0;
- Config.prototype.minRateLimit = 10 * 1024;
+Config.prototype.minRateLimit = 10 * 1024;
- Config.prototype.rateLimitHistory = 5.0;
+Config.prototype.rateLimitHistory = 5.0;
- Config.prototype.defaultBrokerPollInterval = 5.0 * 1000;
+Config.prototype.defaultBrokerPollInterval = 5.0 * 1000;
- Config.prototype.maxNumClients = 1;
+Config.prototype.maxNumClients = 1;
- Config.prototype.connectionsPerClient = 1;
+Config.prototype.connectionsPerClient = 1;
- // TODO: Different ICE servers.
- Config.prototype.pcConfig = {
- iceServers: [
- {
- urls: ['stun:stun.l.google.com:19302']
- }
- ]
- };
-
- return Config;
-
-}).call(this);
+// TODO: Different ICE servers.
+Config.prototype.pcConfig = {
+ iceServers: [
+ {
+ urls: ['stun:stun.l.google.com:19302']
+ }
+ ]
+};
diff --git a/proxy/init-badge.js b/proxy/init-badge.js
index 136835b..7e5277f 100644
--- a/proxy/init-badge.js
+++ b/proxy/init-badge.js
@@ -1,37 +1,35 @@
-// Generated by CoffeeScript 2.4.1
/*
Entry point.
*/
-var dbg, debug, init, log, query, silenceNotifications, snowflake;
if (((typeof TESTING === "undefined" || TESTING === null) || !TESTING) && !Util.featureDetect()) {
console.log('webrtc feature not detected. shutting down');
return;
}
-snowflake = null;
+var snowflake = null;
-query = Query.parse(location);
+var query = Query.parse(location);
-debug = Params.getBool(query, 'debug', false);
+var debug = Params.getBool(query, 'debug', false);
-silenceNotifications = Params.getBool(query, 'silent', false);
+var silenceNotifications = Params.getBool(query, 'silent', false);
// Log to both console and UI if applicable.
// Requires that the snowflake and UI objects are hooked up in order to
// log to console.
-log = function(msg) {
+var log = function(msg) {
console.log('Snowflake: ' + msg);
return snowflake != null ? snowflake.ui.log(msg) : void 0;
};
-dbg = function(msg) {
+var dbg = function(msg) {
if (debug || ((snowflake != null ? snowflake.ui : void 0) instanceof DebugUI)) {
return log(msg);
}
};
-init = function() {
+var init = function() {
var broker, config, ui;
config = new Config;
if ('off' !== query['ratelimit']) {
diff --git a/proxy/init-node.js b/proxy/init-node.js
index c6e2e52..9efd486 100644
--- a/proxy/init-node.js
+++ b/proxy/init-node.js
@@ -1,22 +1,20 @@
-// Generated by CoffeeScript 2.4.1
/*
Entry point.
*/
-var broker, config, dbg, log, snowflake, ui;
-config = new Config;
+var config = new Config;
-ui = new UI();
+var ui = new UI();
-broker = new Broker(config.brokerUrl);
+var broker = new Broker(config.brokerUrl);
-snowflake = new Snowflake(config, ui, broker);
+var snowflake = new Snowflake(config, ui, broker);
-log = function(msg) {
+var log = function(msg) {
return console.log('Snowflake: ' + msg);
};
-dbg = log;
+var dbg = log;
log('== snowflake proxy ==');
diff --git a/proxy/init-webext.js b/proxy/init-webext.js
index 4b23403..89072b8 100644
--- a/proxy/init-webext.js
+++ b/proxy/init-webext.js
@@ -1,28 +1,26 @@
-// Generated by CoffeeScript 2.4.1
/*
Entry point.
*/
-var broker, config, dbg, debug, init, log, snowflake, ui, update;
-debug = false;
+var debug = false;
-snowflake = null;
+var snowflake = null;
-config = null;
+var config = null;
-broker = null;
+var broker = null;
-ui = null;
+var ui = null;
// Log to both console and UI if applicable.
// Requires that the snowflake and UI objects are hooked up in order to
// log to console.
-log = function(msg) {
+var log = function(msg) {
console.log('Snowflake: ' + msg);
return snowflake != null ? snowflake.ui.log(msg) : void 0;
};
-dbg = function(msg) {
+var dbg = function(msg) {
if (debug) {
return log(msg);
}
@@ -37,7 +35,7 @@ if (!Util.featureDetect()) {
return;
}
-init = function() {
+var init = function() {
config = new Config;
ui = new WebExtUI();
broker = new Broker(config.brokerUrl);
@@ -46,7 +44,7 @@ init = function() {
return ui.initToggle();
};
-update = function() {
+var update = function() {
if (!ui.enabled) {
// Do not activate the proxy if any number of conditions are true.
snowflake.disable();
diff --git a/proxy/proxypair.js b/proxy/proxypair.js
index 40f7b38..c162807 100644
--- a/proxy/proxypair.js
+++ b/proxy/proxypair.js
@@ -1,4 +1,3 @@
-// Generated by CoffeeScript 2.4.1
/*
Represents a single:
@@ -7,256 +6,251 @@ Represents a single:
Every ProxyPair has a Snowflake ID, which is necessary when responding to the
Broker with an WebRTC answer.
*/
-var ProxyPair;
-ProxyPair = (function() {
- class ProxyPair {
- /*
- Constructs a ProxyPair where:
- - @relayAddr is the destination relay
- - @rateLimit specifies a rate limit on traffic
- */
- constructor(relayAddr, rateLimit, pcConfig) {
- // Given a WebRTC DataChannel, prepare callbacks.
- this.prepareDataChannel = this.prepareDataChannel.bind(this);
- // Assumes WebRTC datachannel is connected.
- this.connectRelay = this.connectRelay.bind(this);
- // WebRTC --> websocket
- this.onClientToRelayMessage = this.onClientToRelayMessage.bind(this);
- // websocket --> WebRTC
- this.onRelayToClientMessage = this.onRelayToClientMessage.bind(this);
- this.onError = this.onError.bind(this);
- // Send as much data in both directions as the rate limit currently allows.
- this.flush = this.flush.bind(this);
- this.relayAddr = relayAddr;
- this.rateLimit = rateLimit;
- this.pcConfig = pcConfig;
- this.id = Util.genSnowflakeID();
- this.c2rSchedule = [];
- this.r2cSchedule = [];
- }
-
- // Prepare a WebRTC PeerConnection and await for an SDP offer.
- begin() {
- this.pc = new PeerConnection(this.pcConfig, {
- optional: [
- {
- DtlsSrtpKeyAgreement: true
- },
- {
- RtpDataChannels: false
- }
- ]
- });
- this.pc.onicecandidate = (evt) => {
- // Browser sends a null candidate once the ICE gathering completes.
- if (null === evt.candidate) {
- // TODO: Use a promise.all to tell Snowflake about all offers at once,
- // once multiple proxypairs are supported.
- dbg('Finished gathering ICE candidates.');
- return snowflake.broker.sendAnswer(this.id, this.pc.localDescription);
- }
- };
- // OnDataChannel triggered remotely from the client when connection succeeds.
- return this.pc.ondatachannel = (dc) => {
- var channel;
- channel = dc.channel;
- dbg('Data Channel established...');
- this.prepareDataChannel(channel);
- return this.client = channel;
- };
- }
-
- receiveWebRTCOffer(offer) {
- var e, err;
- if ('offer' !== offer.type) {
- log('Invalid SDP received -- was not an offer.');
- return false;
- }
- try {
- err = this.pc.setRemoteDescription(offer);
- } catch (error) {
- e = error;
- log('Invalid SDP message.');
- return false;
- }
- dbg('SDP ' + offer.type + ' successfully received.');
- return true;
- }
+class ProxyPair {
- prepareDataChannel(channel) {
- channel.onopen = () => {
- log('WebRTC DataChannel opened!');
- snowflake.state = Snowflake.MODE.WEBRTC_READY;
- snowflake.ui.setActive(true);
- // This is the point when the WebRTC datachannel is done, so the next step
- // is to establish websocket to the server.
- return this.connectRelay();
- };
- channel.onclose = () => {
- log('WebRTC DataChannel closed.');
- snowflake.ui.setStatus('disconnected by webrtc.');
- snowflake.ui.setActive(false);
- snowflake.state = Snowflake.MODE.INIT;
- this.flush();
- return this.close();
- };
- channel.onerror = function() {
- return log('Data channel error!');
- };
- channel.binaryType = "arraybuffer";
- return channel.onmessage = this.onClientToRelayMessage;
- }
+ /*
+ Constructs a ProxyPair where:
+ - @relayAddr is the destination relay
+ - @rateLimit specifies a rate limit on traffic
+ */
+ constructor(relayAddr, rateLimit, pcConfig) {
+ // Given a WebRTC DataChannel, prepare callbacks.
+ this.prepareDataChannel = this.prepareDataChannel.bind(this);
+ // Assumes WebRTC datachannel is connected.
+ this.connectRelay = this.connectRelay.bind(this);
+ // WebRTC --> websocket
+ this.onClientToRelayMessage = this.onClientToRelayMessage.bind(this);
+ // websocket --> WebRTC
+ this.onRelayToClientMessage = this.onRelayToClientMessage.bind(this);
+ this.onError = this.onError.bind(this);
+ // Send as much data in both directions as the rate limit currently allows.
+ this.flush = this.flush.bind(this);
+ this.relayAddr = relayAddr;
+ this.rateLimit = rateLimit;
+ this.pcConfig = pcConfig;
+ this.id = Util.genSnowflakeID();
+ this.c2rSchedule = [];
+ this.r2cSchedule = [];
+ }
- connectRelay() {
- var params, peer_ip, ref;
- dbg('Connecting to relay...');
- // Get a remote IP address from the PeerConnection, if possible. Add it to
- // the WebSocket URL's query string if available.
- // MDN marks remoteDescription as "experimental". However the other two
- // options, currentRemoteDescription and pendingRemoteDescription, which
- // are not marked experimental, were undefined when I tried them in Firefox
- // 52.2.0.
- // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/remoteDescription
- peer_ip = Parse.ipFromSDP((ref = this.pc.remoteDescription) != null ? ref.sdp : void 0);
- params = [];
- if (peer_ip != null) {
- params.push(["client_ip", peer_ip]);
- }
- this.relay = WS.makeWebsocket(this.relayAddr, params);
- this.relay.label = 'websocket-relay';
- this.relay.onopen = () => {
- if (this.timer) {
- clearTimeout(this.timer);
- this.timer = 0;
+ // Prepare a WebRTC PeerConnection and await for an SDP offer.
+ begin() {
+ this.pc = new PeerConnection(this.pcConfig, {
+ optional: [
+ {
+ DtlsSrtpKeyAgreement: true
+ },
+ {
+ RtpDataChannels: false
}
- log(this.relay.label + ' connected!');
- return snowflake.ui.setStatus('connected');
- };
- this.relay.onclose = () => {
- log(this.relay.label + ' closed.');
- snowflake.ui.setStatus('disconnected.');
- snowflake.ui.setActive(false);
- snowflake.state = Snowflake.MODE.INIT;
- this.flush();
- return this.close();
- };
- this.relay.onerror = this.onError;
- this.relay.onmessage = this.onRelayToClientMessage;
- // TODO: Better websocket timeout handling.
- return this.timer = setTimeout((() => {
- if (0 === this.timer) {
- return;
- }
- log(this.relay.label + ' timed out connecting.');
- return this.relay.onclose();
- }), 5000);
- }
+ ]
+ });
+ this.pc.onicecandidate = (evt) => {
+ // Browser sends a null candidate once the ICE gathering completes.
+ if (null === evt.candidate) {
+ // TODO: Use a promise.all to tell Snowflake about all offers at once,
+ // once multiple proxypairs are supported.
+ dbg('Finished gathering ICE candidates.');
+ return snowflake.broker.sendAnswer(this.id, this.pc.localDescription);
+ }
+ };
+ // OnDataChannel triggered remotely from the client when connection succeeds.
+ return this.pc.ondatachannel = (dc) => {
+ var channel;
+ channel = dc.channel;
+ dbg('Data Channel established...');
+ this.prepareDataChannel(channel);
+ return this.client = channel;
+ };
+ }
- onClientToRelayMessage(msg) {
- dbg('WebRTC --> websocket data: ' + msg.data.byteLength + ' bytes');
- this.c2rSchedule.push(msg.data);
- return this.flush();
+ receiveWebRTCOffer(offer) {
+ var e, err;
+ if ('offer' !== offer.type) {
+ log('Invalid SDP received -- was not an offer.');
+ return false;
}
-
- onRelayToClientMessage(event) {
- dbg('websocket --> WebRTC data: ' + event.data.byteLength + ' bytes');
- this.r2cSchedule.push(event.data);
- return this.flush();
+ try {
+ err = this.pc.setRemoteDescription(offer);
+ } catch (error) {
+ e = error;
+ log('Invalid SDP message.');
+ return false;
}
+ dbg('SDP ' + offer.type + ' successfully received.');
+ return true;
+ }
- onError(event) {
- var ws;
- ws = event.target;
- log(ws.label + ' error.');
+ prepareDataChannel(channel) {
+ channel.onopen = () => {
+ log('WebRTC DataChannel opened!');
+ snowflake.state = Snowflake.MODE.WEBRTC_READY;
+ snowflake.ui.setActive(true);
+ // This is the point when the WebRTC datachannel is done, so the next step
+ // is to establish websocket to the server.
+ return this.connectRelay();
+ };
+ channel.onclose = () => {
+ log('WebRTC DataChannel closed.');
+ snowflake.ui.setStatus('disconnected by webrtc.');
+ snowflake.ui.setActive(false);
+ snowflake.state = Snowflake.MODE.INIT;
+ this.flush();
return this.close();
- }
+ };
+ channel.onerror = function() {
+ return log('Data channel error!');
+ };
+ channel.binaryType = "arraybuffer";
+ return channel.onmessage = this.onClientToRelayMessage;
+ }
- // Close both WebRTC and websocket.
- close() {
- var relay;
+ connectRelay() {
+ var params, peer_ip, ref;
+ dbg('Connecting to relay...');
+ // Get a remote IP address from the PeerConnection, if possible. Add it to
+ // the WebSocket URL's query string if available.
+ // MDN marks remoteDescription as "experimental". However the other two
+ // options, currentRemoteDescription and pendingRemoteDescription, which
+ // are not marked experimental, were undefined when I tried them in Firefox
+ // 52.2.0.
+ // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/remoteDescription
+ peer_ip = Parse.ipFromSDP((ref = this.pc.remoteDescription) != null ? ref.sdp : void 0);
+ params = [];
+ if (peer_ip != null) {
+ params.push(["client_ip", peer_ip]);
+ }
+ this.relay = WS.makeWebsocket(this.relayAddr, params);
+ this.relay.label = 'websocket-relay';
+ this.relay.onopen = () => {
if (this.timer) {
clearTimeout(this.timer);
this.timer = 0;
}
- this.running = false;
- if (this.webrtcIsReady()) {
- this.client.close();
- }
- if (this.relayIsReady()) {
- this.relay.close();
+ log(this.relay.label + ' connected!');
+ return snowflake.ui.setStatus('connected');
+ };
+ this.relay.onclose = () => {
+ log(this.relay.label + ' closed.');
+ snowflake.ui.setStatus('disconnected.');
+ snowflake.ui.setActive(false);
+ snowflake.state = Snowflake.MODE.INIT;
+ this.flush();
+ return this.close();
+ };
+ this.relay.onerror = this.onError;
+ this.relay.onmessage = this.onRelayToClientMessage;
+ // TODO: Better websocket timeout handling.
+ return this.timer = setTimeout((() => {
+ if (0 === this.timer) {
+ return;
}
- relay = null;
- return this.onCleanup();
+ log(this.relay.label + ' timed out connecting.');
+ return this.relay.onclose();
+ }), 5000);
+ }
+
+ onClientToRelayMessage(msg) {
+ dbg('WebRTC --> websocket data: ' + msg.data.byteLength + ' bytes');
+ this.c2rSchedule.push(msg.data);
+ return this.flush();
+ }
+
+ onRelayToClientMessage(event) {
+ dbg('websocket --> WebRTC data: ' + event.data.byteLength + ' bytes');
+ this.r2cSchedule.push(event.data);
+ return this.flush();
+ }
+
+ onError(event) {
+ var ws;
+ ws = event.target;
+ log(ws.label + ' error.');
+ return this.close();
+ }
+
+ // Close both WebRTC and websocket.
+ close() {
+ var relay;
+ if (this.timer) {
+ clearTimeout(this.timer);
+ this.timer = 0;
+ }
+ this.running = false;
+ if (this.webrtcIsReady()) {
+ this.client.close();
}
+ if (this.relayIsReady()) {
+ this.relay.close();
+ }
+ relay = null;
+ return this.onCleanup();
+ }
- flush() {
- var busy, checkChunks;
- if (this.flush_timeout_id) {
- clearTimeout(this.flush_timeout_id);
- }
- this.flush_timeout_id = null;
- busy = true;
- checkChunks = () => {
- var chunk;
- busy = false;
- // WebRTC --> websocket
- if (this.relayIsReady() && this.relay.bufferedAmount < this.MAX_BUFFER && this.c2rSchedule.length > 0) {
- chunk = this.c2rSchedule.shift();
- this.rateLimit.update(chunk.byteLength);
- this.relay.send(chunk);
- busy = true;
- }
- // websocket --> WebRTC
- if (this.webrtcIsReady() && this.client.bufferedAmount < this.MAX_BUFFER && this.r2cSchedule.length > 0) {
- chunk = this.r2cSchedule.shift();
- this.rateLimit.update(chunk.byteLength);
- this.client.send(chunk);
- return busy = true;
- }
- };
- while (busy && !this.rateLimit.isLimited()) {
- checkChunks();
+ flush() {
+ var busy, checkChunks;
+ if (this.flush_timeout_id) {
+ clearTimeout(this.flush_timeout_id);
+ }
+ this.flush_timeout_id = null;
+ busy = true;
+ checkChunks = () => {
+ var chunk;
+ busy = false;
+ // WebRTC --> websocket
+ if (this.relayIsReady() && this.relay.bufferedAmount < this.MAX_BUFFER && this.c2rSchedule.length > 0) {
+ chunk = this.c2rSchedule.shift();
+ this.rateLimit.update(chunk.byteLength);
+ this.relay.send(chunk);
+ busy = true;
}
- if (this.r2cSchedule.length > 0 || this.c2rSchedule.length > 0 || (this.relayIsReady() && this.relay.bufferedAmount > 0) || (this.webrtcIsReady() && this.client.bufferedAmount > 0)) {
- return this.flush_timeout_id = setTimeout(this.flush, this.rateLimit.when() * 1000);
+ // websocket --> WebRTC
+ if (this.webrtcIsReady() && this.client.bufferedAmount < this.MAX_BUFFER && this.r2cSchedule.length > 0) {
+ chunk = this.r2cSchedule.shift();
+ this.rateLimit.update(chunk.byteLength);
+ this.client.send(chunk);
+ return busy = true;
}
+ };
+ while (busy && !this.rateLimit.isLimited()) {
+ checkChunks();
}
-
- webrtcIsReady() {
- return null !== this.client && 'open' === this.client.readyState;
- }
-
- relayIsReady() {
- return (null !== this.relay) && (WebSocket.OPEN === this.relay.readyState);
+ if (this.r2cSchedule.length > 0 || this.c2rSchedule.length > 0 || (this.relayIsReady() && this.relay.bufferedAmount > 0) || (this.webrtcIsReady() && this.client.bufferedAmount > 0)) {
+ return this.flush_timeout_id = setTimeout(this.flush, this.rateLimit.when() * 1000);
}
+ }
- isClosed(ws) {
- return void 0 === ws || WebSocket.CLOSED === ws.readyState;
- }
+ webrtcIsReady() {
+ return null !== this.client && 'open' === this.client.readyState;
+ }
- };
+ relayIsReady() {
+ return (null !== this.relay) && (WebSocket.OPEN === this.relay.readyState);
+ }
- ProxyPair.prototype.MAX_BUFFER = 10 * 1024 * 1024;
+ isClosed(ws) {
+ return void 0 === ws || WebSocket.CLOSED === ws.readyState;
+ }
- ProxyPair.prototype.pc = null;
+};
- ProxyPair.prototype.client = null; // WebRTC Data channel
+ProxyPair.prototype.MAX_BUFFER = 10 * 1024 * 1024;
- ProxyPair.prototype.relay = null; // websocket
+ProxyPair.prototype.pc = null;
- ProxyPair.prototype.timer = 0;
+ProxyPair.prototype.client = null; // WebRTC Data channel
- ProxyPair.prototype.running = true;
+ProxyPair.prototype.relay = null; // websocket
- ProxyPair.prototype.active = false; // Whether serving a client.
+ProxyPair.prototype.timer = 0;
- ProxyPair.prototype.flush_timeout_id = null;
+ProxyPair.prototype.running = true;
- ProxyPair.prototype.onCleanup = null;
+ProxyPair.prototype.active = false; // Whether serving a client.
- ProxyPair.prototype.id = null;
+ProxyPair.prototype.flush_timeout_id = null;
- return ProxyPair;
+ProxyPair.prototype.onCleanup = null;
-}).call(this);
+ProxyPair.prototype.id = null;
diff --git a/proxy/shims.js b/proxy/shims.js
index 0e33236..4fc0b38 100644
--- a/proxy/shims.js
+++ b/proxy/shims.js
@@ -1,8 +1,6 @@
-// Generated by CoffeeScript 2.4.1
/*
WebRTC shims for multiple browsers.
*/
-var IceCandidate, PeerConnection, SessionDescription, WebSocket, XMLHttpRequest, chrome, document, location, webrtc, window;
if (typeof module !== "undefined" && module !== null ? module.exports : void 0) {
window = {};
@@ -19,10 +17,9 @@ if (typeof module !== "undefined" && module !== null ? module.exports : void 0)
IceCandidate = webrtc.RTCIceCandidate;
SessionDescription = webrtc.RTCSessionDescription;
WebSocket = require('ws');
- ({XMLHttpRequest} = require('xmlhttprequest'));
+ ({ XMLHttpRequest } = require('xmlhttprequest'));
}
} else {
- window = this;
document = window.document;
chrome = window.chrome;
location = window.location.search.substr(1);
diff --git a/proxy/snowflake.js b/proxy/snowflake.js
index c150452..7b584d1 100644
--- a/proxy/snowflake.js
+++ b/proxy/snowflake.js
@@ -1,4 +1,3 @@
-// Generated by CoffeeScript 2.4.1
/*
A Coffeescript WebRTC snowflake proxy
@@ -9,174 +8,169 @@ this proxy must always act as the answerer.
TODO: More documentation
*/
-var Snowflake;
-
-Snowflake = (function() {
- // Minimum viable snowflake for now - just 1 client.
- class Snowflake {
- // Prepare the Snowflake with a Broker (to find clients) and optional UI.
- constructor(config, ui, broker) {
- // Receive an SDP offer from some client assigned by the Broker,
- // |pair| - an available ProxyPair.
- this.receiveOffer = this.receiveOffer.bind(this);
- this.config = config;
- this.ui = ui;
- this.broker = broker;
- this.state = Snowflake.MODE.INIT;
- this.proxyPairs = [];
- if (void 0 === this.config.rateLimitBytes) {
- this.rateLimit = new DummyRateLimit();
- } else {
- this.rateLimit = new BucketRateLimit(this.config.rateLimitBytes * this.config.rateLimitHistory, this.config.rateLimitHistory);
- }
- this.retries = 0;
- }
- // Set the target relay address spec, which is expected to be websocket.
- // TODO: Should potentially fetch the target from broker later, or modify
- // entirely for the Tor-independent version.
- setRelayAddr(relayAddr) {
- this.relayAddr = relayAddr;
- log('Using ' + relayAddr.host + ':' + relayAddr.port + ' as Relay.');
- return true;
+// Minimum viable snowflake for now - just 1 client.
+class Snowflake {
+
+ // Prepare the Snowflake with a Broker (to find clients) and optional UI.
+ constructor(config, ui, broker) {
+ // Receive an SDP offer from some client assigned by the Broker,
+ // |pair| - an available ProxyPair.
+ this.receiveOffer = this.receiveOffer.bind(this);
+ this.config = config;
+ this.ui = ui;
+ this.broker = broker;
+ this.state = Snowflake.MODE.INIT;
+ this.proxyPairs = [];
+ if (void 0 === this.config.rateLimitBytes) {
+ this.rateLimit = new DummyRateLimit();
+ } else {
+ this.rateLimit = new BucketRateLimit(this.config.rateLimitBytes * this.config.rateLimitHistory, this.config.rateLimitHistory);
}
-
- // Initialize WebRTC PeerConnection, which requires beginning the signalling
- // process. |pollBroker| automatically arranges signalling.
- beginWebRTC() {
- this.state = Snowflake.MODE.WEBRTC_CONNECTING;
- log('ProxyPair Slots: ' + this.proxyPairs.length);
- log('Snowflake IDs: ' + (this.proxyPairs.map(function(p) {
- return p.id;
- })).join(' | '));
- this.pollBroker();
- return this.pollInterval = setInterval((() => {
- return this.pollBroker();
- }), this.config.defaultBrokerPollInterval);
+ this.retries = 0;
+ }
+
+ // Set the target relay address spec, which is expected to be websocket.
+ // TODO: Should potentially fetch the target from broker later, or modify
+ // entirely for the Tor-independent version.
+ setRelayAddr(relayAddr) {
+ this.relayAddr = relayAddr;
+ log('Using ' + relayAddr.host + ':' + relayAddr.port + ' as Relay.');
+ return true;
+ }
+
+ // Initialize WebRTC PeerConnection, which requires beginning the signalling
+ // process. |pollBroker| automatically arranges signalling.
+ beginWebRTC() {
+ this.state = Snowflake.MODE.WEBRTC_CONNECTING;
+ log('ProxyPair Slots: ' + this.proxyPairs.length);
+ log('Snowflake IDs: ' + (this.proxyPairs.map(function(p) {
+ return p.id;
+ })).join(' | '));
+ this.pollBroker();
+ return this.pollInterval = setInterval((() => {
+ return this.pollBroker();
+ }), this.config.defaultBrokerPollInterval);
+ }
+
+ // Regularly poll Broker for clients to serve until this snowflake is
+ // serving at capacity, at which point stop polling.
+ pollBroker() {
+ var msg, pair, recv;
+ // Poll broker for clients.
+ pair = this.nextAvailableProxyPair();
+ if (!pair) {
+ log('At client capacity.');
+ return;
}
-
- // Regularly poll Broker for clients to serve until this snowflake is
- // serving at capacity, at which point stop polling.
- pollBroker() {
- var msg, pair, recv;
- // Poll broker for clients.
- pair = this.nextAvailableProxyPair();
- if (!pair) {
- log('At client capacity.');
- return;
- }
- // Do nothing until a new proxyPair is available.
- pair.active = true;
- msg = 'Polling for client ... ';
- if (this.retries > 0) {
- msg += '[retries: ' + this.retries + ']';
- }
- this.ui.setStatus(msg);
- recv = this.broker.getClientOffer(pair.id);
- recv.then((desc) => {
- if (pair.running) {
- if (!this.receiveOffer(pair, desc)) {
- return pair.active = false;
- }
- } else {
+ // Do nothing until a new proxyPair is available.
+ pair.active = true;
+ msg = 'Polling for client ... ';
+ if (this.retries > 0) {
+ msg += '[retries: ' + this.retries + ']';
+ }
+ this.ui.setStatus(msg);
+ recv = this.broker.getClientOffer(pair.id);
+ recv.then((desc) => {
+ if (pair.running) {
+ if (!this.receiveOffer(pair, desc)) {
return pair.active = false;
}
- }, function(err) {
+ } else {
return pair.active = false;
- });
- return this.retries++;
- }
-
- // Returns the first ProxyPair that's available to connect.
- nextAvailableProxyPair() {
- if (this.proxyPairs.length < this.config.connectionsPerClient) {
- return this.makeProxyPair(this.relayAddr);
}
- return this.proxyPairs.find(function(pp, i, arr) {
- return !pp.active;
- });
+ }, function(err) {
+ return pair.active = false;
+ });
+ return this.retries++;
+ }
+
+ // Returns the first ProxyPair that's available to connect.
+ nextAvailableProxyPair() {
+ if (this.proxyPairs.length < this.config.connectionsPerClient) {
+ return this.makeProxyPair(this.relayAddr);
}
-
- receiveOffer(pair, desc) {
- var e, offer, sdp;
- try {
- offer = JSON.parse(desc);
- dbg('Received:\n\n' + offer.sdp + '\n');
- sdp = new SessionDescription(offer);
- if (pair.receiveWebRTCOffer(sdp)) {
- this.sendAnswer(pair);
- return true;
- } else {
- return false;
- }
- } catch (error) {
- e = error;
- log('ERROR: Unable to receive Offer: ' + e);
+ return this.proxyPairs.find(function(pp, i, arr) {
+ return !pp.active;
+ });
+ }
+
+ receiveOffer(pair, desc) {
+ var e, offer, sdp;
+ try {
+ offer = JSON.parse(desc);
+ dbg('Received:\n\n' + offer.sdp + '\n');
+ sdp = new SessionDescription(offer);
+ if (pair.receiveWebRTCOffer(sdp)) {
+ this.sendAnswer(pair);
+ return true;
+ } else {
return false;
}
+ } catch (error) {
+ e = error;
+ log('ERROR: Unable to receive Offer: ' + e);
+ return false;
}
-
- sendAnswer(pair) {
- var fail, next;
- next = function(sdp) {
- dbg('webrtc: Answer ready.');
- return pair.pc.setLocalDescription(sdp);
- };
- fail = function() {
- return dbg('webrtc: Failed to create Answer');
- };
- return pair.pc.createAnswer().then(next).catch(fail);
- }
-
- makeProxyPair(relay) {
- var pair;
- pair = new ProxyPair(relay, this.rateLimit, this.config.pcConfig);
- this.proxyPairs.push(pair);
- pair.onCleanup = (event) => {
- var ind;
- // Delete from the list of active proxy pairs.
- ind = this.proxyPairs.indexOf(pair);
- if (ind > -1) {
- return this.proxyPairs.splice(ind, 1);
- }
- };
- pair.begin();
- return pair;
- }
-
- // Stop all proxypairs.
- disable() {
- var results;
- log('Disabling Snowflake.');
- clearInterval(this.pollInterval);
- results = [];
- while (this.proxyPairs.length > 0) {
- results.push(this.proxyPairs.pop().close());
+ }
+
+ sendAnswer(pair) {
+ var fail, next;
+ next = function(sdp) {
+ dbg('webrtc: Answer ready.');
+ return pair.pc.setLocalDescription(sdp);
+ };
+ fail = function() {
+ return dbg('webrtc: Failed to create Answer');
+ };
+ return pair.pc.createAnswer().then(next).catch(fail);
+ }
+
+ makeProxyPair(relay) {
+ var pair;
+ pair = new ProxyPair(relay, this.rateLimit, this.config.pcConfig);
+ this.proxyPairs.push(pair);
+ pair.onCleanup = (event) => {
+ var ind;
+ // Delete from the list of active proxy pairs.
+ ind = this.proxyPairs.indexOf(pair);
+ if (ind > -1) {
+ return this.proxyPairs.splice(ind, 1);
}
- return results;
+ };
+ pair.begin();
+ return pair;
+ }
+
+ // Stop all proxypairs.
+ disable() {
+ var results;
+ log('Disabling Snowflake.');
+ clearInterval(this.pollInterval);
+ results = [];
+ while (this.proxyPairs.length > 0) {
+ results.push(this.proxyPairs.pop().close());
}
+ return results;
+ }
- };
-
- Snowflake.prototype.relayAddr = null;
-
- Snowflake.prototype.rateLimit = null;
+};
- Snowflake.prototype.pollInterval = null;
+Snowflake.prototype.relayAddr = null;
- Snowflake.prototype.retries = 0;
+Snowflake.prototype.rateLimit = null;
- // Janky state machine
- Snowflake.MODE = {
- INIT: 0,
- WEBRTC_CONNECTING: 1,
- WEBRTC_READY: 2
- };
+Snowflake.prototype.pollInterval = null;
- Snowflake.MESSAGE = {
- CONFIRMATION: 'You\'re currently serving a Tor user via Snowflake.'
- };
+Snowflake.prototype.retries = 0;
- return Snowflake;
+// Janky state machine
+Snowflake.MODE = {
+ INIT: 0,
+ WEBRTC_CONNECTING: 1,
+ WEBRTC_READY: 2
+};
-}).call(this);
+Snowflake.MESSAGE = {
+ CONFIRMATION: 'You\'re currently serving a Tor user via Snowflake.'
+};
diff --git a/proxy/spec/broker.spec.js b/proxy/spec/broker.spec.js
index 7d5e0a2..a7c2e1d 100644
--- a/proxy/spec/broker.spec.js
+++ b/proxy/spec/broker.spec.js
@@ -1,39 +1,32 @@
-// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake broker
*/
-var XMLHttpRequest;
-XMLHttpRequest = (function() {
- // fake xhr
- // class XMLHttpRequest
- class XMLHttpRequest {
- constructor() {
- this.onreadystatechange = null;
- }
+// fake xhr
+// class XMLHttpRequest
+class XMLHttpRequest {
+ constructor() {
+ this.onreadystatechange = null;
+ }
+ open() {}
+ setRequestHeader() {}
+ send() {}
+};
- open() {}
+XMLHttpRequest.prototype.DONE = 1;
- setRequestHeader() {}
-
- send() {}
-
- };
-
- XMLHttpRequest.prototype.DONE = 1;
-
- return XMLHttpRequest;
-
-}).call(this);
describe('Broker', function() {
+
it('can be created', function() {
var b;
b = new Broker('fake');
expect(b.url).toEqual('https://fake/');
- return expect(b.id).not.toBeNull();
+ expect(b.id).not.toBeNull();
});
+
describe('getClientOffer', function() {
+
it('polls and promises a client offer', function(done) {
var b, poll;
b = new Broker('fake');
@@ -55,6 +48,7 @@ describe('Broker', function() {
return done();
});
});
+
it('rejects if the broker timed-out', function(done) {
var b, poll;
b = new Broker('fake');
@@ -75,7 +69,8 @@ describe('Broker', function() {
return done();
});
});
- return it('rejects on any other status', function(done) {
+
+ it('rejects on any other status', function(done) {
var b, poll;
b = new Broker('fake');
// fake timed-out request from broker
@@ -95,18 +90,20 @@ describe('Broker', function() {
expect(b._xhr.status).toBe(1337);
return done();
});
+
});
+
});
+
it('responds to the broker with answer', function() {
- var b;
- b = new Broker('fake');
+ var b = new Broker('fake');
spyOn(b, '_postRequest');
b.sendAnswer('fake id', 123);
- return expect(b._postRequest).toHaveBeenCalledWith('fake id', jasmine.any(Object), 'answer', '123');
+ expect(b._postRequest).toHaveBeenCalledWith('fake id', jasmine.any(Object), 'answer', '123');
});
- return it('POST XMLHttpRequests to the broker', function() {
- var b;
- b = new Broker('fake');
+
+ it('POST XMLHttpRequests to the broker', function() {
+ var b = new Broker('fake');
b._xhr = new XMLHttpRequest();
spyOn(b._xhr, 'open');
spyOn(b._xhr, 'setRequestHeader');
@@ -114,6 +111,7 @@ describe('Broker', function() {
b._postRequest(0, b._xhr, 'test', 'data');
expect(b._xhr.open).toHaveBeenCalled();
expect(b._xhr.setRequestHeader).toHaveBeenCalled();
- return expect(b._xhr.send).toHaveBeenCalled();
+ expect(b._xhr.send).toHaveBeenCalled();
});
+
});
diff --git a/proxy/spec/init.spec.js b/proxy/spec/init.spec.js
index 70ec7e9..baa7388 100644
--- a/proxy/spec/init.spec.js
+++ b/proxy/spec/init.spec.js
@@ -1,8 +1,6 @@
-// Generated by CoffeeScript 2.4.1
// Fake snowflake to interact with
-var snowflake;
-snowflake = {
+var snowflake = {
ui: new UI,
broker: {
sendAnswer: function() {}
@@ -11,24 +9,25 @@ snowflake = {
};
describe('Init', function() {
+
it('gives a dialog when closing, only while active', function() {
- var msg, silenceNotifications;
silenceNotifications = false;
snowflake.state = Snowflake.MODE.WEBRTC_READY;
- msg = window.onbeforeunload();
+ var msg = window.onbeforeunload();
expect(snowflake.state).toBe(Snowflake.MODE.WEBRTC_READY);
expect(msg).toBe(Snowflake.MESSAGE.CONFIRMATION);
snowflake.state = Snowflake.MODE.INIT;
msg = window.onbeforeunload();
expect(snowflake.state).toBe(Snowflake.MODE.INIT);
- return expect(msg).toBe(null);
+ expect(msg).toBe(null);
});
- return it('does not give a dialog when silent flag is on', function() {
- var msg, silenceNotifications;
+
+ it('does not give a dialog when silent flag is on', function() {
silenceNotifications = true;
snowflake.state = Snowflake.MODE.WEBRTC_READY;
- msg = window.onbeforeunload();
+ var msg = window.onbeforeunload();
expect(snowflake.state).toBe(Snowflake.MODE.WEBRTC_READY);
- return expect(msg).toBe(null);
+ expect(msg).toBe(null);
});
+
});
diff --git a/proxy/spec/proxypair.spec.js b/proxy/spec/proxypair.spec.js
index af6a5a6..59ad85a 100644
--- a/proxy/spec/proxypair.spec.js
+++ b/proxy/spec/proxypair.spec.js
@@ -1,17 +1,15 @@
-// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake proxypair
*/
-var MessageEvent, arrayMatching;
// Replacement for MessageEvent constructor.
// https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/MessageEvent
-MessageEvent = function(type, init) {
+var MessageEvent = function(type, init) {
return init;
};
// Asymmetic matcher that checks that two arrays have the same contents.
-arrayMatching = function(sample) {
+var arrayMatching = function(sample) {
return {
asymmetricMatch: function(other) {
var _, a, b, i, j, len;
@@ -35,46 +33,57 @@ arrayMatching = function(sample) {
};
describe('ProxyPair', function() {
+
var config, destination, fakeRelay, pp, rateLimit;
fakeRelay = Parse.address('0.0.0.0:12345');
rateLimit = new DummyRateLimit;
config = new Config;
destination = [];
+
// Using the mock PeerConnection definition from spec/snowflake.spec.coffee.
- pp = new ProxyPair(fakeRelay, rateLimit, config.pcConfig);
+ var pp = new ProxyPair(fakeRelay, rateLimit, config.pcConfig);
+
beforeEach(function() {
return pp.begin();
});
+
it('begins webrtc connection', function() {
return expect(pp.pc).not.toBeNull();
});
+
describe('accepts WebRTC offer from some client', function() {
+
beforeEach(function() {
return pp.begin();
});
+
it('rejects invalid offers', function() {
expect(typeof pp.pc.setRemoteDescription).toBe("function");
expect(pp.pc).not.toBeNull();
expect(pp.receiveWebRTCOffer({})).toBe(false);
- return expect(pp.receiveWebRTCOffer({
+ expect(pp.receiveWebRTCOffer({
type: 'answer'
})).toBe(false);
});
- return it('accepts valid offers', function() {
+
+ it('accepts valid offers', function() {
expect(pp.pc).not.toBeNull();
- return expect(pp.receiveWebRTCOffer({
+ expect(pp.receiveWebRTCOffer({
type: 'offer',
sdp: 'foo'
})).toBe(true);
});
+
});
+
it('responds with a WebRTC answer correctly', function() {
spyOn(snowflake.broker, 'sendAnswer');
pp.pc.onicecandidate({
candidate: null
});
- return expect(snowflake.broker.sendAnswer).toHaveBeenCalled();
+ expect(snowflake.broker.sendAnswer).toHaveBeenCalled();
});
+
it('handles a new data channel correctly', function() {
expect(pp.client).toBeNull();
pp.pc.ondatachannel({
@@ -84,21 +93,25 @@ describe('ProxyPair', function() {
expect(pp.client.onopen).not.toBeNull();
expect(pp.client.onclose).not.toBeNull();
expect(pp.client.onerror).not.toBeNull();
- return expect(pp.client.onmessage).not.toBeNull();
+ expect(pp.client.onmessage).not.toBeNull();
});
+
it('connects to the relay once datachannel opens', function() {
spyOn(pp, 'connectRelay');
pp.client.onopen();
- return expect(pp.connectRelay).toHaveBeenCalled();
+ expect(pp.connectRelay).toHaveBeenCalled();
});
+
it('connects to a relay', function() {
pp.connectRelay();
expect(pp.relay.onopen).not.toBeNull();
expect(pp.relay.onclose).not.toBeNull();
expect(pp.relay.onerror).not.toBeNull();
- return expect(pp.relay.onmessage).not.toBeNull();
+ expect(pp.relay.onmessage).not.toBeNull();
});
- return describe('flushes data between client and relay', function() {
+
+ describe('flushes data between client and relay', function() {
+
it('proxies data from client to relay', function() {
var msg;
pp.pc.ondatachannel({
@@ -116,8 +129,9 @@ describe('ProxyPair', function() {
pp.onClientToRelayMessage(msg);
pp.flush();
expect(pp.client.send).not.toHaveBeenCalled();
- return expect(pp.relay.send).toHaveBeenCalledWith(arrayMatching([1, 2, 3]));
+ expect(pp.relay.send).toHaveBeenCalledWith(arrayMatching([1, 2, 3]));
});
+
it('proxies data from relay to client', function() {
var msg;
spyOn(pp.client, 'send');
@@ -128,16 +142,19 @@ describe('ProxyPair', function() {
pp.onRelayToClientMessage(msg);
pp.flush();
expect(pp.client.send).toHaveBeenCalledWith(arrayMatching([4, 5, 6]));
- return expect(pp.relay.send).not.toHaveBeenCalled();
+ expect(pp.relay.send).not.toHaveBeenCalled();
});
- return it('sends nothing with nothing to flush', function() {
+
+ it('sends nothing with nothing to flush', function() {
spyOn(pp.client, 'send');
spyOn(pp.relay, 'send');
pp.flush();
expect(pp.client.send).not.toHaveBeenCalled();
- return expect(pp.relay.send).not.toHaveBeenCalled();
+ expect(pp.relay.send).not.toHaveBeenCalled();
});
+
});
+
});
// TODO: rate limit tests
diff --git a/proxy/spec/snowflake.spec.js b/proxy/spec/snowflake.spec.js
index d3fb988..eccc24d 100644
--- a/proxy/spec/snowflake.spec.js
+++ b/proxy/spec/snowflake.spec.js
@@ -1,62 +1,43 @@
-// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake
*/
-var FakeBroker, PeerConnection, SessionDescription, WebSocket, config, log, ui;
// Fake browser functionality:
-PeerConnection = class PeerConnection {
+class PeerConnection {
setRemoteDescription() {
return true;
}
-
send(data) {}
-
};
-SessionDescription = (function() {
- class SessionDescription {};
-
- SessionDescription.prototype.type = 'offer';
-
- return SessionDescription;
-
-}).call(this);
-
-WebSocket = (function() {
- class WebSocket {
- constructor() {
- this.bufferedAmount = 0;
- }
-
- send(data) {}
-
- };
-
- WebSocket.prototype.OPEN = 1;
-
- WebSocket.prototype.CLOSED = 0;
-
- return WebSocket;
+class SessionDescription {};
+SessionDescription.prototype.type = 'offer';
-}).call(this);
+class WebSocket {
+ constructor() {
+ this.bufferedAmount = 0;
+ }
+ send(data) {}
+};
+WebSocket.prototype.OPEN = 1;
+WebSocket.prototype.CLOSED = 0;
-log = function() {};
+var log = function() {};
-config = new Config;
+var config = new Config;
-ui = new UI;
+var ui = new UI;
-FakeBroker = class FakeBroker {
+class FakeBroker {
getClientOffer() {
return new Promise(function(F, R) {
return {};
});
}
-
};
describe('Snowflake', function() {
+
it('constructs correctly', function() {
var s;
s = new Snowflake(config, ui, {
@@ -67,22 +48,25 @@ describe('Snowflake', function() {
fake: 'broker'
});
expect(s.ui).not.toBeNull();
- return expect(s.retries).toBe(0);
+ expect(s.retries).toBe(0);
});
+
it('sets relay address correctly', function() {
var s;
s = new Snowflake(config, ui, null);
s.setRelayAddr('foo');
- return expect(s.relayAddr).toEqual('foo');
+ expect(s.relayAddr).toEqual('foo');
});
+
it('initalizes WebRTC connection', function() {
var s;
s = new Snowflake(config, ui, new FakeBroker());
spyOn(s.broker, 'getClientOffer').and.callThrough();
s.beginWebRTC();
expect(s.retries).toBe(1);
- return expect(s.broker.getClientOffer).toHaveBeenCalled();
+ expect(s.broker.getClientOffer).toHaveBeenCalled();
});
+
it('receives SDP offer and sends answer', function() {
var pair, s;
s = new Snowflake(config, ui, new FakeBroker());
@@ -92,8 +76,9 @@ describe('Snowflake', function() {
spyOn(pair, 'receiveWebRTCOffer').and.returnValue(true);
spyOn(s, 'sendAnswer');
s.receiveOffer(pair, '{"type":"offer","sdp":"foo"}');
- return expect(s.sendAnswer).toHaveBeenCalled();
+ expect(s.sendAnswer).toHaveBeenCalled();
});
+
it('does not send answer when receiving invalid offer', function() {
var pair, s;
s = new Snowflake(config, ui, new FakeBroker());
@@ -103,12 +88,14 @@ describe('Snowflake', function() {
spyOn(pair, 'receiveWebRTCOffer').and.returnValue(false);
spyOn(s, 'sendAnswer');
s.receiveOffer(pair, '{"type":"not a good offer","sdp":"foo"}');
- return expect(s.sendAnswer).not.toHaveBeenCalled();
+ expect(s.sendAnswer).not.toHaveBeenCalled();
});
- return it('can make a proxypair', function() {
+
+ it('can make a proxypair', function() {
var s;
s = new Snowflake(config, ui, new FakeBroker());
s.makeProxyPair();
- return expect(s.proxyPairs.length).toBe(1);
+ expect(s.proxyPairs.length).toBe(1);
});
+
});
diff --git a/proxy/spec/ui.spec.js b/proxy/spec/ui.spec.js
index 380f41a..8ae141f 100644
--- a/proxy/spec/ui.spec.js
+++ b/proxy/spec/ui.spec.js
@@ -1,10 +1,7 @@
-// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake UI
*/
-var document;
-
-document = {
+var document = {
getElementById: function(id) {
return {};
},
@@ -14,6 +11,7 @@ document = {
};
describe('UI', function() {
+
it('activates debug mode when badge does not exist', function() {
var u;
spyOn(document, 'getElementById').and.callFake(function(id) {
@@ -25,8 +23,9 @@ describe('UI', function() {
u = new DebugUI();
expect(document.getElementById.calls.count()).toEqual(2);
expect(u.$status).not.toBeNull();
- return expect(u.$msglog).not.toBeNull();
+ expect(u.$msglog).not.toBeNull();
});
+
it('is not debug mode when badge exists', function() {
var u;
spyOn(document, 'getElementById').and.callFake(function(id) {
@@ -38,8 +37,9 @@ describe('UI', function() {
u = new BadgeUI();
expect(document.getElementById).toHaveBeenCalled();
expect(document.getElementById.calls.count()).toEqual(1);
- return expect(u.$badge).not.toBeNull();
+ expect(u.$badge).not.toBeNull();
});
+
it('sets status message when in debug mode', function() {
var u;
u = new DebugUI();
@@ -50,16 +50,18 @@ describe('UI', function() {
}
};
u.setStatus('test');
- return expect(u.$status.innerHTML).toEqual('Status: test');
+ expect(u.$status.innerHTML).toEqual('Status: test');
});
+
it('sets message log css correctly for debug mode', function() {
var u;
u = new DebugUI();
u.setActive(true);
expect(u.$msglog.className).toEqual('active');
u.setActive(false);
- return expect(u.$msglog.className).toEqual('');
+ expect(u.$msglog.className).toEqual('');
});
+
it('sets badge css correctly for non-debug mode', function() {
var u;
u = new BadgeUI();
@@ -67,9 +69,10 @@ describe('UI', function() {
u.setActive(true);
expect(u.$badge.className).toEqual('active');
u.setActive(false);
- return expect(u.$badge.className).toEqual('');
+ expect(u.$badge.className).toEqual('');
});
- return it('logs to the textarea correctly when debug mode', function() {
+
+ it('logs to the textarea correctly when debug mode', function() {
var u;
u = new DebugUI();
u.$msglog = {
@@ -79,6 +82,7 @@ describe('UI', function() {
};
u.log('test');
expect(u.$msglog.value).toEqual('test\n');
- return expect(u.$msglog.scrollTop).toEqual(1337);
+ expect(u.$msglog.scrollTop).toEqual(1337);
});
+
});
diff --git a/proxy/spec/util.spec.js b/proxy/spec/util.spec.js
index 65f2324..c885b25 100644
--- a/proxy/spec/util.spec.js
+++ b/proxy/spec/util.spec.js
@@ -1,10 +1,12 @@
-// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake utils
*/
+
describe('Parse', function() {
+
describe('cookie', function() {
- return it('parses correctly', function() {
+
+ it('parses correctly', function() {
expect(Parse.cookie('')).toEqual({});
expect(Parse.cookie('a=b')).toEqual({
a: 'b'
@@ -30,12 +32,15 @@ describe('Parse', function() {
expect(Parse.cookie('key=%26%20')).toEqual({
key: '& '
});
- return expect(Parse.cookie('a=\'\'')).toEqual({
+ expect(Parse.cookie('a=\'\'')).toEqual({
a: '\'\''
});
});
+
});
+
describe('address', function() {
+
it('parses IPv4', function() {
expect(Parse.address('')).toBeNull();
expect(Parse.address('3.3.3.3:4444')).toEqual({
@@ -45,9 +50,10 @@ describe('Parse', function() {
expect(Parse.address('3.3.3.3')).toBeNull();
expect(Parse.address('3.3.3.3:0x1111')).toBeNull();
expect(Parse.address('3.3.3.3:-4444')).toBeNull();
- return expect(Parse.address('3.3.3.3:65536')).toBeNull();
+ expect(Parse.address('3.3.3.3:65536')).toBeNull();
});
- return it('parses IPv6', function() {
+
+ it('parses IPv6', function() {
expect(Parse.address('[1:2::a:f]:4444')).toEqual({
host: '1:2::a:f',
port: 4444
@@ -56,15 +62,17 @@ describe('Parse', function() {
expect(Parse.address('[1:2::a:f]:0x1111')).toBeNull();
expect(Parse.address('[1:2::a:f]:-4444')).toBeNull();
expect(Parse.address('[1:2::a:f]:65536')).toBeNull();
- return expect(Parse.address('[1:2::ffff:1.2.3.4]:4444')).toEqual({
+ expect(Parse.address('[1:2::ffff:1.2.3.4]:4444')).toEqual({
host: '1:2::ffff:1.2.3.4',
port: 4444
});
});
+
});
- return describe('ipFromSDP', function() {
- var testCases;
- testCases = [
+
+ describe('ipFromSDP', function() {
+
+ var testCases = [
{
// https://tools.ietf.org/html/rfc4566#section-5
sdp: "v=0\no=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\ns=SDP Seminar\ni=A Seminar on the session description protocol\nu=http://www.example.com/seminars/sdp.pdf\ne=j.doe@xxxxxxxxxxx (Jane Doe)\nc=IN IP4 224.2.17.12/127\nt=2873397496 2873404696\na=recvonly\nm=audio 49170 RTP/AVP 0\nm=video 51372 RTP/AVP 99\na=rtpmap:99 h263-1998/90000",
@@ -128,7 +136,8 @@ describe('Parse', function() {
expected: void 0
}
];
- return it('parses SDP', function() {
+
+ it('parses SDP', function() {
var i, len, ref, ref1, results, test;
results = [];
for (i = 0, len = testCases.length; i < len; i++) {
@@ -143,10 +152,13 @@ describe('Parse', function() {
}
return results;
});
+
});
+
});
describe('query string', function() {
+
it('should parse correctly', function() {
expect(Query.parse('')).toEqual({});
expect(Query.parse('a=b')).toEqual({
@@ -178,11 +190,12 @@ describe('query string', function() {
expect(Query.parse('a+b=c')).toEqual({
'a b': 'c'
});
- return expect(Query.parse('a=b+c+d')).toEqual({
+ expect(Query.parse('a=b+c+d')).toEqual({
a: 'b c d'
});
});
- return it('uses the first appearance of duplicate key', function() {
+
+ it('uses the first appearance of duplicate key', function() {
expect(Query.parse('a=b&c=d&a=e')).toEqual({
a: 'b',
c: 'd'
@@ -201,21 +214,24 @@ describe('query string', function() {
a: 'b',
'': ''
});
- return expect(Query.parse('a=b&&c=d')).toEqual({
+ expect(Query.parse('a=b&&c=d')).toEqual({
a: 'b',
'': '',
c: 'd'
});
});
+
});
describe('Params', function() {
+
describe('bool', function() {
- var getBool;
- getBool = function(query) {
+
+ var getBool = function(query) {
return Params.getBool(Query.parse(query), 'param', false);
};
- return it('parses correctly', function() {
+
+ it('parses correctly', function() {
expect(getBool('param=true')).toBe(true);
expect(getBool('param')).toBe(true);
expect(getBool('param=')).toBe(true);
@@ -223,19 +239,23 @@ describe('Params', function() {
expect(getBool('param=0')).toBe(false);
expect(getBool('param=false')).toBe(false);
expect(getBool('param=unexpected')).toBeNull();
- return expect(getBool('pram=true')).toBe(false);
+ expect(getBool('pram=true')).toBe(false);
});
+
});
- return describe('address', function() {
- var DEFAULT, getAddress;
- DEFAULT = {
+
+ describe('address', function() {
+
+ var DEFAULT = {
host: '1.1.1.1',
port: 2222
};
- getAddress = function(query) {
+
+ var getAddress = function(query) {
return Params.getAddress(query, 'addr', DEFAULT);
};
- return it('parses correctly', function() {
+
+ it('parses correctly', function() {
expect(getAddress({})).toEqual(DEFAULT);
expect(getAddress({
addr: '3.3.3.3:4444'
@@ -246,9 +266,11 @@ describe('Params', function() {
expect(getAddress({
x: '3.3.3.3:4444'
})).toEqual(DEFAULT);
- return expect(getAddress({
+ expect(getAddress({
addr: '---'
})).toBeNull();
});
+
});
+
});
diff --git a/proxy/spec/websocket.spec.js b/proxy/spec/websocket.spec.js
index 41314df..370995a 100644
--- a/proxy/spec/websocket.spec.js
+++ b/proxy/spec/websocket.spec.js
@@ -1,32 +1,39 @@
-// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake websocket
*/
+
describe('BuildUrl', function() {
+
it('should parse just protocol and host', function() {
- return expect(WS.buildUrl('http', 'example.com')).toBe('http://example.com');
+ expect(WS.buildUrl('http', 'example.com')).toBe('http://example.com');
});
+
it('should handle different ports', function() {
expect(WS.buildUrl('http', 'example.com', 80)).toBe('http://example.com');
expect(WS.buildUrl('http', 'example.com', 81)).toBe('http://example.com:81');
expect(WS.buildUrl('http', 'example.com', 443)).toBe('http://example.com:443');
- return expect(WS.buildUrl('http', 'example.com', 444)).toBe('http://example.com:444');
+ expect(WS.buildUrl('http', 'example.com', 444)).toBe('http://example.com:444');
});
+
it('should handle paths', function() {
expect(WS.buildUrl('http', 'example.com', 80, '/')).toBe('http://example.com/');
expect(WS.buildUrl('http', 'example.com', 80, '/test?k=%#v')).toBe('http://example.com/test%3Fk%3D%25%23v');
- return expect(WS.buildUrl('http', 'example.com', 80, '/test')).toBe('http://example.com/test');
+ expect(WS.buildUrl('http', 'example.com', 80, '/test')).toBe('http://example.com/test');
});
+
it('should handle params', function() {
expect(WS.buildUrl('http', 'example.com', 80, '/test', [['k', '%#v']])).toBe('http://example.com/test?k=%25%23v');
- return expect(WS.buildUrl('http', 'example.com', 80, '/test', [['a', 'b'], ['c', 'd']])).toBe('http://example.com/test?a=b&c=d');
+ expect(WS.buildUrl('http', 'example.com', 80, '/test', [['a', 'b'], ['c', 'd']])).toBe('http://example.com/test?a=b&c=d');
});
+
it('should handle ips', function() {
expect(WS.buildUrl('http', '1.2.3.4')).toBe('http://1.2.3.4');
- return expect(WS.buildUrl('http', '1:2::3:4')).toBe('http://[1:2::3:4]');
+ expect(WS.buildUrl('http', '1:2::3:4')).toBe('http://[1:2::3:4]');
});
- return it('should handle bogus', function() {
+
+ it('should handle bogus', function() {
expect(WS.buildUrl('http', 'bog][us')).toBe('http://bog%5D%5Bus');
- return expect(WS.buildUrl('http', 'bog:u]s')).toBe('http://bog%3Au%5Ds');
+ expect(WS.buildUrl('http', 'bog:u]s')).toBe('http://bog%3Au%5Ds');
});
+
});
diff --git a/proxy/ui.js b/proxy/ui.js
index b3f0ae1..da14800 100644
--- a/proxy/ui.js
+++ b/proxy/ui.js
@@ -1,197 +1,178 @@
-// Generated by CoffeeScript 2.4.1
- /*
- All of Snowflake's DOM manipulation and inputs.
- */
-var BadgeUI, DebugUI, UI, WebExtUI,
- boundMethodCheck = function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } };
-
-UI = (function() {
- class UI {
- setStatus(msg) {}
-
- setActive(connected) {
- return this.active = connected;
- }
+/*
+All of Snowflake's DOM manipulation and inputs.
+*/
- log(msg) {}
+class UI {
- };
+ setStatus(msg) {}
- UI.prototype.active = false;
+ setActive(connected) {
+ return this.active = connected;
+ }
- UI.prototype.enabled = true;
+ log(msg) {}
- return UI;
+};
-}).call(this);
+UI.prototype.active = false;
-BadgeUI = (function() {
- class BadgeUI extends UI {
- constructor() {
- super();
- this.$badge = document.getElementById('badge');
- }
+UI.prototype.enabled = true;
- setActive(connected) {
- super.setActive(connected);
- return this.$badge.className = connected ? 'active' : '';
- }
- };
+class BadgeUI extends UI {
- BadgeUI.prototype.$badge = null;
+ constructor() {
+ super();
+ this.$badge = document.getElementById('badge');
+ }
- return BadgeUI;
+ setActive(connected) {
+ super.setActive(connected);
+ return this.$badge.className = connected ? 'active' : '';
+ }
-}).call(this);
+};
-DebugUI = (function() {
- class DebugUI extends UI {
- constructor() {
- super();
- // Setup other DOM handlers if it's debug mode.
- this.$status = document.getElementById('status');
- this.$msglog = document.getElementById('msglog');
- this.$msglog.value = '';
- }
+BadgeUI.prototype.$badge = null;
- // Status bar
- setStatus(msg) {
- var txt;
- txt = document.createTextNode('Status: ' + msg);
- while (this.$status.firstChild) {
- this.$status.removeChild(this.$status.firstChild);
- }
- return this.$status.appendChild(txt);
- }
- setActive(connected) {
- super.setActive(connected);
- return this.$msglog.className = connected ? 'active' : '';
- }
+class DebugUI extends UI {
- log(msg) {
- // Scroll to latest
- this.$msglog.value += msg + '\n';
- return this.$msglog.scrollTop = this.$msglog.scrollHeight;
- }
+ constructor() {
+ super();
+ // Setup other DOM handlers if it's debug mode.
+ this.$status = document.getElementById('status');
+ this.$msglog = document.getElementById('msglog');
+ this.$msglog.value = '';
+ }
- };
+ // Status bar
+ setStatus(msg) {
+ var txt;
+ txt = document.createTextNode('Status: ' + msg);
+ while (this.$status.firstChild) {
+ this.$status.removeChild(this.$status.firstChild);
+ }
+ return this.$status.appendChild(txt);
+ }
- // DOM elements references.
- DebugUI.prototype.$msglog = null;
+ setActive(connected) {
+ super.setActive(connected);
+ return this.$msglog.className = connected ? 'active' : '';
+ }
- DebugUI.prototype.$status = null;
+ log(msg) {
+ // Scroll to latest
+ this.$msglog.value += msg + '\n';
+ return this.$msglog.scrollTop = this.$msglog.scrollHeight;
+ }
- return DebugUI;
+};
-}).call(this);
+// DOM elements references.
+DebugUI.prototype.$msglog = null;
-WebExtUI = (function() {
- class WebExtUI extends UI {
- constructor() {
- super();
- this.onConnect = this.onConnect.bind(this);
- this.onMessage = this.onMessage.bind(this);
- this.onDisconnect = this.onDisconnect.bind(this);
- this.initStats();
- chrome.runtime.onConnect.addListener(this.onConnect);
- }
+DebugUI.prototype.$status = null;
- initStats() {
- this.stats = [0];
- return setInterval((() => {
- this.stats.unshift(0);
- this.stats.splice(24);
- return this.postActive();
- }), 60 * 60 * 1000);
- }
- initToggle() {
- var getting;
- return getting = chrome.storage.local.get("snowflake-enabled", (result) => {
- if (result['snowflake-enabled'] !== void 0) {
- this.enabled = result['snowflake-enabled'];
- } else {
- log("Toggle state not yet saved");
- }
- return this.setEnabled(this.enabled);
- });
- }
+class WebExtUI extends UI {
- postActive() {
- var ref;
- return (ref = this.port) != null ? ref.postMessage({
- active: this.active,
- total: this.stats.reduce((function(t, c) {
- return t + c;
- }), 0),
- enabled: this.enabled
- }) : void 0;
- }
+ constructor() {
+ super();
+ this.onConnect = this.onConnect.bind(this);
+ this.onMessage = this.onMessage.bind(this);
+ this.onDisconnect = this.onDisconnect.bind(this);
+ this.initStats();
+ chrome.runtime.onConnect.addListener(this.onConnect);
+ }
- onConnect(port) {
- boundMethodCheck(this, WebExtUI);
- this.port = port;
- port.onDisconnect.addListener(this.onDisconnect);
- port.onMessage.addListener(this.onMessage);
+ initStats() {
+ this.stats = [0];
+ return setInterval((() => {
+ this.stats.unshift(0);
+ this.stats.splice(24);
return this.postActive();
- }
-
- onMessage(m) {
- var storing;
- boundMethodCheck(this, WebExtUI);
- this.enabled = m.enabled;
- this.setEnabled(this.enabled);
- this.postActive();
- return storing = chrome.storage.local.set({
- "snowflake-enabled": this.enabled
- }, function() {
- return log("Stored toggle state");
- });
- }
-
- onDisconnect(port) {
- boundMethodCheck(this, WebExtUI);
- return this.port = null;
- }
-
- setActive(connected) {
- super.setActive(connected);
- if (connected) {
- this.stats[0] += 1;
- }
- this.postActive();
- if (this.active) {
- return chrome.browserAction.setIcon({
- path: {
- 32: "icons/status-running.png"
- }
- });
+ }), 60 * 60 * 1000);
+ }
+
+ initToggle() {
+ var getting;
+ return getting = chrome.storage.local.get("snowflake-enabled", (result) => {
+ if (result['snowflake-enabled'] !== void 0) {
+ this.enabled = result['snowflake-enabled'];
} else {
- return chrome.browserAction.setIcon({
- path: {
- 32: "icons/status-on.png"
- }
- });
+ log("Toggle state not yet saved");
}
- }
-
- setEnabled(enabled) {
- update();
+ return this.setEnabled(this.enabled);
+ });
+ }
+
+ postActive() {
+ var ref;
+ return (ref = this.port) != null ? ref.postMessage({
+ active: this.active,
+ total: this.stats.reduce((function(t, c) {
+ return t + c;
+ }), 0),
+ enabled: this.enabled
+ }) : void 0;
+ }
+
+ onConnect(port) {
+ this.port = port;
+ port.onDisconnect.addListener(this.onDisconnect);
+ port.onMessage.addListener(this.onMessage);
+ return this.postActive();
+ }
+
+ onMessage(m) {
+ var storing;
+ this.enabled = m.enabled;
+ this.setEnabled(this.enabled);
+ this.postActive();
+ return storing = chrome.storage.local.set({
+ "snowflake-enabled": this.enabled
+ }, function() {
+ return log("Stored toggle state");
+ });
+ }
+
+ onDisconnect(port) {
+ return this.port = null;
+ }
+
+ setActive(connected) {
+ super.setActive(connected);
+ if (connected) {
+ this.stats[0] += 1;
+ }
+ this.postActive();
+ if (this.active) {
return chrome.browserAction.setIcon({
path: {
- 32: "icons/status-" + (enabled ? "on" : "off") + ".png"
+ 32: "icons/status-running.png"
+ }
+ });
+ } else {
+ return chrome.browserAction.setIcon({
+ path: {
+ 32: "icons/status-on.png"
}
});
}
+ }
- };
-
- WebExtUI.prototype.port = null;
+ setEnabled(enabled) {
+ update();
+ return chrome.browserAction.setIcon({
+ path: {
+ 32: "icons/status-" + (enabled ? "on" : "off") + ".png"
+ }
+ });
+ }
- WebExtUI.prototype.stats = null;
+};
- return WebExtUI;
+WebExtUI.prototype.port = null;
-}).call(this);
+WebExtUI.prototype.stats = null;
diff --git a/proxy/util.js b/proxy/util.js
index 1feeb5d..328fd9b 100644
--- a/proxy/util.js
+++ b/proxy/util.js
@@ -1,53 +1,54 @@
-// Generated by CoffeeScript 2.4.1
/*
A Coffeescript WebRTC snowflake proxy
Contains helpers for parsing query strings and other utilities.
*/
-var BucketRateLimit, DummyRateLimit, Params, Parse, Query, Util;
-Util = (function() {
- class Util {
- static mightBeTBB() {
- return Util.TBB_UAS.indexOf(window.navigator.userAgent) > -1 && (window.navigator.mimeTypes && window.navigator.mimeTypes.length === 0);
- }
+class Util {
- static genSnowflakeID() {
- return Math.random().toString(36).substring(2);
- }
+ static mightBeTBB() {
+ return Util.TBB_UAS.indexOf(window.navigator.userAgent) > -1 && (window.navigator.mimeTypes && window.navigator.mimeTypes.length === 0);
+ }
- static snowflakeIsDisabled(cookieName) {
- var cookies;
- cookies = Parse.cookie(document.cookie);
- // Do nothing if snowflake has not been opted in by user.
- if (cookies[cookieName] !== '1') {
- log('Not opted-in. Please click the badge to change options.');
- return true;
- }
- // Also do nothing if running in Tor Browser.
- if (Util.mightBeTBB()) {
- log('Will not run within Tor Browser.');
- return true;
- }
- return false;
- }
+ static genSnowflakeID() {
+ return Math.random().toString(36).substring(2);
+ }
- static featureDetect() {
- return typeof PeerConnection === 'function';
+ static snowflakeIsDisabled(cookieName) {
+ var cookies;
+ cookies = Parse.cookie(document.cookie);
+ // Do nothing if snowflake has not been opted in by user.
+ if (cookies[cookieName] !== '1') {
+ log('Not opted-in. Please click the badge to change options.');
+ return true;
+ }
+ // Also do nothing if running in Tor Browser.
+ if (Util.mightBeTBB()) {
+ log('Will not run within Tor Browser.');
+ return true;
}
+ return false;
+ }
+
+ static featureDetect() {
+ return typeof PeerConnection === 'function';
+ }
- };
+};
- // It would not be effective for Tor Browser users to run the proxy.
- // Do we seem to be running in Tor Browser? Check the user-agent string and for
- // no listing of supported MIME types.
- Util.TBB_UAS = ['Mozilla/5.0 (Windows NT 6.1; rv:10.0) Gecko/20100101 Firefox/10.0', 'Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20100101 Firefox/17.0', 'Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.0', 'Mozilla/5.0 (Windows NT 6.1; rv:31.0) Gecko/20100101 Firefox/31.0'];
+// It would not be effective for Tor Browser users to run the proxy.
+// Do we seem to be running in Tor Browser? Check the user-agent string and for
+// no listing of supported MIME types.
+Util.TBB_UAS = [
+ 'Mozilla/5.0 (Windows NT 6.1; rv:10.0) Gecko/20100101 Firefox/10.0',
+ 'Mozilla/5.0 (Windows NT 6.1; rv:17.0) Gecko/20100101 Firefox/17.0',
+ 'Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.0',
+ 'Mozilla/5.0 (Windows NT 6.1; rv:31.0) Gecko/20100101 Firefox/31.0'
+];
- return Util;
-}).call(this);
+class Query {
-Query = class Query {
/*
Parse a URL query string or application/x-www-form-urlencoded body. The
return type is an object mapping string keys to string values. By design,
@@ -100,7 +101,9 @@ Query = class Query {
};
-Parse = class Parse {
+
+class Parse {
+
// Parse a cookie data string (usually document.cookie). The return type is an
// object mapping cookies names to values. Returns null on error.
// http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-8747038
@@ -202,7 +205,9 @@ Parse = class Parse {
};
-Params = class Params {
+
+class Params {
+
static getBool(query, param, defaultValue) {
var val;
val = query[param];
@@ -254,53 +259,52 @@ Params = class Params {
};
-BucketRateLimit = (function() {
- class BucketRateLimit {
- constructor(capacity, time) {
- this.capacity = capacity;
- this.time = time;
- }
- age() {
- var delta, now;
- now = new Date();
- delta = (now - this.lastUpdate) / 1000.0;
- this.lastUpdate = now;
- this.amount -= delta * this.capacity / this.time;
- if (this.amount < 0.0) {
- return this.amount = 0.0;
- }
- }
+class BucketRateLimit {
- update(n) {
- this.age();
- this.amount += n;
- return this.amount <= this.capacity;
- }
+ constructor(capacity, time) {
+ this.capacity = capacity;
+ this.time = time;
+ }
- // How many seconds in the future will the limit expire?
- when() {
- this.age();
- return (this.amount - this.capacity) / (this.capacity / this.time);
+ age() {
+ var delta, now;
+ now = new Date();
+ delta = (now - this.lastUpdate) / 1000.0;
+ this.lastUpdate = now;
+ this.amount -= delta * this.capacity / this.time;
+ if (this.amount < 0.0) {
+ return this.amount = 0.0;
}
+ }
- isLimited() {
- this.age();
- return this.amount > this.capacity;
- }
+ update(n) {
+ this.age();
+ this.amount += n;
+ return this.amount <= this.capacity;
+ }
- };
+ // How many seconds in the future will the limit expire?
+ when() {
+ this.age();
+ return (this.amount - this.capacity) / (this.capacity / this.time);
+ }
- BucketRateLimit.prototype.amount = 0.0;
+ isLimited() {
+ this.age();
+ return this.amount > this.capacity;
+ }
+
+};
- BucketRateLimit.prototype.lastUpdate = new Date();
+BucketRateLimit.prototype.amount = 0.0;
- return BucketRateLimit;
+BucketRateLimit.prototype.lastUpdate = new Date();
-}).call(this);
// A rate limiter that never limits.
-DummyRateLimit = class DummyRateLimit {
+class DummyRateLimit {
+
constructor(capacity, time) {
this.capacity = capacity;
this.time = time;
diff --git a/proxy/websocket.js b/proxy/websocket.js
index 9d4ec60..2a124aa 100644
--- a/proxy/websocket.js
+++ b/proxy/websocket.js
@@ -1,70 +1,64 @@
-// Generated by CoffeeScript 2.4.1
/*
Only websocket-specific stuff.
*/
-var WS;
-WS = (function() {
- class WS {
- // Build an escaped URL string from unescaped components. Only scheme and host
- // are required. See RFC 3986, section 3.
- static buildUrl(scheme, host, port, path, params) {
- var parts;
- parts = [];
- parts.push(encodeURIComponent(scheme));
- parts.push('://');
- // If it contains a colon but no square brackets, treat it as IPv6.
- if (host.match(/:/) && !host.match(/[[\]]/)) {
- parts.push('[');
- parts.push(host);
- parts.push(']');
- } else {
- parts.push(encodeURIComponent(host));
- }
- if (void 0 !== port && this.DEFAULT_PORTS[scheme] !== port) {
- parts.push(':');
- parts.push(encodeURIComponent(port.toString()));
- }
- if (void 0 !== path && '' !== path) {
- if (!path.match(/^\//)) {
- path = '/' + path;
- }
- path = path.replace(/[^\/]+/, function(m) {
- return encodeURIComponent(m);
- });
- parts.push(path);
- }
- if (void 0 !== params) {
- parts.push('?');
- parts.push(Query.buildString(params));
+class WS {
+
+ // Build an escaped URL string from unescaped components. Only scheme and host
+ // are required. See RFC 3986, section 3.
+ static buildUrl(scheme, host, port, path, params) {
+ var parts;
+ parts = [];
+ parts.push(encodeURIComponent(scheme));
+ parts.push('://');
+ // If it contains a colon but no square brackets, treat it as IPv6.
+ if (host.match(/:/) && !host.match(/[[\]]/)) {
+ parts.push('[');
+ parts.push(host);
+ parts.push(']');
+ } else {
+ parts.push(encodeURIComponent(host));
+ }
+ if (void 0 !== port && this.DEFAULT_PORTS[scheme] !== port) {
+ parts.push(':');
+ parts.push(encodeURIComponent(port.toString()));
+ }
+ if (void 0 !== path && '' !== path) {
+ if (!path.match(/^\//)) {
+ path = '/' + path;
}
- return parts.join('');
+ path = path.replace(/[^\/]+/, function(m) {
+ return encodeURIComponent(m);
+ });
+ parts.push(path);
}
-
- static makeWebsocket(addr, params) {
- var url, ws, wsProtocol;
- wsProtocol = this.WSS_ENABLED ? 'wss' : 'ws';
- url = this.buildUrl(wsProtocol, addr.host, addr.port, '/', params);
- ws = new WebSocket(url);
- /*
- 'User agents can use this as a hint for how to handle incoming binary data:
- if the attribute is set to 'blob', it is safe to spool it to disk, and if it
- is set to 'arraybuffer', it is likely more efficient to keep the data in
- memory.'
- */
- ws.binaryType = 'arraybuffer';
- return ws;
+ if (void 0 !== params) {
+ parts.push('?');
+ parts.push(Query.buildString(params));
}
+ return parts.join('');
+ }
- };
-
- WS.WSS_ENABLED = true;
+ static makeWebsocket(addr, params) {
+ var url, ws, wsProtocol;
+ wsProtocol = this.WSS_ENABLED ? 'wss' : 'ws';
+ url = this.buildUrl(wsProtocol, addr.host, addr.port, '/', params);
+ ws = new WebSocket(url);
+ /*
+ 'User agents can use this as a hint for how to handle incoming binary data:
+ if the attribute is set to 'blob', it is safe to spool it to disk, and if it
+ is set to 'arraybuffer', it is likely more efficient to keep the data in
+ memory.'
+ */
+ ws.binaryType = 'arraybuffer';
+ return ws;
+ }
- WS.DEFAULT_PORTS = {
- http: 80,
- https: 443
- };
+};
- return WS;
+WS.WSS_ENABLED = true;
-}).call(this);
+WS.DEFAULT_PORTS = {
+ http: 80,
+ https: 443
+};
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits