/// /// /// /// import arraybuffers = require('../../../../third_party/uproxy-lib/arraybuffers/arraybuffers'); import rtc_to_net = require('../../rtc-to-net/rtc-to-net'); import socks_to_rtc = require('../../socks-to-rtc/socks-to-rtc'); import net = require('../../net/net.types'); import signals = require('../../../../third_party/uproxy-lib/webrtc/signals'); import logging = require('../../../../third_party/uproxy-lib/logging/logging'); import loggingTypes = require('../../../../third_party/uproxy-lib/loggingprovider/loggingprovider.types'); // Set each module to info, warn, error, or debug depending on which module // you're debugging. Since the proxy outputs quite a lot of messages, show only // warnings by default from the rest of the system. Note that the proxy is // extremely slow in debug mode. freedom['loggingcontroller']().setDefaultFilter(loggingTypes.Destination.console, loggingTypes.Level.info); freedom['loggingcontroller']().setFilters(loggingTypes.Destination.console, { 'SocksToRtc': loggingTypes.Level.info, 'RtcToNet': loggingTypes.Level.info }); var log :logging.Log = new logging.Log('copypaste-socks'); var pgp :PgpProvider = freedom['pgp'](); var friendKey :string; // TODO interactive setup w/real passphrase pgp.setup('', 'uProxy user '); var parentModule = freedom(); pgp.exportKey().then((publicKey:string) => { parentModule.emit('publicKeyExport', publicKey); }); var pcConfig :freedom_RTCPeerConnection.RTCConfiguration = { iceServers: [{urls: ['stun:stun.l.google.com:19302']}, {urls: ['stun:stun1.l.google.com:19302']}] }; // These two modules together comprise a SOCKS server: // - socks-to-rtc is the frontend, which speaks the SOCKS protocol // - rtc-to-net creates sockets on behalf of socks-to-rtc // // The two modules communicate via a peer-to-peer connection. // // If we receive the 'start' signal from the UI then we create a // socks-to-rtc module and this app will run the SOCKS frontend. // If we receive signalling channel messages without having received // the 'start' signal then we create an rtc-to-net instance and // will act as the SOCKS backend. var socksRtc:socks_to_rtc.SocksToRtc; var rtcNet:rtc_to_net.RtcToNet; parentModule.on('start', () => { var localhostEndpoint:net.Endpoint = { address: '127.0.0.1', port: 9999 }; socksRtc = new socks_to_rtc.SocksToRtc(); // Forward signalling channel messages to the UI. socksRtc.on('signalForPeer', (signal:any) => { parentModule.emit('signalForPeer', signal); }); // SocksToRtc adds the number of bytes it sends/receives to its respective // queue as it proxies. When new numbers (of bytes) are added to these queues, // emit the number to the UI (look for corresponding freedom.on in main.html). socksRtc.on('bytesReceivedFromPeer', (numBytes:number) => { parentModule.emit('bytesReceived', numBytes); }); socksRtc.on('bytesSentToPeer', (numBytes:number) => { parentModule.emit('bytesSent', numBytes); }); socksRtc.on('stopped', () => { parentModule.emit('proxyingStopped'); }); socksRtc.startFromConfig( localhostEndpoint, pcConfig, false) // obfuscate .then((endpoint:net.Endpoint) => { log.info('socksRtc ready. listening to SOCKS5 on: ' + JSON.stringify(endpoint)); log.info('` curl -x socks5h://localhost:9999 www.google.com `') parentModule.emit('proxyingStarted', endpoint); }) .catch((e) => { console.error('socksRtc Error: ' + e + '; ' + this.socksRtc.toString()); }); log.info('created socks-to-rtc'); }); // Receive signalling channel messages from the UI. // Messages are dispatched to either the socks-to-rtc or rtc-to-net // modules depending on whether we're acting as the frontend or backend, // respectively. parentModule.on('handleSignalMessage', (message:signals.Message) => { if (socksRtc !== undefined) { socksRtc.handleSignalFromPeer(message); } else { if (rtcNet === undefined) { rtcNet = new rtc_to_net.RtcToNet(); rtcNet.startFromConfig( { allowNonUnicast:true }, pcConfig, false); // obfuscate log.info('created rtc-to-net'); // Forward signalling channel messages to the UI. rtcNet.signalsForPeer.setSyncHandler((message:signals.Message) => { parentModule.emit('signalForPeer', message); }); // Similarly to with SocksToRtc, emit the number of bytes sent/received // in RtcToNet to the UI. rtcNet.bytesReceivedFromPeer.setSyncHandler((numBytes:number) => { parentModule.emit('bytesReceived', numBytes); }); rtcNet.bytesSentToPeer.setSyncHandler((numBytes:number) => { parentModule.emit('bytesSent', numBytes); }); rtcNet.onceReady.then(() => { log.info('rtcNet ready.'); parentModule.emit('proxyingStarted', null); }); rtcNet.onceStopped.then(() => { parentModule.emit('proxyingStopped'); }); } rtcNet.handleSignalFromPeer(message); } }); // Crypto request messages parentModule.on('friendKey', (newFriendKey:string) => { friendKey = newFriendKey; }); parentModule.on('signEncrypt', (message:string) => { pgp.signEncrypt(arraybuffers.stringToArrayBuffer(message), friendKey) .then((cipherdata:ArrayBuffer) => { return pgp.armor(cipherdata); }) .then((ciphertext:string) => { parentModule.emit('ciphertext', ciphertext); }); }); parentModule.on('verifyDecrypt', (ciphertext:string) => { pgp.dearmor(ciphertext) .then((cipherdata:ArrayBuffer) => { return pgp.verifyDecrypt(cipherdata, friendKey); }) .then((result:VerifyDecryptResult) => { parentModule.emit('verifyDecryptResult', result); }); }); // Stops proxying. parentModule.on('stop', () => { if (socksRtc !== undefined) { socksRtc.stop(); } else if (rtcNet !== undefined) { rtcNet.stop(); } });