stunnel
Advanced tools
Comparing version 0.9.6 to 0.9.7
{ | ||
"name": "stunnel", | ||
"version": "0.9.6", | ||
"version": "0.9.7", | ||
"description": "A pure-JavaScript tunnel client for http and https similar to localtunnel.me, but uses TLS (SSL) with ServerName Indication (SNI) over https to work even in harsh network conditions such as in student dorms and behind HOAs, corporate firewalls, public libraries, airports, airplanes, etc. Can also tunnel tls and plain tcp.", | ||
@@ -54,4 +54,4 @@ "main": "wsclient.js", | ||
"tunnel-packer": "^1.1.0", | ||
"ws": "^1.1.1" | ||
"ws": "^2.2.3" | ||
} | ||
} |
@@ -33,2 +33,8 @@ <!-- BANNER_TPL_BEGIN --> | ||
```bash | ||
npm install -g 'git+https://git@git.daplie.com/Daplie/node-tunnel-client.git#v1' | ||
``` | ||
Or if you want to bow down to the kings of the centralized dictator-net: | ||
```bash | ||
npm install -g stunnel | ||
@@ -35,0 +41,0 @@ ``` |
292
wsclient.js
@@ -7,14 +7,68 @@ (function () { | ||
var Packer = require('tunnel-packer'); | ||
var authenticated = false; | ||
function run(copts) { | ||
var tunnelUrl = copts.stunneld.replace(/\/$/, '') + '/?access_token=' + copts.token; | ||
var activityTimeout = copts.activityTimeout || 2*60*1000; | ||
var pongTimeout = copts.pongTimeout || 10*1000; | ||
var wstunneler; | ||
var authenticated = false; | ||
var localclients = {}; | ||
// BaaS / Backendless / noBackend / horizon.io | ||
// user authentication | ||
// a place to store data | ||
// file management | ||
// Synergy Teamwork Paradigm = Jabberwocky | ||
var handlers = { | ||
var clientHandlers = { | ||
onClose: function (cid, opts, err) { | ||
wsHandlers.sendMessage(Packer.pack(opts, null, err && 'error' || 'end')); | ||
delete localclients[cid]; | ||
console.log('[local onClose] closed "' + cid + '" (' + clientHandlers.count() + ' clients)'); | ||
} | ||
, onError: function(cid, opts, err) { | ||
console.info("[local onError] closing '" + cid + "' because '" + err.message + "'"); | ||
clientHandlers.onClose(cid, opts, err); | ||
} | ||
, closeSingle: function (cid) { | ||
if (!localclients[cid]) { | ||
return; | ||
} | ||
console.log('[closeSingle]', cid); | ||
try { | ||
localclients[cid].end(); | ||
setTimeout(function () { | ||
if (localclients[cid]) { | ||
console.warn('[closeSingle]', cid, 'connection still present'); | ||
delete localclients[cid]; | ||
} | ||
}, 500); | ||
} catch (err) { | ||
console.warn('[closeSingle] failed to close connection', cid, err); | ||
delete localclients[cid]; | ||
} | ||
} | ||
, closeAll: function () { | ||
console.log('[closeAll]'); | ||
Object.keys(localclients).forEach(function (cid) { | ||
try { | ||
localclients[cid].end(); | ||
} catch (err) { | ||
console.warn('[closeAll] failed to close connection', cid, err); | ||
} | ||
}); | ||
setTimeout(function () { | ||
Object.keys(localclients).forEach(function (cid) { | ||
if (localclients[cid]) { | ||
console.warn('[closeAll]', cid, 'connection still present'); | ||
delete localclients[cid]; | ||
} | ||
}); | ||
}, 500); | ||
} | ||
, count: function () { | ||
return Object.keys(localclients).length; | ||
} | ||
}; | ||
var packerHandlers = { | ||
onmessage: function (opts) { | ||
@@ -38,3 +92,3 @@ var net = copts.net || require('net'); | ||
if (!portList) { | ||
handlers._onLocalError(cid, opts, new Error("unsupported service '" + service + "'")); | ||
packerHandlers._onConnectError(cid, opts, new Error("unsupported service '" + service + "'")); | ||
return; | ||
@@ -57,10 +111,7 @@ } | ||
//console.warn(opts.data.toString()); | ||
handlers._onLocalError(cid, opts, new Error("missing servername for '" + cid + "' " + opts.data.byteLength)); | ||
packerHandlers._onConnectError(cid, opts, new Error("missing servername for '" + cid + "' " + opts.data.byteLength)); | ||
return; | ||
} | ||
port = portList[servername] || portList['*']; | ||
console.info("[connect] new client '" + cid + "' for '" + servername + "' (" + (handlers._numClients() + 1) + " clients)"); | ||
console.log('port', port, opts.port, service, portList); | ||
localclients[cid] = net.createConnection({ | ||
@@ -80,11 +131,4 @@ port: port | ||
}); | ||
// 'data' | ||
/* | ||
localclients[cid].on('data', function (chunk) { | ||
//console.log("[<=] local '" + opts.service + "' sent to '" + cid + "' <= ", chunk.byteLength, "bytes"); | ||
//console.log(JSON.stringify(chunk.toString())); | ||
wstunneler.send(Packer.pack(opts, chunk), { binary: true }); | ||
}); | ||
//*/ | ||
///* | ||
console.info("[connect] new client '" + cid + "' for '" + servername + "' (" + clientHandlers.count() + " clients)"); | ||
localclients[cid].on('readable', function (size) { | ||
@@ -105,17 +149,9 @@ var chunk; | ||
chunk = localclients[cid].read(size); | ||
//console.log("[<=] local '" + opts.service + "' sent to '" + cid + "' <= ", chunk.byteLength, "bytes"); | ||
//console.log(JSON.stringify(chunk.toString())); | ||
if (chunk) { | ||
wstunneler.send(Packer.pack(opts, chunk), { binary: true }); | ||
wsHandlers.sendMessage(Packer.pack(opts, chunk)); | ||
} | ||
} while (chunk); | ||
}); | ||
//*/ | ||
localclients[cid].on('error', function (err) { | ||
handlers._onLocalError(cid, opts, err); | ||
}); | ||
localclients[cid].on('end', function () { | ||
console.info("[end] closing client '" + cid + "' for '" + servername + "' (" + (handlers._numClients() - 1) + " clients)"); | ||
handlers._onLocalClose(cid, opts); | ||
}); | ||
localclients[cid].on('error', clientHandlers.onError.bind(null, cid, opts)); | ||
localclients[cid].on('end', clientHandlers.onClose.bind(null, cid, opts)); | ||
} | ||
@@ -125,3 +161,3 @@ , onend: function (opts) { | ||
//console.log("[end] '" + cid + "'"); | ||
handlers._onend(cid); | ||
clientHandlers.closeSingle(cid); | ||
} | ||
@@ -131,66 +167,71 @@ , onerror: function (opts) { | ||
//console.log("[error] '" + cid + "'", opts.code || '', opts.message); | ||
handlers._onend(cid); | ||
clientHandlers.closeSingle(cid); | ||
} | ||
, _onend: function (cid) { | ||
console.log('[_onend]'); | ||
if (localclients[cid]) { | ||
try { | ||
localclients[cid].end(); | ||
} catch(e) { | ||
// ignore | ||
} | ||
} | ||
delete localclients[cid]; | ||
, _onConnectError: function (cid, opts, err) { | ||
console.info("[_onConnectError] opening '" + cid + "' failed because " + err.message); | ||
wsHandlers.sendMessage(Packer.pack(opts, null, 'error')); | ||
} | ||
, _onLocalClose: function (cid, opts, err) { | ||
console.log('[_onLocalClose]'); | ||
try { | ||
wstunneler.send(Packer.pack(opts, null, err && 'error' || 'end'), { binary: true }); | ||
} catch(e) { | ||
// ignore | ||
} | ||
delete localclients[cid]; | ||
} | ||
, _onLocalError: function (cid, opts, err) { | ||
console.info("[error] closing '" + cid + "' because '" + err.message + "' (" + (handlers._numClients() - 1) + " clients)"); | ||
handlers._onLocalClose(cid, opts, err); | ||
} | ||
, _numClients: function () { | ||
return Object.keys(localclients).length; | ||
} | ||
}; | ||
var retry = true; | ||
var lastActivity; | ||
var timeoutId; | ||
var wsHandlers = { | ||
onOpen: function () { | ||
console.info("[open] connected to '" + copts.stunneld + "'"); | ||
refreshTimeout: function () { | ||
lastActivity = Date.now(); | ||
} | ||
, checkTimeout: function () { | ||
if (!wstunneler) { | ||
console.warn('checkTimeout called when websocket already closed'); | ||
return; | ||
} | ||
// Determine how long the connection has been "silent", ie no activity. | ||
var silent = Date.now() - lastActivity; | ||
, retry: true | ||
, closeClients: function () { | ||
console.log('[close clients]'); | ||
Object.keys(localclients).forEach(function (cid) { | ||
// If we have had activity within the last activityTimeout then all we need to do is | ||
// call this function again at the soonest time when the connection could be timed out. | ||
if (silent < activityTimeout) { | ||
timeoutId = setTimeout(wsHandlers.checkTimeout, activityTimeout-silent); | ||
} | ||
// Otherwise we check to see if the pong has also timed out, and if not we send a ping | ||
// and call this function again when the pong will have timed out. | ||
else if (silent < activityTimeout + pongTimeout) { | ||
console.log('pinging tunnel server'); | ||
try { | ||
localclients[cid].end(); | ||
} catch(e) { | ||
// ignore | ||
wstunneler.ping(); | ||
} catch (err) { | ||
console.warn('failed to ping tunnel server', err); | ||
} | ||
delete localclients[cid]; | ||
}); | ||
timeoutId = setTimeout(wsHandlers.checkTimeout, pongTimeout); | ||
} | ||
// Last case means the ping we sent before didn't get a response soon enough, so we | ||
// need to close the websocket connection. | ||
else { | ||
console.log('connection timed out'); | ||
wstunneler.close(1000, 'connection timeout'); | ||
} | ||
} | ||
, onOpen: function () { | ||
console.info("[open] connected to '" + copts.stunneld + "'"); | ||
wsHandlers.refreshTimeout(); | ||
timeoutId = setTimeout(wsHandlers.checkTimeout, activityTimeout); | ||
} | ||
, onClose: function () { | ||
console.log('ON CLOSE'); | ||
console.log('ON CLOSE'); | ||
clearTimeout(timeoutId); | ||
wstunneler = null; | ||
clientHandlers.closeAll(); | ||
if (!authenticated) { | ||
console.info('[close] failed on first attempt... check authentication.'); | ||
timeoutId = null; | ||
} | ||
else if (wsHandlers.retry) { | ||
else if (retry) { | ||
console.info('[retry] disconnected and waiting...'); | ||
setTimeout(run, 5000, copts); | ||
timeoutId = setTimeout(connect, 5000); | ||
} | ||
else { | ||
console.info('[close] closing tunnel to exit...'); | ||
} | ||
process.removeListener('exit', wsHandlers.onExit); | ||
process.removeListener('SIGINT', wsHandlers.onExit); | ||
wsHandlers.closeClients(); | ||
} | ||
@@ -203,6 +244,55 @@ | ||
, onExit: function () { | ||
console.log('[wait] closing wstunneler...'); | ||
wsHandlers.retry = false; | ||
wsHandlers.closeClients(); | ||
, sendMessage: function (msg) { | ||
if (wstunneler) { | ||
try { | ||
wstunneler.send(msg, {binary: true}); | ||
} catch (err) { | ||
console.warn('[sendMessage] error sending websocket message', err); | ||
} | ||
} | ||
} | ||
}; | ||
function connect() { | ||
if (!retry) { | ||
return; | ||
} | ||
timeoutId = null; | ||
var machine = require('tunnel-packer').create(packerHandlers); | ||
console.info("[connect] '" + copts.stunneld + "'"); | ||
wstunneler = new WebSocket(tunnelUrl, { rejectUnauthorized: !copts.insecure }); | ||
wstunneler.on('open', wsHandlers.onOpen); | ||
wstunneler.on('close', wsHandlers.onClose); | ||
wstunneler.on('error', wsHandlers.onError); | ||
// Our library will automatically handle sending the pong respose to ping requests. | ||
wstunneler.on('ping', wsHandlers.refreshTimeout); | ||
wstunneler.on('pong', wsHandlers.refreshTimeout); | ||
wstunneler.on('message', function (data, flags) { | ||
wsHandlers.refreshTimeout(); | ||
if (data.error || '{' === data[0]) { | ||
console.log(data); | ||
return; | ||
} | ||
machine.fns.addChunk(data, flags); | ||
}); | ||
} | ||
connect(); | ||
function sigHandler() { | ||
console.log('SIGINT'); | ||
// We want to handle cleanup properly unless something is broken in our cleanup process | ||
// that prevents us from exitting, in which case we want the user to be able to send | ||
// the signal again and exit the way it normally would. | ||
process.removeListener('SIGINT', sigHandler); | ||
retry = false; | ||
if (timeoutId) { | ||
clearTimeout(timeoutId); | ||
timeoutId = null; | ||
} | ||
if (wstunneler) { | ||
try { | ||
@@ -213,32 +303,6 @@ wstunneler.close(); | ||
console.error(e); | ||
// ignore | ||
} | ||
} | ||
}; | ||
var machine = require('tunnel-packer').create(handlers); | ||
console.info("[connect] '" + copts.stunneld + "'"); | ||
wstunneler = new WebSocket(tunnelUrl, { rejectUnauthorized: !copts.insecure }); | ||
wstunneler.on('open', wsHandlers.onOpen); | ||
wstunneler.on('message', function (data, flags) { | ||
if (data.error || '{' === data[0]) { | ||
console.log(data); | ||
return; | ||
} | ||
machine.fns.addChunk(data, flags); | ||
}); | ||
wstunneler.on('close', wsHandlers.onClose); | ||
wstunneler.on('error', wsHandlers.onError); | ||
process.on('beforeExit', function (x) { | ||
console.log('[beforeExit] event loop closing?', x); | ||
}); | ||
process.on('exit', function (x) { | ||
console.log('[exit] loop closed', x); | ||
//wsHandlers.onExit(x); | ||
}); | ||
process.on('SIGINT', function (x) { | ||
console.log('SIGINT'); | ||
wsHandlers.onExit(x); | ||
}); | ||
} | ||
process.on('SIGINT', sigHandler); | ||
} | ||
@@ -245,0 +309,0 @@ |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
197
2
37551
8
521
+ Addedsafe-buffer@5.0.1(transitive)
+ Addedultron@1.1.1(transitive)
+ Addedws@2.3.1(transitive)
- Removedoptions@0.0.6(transitive)
- Removedultron@1.0.2(transitive)
- Removedws@1.1.5(transitive)
Updatedws@^2.2.3