mirror of
				https://git.coolaj86.com/coolaj86/telebit-relay.js.git
				synced 2025-11-04 10:22:46 +00:00 
			
		
		
		
	updates
This commit is contained in:
		
							parent
							
								
									d6f517ed2b
								
							
						
					
					
						commit
						0013930dbd
					
				@ -13,3 +13,7 @@ greenlock:
 | 
				
			|||||||
    strategy: le-store-certbot # certificate storage plugin
 | 
					    strategy: le-store-certbot # certificate storage plugin
 | 
				
			||||||
  config_dir: /etc/acme        # directory for ssl certificates
 | 
					  config_dir: /etc/acme        # directory for ssl certificates
 | 
				
			||||||
secret: ''                     # generate with node -e "console.log(crypto.randomBytes(16).toString('hex'))"
 | 
					secret: ''                     # generate with node -e "console.log(crypto.randomBytes(16).toString('hex'))"
 | 
				
			||||||
 | 
					mailer:
 | 
				
			||||||
 | 
					  url: 'https://api.mailgun.net/v3/EXAMPLE.COM/messages'
 | 
				
			||||||
 | 
					  api_key: 'key-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
 | 
				
			||||||
 | 
					  from: 'Example Mailer <MALIER@EXAMPLE.COM>'
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										29
									
								
								lib/extensions/admin/login/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								lib/extensions/admin/login/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html>
 | 
				
			||||||
 | 
					<head>
 | 
				
			||||||
 | 
					  <!--meta http-equiv="refresh" content="5;url=https://' + tokenData.domains.join(',') + '/?serviceport=' + tokenData.ports.join(',')" /-->
 | 
				
			||||||
 | 
					</head>
 | 
				
			||||||
 | 
					<body>
 | 
				
			||||||
 | 
					  <script>document.body.hidden = true;</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <div class="js-error" hidden>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <div class="js-magic" hidden>
 | 
				
			||||||
 | 
					    <h1>Give us about 30 seconds...</h1>
 | 
				
			||||||
 | 
					    We're initializing our connection, redirecting you to your device at
 | 
				
			||||||
 | 
					    <a class="js-new-href">{{js-new-href}}</a>
 | 
				
			||||||
 | 
					    which will then take a few seconds to initialize as it gets your https certificates for peer-to-peer, end-to-end encryption
 | 
				
			||||||
 | 
					    <br>
 | 
				
			||||||
 | 
					    <br>
 | 
				
			||||||
 | 
					    <small><pre><code class="js-token-data">{{js-token-data}}</code></pre></small>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <script src="js/app.js"></script>
 | 
				
			||||||
 | 
					</body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    res.send("<h1>Invalid Magic Link</h1>"
 | 
				
			||||||
 | 
					    + "<pre><code>'" + magic + "' isn't a valid link.\nLinks are only good for 5 minutes, so act fast.\n"
 | 
				
			||||||
 | 
					    + "(" + new Date(1000*((_auths[magic]||{}).dt||0)).toISOString() + ")</code></pre>\n"
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
							
								
								
									
										23
									
								
								lib/extensions/admin/login/js/app.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								lib/extensions/admin/login/js/app.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					(function () {
 | 
				
			||||||
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var magic = (window.location.hash || '').substr(2).replace(/magic=/, '');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (magic) {
 | 
				
			||||||
 | 
					  window.fetch('https://api.' + location.hostname + '/api/telebit.cloud/magic/' + magic, {
 | 
				
			||||||
 | 
					    method: 'GET'
 | 
				
			||||||
 | 
					  , cors: true
 | 
				
			||||||
 | 
					  }).then(function (resp) {
 | 
				
			||||||
 | 
					    return resp.json().then(function (json) {
 | 
				
			||||||
 | 
					      document.querySelector('body').hidden = false;
 | 
				
			||||||
 | 
					      document.querySelector('js-magic').hidden = false;
 | 
				
			||||||
 | 
					      document.querySelector('js-token-data').innerText = JSON.stringify(json, null, 2);
 | 
				
			||||||
 | 
					      document.querySelector('js-new-href').href = json.domains[0];
 | 
				
			||||||
 | 
					      document.querySelector('js-new-href').innerText = json.domains[0];
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					} else {
 | 
				
			||||||
 | 
					  document.querySelector('body').hidden = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}());
 | 
				
			||||||
							
								
								
									
										0
									
								
								lib/extensions/emails/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								lib/extensions/emails/.gitkeep
									
									
									
									
									
										Normal file
									
								
							@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					'use strict';
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
curl -s --user 'api:YOUR_API_KEY' \
 | 
					curl -s --user 'api:YOUR_API_KEY' \
 | 
				
			||||||
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
 | 
					    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
 | 
				
			||||||
@ -8,6 +9,7 @@ curl -s --user 'api:YOUR_API_KEY' \
 | 
				
			|||||||
    -F text='Testing some Mailgun awesomeness!'
 | 
					    -F text='Testing some Mailgun awesomeness!'
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
var fs = require('fs');
 | 
					var fs = require('fs');
 | 
				
			||||||
 | 
					var escapeHtml = require('escape-html');
 | 
				
			||||||
var _auths = module.exports._auths = {};
 | 
					var _auths = module.exports._auths = {};
 | 
				
			||||||
module.exports.authenticate = function (opts) {
 | 
					module.exports.authenticate = function (opts) {
 | 
				
			||||||
  console.log("It's auth'n time!");
 | 
					  console.log("It's auth'n time!");
 | 
				
			||||||
@ -16,41 +18,48 @@ module.exports.authenticate = function (opts) {
 | 
				
			|||||||
  var state = opts.state;
 | 
					  var state = opts.state;
 | 
				
			||||||
  var jwtoken = opts.auth;
 | 
					  var jwtoken = opts.auth;
 | 
				
			||||||
  var auth;
 | 
					  var auth;
 | 
				
			||||||
  var mailer = {
 | 
					 | 
				
			||||||
    user: 'wizard@telebit.cloud'
 | 
					 | 
				
			||||||
  , secret: 'fbbf21d73c9d2f480bd0e71f5f18494e'
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
  var crypto = require('crypto');
 | 
					  var crypto = require('crypto');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console.log('[DEBUG] ext auth', jwtoken);
 | 
					  console.log('[DEBUG] ext auth', jwtoken);
 | 
				
			||||||
  auth = jwtoken;
 | 
					  auth = jwtoken;
 | 
				
			||||||
  if ('object' === typeof auth && /^.+@.+\..+$/.test(auth.subject)) {
 | 
					  if ('object' === typeof auth && /^.+@.+\..+$/.test(auth.subject)) {
 | 
				
			||||||
    console.log('parsed');
 | 
					 | 
				
			||||||
    var id = crypto.randomBytes(12).toString('hex');
 | 
					 | 
				
			||||||
    //var id = crypto.randomBytes(16).toString('base64').replace(/\+/g,'-').replace(/\//g,'_').replace(/=/g,'');
 | 
					 | 
				
			||||||
    console.log("[DEBUG] gonna send email");
 | 
					    console.log("[DEBUG] gonna send email");
 | 
				
			||||||
 | 
					    auth.id = crypto.randomBytes(12).toString('hex');
 | 
				
			||||||
 | 
					    //var id = crypto.randomBytes(16).toString('base64').replace(/\+/g,'-').replace(/\//g,'_').replace(/=/g,'');
 | 
				
			||||||
 | 
					    var subj = 'Confirm New Device Connection';
 | 
				
			||||||
 | 
					    var text = "You tried connecting with '{{hostname}}' for the first time. Confirm to continue connecting:\n"
 | 
				
			||||||
 | 
					          + '\n'
 | 
				
			||||||
 | 
					          + '    https://' + state.config.webminDomain + '/login/#/magic={{id}}\n'
 | 
				
			||||||
 | 
					          + '\n'
 | 
				
			||||||
 | 
					          + "({{os_arch}} {{os_platform}} {{os_release}})\n"
 | 
				
			||||||
 | 
					          + '\n'
 | 
				
			||||||
 | 
					          ;
 | 
				
			||||||
 | 
					    var html = "You tried connecting with '{{hostname}}' for the first time. Confirm to continue connecting:<br>"
 | 
				
			||||||
 | 
					          + '<br>'
 | 
				
			||||||
 | 
					          + '          <a href="https://' + state.config.webminDomain + '/login/#/magic={{id}}">Confirm Device</a><br>'
 | 
				
			||||||
 | 
					          + '<br>'
 | 
				
			||||||
 | 
					          + '          <small>or copy and paste this link:</small><br>'
 | 
				
			||||||
 | 
					          + '          <small>https://' + state.config.webminDomain + '/login/#/magic={{id}}</small><br>'
 | 
				
			||||||
 | 
					          + '<br>'
 | 
				
			||||||
 | 
					          + "({{os_arch}} {{os_platform}} {{os_release}})<br>"
 | 
				
			||||||
 | 
					          + '<br>'
 | 
				
			||||||
 | 
					          ;
 | 
				
			||||||
 | 
					    [ 'id', 'hostname', 'os_arch', 'os_platform', 'os_release' ].forEach(function (key) {
 | 
				
			||||||
 | 
					      var val = escapeHtml(auth[key]);
 | 
				
			||||||
 | 
					      subj = subj.replace(new RegExp('{{' + key + '}}', 'g'), val);
 | 
				
			||||||
 | 
					      text = text.replace(new RegExp('{{' + key + '}}', 'g'), val);
 | 
				
			||||||
 | 
					      html = html.replace(new RegExp('{{' + key + '}}', 'g'), val);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    return requestAsync({
 | 
					    return requestAsync({
 | 
				
			||||||
      url: 'https://api.mailgun.net/v3/telebit.cloud/messages'
 | 
					      url: state.config.mailer.url
 | 
				
			||||||
    , method: 'POST'
 | 
					    , method: 'POST'
 | 
				
			||||||
    , auth: { user: 'api', pass: 'key-70ef48178081df19783ecfbe6fed5e9a' }
 | 
					    , auth: { user: 'api', pass: state.config.mailer.apiKey }
 | 
				
			||||||
    , formData: {
 | 
					    , formData: {
 | 
				
			||||||
        from: 'Telebit Wizard <wizard@telebit.cloud>'
 | 
					        from: state.config.mailer.from 
 | 
				
			||||||
      , to: auth.subject
 | 
					      , to: auth.subject
 | 
				
			||||||
      , subject: 'Confirm New Device Connection'
 | 
					      , subject: subj 
 | 
				
			||||||
      , text: "You tried connecting with '" + auth.hostname + "' for the first time. Confirm to continue connecting:\n"
 | 
					      , text: text
 | 
				
			||||||
          + '\n'
 | 
					      , html: html
 | 
				
			||||||
          + '    https://www.telebit.cloud/login/?magic=' + id + '\n'
 | 
					 | 
				
			||||||
          + '\n'
 | 
					 | 
				
			||||||
          + "(" + auth.os_arch + " " + auth.os_platform + " " + auth.os_release + ")\n"
 | 
					 | 
				
			||||||
          + '\n'
 | 
					 | 
				
			||||||
      , html: "You tried connecting with '" + auth.hostname + "' for the first time. Confirm to continue connecting:<br>"
 | 
					 | 
				
			||||||
          + '<br>'
 | 
					 | 
				
			||||||
          + '          <a href="https://www.telebit.cloud/login/?magic=' + id + '">Confirm Device</a><br>'
 | 
					 | 
				
			||||||
          + '<br>'
 | 
					 | 
				
			||||||
          + '          <small>or copy and paste this link:<br>https://www.telebit.cloud/login/?magic=' + id + '</small><br>'
 | 
					 | 
				
			||||||
          + '<br>'
 | 
					 | 
				
			||||||
          + "(" + auth.os_arch + " " + auth.os_platform + " " + auth.os_release + ")<br>"
 | 
					 | 
				
			||||||
          + '<br>'
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }).then(function (resp) {
 | 
					    }).then(function (resp) {
 | 
				
			||||||
      console.log("[DEBUG] email was sent, or so they say");
 | 
					      console.log("[DEBUG] email was sent, or so they say");
 | 
				
			||||||
@ -76,12 +85,12 @@ module.exports.authenticate = function (opts) {
 | 
				
			|||||||
          clearTimeout(t);
 | 
					          clearTimeout(t);
 | 
				
			||||||
          delete _auths[id];
 | 
					          delete _auths[id];
 | 
				
			||||||
          var hri = require('human-readable-ids').hri;
 | 
					          var hri = require('human-readable-ids').hri;
 | 
				
			||||||
          var hrname = hri.random() + '.telebit.cloud';
 | 
					          var hrname = hri.random() + '.' + state.config.sharedDomain;
 | 
				
			||||||
          var jwt = require('jsonwebtoken');
 | 
					          var jwt = require('jsonwebtoken');
 | 
				
			||||||
          var tokenData = {
 | 
					          var tokenData = {
 | 
				
			||||||
            domains: [ hrname ]
 | 
					            domains: [ hrname ]
 | 
				
			||||||
          , ports: [ 1024 + Math.round(Math.random() * 6300) ]
 | 
					          , ports: [ 1024 + Math.round(Math.random() * 6300) ]
 | 
				
			||||||
          , aud: 'telebit.cloud'
 | 
					          , aud: state.config.webminDomain
 | 
				
			||||||
          , iss: Math.round(Date.now() / 1000)
 | 
					          , iss: Math.round(Date.now() / 1000)
 | 
				
			||||||
          , id: id
 | 
					          , id: id
 | 
				
			||||||
          , hostname: auth.hostname
 | 
					          , hostname: auth.hostname
 | 
				
			||||||
@ -108,6 +117,7 @@ module.exports.authenticate = function (opts) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  console.log("just trying a normal token...");
 | 
					  console.log("just trying a normal token...");
 | 
				
			||||||
 | 
					  var decoded;
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    decoded = jwt.decode(jwtoken, { complete: true });
 | 
					    decoded = jwt.decode(jwtoken, { complete: true });
 | 
				
			||||||
  } catch(e) {
 | 
					  } catch(e) {
 | 
				
			||||||
@ -120,35 +130,45 @@ module.exports.authenticate = function (opts) {
 | 
				
			|||||||
var path = require('path');
 | 
					var path = require('path');
 | 
				
			||||||
var express = require('express');
 | 
					var express = require('express');
 | 
				
			||||||
var app = express();
 | 
					var app = express();
 | 
				
			||||||
app.use('/', express.static(path.join(__dirname, 'extensions/admin')));
 | 
					var staticApp = express();
 | 
				
			||||||
app.use('/login', function (req, res) {
 | 
					var nowww = require('nowww')();
 | 
				
			||||||
 | 
					var CORS = require('connect-cors');
 | 
				
			||||||
 | 
					staticApp.use('/', express.static(path.join(__dirname, 'admin')));
 | 
				
			||||||
 | 
					app.use('/api', CORS({}));
 | 
				
			||||||
 | 
					app.get('/api/telebit.cloud/magic/:magic', function (req, res) {
 | 
				
			||||||
 | 
					  console.log("DEBUG telebit.cloud magic");
 | 
				
			||||||
  var tokenData;
 | 
					  var tokenData;
 | 
				
			||||||
  var magic = req.query.magic;
 | 
					  var magic = req.params.magic || req.query.magic;
 | 
				
			||||||
 | 
					  console.log("DEBUG telebit.cloud magic 1a");
 | 
				
			||||||
  if (_auths[magic]) {
 | 
					  if (_auths[magic]) {
 | 
				
			||||||
 | 
					    console.log("DEBUG telebit.cloud magic 1b");
 | 
				
			||||||
    tokenData = _auths[magic].resolve();
 | 
					    tokenData = _auths[magic].resolve();
 | 
				
			||||||
    res.send('<!DOCTYPE html><html>'
 | 
					    console.log("DEBUG telebit.cloud magic 1c");
 | 
				
			||||||
      + '<head><meta http-equiv="refresh" content="5;url='
 | 
					    res.send(tokenData);
 | 
				
			||||||
        + 'https://' + tokenData.domains.join(',') + '/?serviceport=' + tokenData.ports.join(',')
 | 
					 | 
				
			||||||
      + '" /></head>'
 | 
					 | 
				
			||||||
      + '<body>'
 | 
					 | 
				
			||||||
      + '<h1>Give us about 30 seconds...</h1>'
 | 
					 | 
				
			||||||
      + 'We\'re initializing our connection, redirecting you to your device at <a href="https://' + tokenData.domains[0] + '">'
 | 
					 | 
				
			||||||
        + tokenData.domains[0]
 | 
					 | 
				
			||||||
      + '</a>, which will then take a few seconds to initialize as it gets your https certificates for peer-to-peer, end-to-end encryption'
 | 
					 | 
				
			||||||
      + '<br>'
 | 
					 | 
				
			||||||
      + '<br>'
 | 
					 | 
				
			||||||
      + '<small><pre><code>' + JSON.stringify(tokenData, null, 2) + '</code></pre></small>'
 | 
					 | 
				
			||||||
      + '</body></html>'
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    res.send("<h1>Invalid Magic Link</h1>"
 | 
					    console.log("DEBUG telebit.cloud magic 2");
 | 
				
			||||||
    + "<pre><code>'" + magic + "' isn't a valid link.\nLinks are only good for 5 minutes, so act fast.\n"
 | 
					    res.send({ error: { code: "E_TOKEN", message: "Invalid or expired magic link." } });
 | 
				
			||||||
    + "(" + new Date(1000*((_auths[magic]||{}).dt||0)).toISOString() + ")</code></pre>\n"
 | 
					    console.log("DEBUG telebit.cloud magic 2b");
 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
module.exports.webadmin = function (state, req, res) {
 | 
					module.exports.webadmin = function (state, req, res) {
 | 
				
			||||||
  //if (!loaded) { loaded = true; app.use('/', state.defaults.webadmin); }
 | 
					  //if (!loaded) { loaded = true; app.use('/', state.defaults.webadmin); }
 | 
				
			||||||
  console.log('[DEBUG] extensions webadmin');
 | 
					  console.log('[DEBUG] extensions webadmin');
 | 
				
			||||||
  app(req, res);
 | 
					  var host = (req.headers.host || '').toLowerCase().split(':')[0];
 | 
				
			||||||
 | 
					  if (state.config.webminDomain === host) {
 | 
				
			||||||
 | 
					    console.log("DEBUG going to static");
 | 
				
			||||||
 | 
					    staticApp(req, res);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if ('api.' + state.config.webminDomain === host) {
 | 
				
			||||||
 | 
					    console.log("DEBUG going to api");
 | 
				
			||||||
 | 
					    app(req, res);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  if ('www.' + state.config.webminDomain === host) {
 | 
				
			||||||
 | 
					    console.log("DEBUG going to www");
 | 
				
			||||||
 | 
					    nowww(req, res);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  res.end("Didn't recognize '" + escapeHtml(host) + "'. Not sure what to do.");
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -39,12 +39,15 @@
 | 
				
			|||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "bluebird": "^3.5.1",
 | 
					    "bluebird": "^3.5.1",
 | 
				
			||||||
    "cluster-store": "^2.0.8",
 | 
					    "cluster-store": "^2.0.8",
 | 
				
			||||||
 | 
					    "connect-cors": "^0.5.6",
 | 
				
			||||||
 | 
					    "escape-html": "^1.0.3",
 | 
				
			||||||
    "express": "^4.16.3",
 | 
					    "express": "^4.16.3",
 | 
				
			||||||
    "finalhandler": "^1.1.1",
 | 
					    "finalhandler": "^1.1.1",
 | 
				
			||||||
    "greenlock": "^2.2.4",
 | 
					    "greenlock": "^2.2.4",
 | 
				
			||||||
    "human-readable-ids": "^1.0.4",
 | 
					    "human-readable-ids": "^1.0.4",
 | 
				
			||||||
    "js-yaml": "^3.11.0",
 | 
					    "js-yaml": "^3.11.0",
 | 
				
			||||||
    "jsonwebtoken": "^8.2.1",
 | 
					    "jsonwebtoken": "^8.2.1",
 | 
				
			||||||
 | 
					    "nowww": "^1.2.1",
 | 
				
			||||||
    "proxy-packer": "^1.4.3",
 | 
					    "proxy-packer": "^1.4.3",
 | 
				
			||||||
    "recase": "^1.0.4",
 | 
					    "recase": "^1.0.4",
 | 
				
			||||||
    "redirect-https": "^1.1.5",
 | 
					    "redirect-https": "^1.1.5",
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user