Skip to content
This repository was archived by the owner on Dec 13, 2023. It is now read-only.

Commit a2548af

Browse files
authored
Run locally optimized (#29)
* not pretty, but starting to work * might actually be working * thinking we're sending the buffer right, but we're missing something.. * Removed excess logging, fixed finished state when sending data * unnecessary function * TLS working again, thank you Reese * better naming * upd to 1.0.0? * don't compress messages over the socket * functions need to be moved up * version bump * cleaned up logging * updated readme * updated logs
1 parent d447fe5 commit a2548af

File tree

6 files changed

+155
-37
lines changed

6 files changed

+155
-37
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,4 @@ There are three options provided for you to do this:
187187
- type 'pkg ./cmd_start.js --targets TARGETSTRING --output OUTPUTBINARYPATH'
188188

189189
(for target string information see: https://github.com/zeit/pkg)
190+

api.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ var encodeAuth = function(username, authkey){
2727
var makeApiCall = function(server, method, path, qs, username, authkey, callback){
2828
// this is a generic function to make different api calls to cbt
2929
// console.log(`about to make a ${method} request to ${server} at ${path} for ${username}`)
30+
3031
var options = {
3132
url: server + '/api/v3/' + path,
3233
method: method,
@@ -38,6 +39,11 @@ var makeApiCall = function(server, method, path, qs, username, authkey, callback
3839
options.qs = qs;
3940
}
4041
request(options, (err, resp, body) => {
42+
if (global.isLocal) {
43+
global.logger.info('Running separately, error calling callback URL not thrown.');
44+
return callback(null, {});
45+
}
46+
4147
if( err ){
4248
return callback(err);
4349
}

cbt_tunnels.js

Lines changed: 93 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,55 @@ var net = require('net'),
1010
WebSocket = require('ws'),
1111
proxyAgent = require('https-proxy-agent'),
1212
os = require('os'),
13-
crypto = require('crypto');
13+
crypto = require('crypto'),
14+
version = require('./package.json').version;
1415

1516
function pad(n, width, z) {
1617
z = z || '0';
1718
n = n + '';
1819
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
1920
}
2021

22+
function padHeaderLength(lengthNumber) {
23+
while (lengthNumber.length < 4) {
24+
lengthNumber = '0' + lengthNumber;
25+
}
26+
27+
return lengthNumber;
28+
}
29+
30+
// takes an header object and packs it alongside binary blob
31+
function packData(obj, dataReceived) {
32+
var binaryObject = Buffer.from(JSON.stringify(obj));
33+
var paddedLength = padHeaderLength(String(binaryObject.byteLength));
34+
var objectLength = Buffer.from(paddedLength);
35+
if (!dataReceived) {
36+
return Buffer.concat([objectLength, binaryObject]);
37+
}
38+
39+
return Buffer.concat([objectLength, binaryObject, dataReceived]);
40+
}
41+
42+
function unpackData(binaryData) {
43+
// look at first three bytes to get the length of the header
44+
var length = binaryData.slice(0,4);
45+
length = parseInt(length);
46+
var headerData = binaryData.slice(4, length+4);
47+
48+
headerData = JSON.parse(headerData);
49+
if (length + 4 == binaryData.byteLength){
50+
headerData.data = null;
51+
} else {
52+
headerData.data = binaryData.slice(length+4, binaryData.byteLength);
53+
}
54+
return headerData;
55+
}
56+
2157
function cbtSocket(api, params) {
2258
var inbound;
2359
var outbound;
2460
var self = this;
61+
2562
var killLever = utils.killLever(self);
2663
params.context = self;
2764

@@ -68,23 +105,34 @@ function cbtSocket(api, params) {
68105

69106
var tType = self.tType = params.tType;
70107
self.auth_header = (Buffer.from(params.username+':'+params.authkey)).toString('base64');
108+
109+
// not used elsewhere
71110
self.t = params.t;
72111
self.userId = params.userId;
73112
self.authkey = params.authkey;
74113
self.qPort = (params.bytecode ? pad((params.tcpPort-11000),3) : pad((params.tcpPort-11000), 3));
75114
self.wsPort = params.tcpPort+1000;
115+
76116
self.cbtServer = 'https://'+params.cbtServer;
77117
self.cbtApp = 'https://'+params.urls.node;
78118
self.path = '/wsstunnel' + self.qPort + '/socket.io';
79119
self.query = 'userid=' + self.userId + '&authkey=' + self.authkey;
120+
80121
self.wsPath = self.cbtServer+self.path+'?'+self.query;
122+
123+
if (global.isLocal) {
124+
self.wsPath = params.wssUrl;
125+
global.logger.info(`change wsPath to ${self.path}`);
126+
}
127+
81128
self.tunnelapi = params.urls.node+'/api/v3/tunnels/'+params.tid;
82129
var proxyAuthString = self.proxyAuthString = '';
83130
self.nokill = params.nokill;
84131
if(!!params.proxyUser && !!params.proxyPass){
85132
proxyAuthString = self.proxyAuthString = 'Proxy-Authorization: Basic ' + (Buffer.from(params.proxyUser + ':' + params.proxyPass)).toString('base64');
86133
}
87134
self.ready = params.ready;
135+
88136
switch(tType){
89137
case 'simple':
90138
break;
@@ -104,8 +152,9 @@ function cbtSocket(api, params) {
104152
var agent = makeProxyAgent();
105153
conn = self.conn = new WebSocket(self.wsPath,{agent: agent});
106154
}else{
107-
conn = self.conn = new WebSocket(self.wsPath,{});
155+
conn = self.conn = new WebSocket(self.wsPath,{ perMessageDeflate: false });
108156
}
157+
self.conn.bufferType = "arraybuffer";
109158
if(!params.rejectUnauthorized){
110159
conn.rejectUnauthorized = false;
111160
}
@@ -115,7 +164,8 @@ function cbtSocket(api, params) {
115164
event:'clientLog',
116165
client_verbose_log: log
117166
}
118-
conn.send(JSON.stringify(dataToServer));
167+
var payload = packData(dataToServer, Buffer.from([]))
168+
conn.send(payload);
119169
}
120170

121171
self.start = function(cb){
@@ -134,7 +184,17 @@ function cbtSocket(api, params) {
134184
global.logger.debug('Started connection attempt!');
135185
conn.on('message',function(message){
136186
try{
137-
msg = JSON.parse(message);
187+
/*
188+
the first hello we get will be a string,
189+
we'll respond with a buffer, and from that
190+
point forward, we'll be talking buffers.
191+
*/
192+
if (_.isString(message)) {
193+
global.logger.debug("Incoming message is string");
194+
msg = JSON.parse(message);
195+
} else {
196+
msg = unpackData(message)
197+
}
138198
self.handleMessage(msg);
139199
}catch(e){
140200
warn(e.message);
@@ -206,9 +266,11 @@ function cbtSocket(api, params) {
206266
case 'hello':
207267
var dataToServer = {
208268
event: 'established',
209-
wsid: wsid
269+
wsid: wsid,
210270
}
211-
conn.send(JSON.stringify(dataToServer));
271+
// versions of cbt_tunnels > 1.0.0 send their version to server.js on hello. - CC
272+
var payload = packData(dataToServer, Buffer.from(version));
273+
conn.send(payload);
212274
break;
213275
case 'versions':
214276
var checkResult = utils.checkVersion(msg,params);
@@ -228,10 +290,10 @@ function cbtSocket(api, params) {
228290
var data = err;
229291
var dataToServer = {
230292
event: 'checkrecv',
231-
data: data,
232293
wsid: wsid
233294
}
234-
conn.send(JSON.stringify(dataToServer));
295+
var payload = packData(dataToServer, data)
296+
conn.send(payload);
235297
} else {
236298
try{
237299
global.logger.debug('IP appears to CBT as: '+resp.ip);
@@ -240,15 +302,17 @@ function cbtSocket(api, params) {
240302
ip: resp.ip,
241303
wsid: wsid
242304
}
243-
conn.send(JSON.stringify(dataToServer));
305+
var payload = packData(dataToServer, Buffer.from([]))
306+
conn.send(payload);
244307
}catch(e){
245308
warn('Parsing response failed: '+e);
246309
var dataToServer = {
247310
event: 'checkrecv',
248311
error: e,
249312
wsid: wsid
250313
}
251-
conn.send(JSON.stringify(dataToServer));
314+
var payload = packData(dataToServer, Buffer.from([]))
315+
conn.send(payload);
252316
}
253317
}
254318
});
@@ -270,6 +334,7 @@ function cbtSocket(api, params) {
270334

271335
self.handleData = function(msg){
272336
var data = msg;
337+
273338
var id = msg.id;
274339
var wsid = msg.wsid;
275340

@@ -320,11 +385,11 @@ function cbtSocket(api, params) {
320385
var dataToServer = {
321386
event: 'ack ack ack',
322387
id : id,
323-
data : null,
324388
finished : false,
325389
wsid: wsid
326390
}
327-
conn.send(JSON.stringify(dataToServer));
391+
var payload = packData(dataToServer, Buffer.from([]))
392+
conn.send(payload);
328393
global.logger.debug('Created TCP socket: '+data._type+' '+host+' '+port+' '+id);
329394
sendLog('Created TCP socket: '+data._type+' '+host+' '+port+' '+id);
330395
});
@@ -336,11 +401,11 @@ function cbtSocket(api, params) {
336401
var dataToServer = {
337402
event: 'htmlrecv',
338403
id : id,
339-
data : null,
340404
finished : true,
341405
wsid: wsid
342406
}
343-
conn.send(JSON.stringify(dataToServer));
407+
var payload = packData(dataToServer, Buffer.from([]))
408+
conn.send(payload);
344409
connection_list[id].established=false;
345410
client.end();
346411
connection_list[id].ended=true;
@@ -349,21 +414,22 @@ function cbtSocket(api, params) {
349414
client.on('data', function(dataRcvd){
350415
if(socketExists(id)){
351416
global.logger.debug('TCP socket '+id+' received data: Port:'+port+' Host:'+host);
352-
sendLog('TCP socket '+id+' received data: Port:'+port+' Host:'+host);
417+
353418
var dataToServer = {
354419
event: 'htmlrecv',
355420
id : id,
356-
data : dataRcvd,
357-
finished : true,
421+
finished : false,
358422
wsid: wsid
359423
}
424+
425+
var payload = packData(dataToServer, dataRcvd)
426+
360427
self.isConnected(dataRcvd,id,function(err,connected){
361428
if(err){
362429
throw err;
363430
}else if(!err&&!connected){
364-
conn.send(JSON.stringify(dataToServer));
431+
conn.send(payload);
365432
global.logger.debug('TCP socket '+id+' internet data emitted to server.js!');
366-
sendLog('TCP socket '+id+' internet data emitted to server.js!');
367433
}else if(connected){
368434
connection_list[id].connected = true;
369435
}
@@ -379,11 +445,11 @@ function cbtSocket(api, params) {
379445
var dataToServer = {
380446
event: 'htmlrecv',
381447
id : id,
382-
data : null,
383448
finished : true,
384449
wsid: wsid
385450
}
386-
conn.send(JSON.stringify(dataToServer));
451+
var payload = packData(dataToServer, Buffer.from([]))
452+
conn.send(payload);
387453
client.write('end');
388454
client.end();
389455
client.destroy();
@@ -401,11 +467,11 @@ function cbtSocket(api, params) {
401467
var dataToServer = {
402468
event: 'htmlrecv',
403469
id : id,
404-
data : null,
405470
finished : true,
406471
wsid: wsid
407472
}
408-
conn.send(JSON.stringify(dataToServer));
473+
var payload = packData(dataToServer, Buffer.from([]))
474+
conn.send(payload);
409475
connection_list[id].established=false;
410476
client.write('end');
411477
client.end();
@@ -424,11 +490,11 @@ function cbtSocket(api, params) {
424490
var dataToServer = {
425491
event: 'htmlrecv',
426492
id : id,
427-
data : null,
428493
finished : true,
429494
wsid: wsid
430495
}
431-
conn.send(JSON.stringify(dataToServer));
496+
var payload = packData(dataToServer, Buffer.from([]))
497+
conn.send(payload);
432498
connection_list[id].established=false;
433499
client.write('end');
434500
client.end();
@@ -450,12 +516,9 @@ function cbtSocket(api, params) {
450516
}
451517
self.isTLSHello(connection_list[id],data.data,id,function(err){
452518
if(!err){
453-
var bufferToSend = Buffer.from(data.data);
519+
var bufferToSend = Buffer.from(data.data.toJSON());
454520
client.write(bufferToSend, function(err){
455521
if(err){
456-
global.logger.debug('Error writing data to: ');
457-
global.logger.debug(util.inspect(client));
458-
global.logger.debug(util.inspect(err));
459522
sendLog('Error writing data to: '+util.inspect(client)+' '+util.inspect(err));
460523
var dataToServer = {
461524
event: 'htmlrecv',
@@ -471,7 +534,6 @@ function cbtSocket(api, params) {
471534
}
472535
outbound+=1;
473536
global.logger.debug('Wrote to TCP socket '+id);
474-
sendLog('Wrote to TCP socket '+id);
475537
});
476538
}else{
477539
global.logger.debug('TLS error:');
@@ -568,7 +630,7 @@ function cbtSocket(api, params) {
568630

569631
self.isTLSHello = function(connection,packet,id,cb){
570632
//&&(packet[4]===0x7C||packet[4]===0x7C)
571-
if((packet[0]===0x16&&packet[5]===0x01)&&connection_list[id].manipulateHeaders){
633+
if((packet[0]===22&&packet[5]===191 && connection_list[id].manipulateHeaders)){
572634
var client = connection.client;
573635
global.logger.debug(id+' This is a TLS HELLO! Sending CONNECT...');
574636
sendLog('Client found TLS hello on: '+id);
@@ -594,7 +656,6 @@ function cbtSocket(api, params) {
594656
}
595657
outbound+=1;
596658
global.logger.debug('Wrote to TCP socket '+id);
597-
sendLog('Wrote to TCP socket '+id);
598659
var connectedInterval = setInterval(function(){
599660
if(connection_list[id].connected){
600661
if(params.verbose){

gfx.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ module.exports = {
4343
+ ' sites, use the domain "local" as opposed to '
4444
+ ' "localhost":\n\n\te.g. http://local';
4545
break;
46+
case 'local':
47+
typeMsg = `
48+
Tunnel running locally.
49+
`;
50+
51+
break;
4652
default:
4753
typeMsg = 'How did you get here...';
4854
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cbt_tunnels",
3-
"version": "0.9.12",
3+
"version": "0.9.13",
44
"description": "Creates a local connection to CrossBrowserTesting.com which allows you to test sites behind your firewall or to access web pages that are saved locally on your machine. In just a few seconds, you can establish a connection which allows you to do live testing, screenshots, or run Selenium scripts against any of the internal sites you have access to. This command line version uses WSS (secure websockets over https, port 443) to create the local connection. It can be scripted, so it is useful if you want to initiate a local connection programmatically before running automated javascript, screenshots, or selenium tests.",
55
"dependencies": {
66
"cli-color": "1.1.0",

0 commit comments

Comments
 (0)