working: manage token with client

This commit is contained in:
AJ ONeal 2018-06-29 14:51:56 -06:00
parent fce8e366c6
commit 5584638907
4 changed files with 65 additions and 19 deletions

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
node_modules.*
*.*.sw*
etc/acme/
bin/node
bin/npm
bin/npx

View File

@ -264,7 +264,8 @@ function askForConfig(state, mainCb) {
var jwt = require('jsonwebtoken');
resp = (resp || '').trim();
try {
state.config.token = jwt.decode(resp);
jwt.decode(resp);
state.config.token = resp;
} catch(e) {
// is not jwt
}
@ -474,6 +475,13 @@ function makeRpc(key) {
function packConfig(config) {
return Object.keys(config).map(function (key) {
var val = config[key];
if ('undefined' === val) {
throw new Error("'undefined' used as a string value");
}
if ('undefined' === typeof val) {
//console.warn('[DEBUG]', key, 'is present but undefined');
return;
}
if (val && 'object' === typeof val && !Array.isArray(val)) {
val = JSON.stringify(val);
}
@ -495,19 +503,18 @@ function getToken(err, state) {
return;
}
, directory: function (dir, next) {
//console.log('Telebit Relay Discovered:');
state._apiDirectory = dir;
//console.log('[directory] Telebit Relay Discovered:');
//console.log(dir);
//console.log();
state._apiDirectory = dir;
next();
}
, tunnelUrl: function (tunnelUrl, next) {
//console.log('Telebit Relay Tunnel Socket:', tunnelUrl);
//console.log('[tunnelUrl] Telebit Relay Tunnel Socket:', tunnelUrl);
state.wss = tunnelUrl;
next();
}
, requested: function (authReq, next) {
//console.log("Pairing Requested");
//console.log("[requested] Pairing Requested");
state.config._otp = state.config._otp = authReq.otp;
if (!state.config.token && state._can_pair) {
@ -527,12 +534,11 @@ function getToken(err, state) {
next();
}
, connect: function (pretoken, next) {
//console.log("Enabling Pairing Locally...");
//console.log("[connect] Enabling Pairing Locally...");
state.config.pretoken = pretoken;
state._connecting = true;
// TODO use php-style object querification
// TODO XXX
utils.putConfig('config', packConfig(state.config), function (err/*, body*/) {
if (err) {
state._error = err;
@ -545,15 +551,19 @@ function getToken(err, state) {
});
}
, offer: function (token, next) {
//console.log("Pairing Enabled by Relay");
//console.log("[offer] Pairing Enabled by Relay");
state.config.token = token;
if (state._error) {
return;
}
if (state._connecting) {
return;
}
state._connecting = true;
console.log("Token Offered:");
console.log(token);
try {
console.log(require('jsonwebtoken').decode(token));
} catch(e) {
console.warn("[warning] could not decode token");
}
utils.putConfig('config', packConfig(state.config), function (err/*, body*/) {
if (err) {
state._error = err;
@ -566,13 +576,13 @@ function getToken(err, state) {
});
}
, granted: function (_, next) {
//console.log("Pairing complete!");
//console.log("[grant] Pairing complete!");
next();
}
, end: function () {
utils.putConfig('enable', [], function (err) {
if (err) { console.error(err); return; }
//console.info("Success");
console.info("[end] Success");
// workaround for https://github.com/nodejs/node/issues/21319
if (state._useTty) {
@ -644,7 +654,7 @@ function handleConfig(err, config) {
state.config.relay = 'telebit.cloud';
}
console.log("question the user?", Date.now());
//console.log("question the user?", Date.now());
askForConfig(state, function (err, state) {
// no errors actually get passed, so this is just future-proofing
if (err) { throw err; }
@ -653,7 +663,7 @@ function handleConfig(err, config) {
state.config._otp = common.otp();
}
console.log("done questioning:", Date.now());
//console.log("done questioning:", Date.now());
state.relay = state.config.relay;
if (!state.token && !state.config.token) {
getToken(err, state);
@ -664,7 +674,7 @@ function handleConfig(err, config) {
return;
}
console.log("no questioning:");
//console.log("no questioning:");
parseCli(state);
}

View File

@ -70,6 +70,7 @@ var tokenpath = path.join(path.dirname(confpath), 'access_token.txt');
var token;
try {
token = fs.readFileSync(tokenpath, 'ascii').trim();
console.log('[DEBUG] access_token', typeof token, token);
} catch(e) {
// ignore
}
@ -129,6 +130,8 @@ function serveControlsHelper() {
// without proper config
//
function saveAndReport(err, _tun) {
console.log('[DEBUG] saveAndReport config write', confpath);
console.log(YAML.safeDump(snakeCopy(state.config)));
if (err) { throw err; }
tun = _tun;
fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) {
@ -174,15 +177,27 @@ function serveControlsHelper() {
}
state.otp = conf._otp || '0000'; // this should only be done on the client side
state.config.relay = conf.relay || state.config.relay || '';
console.log();
console.log('conf.token', typeof conf.token, conf.token);
console.log('state.config.token', typeof state.config.token, state.config.token);
state.config.token = conf.token || state.config.token || null;
state.config.secret = conf.secret || state.config.secret || null;
state.pretoken = conf.pretoken || state.config.pretoken || null;
if (state.secret) {
console.log('state.secret');
state.token = common.signToken(state);
}
if (!state.token) {
console.log('!state.token');
state.token = conf._token;
}
console.log();
console.log('JSON.stringify(conf)');
console.log(JSON.stringify(conf));
console.log();
console.log('JSON.stringify(state)');
console.log(JSON.stringify(state));
console.log();
if ('undefined' !== typeof conf.newsletter) {
state.config.newsletter = conf.newsletter;
}
@ -209,6 +224,7 @@ function serveControlsHelper() {
}
if (!state.config.relay || !state.config.email || !state.config.agreeTos) {
console.log('aborting for some reason');
res.statusCode = 400;
res.setHeader('Content-Type', 'application/json');
@ -225,16 +241,20 @@ function serveControlsHelper() {
}
if (tun) {
console.log('ending existing tunnel, starting anew');
tun.end(function () {
console.log('success ending');
rawTunnel(saveAndReport);
});
tun = null;
setTimeout(function () {
if (!tun) {
console.log('failed to end, but starting anyway');
rawTunnel(saveAndReport);
}
}, 3000);
} else {
console.log('no tunnel, starting anew');
rawTunnel(saveAndReport);
}
return;
@ -602,6 +622,7 @@ function rawTunnel(rawCb) {
state.insecure = state.config.relay_ignore_invalid_certificates;
// { relay, config, servernames, ports, sortingHat, net, insecure, token, handlers, greenlockConfig }
console.log("[DEBUG] token", typeof token, token);
tun = remote.connect({
relay: state.relay
, wss: state.wss
@ -659,8 +680,13 @@ state.handlers = {
});
}
, access_token: function (opts) {
state.token = opts.jwt;
state.config.token = opts.jwt;
if ('undefined' === opts.jwt || !opts.jwt) {
console.error("Granted empty access token... ??");
console.error(JSON.stringify(opts));
return;
}
state.token = opts.jwt || opts.access_token;
state.config.token = opts.jwt || opts.access_token;
console.info("Updating '" + tokenpath + "' with new token:");
try {
require('fs').writeFileSync(tokenpath, opts.jwt);

View File

@ -32,6 +32,9 @@ function _connect(state) {
state.sortingHat = "./sorting-hat.js";
}
if (state.token) {
if ('undefined' === state.token) {
throw new Error("passed string 'undefined' as token");
}
tokens.push(state.token);
}
@ -569,6 +572,12 @@ function _connect(state) {
}
}
, append: function (token) {
if (!token) {
throw new Error("attempted to append empty token");
}
if ('undefined' === token) {
throw new Error("attempted to append token as the string 'undefined'");
}
if (tokens.indexOf(token) >= 0) {
return PromiseA.resolve();
}