Compare commits

..

No commits in common. "4aed537130c3d09fe918dc3962ddfcc258dcc34c" and "f2b16a5bcbde8be99df1a040599d9477488935fe" have entirely different histories.

6 changed files with 77 additions and 278 deletions

View File

@ -57,8 +57,8 @@ function help() {
console.info('\ttelebit http /module/path # load a node module to handle all https traffic'); console.info('\ttelebit http /module/path # load a node module to handle all https traffic');
console.info(''); console.info('');
console.info('\ttelebit http none example.com # remove https handler from example.com'); console.info('\ttelebit http none example.com # remove https handler from example.com');
console.info('\ttelebit http 3001 sub.example.com # forward https traffic for sub.example.com to port 3001'); console.info('\ttelebit http 3001 example.com # forward https traffic for example.com to port 3001');
console.info('\ttelebit http /module/path sub # forward https traffic for sub.example.com to port 3001'); console.info('\ttelebit http /module/path example.com # forward https traffic for example.com to port 3001');
console.info(''); console.info('');
console.info('\ttelebit tcp none # remove all tcp handlers'); console.info('\ttelebit tcp none # remove all tcp handlers');
console.info('\ttelebit tcp 5050 # forward all tcp to port 5050'); console.info('\ttelebit tcp 5050 # forward all tcp to port 5050');
@ -644,7 +644,6 @@ function parseCli(/*state*/) {
} else if (/\/|\\/.test(argv[1])) { } else if (/\/|\\/.test(argv[1])) {
// looks like a path // looks like a path
argv[1] = path.resolve(argv[1]); argv[1] = path.resolve(argv[1]);
// TODO make a default assignment here
} else if (-1 === special.indexOf(argv[1])) { } else if (-1 === special.indexOf(argv[1])) {
console.error("Not sure what you meant by '" + argv[1] + "'."); console.error("Not sure what you meant by '" + argv[1] + "'.");
console.error("Remember: paths should begin with ." + path.sep + ", like '." + path.sep + argv[1] + "'"); console.error("Remember: paths should begin with ." + path.sep + ", like '." + path.sep + argv[1] + "'");
@ -670,8 +669,6 @@ function handleConfig(err, config) {
//console.log('CONFIG'); //console.log('CONFIG');
//console.log(config); //console.log(config);
state.config = config; state.config = config;
var verstr = [ pkg.name + ' daemon v' + state.config.version ];
console.info(verstr.join(' '));
if (err) { console.error(err); process.exit(101); return; } if (err) { console.error(err); process.exit(101); return; }

View File

@ -132,60 +132,17 @@ controllers.http = function (req, res, opts) {
var appname = getAppname(portOrPath); var appname = getAppname(portOrPath);
var subdomain = opts.body[1]; var subdomain = opts.body[1];
var remoteHost; var remoteHost;
if (subdomain) {
// Assign an FQDN to brief subdomains
// ex: foo => foo.rando.telebit.cloud
if (subdomain && !/\./.test(subdomain)) {
Object.keys(state.servernames).some(function (key) {
if (state.servernames[key].wildcard) {
subdomain += '.' + key;
}
});
}
if ('none' === portOrPath || 'none' === subdomain) {
// ~/telebit http none // turn off all
// ~/telebit http none none // (same as above)
// ~/telebit http 3000 none // turn off this handler
// ~/telebit http none sub.example.com // turn off this subdomain
// ~/telebit http none sub // TODO
Object.keys(state.servernames).forEach(function (key) {
if ('none' === portOrPath && 'none' === subdomain) {
delete state.servernames[key].handler;
return;
}
if (state.servernames[key].handler === portOrPath) {
delete state.servernames[key].handler;
return;
}
if (!subdomain || key === subdomain) {
if (state.servernames[key].sub) {
delete state.servernames[key];
} else {
delete state.servernames[key].handler;
}
return;
}
});
delete state.servernames[subdomain];
remoteHost = 'none';
} else if (subdomain && 'none' !== subdomain) {
// use a subdomain with this handler
var handlerName = getServername(state.servernames, subdomain); var handlerName = getServername(state.servernames, subdomain);
if (!handlerName) { if (!handlerName) {
active = false; active = false;
} }
if (!state.servernames[subdomain]) { if (!state.servernames[subdomain]) {
state.servernames[subdomain] = { sub: true }; state.servernames[subdomain] = {};
} }
if ('none' === portOrPath) {
delete state.servernames[subdomain].handler;
} else {
state.servernames[subdomain].handler = portOrPath; state.servernames[subdomain].handler = portOrPath;
}
remoteHost = subdomain; remoteHost = subdomain;
} else { } else {
// just replace the default domain
if (!Object.keys(state.servernames).sort(function (a, b) { if (!Object.keys(state.servernames).sort(function (a, b) {
return b.length - a.length; return b.length - a.length;
}).some(function (key) { }).some(function (key) {
@ -195,21 +152,17 @@ controllers.http = function (req, res, opts) {
return true; return true;
} }
if (state.servernames[key].wildcard) { if (state.servernames[key].wildcard) {
//var prefix = appname + '.' + key; if (!state.servernames[appname + '.' + key]) {
var prefix = key; state.servernames[appname + '.' + key] = {};
if (!state.servernames[prefix]) {
state.servernames[prefix] = { sub: undefined };
} }
state.servernames[prefix].handler = portOrPath; state.servernames[appname + '.' + key].handler = portOrPath;
remoteHost = prefix; remoteHost = appname + '.' + key;
return true; return true;
} }
})) { })) {
Object.keys(state.servernames).some(function (key) { Object.keys(state.servernames).some(function (key) {
//var prefix = appname + '.' + key;
var prefix = key;
state.servernames[key].handler = portOrPath; state.servernames[key].handler = portOrPath;
remoteHost = prefix; remoteHost = appname + '.' + key;
return true; return true;
}); });
} }
@ -353,10 +306,8 @@ function serveControlsHelper() {
} }
if (/\b(config)\b/.test(opts.pathname) && /get/i.test(req.method)) { if (/\b(config)\b/.test(opts.pathname) && /get/i.test(req.method)) {
var resp = JSON.parse(JSON.stringify(state.config)); res.setHeader('Content-Type', 'appliCation/json');
resp.version = pkg.version; res.end(JSON.stringify(state.config));
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(resp));
return; return;
} }
@ -445,7 +396,7 @@ function serveControlsHelper() {
if (conf._servernames) { if (conf._servernames) {
(conf._servernames||'').split(/,/g).forEach(function (key) { (conf._servernames||'').split(/,/g).forEach(function (key) {
if (!state.config.servernames[key]) { if (!state.config.servernames[key]) {
state.config.servernames[key] = { sub: undefined }; state.config.servernames[key] = {};
} }
}); });
} }
@ -601,10 +552,6 @@ function serveControlsHelper() {
res.end(JSON.stringify( res.end(JSON.stringify(
{ status: (state.config.disable ? 'disabled' : 'enabled') { status: (state.config.disable ? 'disabled' : 'enabled')
, ready: ((state.config.relay && (state.config.token || state.config.agreeTos)) ? true : false) , ready: ((state.config.relay && (state.config.token || state.config.agreeTos)) ? true : false)
, active: !!tun
, connected: 'maybe (todo)'
, version: pkg.version
, servernames: state.servernames
} }
)); ));
return; return;

View File

@ -157,15 +157,15 @@ module.exports.assign = function (state, tun, cb) {
//if (tun.data) { conn.write(tun.data); } //if (tun.data) { conn.write(tun.data); }
return conn; return conn;
} }
function fileDirTcp(opts, cb) { function fileDirTcp(conf, cb) {
var socketPair = require('socket-pair'); var socketPair = require('socket-pair');
var conn = socketPair.create(function (err, other) { var conn = socketPair.create(function (err, other) {
if (err) { cb(err); return; } if (err) { cb(err); return; }
if (opts.stat.isFile()) { if (conf._stat.isFile()) {
fs.createReadStream(opts.config.handler).pipe(other); fs.createReadStream(conf.handler).pipe(other);
} else { } else {
fs.readdir(opts.config.handler, function (err, nodes) { fs.readdir(conf.handler, function (err, nodes) {
other.write('\n' + nodes.join('\n') + '\n\n'); other.write('\n' + nodes.join('\n') + '\n\n');
other.end(); other.end();
}); });
@ -282,7 +282,8 @@ module.exports.assign = function (state, tun, cb) {
errorTcp(conf, cb); errorTcp(conf, cb);
return; return;
} }
fileDirTcp({ config: conf, stat: stat }, cb); conf._stat = stat;
fileDirTcp(conf, cb);
}); });
}); });
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "telebit", "name": "telebit",
"version": "0.19.28", "version": "0.19.26",
"description": "Break out of localhost. Connect to any device from anywhere over any tcp port or securely in a browser. A secure tunnel. A poor man's reverse VPN.", "description": "Break out of localhost. Connect to any device from anywhere over any tcp port or securely in a browser. A secure tunnel. A poor man's reverse VPN.",
"main": "lib/remote.js", "main": "lib/remote.js",
"files": [ "files": [
@ -60,7 +60,6 @@
"jsonwebtoken": "^7.1.9", "jsonwebtoken": "^7.1.9",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"proxy-packer": "^1.4.3", "proxy-packer": "^1.4.3",
"ps-list": "^5.0.0",
"recase": "^1.0.4", "recase": "^1.0.4",
"redirect-https": "^1.1.5", "redirect-https": "^1.1.5",
"serve-index": "^1.9.1", "serve-index": "^1.9.1",

View File

@ -61,7 +61,4 @@ NoNewPrivileges=true
; NoNewPrivileges=true ; NoNewPrivileges=true
[Install] [Install]
# For system-level service WantedBy=multi-user.target
;WantedBy=multi-user.target
# For userspace service
WantedBy=default.target

View File

@ -7,76 +7,6 @@ var exec = require('child_process').exec;
var path = require('path'); var path = require('path');
var Launcher = module.exports; var Launcher = module.exports;
Launcher._killAll = function (fn) {
var psList = require('ps-list');
psList().then(function (procs) {
procs.forEach(function (proc) {
if ('node' === proc.name && /\btelebitd\b/i.test(proc.cmd)) {
console.log(proc);
process.kill(proc.pid);
return true;
}
});
// Two things:
// 1) wait to see if the process dies
// 2) wait to give time for the socket to connect
setTimeout(function () {
if (fn) { fn(null); return; }
}, 1.75 * 1000);
});
};
Launcher._getError = function getError(err, stderr) {
if (err) { return err; }
if (stderr) {
err = new Error(stderr);
err.code = 'ELAUNCHER';
return err;
}
};
Launcher._detect = function (things, fn) {
if (things.launcher) {
if ('string' === typeof things.launcher) {
fn(null, things.launcher);
return;
}
if ('function' === typeof things.launcher) {
things.launcher(things);
return;
}
}
// could have used "command-exists" but I'm trying to stay low-dependency
// os.platform(), os.type()
if (!/^win/i.test(os.platform())) {
if (/^darwin/i.test(os.platform())) {
exec('command -v launchctl', things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
fn(err, 'launchctl');
});
} else {
exec('command -v systemctl', things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
fn(err, 'systemctl');
});
}
} else {
// https://stackoverflow.com/questions/17908789/how-to-add-an-item-to-registry-to-run-at-startup-without-uac
// wininit? regedit? SCM?
// REG ADD "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /V "My App" /t REG_SZ /F /D "C:\MyAppPath\MyApp.exe"
// https://www.microsoft.com/developerblog/2015/11/09/reading-and-writing-to-the-windows-registry-in-process-from-node-js/
// https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/reg-add
// https://social.msdn.microsoft.com/Forums/en-US/5b318f44-281e-4098-8dee-3ba8435fa391/add-registry-key-for-autostart-of-app-in-ice?forum=quebectools
// utils.elevate
// https://github.com/CatalystCode/windows-registry-node
exec('where reg.exe', things._execOpts, function (err, stdout, stderr) {
//console.log((stdout||'').trim());
if (stderr) {
console.error(stderr);
}
fn(err, 'reg.exe');
});
}
};
Launcher.install = function (things, fn) { Launcher.install = function (things, fn) {
if (!fn) { fn = function (err) { if (err) { console.error(err); } }; } if (!fn) { fn = function (err) { if (err) { console.error(err); } }; }
things = things || {}; things = things || {};
@ -121,6 +51,14 @@ Launcher.install = function (things, fn) {
vars.telebitRwDirs.push(vars.npmConfigPrefix); vars.telebitRwDirs.push(vars.npmConfigPrefix);
} }
vars.telebitRwDirs = vars.telebitRwDirs.join(' '); vars.telebitRwDirs = vars.telebitRwDirs.join(' ');
function getError(err, stderr) {
if (err) { return err; }
if (stderr) {
err = new Error(stderr);
err.code = 'ELAUNCHER';
return err;
}
}
var launchers = { var launchers = {
'node': function () { 'node': function () {
var fs = require('fs'); var fs = require('fs');
@ -192,13 +130,13 @@ Launcher.install = function (things, fn) {
var execstr = launcherstr + "unload -w " + launcher; var execstr = launcherstr + "unload -w " + launcher;
exec(execstr, things._execOpts, function (/*err, stdout, stderr*/) { exec(execstr, things._execOpts, function (/*err, stdout, stderr*/) {
// we probably only need to skip the stderr (saying that it can't stop something that isn't started) // we probably only need to skip the stderr (saying that it can't stop something that isn't started)
//err = Launcher._getError(err, stderr); //err = getError(err, stderr);
//if (err) { fn(err); return; } //if (err) { fn(err); return; }
//console.log((stdout||'').trim()); //console.log((stdout||'').trim());
//console.log('unload worked?'); //console.log('unload worked?');
execstr = launcherstr + "load -w " + launcher; execstr = launcherstr + "load -w " + launcher;
exec(execstr, things._execOpts, function (err, stdout, stderr) { exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr); err = getError(err, stderr);
if (err) { fn(err); return; } if (err) { fn(err); return; }
//console.log((stdout||'').trim()); //console.log((stdout||'').trim());
//console.log('load worked?'); //console.log('load worked?');
@ -232,23 +170,23 @@ Launcher.install = function (things, fn) {
var launcherstr = (vars.userspace ? "" : "sudo ") + "systemctl " + (vars.userspace ? "--user " : ""); var launcherstr = (vars.userspace ? "" : "sudo ") + "systemctl " + (vars.userspace ? "--user " : "");
var execstr = launcherstr + "daemon-reload"; var execstr = launcherstr + "daemon-reload";
exec(execstr, things._execOpts, function (err, stdout, stderr) { exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr); err = getError(err, stderr);
if (err) { fn(err); return; } if (err) { fn(err); return; }
//console.log((stdout||'').trim()); //console.log((stdout||'').trim());
var execstr = launcherstr + "enable " + launchername; var execstr = launcherstr + "enable " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) { exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr && !/Created symlink/i.test(stderr) && stderr || ''); err = getError(err, !/Created symlink/.test(stderr||''));
if (err) { fn(err); return; } if (err) { fn(err); return; }
//console.log((stdout||'').trim()); //console.log((stdout||'').trim());
var execstr = launcherstr + "restart " + launchername; var execstr = launcherstr + "restart " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) { exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr); err = getError(err, stderr);
if (err) { fn(err); return; } if (err) { fn(err); return; }
//console.log((stdout||'').trim()); //console.log((stdout||'').trim());
setTimeout(function () { setTimeout(function () {
var execstr = launcherstr + "status " + launchername; var execstr = launcherstr + "status " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) { exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr); err = getError(err, stderr);
if (err) { fn(err); return; } if (err) { fn(err); return; }
if (!/active.*running/i.test(stdout)) { if (!/active.*running/i.test(stdout)) {
err = new Error("systemd failed to start '" + launchername + "'"); err = new Error("systemd failed to start '" + launchername + "'");
@ -284,7 +222,7 @@ Launcher.install = function (things, fn) {
+ '" /F' + '" /F'
; ;
exec(cmd, things._execOpts, function (err, stdout, stderr) { exec(cmd, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr); err = getError(err, stderr);
if (err) { fn(err); return; } if (err) { fn(err); return; }
// need to start it for the first time ourselves // need to start it for the first time ourselves
run(null, 'node'); run(null, 'node');
@ -311,134 +249,54 @@ Launcher.install = function (things, fn) {
} }
} }
things._vars = vars; if (things.launcher) {
things._userspace = vars.userspace; if ('string' === typeof things.launcher) {
Launcher._detect(things, run); run(null, things.launcher);
}; return;
Launcher.uninstall = function (things, fn) { }
if (!fn) { fn = function (err) { if (err) { console.error(err); } }; } if ('function' === typeof things.launcher) {
things = things || {}; things._vars = vars;
things._userspace = vars.userspace;
// Right now this is just for npm install -g and npx things.launcher(things);
if (things.env) {
things.env.PATH = things.env.PATH || process.env.PATH;
} else {
things.env = process.env;
}
things.argv = things.argv || process.argv;
things._execOpts = { windowsHide: true, env: things.env };
var vars = {
telebitUser: os.userInfo().username
};
vars.userspace = (!things.telebitUser || (things.telebitUser === os.userInfo().username)) ? true : false;
var launchers = {
'node': function () {
Launcher._killAll(fn);
}
, 'launchctl': function () {
var launcher = path.join(os.homedir(), 'Library/LaunchAgents/cloud.telebit.remote.plist');
try {
var launcherstr = (vars.userspace ? "" : "sudo ") + "launchctl ";
var execstr = launcherstr + "unload -w " + launcher;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
// we probably only need to skip the stderr (saying that it can't stop something that isn't started)
//err = Launcher._getError(err, stderr);
//if (err) { fn(err); return; }
//console.log((stdout||'').trim());
//console.log('unload worked?');
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
//console.log('load worked?');
setTimeout(function () {
fn(null);
}, 1.25 * 1000);
});
} catch(e) {
console.error("'" + launcher + "' error (uninstall):");
console.error(e);
if (fn) { fn(e); return; }
}
}
, 'systemctl': function () {
var launcher = path.join(os.homedir(), '.config/systemd/user/telebit.service');
var launchername = 'telebit.service';
try {
mkdirp.sync(path.join(os.homedir(), '.config/systemd/user'));
// IMPORTANT
// It's a dangerous to go alone, take this:
// SYSTEMD_LOG_LEVEL=debug journalctl -xef --user-unit=telebit
// (makes debugging systemd issues not "easy" per se, but possible)
var launcherstr = (vars.userspace ? "" : "sudo ") + "systemctl " + (vars.userspace ? "--user " : "");
var execstr = launcherstr + "disable " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr && !/Removed symlink/i.test(stderr) && stderr || '');
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
var execstr = launcherstr + "stop " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
setTimeout(function () {
var execstr = launcherstr + "status " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
if (!/inactive.*dead/i.test(stdout)) {
err = new Error("systemd failed to stop '" + launchername + "'");
}
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
fn(null);
});
}, 1.25 * 1000);
});
});
} catch(e) {
console.error("'" + launcher + "' error:");
console.error(e);
if (fn) { fn(e); return; }
}
}
, 'reg.exe': function () {
if (!vars.userspace) {
console.warn("sysetm-level, privileged services are not yet supported on windows");
}
var cmd = 'reg.exe add "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"'
+ ' /V "Telebit" /F'
;
exec(cmd, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
// need to start it for the first time ourselves
kill(null, 'node');
});
}
};
function kill(err, launcher) {
if (err) {
console.error("No luck with '" + launcher + "', trying a process.kill() instead...");
console.error(err);
launcher = 'node';
}
if (launchers[launcher]) {
launchers[launcher]();
return; return;
} else {
console.error("No launcher handler (uninstall) for '" + launcher + "'");
} }
} }
things._vars = vars; // could have used "command-exists" but I'm trying to stay low-dependency
things._userspace = vars.userspace; // os.platform(), os.type()
Launcher._detect(things, kill); if (!/^win/i.test(os.platform())) {
if (/^darwin/i.test(os.platform())) {
exec('command -v launchctl', things._execOpts, function (err, stdout, stderr) {
err = getError(err, stderr);
run(err, 'launchctl');
});
} else {
exec('command -v systemctl', things._execOpts, function (err, stdout, stderr) {
err = getError(err, stderr);
run(err, 'systemctl');
});
}
} else {
// https://stackoverflow.com/questions/17908789/how-to-add-an-item-to-registry-to-run-at-startup-without-uac
// wininit? regedit? SCM?
// REG ADD "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /V "My App" /t REG_SZ /F /D "C:\MyAppPath\MyApp.exe"
// https://www.microsoft.com/developerblog/2015/11/09/reading-and-writing-to-the-windows-registry-in-process-from-node-js/
// https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/reg-add
// https://social.msdn.microsoft.com/Forums/en-US/5b318f44-281e-4098-8dee-3ba8435fa391/add-registry-key-for-autostart-of-app-in-ice?forum=quebectools
// utils.elevate
// https://github.com/CatalystCode/windows-registry-node
exec('where reg.exe', things._execOpts, function (err, stdout, stderr) {
//console.log((stdout||'').trim());
if (stderr) {
console.error(stderr);
}
run(err, 'reg.exe');
});
}
}; };
if (module === require.main) { if (module === require.main) {
Launcher.install({ module.exports.install({
argv: process.argv argv: process.argv
, env: process.env , env: process.env
}, function (err) { }, function (err) {