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