From 5584638907901cb9cad9f97e7dfc065074335001 Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Fri, 29 Jun 2018 14:51:56 -0600 Subject: [PATCH] working: manage token with client --- .gitignore | 1 + bin/telebit.js | 44 +++++++++++++++++++++++++++----------------- bin/telebitd.js | 30 ++++++++++++++++++++++++++++-- lib/remote.js | 9 +++++++++ 4 files changed, 65 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 54ebd46..319b82f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules.* *.*.sw* +etc/acme/ bin/node bin/npm bin/npx diff --git a/bin/telebit.js b/bin/telebit.js index 9834e1d..4a4eed7 100755 --- a/bin/telebit.js +++ b/bin/telebit.js @@ -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); } diff --git a/bin/telebitd.js b/bin/telebitd.js index 0e62244..1243501 100755 --- a/bin/telebitd.js +++ b/bin/telebitd.js @@ -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); diff --git a/lib/remote.js b/lib/remote.js index 9ac157b..de57996 100644 --- a/lib/remote.js +++ b/lib/remote.js @@ -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(); }