make the output bearable
This commit is contained in:
parent
a015db2d16
commit
fc0054bbf1
|
@ -435,9 +435,24 @@ var utils = {
|
||||||
} else if ("CONFIG" === body.code) {
|
} else if ("CONFIG" === body.code) {
|
||||||
delete body.code;
|
delete body.code;
|
||||||
console.info(YAML.safeDump(body));
|
console.info(YAML.safeDump(body));
|
||||||
|
} else {
|
||||||
|
if ('http' === body.module) {
|
||||||
|
// TODO we'll support slingshot-ing in the future
|
||||||
|
if (String(body.local) === String(parseInt(body.local, 10))) {
|
||||||
|
console.log('> Forwarding ' + body.remote + ' => localhost:' + body.local);
|
||||||
|
} else {
|
||||||
|
console.log('> Serving ' + body.local + ' as ' + body.remote);
|
||||||
|
}
|
||||||
|
} else if ('tcp' === body.module) {
|
||||||
|
console.log('> Forwarding ' + state.config.relay + ':' + body.remote + ' => localhost:' + body.local);
|
||||||
|
} else if ('ssh' === body.module) {
|
||||||
|
console.log('> Forwarding ' + state.config.relay + ' -p ' + body.remote + ' => localhost:' + body.local);
|
||||||
|
console.log('> Forwarding ssh+https (openssl proxy) => localhost:' + body.local);
|
||||||
} else {
|
} else {
|
||||||
console.info(JSON.stringify(body, null, 2));
|
console.info(JSON.stringify(body, null, 2));
|
||||||
}
|
}
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var body = '';
|
var body = '';
|
||||||
|
|
356
bin/telebitd.js
356
bin/telebitd.js
|
@ -77,6 +77,202 @@ try {
|
||||||
var controlServer;
|
var controlServer;
|
||||||
var tun;
|
var tun;
|
||||||
|
|
||||||
|
var controllers = {};
|
||||||
|
function saveConfig(cb) {
|
||||||
|
fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), cb);
|
||||||
|
}
|
||||||
|
function getServername(servernames, sub) {
|
||||||
|
if (state.servernames[sub]) {
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
var names = Object.keys(servernames).map(function (servername) {
|
||||||
|
if ('*.' === servername.slice(0,2)) {
|
||||||
|
return servername;
|
||||||
|
}
|
||||||
|
return '*.' + servername;
|
||||||
|
}).sort(function (a, b) {
|
||||||
|
return b.length - a.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
return names.filter(function (pattern) {
|
||||||
|
// '.example.com' = '*.example.com'.split(1)
|
||||||
|
var subPiece = pattern.slice(1);
|
||||||
|
// '.com' = 'sub.example.com'.slice(-4)
|
||||||
|
// '.example.com' = 'sub.example.com'.slice(-12)
|
||||||
|
if (subPiece === sub.slice(-subPiece.length)) {
|
||||||
|
return subPiece;
|
||||||
|
}
|
||||||
|
})[0];
|
||||||
|
}
|
||||||
|
controllers.http = function (req, res, opts) {
|
||||||
|
function getAppname(pathname) {
|
||||||
|
// port number
|
||||||
|
if (String(pathname) === String(parseInt(pathname, 10))) {
|
||||||
|
return String(pathname);
|
||||||
|
}
|
||||||
|
var paths = pathname.split(/[\\\/\:]/);
|
||||||
|
// rid trailing slash(es)
|
||||||
|
while (!paths[paths.length -1]) {
|
||||||
|
paths.pop();
|
||||||
|
}
|
||||||
|
var name = paths.pop();
|
||||||
|
name = path.basename(name, path.extname(name));
|
||||||
|
name = name.replace(/\./, '-').replace(/-+/, '-');
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if (!opts.body) {
|
||||||
|
res.statusCode = 422;
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(JSON.stringify({"error":{"message":"module \'http\' needs more arguments"}}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var active = true;
|
||||||
|
var portOrPath = opts.body[0];
|
||||||
|
var appname = getAppname(portOrPath);
|
||||||
|
var subdomain = opts.body[1];
|
||||||
|
var remoteHost;
|
||||||
|
if (subdomain) {
|
||||||
|
var handlerName = getServername(state.servernames, subdomain);
|
||||||
|
if (!handlerName) {
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
if (!state.servernames[subdomain]) {
|
||||||
|
state.servernames[subdomain] = {};
|
||||||
|
}
|
||||||
|
state.servernames[subdomain].handler = portOrPath;
|
||||||
|
remoteHost = subdomain;
|
||||||
|
} else {
|
||||||
|
if (!Object.keys(state.servernames).sort(function (a, b) {
|
||||||
|
return b.length - a.length;
|
||||||
|
}).some(function (key) {
|
||||||
|
if (state.servernames[key].handler === appname) {
|
||||||
|
// example.com.handler: 3000 // already set
|
||||||
|
remoteHost = key;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (state.servernames[key].wildcard) {
|
||||||
|
if (!state.servernames[appname + '.' + key]) {
|
||||||
|
state.servernames[appname + '.' + key] = {};
|
||||||
|
}
|
||||||
|
state.servernames[appname + '.' + key].handler = portOrPath;
|
||||||
|
remoteHost = appname + '.' + key;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})) {
|
||||||
|
Object.keys(state.servernames).some(function (key) {
|
||||||
|
state.servernames[key].handler = portOrPath;
|
||||||
|
remoteHost = appname + '.' + key;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.config.servernames = state.servernames;
|
||||||
|
saveConfig(function (err) {
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
success: true
|
||||||
|
, active: active
|
||||||
|
, remote: remoteHost
|
||||||
|
, local: portOrPath
|
||||||
|
, saved: !err
|
||||||
|
, module: 'http'
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
controllers.tcp = function (req, res, opts) {
|
||||||
|
if (!opts.body) {
|
||||||
|
res.statusCode = 422;
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(JSON.stringify({ error: { message: "module 'tcp' needs more arguments" } }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var active;
|
||||||
|
var remotePort = opts.body[1];
|
||||||
|
var portOrPath = opts.body[0];
|
||||||
|
|
||||||
|
// portnum
|
||||||
|
if (remotePort) {
|
||||||
|
if (!state.ports[remotePort]) {
|
||||||
|
active = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// forward-to port-or-module
|
||||||
|
// TODO we can't send files over tcp until we fix the connect event bug
|
||||||
|
state.ports[remotePort].handler = portOrPath;
|
||||||
|
} else {
|
||||||
|
if (!Object.keys(state.ports).some(function (key) {
|
||||||
|
if (!state.ports[key].handler) {
|
||||||
|
state.ports[key].handler = portOrPath;
|
||||||
|
remotePort = key;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
})) {
|
||||||
|
Object.keys(state.ports).some(function (key) {
|
||||||
|
state.ports[key].handler = portOrPath;
|
||||||
|
remotePort = key;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.config.ports = state.ports;
|
||||||
|
saveConfig(function (err) {
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
success: true
|
||||||
|
, active: active
|
||||||
|
, remote: remotePort
|
||||||
|
, local: portOrPath
|
||||||
|
, saved: !err
|
||||||
|
, module: 'tcp'
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
controllers.ssh = function (req, res, opts) {
|
||||||
|
if (!opts.body) {
|
||||||
|
res.statusCode = 422;
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(JSON.stringify({"error":{"message":"module 'ssh' needs more arguments"}}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sshSuccess() {
|
||||||
|
//state.config.sshAuto = state.sshAuto;
|
||||||
|
saveConfig(function (err) {
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(JSON.stringify({
|
||||||
|
success: true
|
||||||
|
, active: true
|
||||||
|
, remote: Object.keys(state.config.ports)[0]
|
||||||
|
, local: state.config.sshAuto || 22
|
||||||
|
, saved: !err
|
||||||
|
, module: 'ssh'
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var sshAuto = opts.body[0];
|
||||||
|
if (-1 !== [ 'false', 'none', 'off', 'disable' ].indexOf(sshAuto)) {
|
||||||
|
state.config.sshAuto = false;
|
||||||
|
sshSuccess();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (-1 !== [ 'true', 'auto', 'on', 'enable' ].indexOf(sshAuto)) {
|
||||||
|
state.config.sshAuto = 22;
|
||||||
|
sshSuccess();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sshAuto = parseInt(sshAuto, 10);
|
||||||
|
if (!sshAuto || sshAuto <= 0 || sshAuto > 65535) {
|
||||||
|
res.statusCode = 400;
|
||||||
|
res.setHeader('Content-Type', 'application/json');
|
||||||
|
res.end(JSON.stringify({ error: { message: "bad ssh_auto option '" + opts.body[0] + "'" } }));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
state.config.sshAuto = sshAuto;
|
||||||
|
sshSuccess();
|
||||||
|
};
|
||||||
function serveControlsHelper() {
|
function serveControlsHelper() {
|
||||||
controlServer = http.createServer(function (req, res) {
|
controlServer = http.createServer(function (req, res) {
|
||||||
var opts = url.parse(req.url, true);
|
var opts = url.parse(req.url, true);
|
||||||
|
@ -109,17 +305,6 @@ function serveControlsHelper() {
|
||||||
res.end(JSON.stringify(dumpy));
|
res.end(JSON.stringify(dumpy));
|
||||||
}
|
}
|
||||||
|
|
||||||
function sshSuccess() {
|
|
||||||
fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) {
|
|
||||||
if (err) {
|
|
||||||
res.statusCode = 500;
|
|
||||||
res.end('{"error":{"message":"Could not save config file. Perhaps you\'re not running as root?"}}');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
res.end('{"success":true}');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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');
|
res.setHeader('Content-Type', 'appliCation/json');
|
||||||
res.end(JSON.stringify(state.config));
|
res.end(JSON.stringify(state.config));
|
||||||
|
@ -289,119 +474,13 @@ function serveControlsHelper() {
|
||||||
//
|
//
|
||||||
// With proper config
|
// With proper config
|
||||||
//
|
//
|
||||||
function getAppname(pathname) {
|
|
||||||
// port number
|
|
||||||
if (String(pathname) === String(parseInt(pathname, 10))) {
|
|
||||||
return String(pathname);
|
|
||||||
}
|
|
||||||
var paths = pathname.split(/[\\\/\:]/);
|
|
||||||
// rid trailing slash(es)
|
|
||||||
while (!paths[paths.length -1]) {
|
|
||||||
paths.pop();
|
|
||||||
}
|
|
||||||
var name = paths.pop();
|
|
||||||
name = path.basename(name, path.extname(name));
|
|
||||||
name = name.replace(/\./, '-').replace(/-+/, '-');
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
function getServername(servernames, sub) {
|
|
||||||
if (state.servernames[sub]) {
|
|
||||||
return sub;
|
|
||||||
}
|
|
||||||
|
|
||||||
var names = Object.keys(servernames).map(function (servername) {
|
|
||||||
if ('*.' === servername.slice(0,2)) {
|
|
||||||
return servername;
|
|
||||||
}
|
|
||||||
return '*.' + servername;
|
|
||||||
}).sort(function (a, b) {
|
|
||||||
return b.length - a.length;
|
|
||||||
});
|
|
||||||
|
|
||||||
return names.filter(function (pattern) {
|
|
||||||
// '.example.com' = '*.example.com'.split(1)
|
|
||||||
var subPiece = pattern.slice(1);
|
|
||||||
// '.com' = 'sub.example.com'.slice(-4)
|
|
||||||
// '.example.com' = 'sub.example.com'.slice(-12)
|
|
||||||
if (subPiece === sub.slice(-subPiece.length)) {
|
|
||||||
return subPiece;
|
|
||||||
}
|
|
||||||
})[0];
|
|
||||||
}
|
|
||||||
if (/http/.test(opts.pathname)) {
|
if (/http/.test(opts.pathname)) {
|
||||||
if (!opts.body) {
|
controllers.http(req, res, opts);
|
||||||
res.statusCode = 422;
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
res.end(JSON.stringify({"error":{"message":"module \'http\' needs more arguments"}}));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var portOrPath = opts.body[0];
|
|
||||||
var appname = getAppname(portOrPath);
|
|
||||||
var subdomain = opts.body[1];
|
|
||||||
if (subdomain) {
|
|
||||||
var handlerName = getServername(state.servernames, subdomain);
|
|
||||||
if (!handlerName) {
|
|
||||||
res.statusCode = 400;
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
// TODO let the user set up inactive domains
|
|
||||||
res.end(JSON.stringify({ error: { "message":"servername '" + subdomain + "' is not being handled by the remote" } }));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!state.servernames[subdomain]) {
|
|
||||||
state.servernames[subdomain] = {};
|
|
||||||
}
|
|
||||||
state.servernames[subdomain].handler = opts.body[0];
|
|
||||||
} else {
|
|
||||||
if (!Object.keys(state.servernames).sort(function (a, b) {
|
|
||||||
return b.length - a.length;
|
|
||||||
}).some(function (key) {
|
|
||||||
if (state.servernames[key].handler === appname) {
|
|
||||||
// example.com.handler: 3000 // already set
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (state.servernames[key].wildcard) {
|
|
||||||
if (!state.servernames[appname + '.' + key]) {
|
|
||||||
state.servernames[appname + '.' + key] = {};
|
|
||||||
}
|
|
||||||
state.servernames[appname + '.' + key].handler = portOrPath;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
})) {
|
|
||||||
Object.keys(state.servernames).forEach(function (key) {
|
|
||||||
state.servernames[key].handler = portOrPath;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
res.end(JSON.stringify({ success: true }));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/tcp/.test(opts.pathname)) {
|
if (/tcp/.test(opts.pathname)) {
|
||||||
if (!opts.body) {
|
controllers.tcp(req, res, opts);
|
||||||
res.statusCode = 422;
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
res.end(JSON.stringify({ error: { message: "module 'tcp' needs more arguments" } }));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// portnum
|
|
||||||
if (opts.body[1]) {
|
|
||||||
if (!state.ports[opts.body[1]]) {
|
|
||||||
res.statusCode = 400;
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
res.end(JSON.stringify({ error: { "message":"bad port '" + opts.body[1] + "'" } }));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// forward-to port-or-module
|
|
||||||
state.ports[opts.body[1]].handler = opts.body[0];
|
|
||||||
} else {
|
|
||||||
Object.keys(state.ports).forEach(function (key) {
|
|
||||||
state.ports[key].handler = opts.body[0];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
res.end(JSON.stringify({ success: true }));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,34 +502,7 @@ function serveControlsHelper() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/ssh/.test(opts.pathname)) {
|
if (/ssh/.test(opts.pathname)) {
|
||||||
var sshAuto;
|
controllers.ssh(req, res, opts);
|
||||||
if (!opts.body) {
|
|
||||||
res.statusCode = 422;
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
res.end(JSON.stringify({"error":{"message":"module 'ssh' needs more arguments"}}));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sshAuto = opts.body[0];
|
|
||||||
if (-1 !== [ 'false', 'none', 'off', 'disable' ].indexOf(sshAuto)) {
|
|
||||||
state.config.sshAuto = false;
|
|
||||||
sshSuccess();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (-1 !== [ 'true', 'auto', 'on', 'enable' ].indexOf(sshAuto)) {
|
|
||||||
state.config.sshAuto = 22;
|
|
||||||
sshSuccess();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sshAuto = parseInt(sshAuto, 10);
|
|
||||||
if (!sshAuto || sshAuto <= 0 || sshAuto > 65535) {
|
|
||||||
res.statusCode = 400;
|
|
||||||
res.setHeader('Content-Type', 'application/json');
|
|
||||||
res.end(JSON.stringify({ error: { message: "bad ssh_auto option '" + opts.body[0] + "'" } }));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state.config.sshAuto = sshAuto;
|
|
||||||
sshSuccess();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,14 +728,16 @@ function rawTunnel(rawCb) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// by virtue of the fact that it's being tunneled through a
|
// Even though it's being tunneled by a trusted source
|
||||||
// trusted source that is already checking, we're good
|
// we need to make sure we don't get rate-limit spammed
|
||||||
//if (-1 !== state.config.servernames.indexOf(opts.domains[0])) {
|
// with wildcard domains
|
||||||
|
// TODO: finish implementing dynamic dns for wildcard certs
|
||||||
|
if (!getServername(opts.domains[0])) {
|
||||||
opts.email = state.greenlockConf.email || state.config.email;
|
opts.email = state.greenlockConf.email || state.config.email;
|
||||||
opts.agreeTos = state.greenlockConf.agree || state.greenlockConf.agreeTos || state.config.agreeTos;
|
opts.agreeTos = state.greenlockConf.agree || state.greenlockConf.agreeTos || state.config.agreeTos;
|
||||||
cb(null, { options: opts, certs: certs });
|
cb(null, { options: opts, certs: certs });
|
||||||
return;
|
return;
|
||||||
//}
|
}
|
||||||
|
|
||||||
//cb(new Error("servername not found in allowed list"));
|
//cb(new Error("servername not found in allowed list"));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue