Loading broker.js +2 −1 Original line number Diff line number Diff line Loading @@ -67,11 +67,12 @@ class Broker { this._xhr = xhr; // Used by spec to fake async Broker interaction const clients = Math.floor(numClientsConnected / 8) * 8; var data = { Version: "1.2", Version: "1.3", Sid: id, Type: this.config.proxyType, NAT: this.natType, Clients: clients, AcceptedRelayPattern: this.config.allowedRelayPattern, }; return this._postRequest(xhr, 'proxy', JSON.stringify(data)); }); Loading config.js +2 −0 Original line number Diff line number Diff line Loading @@ -51,3 +51,5 @@ Config.prototype.pcConfig = { }; Config.PROBEURL = "https://snowflake-broker.freehaven.net:8443/probe"; Config.prototype.allowedRelayPattern="snowflake.torproject.net"; No newline at end of file proxypair.js +12 −4 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ class ProxyPair { this.onError = this.onError.bind(this); this.flush = this.flush.bind(this); this.relayURL = undefined; this.relayAddr = relayAddr; this.rateLimit = rateLimit; this.config = config; Loading Loading @@ -112,7 +113,10 @@ class ProxyPair { if (peer_ip != null) { params.push(["client_ip", peer_ip]); } var relay = this.relay = WS.makeWebsocket(this.relayAddr, params); var relay = this.relay = (this.relayURL === undefined) ? WS.makeWebsocket(this.relayAddr, params) : WS.makeWebsocketFromURL(this.relayURL, params); this.relay.label = 'websocket-relay'; this.relay.onopen = () => { if (this.timer) { Loading Loading @@ -248,6 +252,10 @@ class ProxyPair { return (null !== this.pc) && ('closed' !== this.pc.connectionState); } setRelayURL(relayURL) { this.relayURL = relayURL; } } ProxyPair.prototype.MAX_BUFFER = 10 * 1024 * 1024; Loading snowflake.js +53 −12 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ class Snowflake { recv = this.broker.getClientOffer(pair.id, this.proxyPairs.length); recv.then((resp) => { var clientNAT = resp.NAT; if (!this.receiveOffer(pair, resp.Offer)) { if (!this.receiveOffer(pair, resp.Offer, resp.RelayURL)) { return pair.close(); } //set a timeout for channel creation Loading Loading @@ -114,9 +114,24 @@ class Snowflake { // Receive an SDP offer from some client assigned by the Broker, // |pair| - an available ProxyPair. receiveOffer(pair, desc) { receiveOffer(pair, desc, relayURL) { var e, offer, sdp; try { if (relayURL !== undefined) { let relayURLParsed = new URL(relayURL); let hostname = relayURLParsed.hostname; let protocol = relayURLParsed.protocol; if (protocol !== "wss:") { log('incorrect relay url protocol'); return false; } if (!this.checkRelayPattern(this.config.allowedRelayPattern, hostname)) { log('relay url hostname does not match allowed pattern'); return false; } pair.setRelayURL(relayURL); } offer = JSON.parse(desc); dbg('Received:\n\n' + offer.sdp + '\n'); sdp = new RTCSessionDescription(offer); Loading Loading @@ -182,6 +197,32 @@ class Snowflake { return results; } /** * checkRelayPattern match str against patten * @param {string} pattern * @param {string} str typically a domain name to be checked * @return {boolean} */ checkRelayPattern(pattern, str) { if (typeof pattern !== "string") { throw 'invalid checkRelayPattern input: pattern'; } if (typeof str !== "string") { throw 'invalid checkRelayPattern input: str'; } let exactMatch = false; if (pattern.charAt(0) === "^") { exactMatch = true; pattern = pattern.substring(1); } if (exactMatch) { return pattern.localeCompare(str) === 0; } return str.endsWith(pattern); } } Snowflake.prototype.relayAddr = null; Loading websocket.js +25 −1 Original line number Diff line number Diff line Loading @@ -54,6 +54,30 @@ class WS { return ws; } /** * Creates a websocket connection from a URL and params to override * @param {URL|string} url * @param {URLSearchParams|string[][]} params * @return {WebSocket} */ static makeWebsocketFromURL(url, params) { let parsedURL = new URL(url); let urlpa = new URLSearchParams(params); urlpa.forEach(function (value, key) { parsedURL.searchParams.set(key, value); }); let 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; } static probeWebsocket(addr) { return new Promise((resolve, reject) => { const ws = WS.makeWebsocket(addr); Loading Loading
broker.js +2 −1 Original line number Diff line number Diff line Loading @@ -67,11 +67,12 @@ class Broker { this._xhr = xhr; // Used by spec to fake async Broker interaction const clients = Math.floor(numClientsConnected / 8) * 8; var data = { Version: "1.2", Version: "1.3", Sid: id, Type: this.config.proxyType, NAT: this.natType, Clients: clients, AcceptedRelayPattern: this.config.allowedRelayPattern, }; return this._postRequest(xhr, 'proxy', JSON.stringify(data)); }); Loading
config.js +2 −0 Original line number Diff line number Diff line Loading @@ -51,3 +51,5 @@ Config.prototype.pcConfig = { }; Config.PROBEURL = "https://snowflake-broker.freehaven.net:8443/probe"; Config.prototype.allowedRelayPattern="snowflake.torproject.net"; No newline at end of file
proxypair.js +12 −4 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ class ProxyPair { this.onError = this.onError.bind(this); this.flush = this.flush.bind(this); this.relayURL = undefined; this.relayAddr = relayAddr; this.rateLimit = rateLimit; this.config = config; Loading Loading @@ -112,7 +113,10 @@ class ProxyPair { if (peer_ip != null) { params.push(["client_ip", peer_ip]); } var relay = this.relay = WS.makeWebsocket(this.relayAddr, params); var relay = this.relay = (this.relayURL === undefined) ? WS.makeWebsocket(this.relayAddr, params) : WS.makeWebsocketFromURL(this.relayURL, params); this.relay.label = 'websocket-relay'; this.relay.onopen = () => { if (this.timer) { Loading Loading @@ -248,6 +252,10 @@ class ProxyPair { return (null !== this.pc) && ('closed' !== this.pc.connectionState); } setRelayURL(relayURL) { this.relayURL = relayURL; } } ProxyPair.prototype.MAX_BUFFER = 10 * 1024 * 1024; Loading
snowflake.js +53 −12 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ class Snowflake { recv = this.broker.getClientOffer(pair.id, this.proxyPairs.length); recv.then((resp) => { var clientNAT = resp.NAT; if (!this.receiveOffer(pair, resp.Offer)) { if (!this.receiveOffer(pair, resp.Offer, resp.RelayURL)) { return pair.close(); } //set a timeout for channel creation Loading Loading @@ -114,9 +114,24 @@ class Snowflake { // Receive an SDP offer from some client assigned by the Broker, // |pair| - an available ProxyPair. receiveOffer(pair, desc) { receiveOffer(pair, desc, relayURL) { var e, offer, sdp; try { if (relayURL !== undefined) { let relayURLParsed = new URL(relayURL); let hostname = relayURLParsed.hostname; let protocol = relayURLParsed.protocol; if (protocol !== "wss:") { log('incorrect relay url protocol'); return false; } if (!this.checkRelayPattern(this.config.allowedRelayPattern, hostname)) { log('relay url hostname does not match allowed pattern'); return false; } pair.setRelayURL(relayURL); } offer = JSON.parse(desc); dbg('Received:\n\n' + offer.sdp + '\n'); sdp = new RTCSessionDescription(offer); Loading Loading @@ -182,6 +197,32 @@ class Snowflake { return results; } /** * checkRelayPattern match str against patten * @param {string} pattern * @param {string} str typically a domain name to be checked * @return {boolean} */ checkRelayPattern(pattern, str) { if (typeof pattern !== "string") { throw 'invalid checkRelayPattern input: pattern'; } if (typeof str !== "string") { throw 'invalid checkRelayPattern input: str'; } let exactMatch = false; if (pattern.charAt(0) === "^") { exactMatch = true; pattern = pattern.substring(1); } if (exactMatch) { return pattern.localeCompare(str) === 0; } return str.endsWith(pattern); } } Snowflake.prototype.relayAddr = null; Loading
websocket.js +25 −1 Original line number Diff line number Diff line Loading @@ -54,6 +54,30 @@ class WS { return ws; } /** * Creates a websocket connection from a URL and params to override * @param {URL|string} url * @param {URLSearchParams|string[][]} params * @return {WebSocket} */ static makeWebsocketFromURL(url, params) { let parsedURL = new URL(url); let urlpa = new URLSearchParams(params); urlpa.forEach(function (value, key) { parsedURL.searchParams.set(key, value); }); let 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; } static probeWebsocket(addr) { return new Promise((resolve, reject) => { const ws = WS.makeWebsocket(addr); Loading