handle pairing request via API
This commit is contained in:
parent
a763ead434
commit
99b891fd99
|
@ -14,6 +14,7 @@ var recase = require('recase').create({});
|
|||
var camelCopy = recase.camelCopy.bind(recase);
|
||||
//var snakeCopy = recase.snakeCopy.bind(recase);
|
||||
|
||||
var urequest = require('@coolaj86/urequest');
|
||||
var common = require('../lib/cli-common.js');
|
||||
|
||||
var argv = process.argv.slice(2);
|
||||
|
@ -141,7 +142,7 @@ function askForConfig(answers, mainCb) {
|
|||
if (!relay) { relay = 'telebit.cloud'; }
|
||||
relay = relay.trim();
|
||||
var urlstr = common.parseUrl(relay) + common.apiDirectory;
|
||||
common.urequest({ url: urlstr, json: true }, function (err, resp, body) {
|
||||
urequest({ url: urlstr, json: true }, function (err, resp, body) {
|
||||
if (err) {
|
||||
console.error("[Network Error] Failed to retrieve '" + urlstr + "'");
|
||||
console.error(err);
|
||||
|
|
173
bin/telebitd.js
173
bin/telebitd.js
|
@ -512,75 +512,9 @@ function connectTunnel() {
|
|||
state.sortingHat = state.config.sortingHat;
|
||||
|
||||
// TODO sortingHat.print(); ?
|
||||
|
||||
if (state.config.email && !state.token) {
|
||||
console.info();
|
||||
console.info('====================================');
|
||||
console.info('= HEY! LISTEN! =');
|
||||
console.info('====================================');
|
||||
console.info('= =');
|
||||
console.info('= 1. Open your email =');
|
||||
console.info('= =');
|
||||
console.info('= 2. Click the magic login link =');
|
||||
console.info('= Login Code (if needed): 0000 ='.replace('0000', state.otp));
|
||||
console.info('= =');
|
||||
console.info('= 3. Check back here for deets =');
|
||||
console.info('= =');
|
||||
console.info('= =');
|
||||
console.info('====================================');
|
||||
console.info();
|
||||
}
|
||||
// TODO Check undefined vs false for greenlock config
|
||||
var remote = require('../');
|
||||
state.handlers = {
|
||||
grant: function (grants) {
|
||||
console.info("");
|
||||
console.info("Connect to your device by any of the following means:");
|
||||
console.info("");
|
||||
grants.forEach(function (arr) {
|
||||
if ('https' === arr[0]) {
|
||||
if (!state.servernames[arr[1]]) {
|
||||
state.servernames[arr[1]] = {};
|
||||
}
|
||||
} else if ('tcp' === arr[0]) {
|
||||
if (!state.ports[arr[2]]) {
|
||||
state.ports[arr[2]] = {};
|
||||
}
|
||||
}
|
||||
|
||||
if ('ssh+https' === arr[0]) {
|
||||
console.info("SSH+HTTPS");
|
||||
} else if ('ssh' === arr[0]) {
|
||||
console.info("SSH");
|
||||
} else if ('tcp' === arr[0]) {
|
||||
console.info("TCP");
|
||||
} else if ('https' === arr[0]) {
|
||||
console.info("HTTPS");
|
||||
}
|
||||
console.info('\t' + arr[0] + '://' + arr[1] + (arr[2] ? (':' + arr[2]) : ''));
|
||||
if ('ssh+https' === arr[0]) {
|
||||
console.info("\tex: ssh -o ProxyCommand='openssl s_client -connect %h:%p -servername %h -quiet' " + arr[1] + " -p 443\n");
|
||||
} else if ('ssh' === arr[0]) {
|
||||
console.info("\tex: ssh " + arr[1] + " -p " + arr[2] + "\n");
|
||||
} else if ('tcp' === arr[0]) {
|
||||
console.info("\tex: netcat " + arr[1] + " " + arr[2] + "\n");
|
||||
} else if ('https' === arr[0]) {
|
||||
console.info("\tex: curl https://" + arr[1] + "\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
, access_token: function (opts) {
|
||||
state.token = opts.jwt;
|
||||
state.config.token = opts.jwt;
|
||||
console.info("Updating '" + tokenpath + "' with new token:");
|
||||
try {
|
||||
require('fs').writeFileSync(tokenpath, opts.jwt);
|
||||
} catch (e) {
|
||||
console.error("Token not saved:");
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
console.log();
|
||||
state.greenlockConfig = {
|
||||
version: state.greenlockConf.version || 'draft-11'
|
||||
|
@ -696,31 +630,122 @@ function rawTunnel(cb) {
|
|||
, os_arch: os.arch()
|
||||
};
|
||||
|
||||
if (state.config.email && !state.token) {
|
||||
console.info();
|
||||
console.info('====================================');
|
||||
console.info('= HEY! LISTEN! =');
|
||||
console.info('====================================');
|
||||
console.info('= =');
|
||||
console.info('= 1. Open your email =');
|
||||
console.info('= =');
|
||||
console.info('= 2. Click the magic login link =');
|
||||
console.info('= Login Code (if needed): 0000 ='.replace('0000', state.otp));
|
||||
console.info('= =');
|
||||
console.info('= 3. Check back here for deets =');
|
||||
console.info('= =');
|
||||
console.info('= =');
|
||||
console.info('====================================');
|
||||
console.info();
|
||||
}
|
||||
|
||||
if (err || !body || !body.pair_request) {
|
||||
cb(null, connectTunnel());
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO do auth stuff
|
||||
var pairRequest = url.resolve('https://' + body.api_host.replace(/:hostname/g, state.relayHostname), body.pair_request.pathname);
|
||||
var pairRequestUrl = url.resolve('https://' + body.api_host.replace(/:hostname/g, state.relayHostname), body.pair_request.pathname);
|
||||
var req = {
|
||||
url: pairRequest
|
||||
url: pairRequestUrl
|
||||
, method: body.pair_request.method
|
||||
, json: state._auth
|
||||
};
|
||||
console.log('[telebitd.js] req');
|
||||
console.log(req);
|
||||
urequest(req, function (err, resp, body) {
|
||||
if (err) { console.error('[telebitd.js] pair request', err); }
|
||||
|
||||
function gotoNext(req) {
|
||||
urequest(req, function (err, resp, body) {
|
||||
if (err) { console.error('[telebitd.js] pair request', err); return; }
|
||||
|
||||
console.log('\nToken Request Body:');
|
||||
console.log(resp.headers);
|
||||
console.log(body);
|
||||
// TODO poll for token
|
||||
//cb(null, connectTunnel());
|
||||
}
|
||||
);
|
||||
console.info('Device Pair Code: 0000'.replace('0000', state.otp));
|
||||
|
||||
// pending, try again
|
||||
if (resp.headers.location) {
|
||||
setTimeout(gotoNext, 2 * 1000, { url: resp.headers.location, json: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if ('ready' !== body.status) {
|
||||
console.error("\n[error] neither ready nor pending...");
|
||||
console.error(body);
|
||||
return;
|
||||
}
|
||||
|
||||
state.token = body.access_token;
|
||||
state.config.token = state.token;
|
||||
state.handlers.access_token({ jwt: state.token });
|
||||
cb(null, connectTunnel());
|
||||
});
|
||||
}
|
||||
|
||||
gotoNext(req);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
state.handlers = {
|
||||
grant: function (grants) {
|
||||
console.info("");
|
||||
console.info("Connect to your device by any of the following means:");
|
||||
console.info("");
|
||||
grants.forEach(function (arr) {
|
||||
if ('https' === arr[0]) {
|
||||
if (!state.servernames[arr[1]]) {
|
||||
state.servernames[arr[1]] = {};
|
||||
}
|
||||
} else if ('tcp' === arr[0]) {
|
||||
if (!state.ports[arr[2]]) {
|
||||
state.ports[arr[2]] = {};
|
||||
}
|
||||
}
|
||||
|
||||
if ('ssh+https' === arr[0]) {
|
||||
console.info("SSH+HTTPS");
|
||||
} else if ('ssh' === arr[0]) {
|
||||
console.info("SSH");
|
||||
} else if ('tcp' === arr[0]) {
|
||||
console.info("TCP");
|
||||
} else if ('https' === arr[0]) {
|
||||
console.info("HTTPS");
|
||||
}
|
||||
console.info('\t' + arr[0] + '://' + arr[1] + (arr[2] ? (':' + arr[2]) : ''));
|
||||
if ('ssh+https' === arr[0]) {
|
||||
console.info("\tex: ssh -o ProxyCommand='openssl s_client -connect %h:%p -servername %h -quiet' " + arr[1] + " -p 443\n");
|
||||
} else if ('ssh' === arr[0]) {
|
||||
console.info("\tex: ssh " + arr[1] + " -p " + arr[2] + "\n");
|
||||
} else if ('tcp' === arr[0]) {
|
||||
console.info("\tex: netcat " + arr[1] + " " + arr[2] + "\n");
|
||||
} else if ('https' === arr[0]) {
|
||||
console.info("\tex: curl https://" + arr[1] + "\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
, access_token: function (opts) {
|
||||
state.token = opts.jwt;
|
||||
state.config.token = opts.jwt;
|
||||
console.info("Updating '" + tokenpath + "' with new token:");
|
||||
try {
|
||||
require('fs').writeFileSync(tokenpath, opts.jwt);
|
||||
} catch (e) {
|
||||
console.error("Token not saved:");
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
require('fs').readFile(confpath, 'utf8', parseConfig);
|
||||
|
||||
}());
|
||||
|
|
|
@ -52,7 +52,8 @@ common.parseHostname = function (hostname) {
|
|||
common.apiDirectory = '_apis/telebit.cloud/index.json';
|
||||
|
||||
function leftpad(i, n, c) {
|
||||
while (i.toString().length < (n || 4)) {
|
||||
i = i.toString();
|
||||
while (i.length < (n || 4)) {
|
||||
i = (c || '0') + i;
|
||||
}
|
||||
return i;
|
||||
|
@ -61,57 +62,6 @@ common.otp = function getOtp() {
|
|||
return leftpad(Math.round(Math.random() * 9999), 4, '0');
|
||||
};
|
||||
|
||||
common.urequest = function (opts, cb) {
|
||||
var https = require('https');
|
||||
// request.js behavior:
|
||||
// encoding: null + json ? unknown
|
||||
// json => attempt to parse, fail silently
|
||||
// encoding => buffer.toString(encoding)
|
||||
// null === encoding => Buffer.concat(buffers)
|
||||
https.get(opts.url, function (resp) {
|
||||
var encoding = opts.encoding;
|
||||
if (null === encoding) {
|
||||
resp._body = [];
|
||||
} else {
|
||||
resp.body = '';
|
||||
}
|
||||
if (!resp.headers['content-length'] || 0 === parseInt(resp.headers['content-length'], 10)) {
|
||||
cb(resp);
|
||||
}
|
||||
resp._bodyLength = 0;
|
||||
resp.on('data', function (chunk) {
|
||||
if ('string' === typeof resp.body) {
|
||||
resp.body += chunk.toString(encoding);
|
||||
} else {
|
||||
resp._body.push(chunk);
|
||||
resp._bodyLength += chunk.length;
|
||||
}
|
||||
});
|
||||
resp.on('end', function () {
|
||||
if ('string' !== typeof resp.body) {
|
||||
if (1 === resp._body.length) {
|
||||
resp.body = resp._body[0];
|
||||
} else {
|
||||
resp.body = Buffer.concat(resp._body, resp._bodyLength);
|
||||
}
|
||||
resp._body = null;
|
||||
}
|
||||
if (opts.json && 'string' === typeof resp.body) {
|
||||
// TODO I would parse based on Content-Type
|
||||
// but request.js doesn't do that.
|
||||
try {
|
||||
resp.body = JSON.parse(resp.body);
|
||||
} catch(e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
cb(null, resp, resp.body);
|
||||
});
|
||||
}).on('error', function (e) {
|
||||
cb(e);
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
mkdirp.sync(path.join(__dirname, '..', 'var', 'log'));
|
||||
mkdirp.sync(path.join(__dirname, '..', 'var', 'run'));
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
"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",
|
||||
"bin": {
|
||||
"telebit": "bin/telebit.js"
|
||||
, "telebitd": "bin/telebitd.js"
|
||||
"telebit": "bin/telebit.js",
|
||||
"telebitd": "bin/telebitd.js"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
|
@ -48,6 +48,7 @@
|
|||
},
|
||||
"homepage": "https://git.coolaj86.com/coolaj86/telebit.js#readme",
|
||||
"dependencies": {
|
||||
"@coolaj86/urequest": "^1.1.1",
|
||||
"bluebird": "^3.5.1",
|
||||
"commander": "^2.9.0",
|
||||
"finalhandler": "^1.1.1",
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
'use strict';
|
||||
|
||||
var email = 'jon@example.com';
|
||||
var pin = Math.round(Math.random() * 999999).toString().padStart(6, '0'); // '321654'
|
||||
|
||||
console.log('Pair Code:', pin);
|
||||
|
||||
var urequest = require('@coolaj86/urequest');
|
||||
var req = {
|
||||
|
@ -11,8 +14,8 @@ var req = {
|
|||
subject: email
|
||||
, subject_scheme: 'mailto'
|
||||
, scope: ''
|
||||
, otp: '321654'
|
||||
, hostname: "Jon's Macbook Pro"
|
||||
, otp: pin
|
||||
, hostname: "User's Macbook Pro"
|
||||
, os_type: 'Linux'
|
||||
, os_platform: 'linux'
|
||||
, os_release: '4.4.0-116-generic'
|
||||
|
|
Loading…
Reference in New Issue