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 camelCopy = recase.camelCopy.bind(recase);
|
||||||
//var snakeCopy = recase.snakeCopy.bind(recase);
|
//var snakeCopy = recase.snakeCopy.bind(recase);
|
||||||
|
|
||||||
|
var urequest = require('@coolaj86/urequest');
|
||||||
var common = require('../lib/cli-common.js');
|
var common = require('../lib/cli-common.js');
|
||||||
|
|
||||||
var argv = process.argv.slice(2);
|
var argv = process.argv.slice(2);
|
||||||
|
@ -141,7 +142,7 @@ function askForConfig(answers, mainCb) {
|
||||||
if (!relay) { relay = 'telebit.cloud'; }
|
if (!relay) { relay = 'telebit.cloud'; }
|
||||||
relay = relay.trim();
|
relay = relay.trim();
|
||||||
var urlstr = common.parseUrl(relay) + common.apiDirectory;
|
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) {
|
if (err) {
|
||||||
console.error("[Network Error] Failed to retrieve '" + urlstr + "'");
|
console.error("[Network Error] Failed to retrieve '" + urlstr + "'");
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
171
bin/telebitd.js
171
bin/telebitd.js
|
@ -512,75 +512,9 @@ function connectTunnel() {
|
||||||
state.sortingHat = state.config.sortingHat;
|
state.sortingHat = state.config.sortingHat;
|
||||||
|
|
||||||
// TODO sortingHat.print(); ?
|
// 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
|
// TODO Check undefined vs false for greenlock config
|
||||||
var remote = require('../');
|
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();
|
console.log();
|
||||||
state.greenlockConfig = {
|
state.greenlockConfig = {
|
||||||
version: state.greenlockConf.version || 'draft-11'
|
version: state.greenlockConf.version || 'draft-11'
|
||||||
|
@ -696,31 +630,122 @@ function rawTunnel(cb) {
|
||||||
, os_arch: os.arch()
|
, 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) {
|
if (err || !body || !body.pair_request) {
|
||||||
cb(null, connectTunnel());
|
cb(null, connectTunnel());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO do auth stuff
|
// 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 = {
|
var req = {
|
||||||
url: pairRequest
|
url: pairRequestUrl
|
||||||
, method: body.pair_request.method
|
, method: body.pair_request.method
|
||||||
, json: state._auth
|
, json: state._auth
|
||||||
};
|
};
|
||||||
console.log('[telebitd.js] req');
|
console.log('[telebitd.js] req');
|
||||||
console.log(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);
|
console.log(body);
|
||||||
// TODO poll for token
|
console.info('Device Pair Code: 0000'.replace('0000', state.otp));
|
||||||
//cb(null, connectTunnel());
|
|
||||||
|
// 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);
|
require('fs').readFile(confpath, 'utf8', parseConfig);
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -52,7 +52,8 @@ common.parseHostname = function (hostname) {
|
||||||
common.apiDirectory = '_apis/telebit.cloud/index.json';
|
common.apiDirectory = '_apis/telebit.cloud/index.json';
|
||||||
|
|
||||||
function leftpad(i, n, c) {
|
function leftpad(i, n, c) {
|
||||||
while (i.toString().length < (n || 4)) {
|
i = i.toString();
|
||||||
|
while (i.length < (n || 4)) {
|
||||||
i = (c || '0') + i;
|
i = (c || '0') + i;
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
|
@ -61,57 +62,6 @@ common.otp = function getOtp() {
|
||||||
return leftpad(Math.round(Math.random() * 9999), 4, '0');
|
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 {
|
try {
|
||||||
mkdirp.sync(path.join(__dirname, '..', 'var', 'log'));
|
mkdirp.sync(path.join(__dirname, '..', 'var', 'log'));
|
||||||
mkdirp.sync(path.join(__dirname, '..', 'var', 'run'));
|
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.",
|
"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",
|
||||||
"bin": {
|
"bin": {
|
||||||
"telebit": "bin/telebit.js"
|
"telebit": "bin/telebit.js",
|
||||||
, "telebitd": "bin/telebitd.js"
|
"telebitd": "bin/telebitd.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
@ -48,6 +48,7 @@
|
||||||
},
|
},
|
||||||
"homepage": "https://git.coolaj86.com/coolaj86/telebit.js#readme",
|
"homepage": "https://git.coolaj86.com/coolaj86/telebit.js#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@coolaj86/urequest": "^1.1.1",
|
||||||
"bluebird": "^3.5.1",
|
"bluebird": "^3.5.1",
|
||||||
"commander": "^2.9.0",
|
"commander": "^2.9.0",
|
||||||
"finalhandler": "^1.1.1",
|
"finalhandler": "^1.1.1",
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var email = 'jon@example.com';
|
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 urequest = require('@coolaj86/urequest');
|
||||||
var req = {
|
var req = {
|
||||||
|
@ -11,8 +14,8 @@ var req = {
|
||||||
subject: email
|
subject: email
|
||||||
, subject_scheme: 'mailto'
|
, subject_scheme: 'mailto'
|
||||||
, scope: ''
|
, scope: ''
|
||||||
, otp: '321654'
|
, otp: pin
|
||||||
, hostname: "Jon's Macbook Pro"
|
, hostname: "User's Macbook Pro"
|
||||||
, os_type: 'Linux'
|
, os_type: 'Linux'
|
||||||
, os_platform: 'linux'
|
, os_platform: 'linux'
|
||||||
, os_release: '4.4.0-116-generic'
|
, os_release: '4.4.0-116-generic'
|
||||||
|
|
Loading…
Reference in New Issue