Compare commits
8 Commits
f2b16a5bcb
...
4aed537130
Author | SHA1 | Date | |
---|---|---|---|
4aed537130 | |||
462c46dc5d | |||
ae32916177 | |||
e1cfecfefc | |||
3be8c28421 | |||
c562cee3a9 | |||
da042f2dba | |||
568bcdcab2 |
@ -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 example.com # forward https traffic for example.com to port 3001');
|
console.info('\ttelebit http 3001 sub.example.com # 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('\ttelebit http /module/path sub # forward https traffic for sub.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,6 +644,7 @@ 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] + "'");
|
||||||
@ -669,6 +670,8 @@ 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; }
|
||||||
|
|
||||||
|
@ -132,17 +132,60 @@ 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] = {};
|
state.servernames[subdomain] = { sub: true };
|
||||||
|
}
|
||||||
|
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) {
|
||||||
@ -152,17 +195,21 @@ controllers.http = function (req, res, opts) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (state.servernames[key].wildcard) {
|
if (state.servernames[key].wildcard) {
|
||||||
if (!state.servernames[appname + '.' + key]) {
|
//var prefix = appname + '.' + key;
|
||||||
state.servernames[appname + '.' + key] = {};
|
var prefix = key;
|
||||||
|
if (!state.servernames[prefix]) {
|
||||||
|
state.servernames[prefix] = { sub: undefined };
|
||||||
}
|
}
|
||||||
state.servernames[appname + '.' + key].handler = portOrPath;
|
state.servernames[prefix].handler = portOrPath;
|
||||||
remoteHost = appname + '.' + key;
|
remoteHost = prefix;
|
||||||
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 = appname + '.' + key;
|
remoteHost = prefix;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -306,8 +353,10 @@ 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)) {
|
||||||
res.setHeader('Content-Type', 'appliCation/json');
|
var resp = JSON.parse(JSON.stringify(state.config));
|
||||||
res.end(JSON.stringify(state.config));
|
resp.version = pkg.version;
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(JSON.stringify(resp));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,7 +445,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] = {};
|
state.config.servernames[key] = { sub: undefined };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -552,6 +601,10 @@ 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;
|
||||||
|
@ -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(conf, cb) {
|
function fileDirTcp(opts, 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 (conf._stat.isFile()) {
|
if (opts.stat.isFile()) {
|
||||||
fs.createReadStream(conf.handler).pipe(other);
|
fs.createReadStream(opts.config.handler).pipe(other);
|
||||||
} else {
|
} else {
|
||||||
fs.readdir(conf.handler, function (err, nodes) {
|
fs.readdir(opts.config.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,8 +282,7 @@ module.exports.assign = function (state, tun, cb) {
|
|||||||
errorTcp(conf, cb);
|
errorTcp(conf, cb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
conf._stat = stat;
|
fileDirTcp({ config: conf, stat: stat }, cb);
|
||||||
fileDirTcp(conf, cb);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "telebit",
|
"name": "telebit",
|
||||||
"version": "0.19.26",
|
"version": "0.19.28",
|
||||||
"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,6 +60,7 @@
|
|||||||
"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",
|
||||||
|
@ -61,4 +61,7 @@ NoNewPrivileges=true
|
|||||||
; NoNewPrivileges=true
|
; NoNewPrivileges=true
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
# For system-level service
|
||||||
|
;WantedBy=multi-user.target
|
||||||
|
# For userspace service
|
||||||
|
WantedBy=default.target
|
||||||
|
@ -7,6 +7,76 @@ 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 || {};
|
||||||
@ -51,14 +121,6 @@ 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');
|
||||||
@ -130,13 +192,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 = getError(err, stderr);
|
//err = Launcher._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 = getError(err, stderr);
|
err = Launcher._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?');
|
||||||
@ -170,23 +232,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 = getError(err, stderr);
|
err = Launcher._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 = getError(err, !/Created symlink/.test(stderr||''));
|
err = Launcher._getError(err, stderr && !/Created symlink/i.test(stderr) && 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 = getError(err, stderr);
|
err = Launcher._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 = getError(err, stderr);
|
err = Launcher._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 + "'");
|
||||||
@ -222,7 +284,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 = getError(err, stderr);
|
err = Launcher._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');
|
||||||
@ -249,54 +311,134 @@ Launcher.install = function (things, fn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (things.launcher) {
|
things._vars = vars;
|
||||||
if ('string' === typeof things.launcher) {
|
things._userspace = vars.userspace;
|
||||||
run(null, things.launcher);
|
Launcher._detect(things, run);
|
||||||
return;
|
};
|
||||||
|
Launcher.uninstall = function (things, fn) {
|
||||||
|
if (!fn) { fn = function (err) { if (err) { console.error(err); } }; }
|
||||||
|
things = things || {};
|
||||||
|
|
||||||
|
// Right now this is just for npm install -g and npx
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
if ('function' === typeof things.launcher) {
|
, 'launchctl': function () {
|
||||||
things._vars = vars;
|
var launcher = path.join(os.homedir(), 'Library/LaunchAgents/cloud.telebit.remote.plist');
|
||||||
things._userspace = vars.userspace;
|
try {
|
||||||
things.launcher(things);
|
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 + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// could have used "command-exists" but I'm trying to stay low-dependency
|
things._vars = vars;
|
||||||
// os.platform(), os.type()
|
things._userspace = vars.userspace;
|
||||||
if (!/^win/i.test(os.platform())) {
|
Launcher._detect(things, kill);
|
||||||
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) {
|
||||||
module.exports.install({
|
Launcher.install({
|
||||||
argv: process.argv
|
argv: process.argv
|
||||||
, env: process.env
|
, env: process.env
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user