| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | ;(function () { | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var Vue = window.Vue; | 
					
						
							| 
									
										
										
										
											2018-10-18 01:52:30 -06:00
										 |  |  | var Telebit = window.TELEBIT; | 
					
						
							| 
									
										
										
										
											2019-05-11 02:17:12 -06:00
										 |  |  | var Keypairs = window.Keypairs; | 
					
						
							| 
									
										
										
										
											2019-05-11 14:00:17 -06:00
										 |  |  | var ACME = window.ACME; | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | var api = {}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-21 03:32:04 -06:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  | function safeFetch(url, opts) { | 
					
						
							|  |  |  |   var controller = new AbortController(); | 
					
						
							|  |  |  |   var tok = setTimeout(function () { | 
					
						
							|  |  |  |     controller.abort(); | 
					
						
							|  |  |  |   }, 4000); | 
					
						
							|  |  |  |   if (!opts) { | 
					
						
							|  |  |  |     opts = {}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   opts.signal = controller.signal; | 
					
						
							|  |  |  |   return window.fetch(url, opts).finally(function () { | 
					
						
							|  |  |  |     clearTimeout(tok); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-21 03:32:04 -06:00
										 |  |  | */ | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | api.config = function apiConfig() { | 
					
						
							| 
									
										
										
										
											2018-10-21 03:32:04 -06:00
										 |  |  |   return Telebit.reqLocalAsync({ | 
					
						
							|  |  |  |     url: "/api/config" | 
					
						
							|  |  |  |   , method: "GET" | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |   }).then(function (resp) { | 
					
						
							| 
									
										
										
										
											2018-10-21 03:32:04 -06:00
										 |  |  |     var json = resp.body; | 
					
						
							|  |  |  |     appData.config = json; | 
					
						
							|  |  |  |     return json; | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | api.status = function apiStatus() { | 
					
						
							| 
									
										
										
										
											2018-10-21 03:32:04 -06:00
										 |  |  |   return Telebit.reqLocalAsync({ url: "/api/status", method: "GET" }).then(function (resp) { | 
					
						
							|  |  |  |     var json = resp.body; | 
					
						
							|  |  |  |     return json; | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-11-01 03:11:47 -06:00
										 |  |  | api.http = function apiHttp(o) { | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |   var opts = { | 
					
						
							|  |  |  |     url: "/api/http" | 
					
						
							|  |  |  |   , method: "POST" | 
					
						
							|  |  |  |   , headers: { 'Content-Type': 'application/json' } | 
					
						
							| 
									
										
										
										
											2018-11-01 03:11:47 -06:00
										 |  |  |   , json: { name: o.name, handler: o.handler, indexes: o.indexes } | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |   }; | 
					
						
							|  |  |  |   return Telebit.reqLocalAsync(opts).then(function (resp) { | 
					
						
							|  |  |  |     var json = resp.body; | 
					
						
							|  |  |  |     appData.initResult = json; | 
					
						
							|  |  |  |     return json; | 
					
						
							|  |  |  |   }).catch(function (err) { | 
					
						
							|  |  |  |     window.alert("Error: [init] " + (err.message || JSON.stringify(err, null, 2))); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | api.ssh = function apiSsh(port) { | 
					
						
							|  |  |  |   var opts = { | 
					
						
							|  |  |  |     url: "/api/ssh" | 
					
						
							|  |  |  |   , method: "POST" | 
					
						
							|  |  |  |   , headers: { 'Content-Type': 'application/json' } | 
					
						
							|  |  |  |   , json: { port: port } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   return Telebit.reqLocalAsync(opts).then(function (resp) { | 
					
						
							|  |  |  |     var json = resp.body; | 
					
						
							|  |  |  |     appData.initResult = json; | 
					
						
							|  |  |  |     return json; | 
					
						
							|  |  |  |   }).catch(function (err) { | 
					
						
							|  |  |  |     window.alert("Error: [init] " + (err.message || JSON.stringify(err, null, 2))); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  | api.enable = function apiEnable() { | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |   var opts = { | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  |     url: "/api/enable" | 
					
						
							| 
									
										
										
										
											2018-10-21 03:32:04 -06:00
										 |  |  |   , method: "POST" | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  |   //, headers: { 'Content-Type': 'application/json' }
 | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   return Telebit.reqLocalAsync(opts).then(function (resp) { | 
					
						
							|  |  |  |     var json = resp.body; | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |     console.log('enable', json); | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  |     return json; | 
					
						
							|  |  |  |   }).catch(function (err) { | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |     window.alert("Error: [enable] " + (err.message || JSON.stringify(err, null, 2))); | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | api.disable = function apiDisable() { | 
					
						
							|  |  |  |   var opts = { | 
					
						
							|  |  |  |     url: "/api/disable" | 
					
						
							|  |  |  |   , method: "POST" | 
					
						
							|  |  |  |   //, headers: { 'Content-Type': 'application/json' }
 | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |   }; | 
					
						
							| 
									
										
										
										
											2018-10-21 03:32:04 -06:00
										 |  |  |   return Telebit.reqLocalAsync(opts).then(function (resp) { | 
					
						
							|  |  |  |     var json = resp.body; | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |     console.log('disable', json); | 
					
						
							| 
									
										
										
										
											2018-10-21 03:32:04 -06:00
										 |  |  |     return json; | 
					
						
							|  |  |  |   }).catch(function (err) { | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |     window.alert("Error: [disable] " + (err.message || JSON.stringify(err, null, 2))); | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  | function showOtp(otp, pollUrl) { | 
					
						
							|  |  |  |   localStorage.setItem('poll_url', pollUrl); | 
					
						
							|  |  |  |   telebitState.pollUrl = pollUrl; | 
					
						
							|  |  |  |   appData.init.otp = otp; | 
					
						
							|  |  |  |   changeState('otp'); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | function doConfigure() { | 
					
						
							|  |  |  |   if (telebitState.dir.pair_request) { | 
					
						
							|  |  |  |     telebitState._can_pair = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   //
 | 
					
						
							|  |  |  |   // Read config from form
 | 
					
						
							|  |  |  |   //
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Create Empty Config, If Necessary
 | 
					
						
							|  |  |  |   if (!telebitState.config) { telebitState.config = {}; } | 
					
						
							|  |  |  |   if (!telebitState.config.greenlock) { telebitState.config.greenlock = {}; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Populate Config
 | 
					
						
							|  |  |  |   if (appData.init.teletos && appData.init.letos) { telebitState.config.agreeTos = true; } | 
					
						
							|  |  |  |   if (appData.init.relay) { telebitState.config.relay = appData.init.relay; } | 
					
						
							|  |  |  |   if (appData.init.email) { telebitState.config.email = appData.init.email; } | 
					
						
							|  |  |  |   if ('undefined' !== typeof appData.init.letos) { telebitState.config.greenlock.agree = appData.init.letos; } | 
					
						
							|  |  |  |   if ('newsletter' === appData.init.notifications) { | 
					
						
							|  |  |  |     telebitState.config.newsletter = true; telebitState.config.communityMember = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if ('important' === appData.init.notifications) { telebitState.config.communityMember = true; } | 
					
						
							|  |  |  |   if (appData.init.acmeVersion) { telebitState.config.greenlock.version = appData.init.acmeVersion; } | 
					
						
							|  |  |  |   if (appData.init.acmeServer) { telebitState.config.greenlock.server = appData.init.acmeServer; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Temporary State
 | 
					
						
							|  |  |  |   telebitState._otp = Telebit.otp(); | 
					
						
							|  |  |  |   appData.init.otp = telebitState._otp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return Telebit.authorize(telebitState, showOtp).then(function () { | 
					
						
							| 
									
										
										
										
											2018-10-24 23:34:12 -06:00
										 |  |  |     return changeState('status'); | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-18 01:11:37 -06:00
										 |  |  | // TODO test for internet connectivity (and telebit connectivity)
 | 
					
						
							|  |  |  | var DEFAULT_RELAY = 'telebit.cloud'; | 
					
						
							|  |  |  | var BETA_RELAY = 'telebit.ppl.family'; | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  | var TELEBIT_RELAYS = [ | 
					
						
							|  |  |  |   DEFAULT_RELAY | 
					
						
							|  |  |  | , BETA_RELAY | 
					
						
							|  |  |  | ]; | 
					
						
							|  |  |  | var PRODUCTION_ACME = 'https://acme-v02.api.letsencrypt.org/directory'; | 
					
						
							|  |  |  | var STAGING_ACME = 'https://acme-staging-v02.api.letsencrypt.org/directory'; | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | var appData = { | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  |   config: {} | 
					
						
							|  |  |  | , status: {} | 
					
						
							| 
									
										
										
										
											2018-10-18 01:11:37 -06:00
										 |  |  | , init: { | 
					
						
							|  |  |  |     teletos: true | 
					
						
							|  |  |  |   , letos: true | 
					
						
							|  |  |  |   , notifications: "important" | 
					
						
							|  |  |  |   , relay: DEFAULT_RELAY | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |   , telemetry: true | 
					
						
							|  |  |  |   , acmeServer: PRODUCTION_ACME | 
					
						
							| 
									
										
										
										
											2018-10-18 01:11:37 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  | , state: {} | 
					
						
							| 
									
										
										
										
											2018-10-18 01:11:37 -06:00
										 |  |  | , views: { | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  |     flash: { | 
					
						
							|  |  |  |       error: "" | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   , section: { | 
					
						
							|  |  |  |       loading: true | 
					
						
							|  |  |  |     , setup: false | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |     , advanced: false | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  |     , otp: false | 
					
						
							|  |  |  |     , status: false | 
					
						
							| 
									
										
										
										
											2018-10-18 01:11:37 -06:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  | , newHttp: {} | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  | var telebitState = {}; | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | var appMethods = { | 
					
						
							|  |  |  |   initialize: function () { | 
					
						
							|  |  |  |     console.log("call initialize"); | 
					
						
							| 
									
										
										
										
											2018-10-18 01:11:37 -06:00
										 |  |  |     if (!appData.init.relay) { | 
					
						
							|  |  |  |       appData.init.relay = DEFAULT_RELAY; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |     appData.init.relay = appData.init.relay.toLowerCase(); | 
					
						
							|  |  |  |     telebitState = { relay: appData.init.relay }; | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |     return Telebit.api.directory(telebitState).then(function (dir) { | 
					
						
							|  |  |  |       if (!dir.api_host) { | 
					
						
							|  |  |  |         window.alert("Error: '" + telebitState.relay + "' does not appear to be a valid telebit service"); | 
					
						
							| 
									
										
										
										
											2018-10-18 01:52:30 -06:00
										 |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |       telebitState.dir = dir; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // If it's one of the well-known relays
 | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |       if (-1 !== TELEBIT_RELAYS.indexOf(appData.init.relay)) { | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  |         return doConfigure(); | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         changeState('advanced'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }).catch(function (err) { | 
					
						
							| 
									
										
										
										
											2018-10-21 03:32:04 -06:00
										 |  |  |       console.error(err); | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  |       window.alert("Error: [initialize] " + (err.message || JSON.stringify(err, null, 2))); | 
					
						
							| 
									
										
										
										
											2018-10-18 01:52:30 -06:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-10-18 01:11:37 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  | , advance: function () { | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  |     return doConfigure(); | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | , productionAcme: function () { | 
					
						
							|  |  |  |     console.log("prod acme:"); | 
					
						
							|  |  |  |     appData.init.acmeServer = PRODUCTION_ACME; | 
					
						
							|  |  |  |     console.log(appData.init.acmeServer); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , stagingAcme: function () { | 
					
						
							|  |  |  |     console.log("staging acme:"); | 
					
						
							|  |  |  |     appData.init.acmeServer = STAGING_ACME; | 
					
						
							|  |  |  |     console.log(appData.init.acmeServer); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-18 01:11:37 -06:00
										 |  |  | , defaultRelay: function () { | 
					
						
							|  |  |  |     appData.init.relay = DEFAULT_RELAY; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , betaRelay: function () { | 
					
						
							|  |  |  |     appData.init.relay = BETA_RELAY; | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  | , enable: function () { | 
					
						
							|  |  |  |     api.enable(); | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  | , disable: function () { | 
					
						
							|  |  |  |     api.disable(); | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  | , ssh: function (port) { | 
					
						
							|  |  |  |     // -1 to disable
 | 
					
						
							|  |  |  |     // 0 is auto (22)
 | 
					
						
							|  |  |  |     // 1-65536
 | 
					
						
							|  |  |  |     api.ssh(port || 22); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-11-01 03:11:47 -06:00
										 |  |  | , createShare: function (sub, domain, handler) { | 
					
						
							|  |  |  |     if (sub) { | 
					
						
							|  |  |  |       domain = sub + '.' + domain; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     api.http({ name: domain, handler: handler, indexes: true }); | 
					
						
							|  |  |  |     appData.newHttp = {}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , createHost: function (sub, domain, handler) { | 
					
						
							|  |  |  |     if (sub) { | 
					
						
							|  |  |  |       domain = sub + '.' + domain; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     api.http({ name: domain, handler: handler, 'x-forwarded-for': name }); | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |     appData.newHttp = {}; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , changePortForward: function (domain, port) { | 
					
						
							| 
									
										
										
										
											2018-11-01 03:11:47 -06:00
										 |  |  |     api.http({ name: domain.name, handler: port }); | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | , deletePortForward: function (domain) { | 
					
						
							| 
									
										
										
										
											2018-11-01 03:11:47 -06:00
										 |  |  |     api.http({ name: domain.name, handler: 'none' }); | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | , changePathHost: function (domain, path) { | 
					
						
							| 
									
										
										
										
											2018-11-01 03:11:47 -06:00
										 |  |  |     api.http({ name: domain.name, handler: path }); | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |   } | 
					
						
							|  |  |  | , deletePathHost: function (domain) { | 
					
						
							| 
									
										
										
										
											2018-11-01 03:11:47 -06:00
										 |  |  |     api.http({ name: domain.name, handler: 'none' }); | 
					
						
							| 
									
										
										
										
											2018-10-23 00:44:59 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-11-01 02:19:07 -06:00
										 |  |  | , changeState: changeState | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  | }; | 
					
						
							|  |  |  | var appStates = { | 
					
						
							|  |  |  |   setup: function () { | 
					
						
							|  |  |  |     appData.views.section = { setup: true }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , advanced: function () { | 
					
						
							|  |  |  |     appData.views.section = { advanced: true }; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  | , otp: function () { | 
					
						
							|  |  |  |     appData.views.section = { otp: true }; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | , status: function () { | 
					
						
							| 
									
										
										
										
											2018-10-23 13:18:58 -06:00
										 |  |  |     function exitState() { | 
					
						
							|  |  |  |       clearInterval(tok); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 13:03:36 -06:00
										 |  |  |     var tok = setInterval(updateStatus, 2000); | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-23 13:03:36 -06:00
										 |  |  |     return updateStatus().then(function () { | 
					
						
							| 
									
										
										
										
											2018-11-01 02:19:07 -06:00
										 |  |  |       appData.views.section = { status: true, status_chooser: true }; | 
					
						
							| 
									
										
										
										
											2018-10-23 13:18:58 -06:00
										 |  |  |       return exitState; | 
					
						
							| 
									
										
										
										
											2018-10-23 13:03:36 -06:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2018-11-01 02:19:07 -06:00
										 |  |  | appStates.status.share = function () { | 
					
						
							|  |  |  |   function exitState() { | 
					
						
							|  |  |  |     clearInterval(tok); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var tok = setInterval(updateStatus, 2000); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   appData.views.section = { status: true, status_share: true }; | 
					
						
							|  |  |  |   return updateStatus().then(function () { | 
					
						
							|  |  |  |     return exitState; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | appStates.status.host = function () { | 
					
						
							|  |  |  |   function exitState() { | 
					
						
							|  |  |  |     clearInterval(tok); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var tok = setInterval(updateStatus, 2000); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   appData.views.section = { status: true, status_host: true }; | 
					
						
							|  |  |  |   return updateStatus().then(function () { | 
					
						
							|  |  |  |     return exitState; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | appStates.status.access = function () { | 
					
						
							|  |  |  |   function exitState() { | 
					
						
							|  |  |  |     clearInterval(tok); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var tok = setInterval(updateStatus, 2000); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   appData.views.section = { status: true, status_access: true }; | 
					
						
							|  |  |  |   return updateStatus().then(function () { | 
					
						
							|  |  |  |     return exitState; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function updateStatus() { | 
					
						
							|  |  |  |   return api.status().then(function (status) { | 
					
						
							|  |  |  |     if (status.error) { | 
					
						
							|  |  |  |       appData.views.flash.error = status.error.message || JSON.stringify(status.error, null, 2); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     var wilddomains = []; | 
					
						
							|  |  |  |     var rootdomains = []; | 
					
						
							|  |  |  |     var subdomains = []; | 
					
						
							|  |  |  |     var directories = []; | 
					
						
							|  |  |  |     var portforwards = []; | 
					
						
							|  |  |  |     var free = []; | 
					
						
							|  |  |  |     appData.status = status; | 
					
						
							|  |  |  |     if ('maybe' === status.ssh_requests_password) { | 
					
						
							|  |  |  |       appData.status.ssh_active = false; | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       appData.status.ssh_active = true; | 
					
						
							|  |  |  |       if ('yes' === status.ssh_requests_password) { | 
					
						
							|  |  |  |         appData.status.ssh_insecure = true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ('yes' === status.ssh_password_authentication) { | 
					
						
							|  |  |  |       appData.status.ssh_insecure = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ('yes' === status.ssh_permit_root_login) { | 
					
						
							|  |  |  |       appData.status.ssh_insecure = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // only update what's changed
 | 
					
						
							|  |  |  |     if (appData.state.ssh !== appData.status.ssh) { | 
					
						
							|  |  |  |       appData.state.ssh = appData.status.ssh; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (appData.state.ssh_insecure !== appData.status.ssh_insecure) { | 
					
						
							|  |  |  |       appData.state.ssh_insecure = appData.status.ssh_insecure; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (appData.state.ssh_active !== appData.status.ssh_active) { | 
					
						
							|  |  |  |       appData.state.ssh_active = appData.status.ssh_active; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     Object.keys(appData.status.servernames).forEach(function (k) { | 
					
						
							|  |  |  |       var s = appData.status.servernames[k]; | 
					
						
							|  |  |  |       s.name = k; | 
					
						
							|  |  |  |       if (s.wildcard) { wilddomains.push(s); } | 
					
						
							|  |  |  |       if (!s.sub && !s.wildcard) { rootdomains.push(s); } | 
					
						
							|  |  |  |       if (s.sub) { subdomains.push(s); } | 
					
						
							|  |  |  |       if (s.handler) { | 
					
						
							|  |  |  |         if (s.handler.toString() === parseInt(s.handler, 10).toString()) { | 
					
						
							|  |  |  |           s._port = s.handler; | 
					
						
							|  |  |  |           portforwards.push(s); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           s.path = s.handler; | 
					
						
							|  |  |  |           directories.push(s); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         free.push(s); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     appData.status.portForwards = portforwards; | 
					
						
							|  |  |  |     appData.status.pathHosting = directories; | 
					
						
							|  |  |  |     appData.status.wildDomains = wilddomains; | 
					
						
							|  |  |  |     appData.newHttp.name = (appData.status.wildDomains[0] || {}).name; | 
					
						
							|  |  |  |     appData.state.ssh = (appData.status.ssh > 0) && appData.status.ssh || undefined; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  | function changeState(newstate) { | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  |   var newhash = '#/' + newstate + '/'; | 
					
						
							|  |  |  |   if (location.hash === newhash) { | 
					
						
							|  |  |  |     if (!telebitState.firstState) { | 
					
						
							|  |  |  |       telebitState.firstState = true; | 
					
						
							|  |  |  |       setState(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   location.hash = newhash; | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  | /*globals Promise*/ | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  | window.addEventListener('hashchange', setState, false); | 
					
						
							|  |  |  | function setState(/*ev*/) { | 
					
						
							|  |  |  |   //ev.oldURL
 | 
					
						
							|  |  |  |   //ev.newURL
 | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  |   if (appData.exit) { | 
					
						
							| 
									
										
										
										
											2018-11-01 02:19:07 -06:00
										 |  |  |     console.log('previous state exiting'); | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  |     appData.exit.then(function (exit) { | 
					
						
							| 
									
										
										
										
											2018-11-01 03:11:47 -06:00
										 |  |  |       if ('function' === typeof exit) { | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  |         exit(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-11-01 02:19:07 -06:00
										 |  |  |   var parts = location.hash.substr(1).replace(/^\//, '').replace(/\/$/, '').split('/').filter(Boolean); | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |   var fn = appStates; | 
					
						
							|  |  |  |   parts.forEach(function (s) { | 
					
						
							|  |  |  |     console.log("state:", s); | 
					
						
							|  |  |  |     fn = fn[s]; | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  |   appData.exit = Promise.resolve(fn()); | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  |   //appMethods.states[newstate]();
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  | function msToHumanReadable(ms) { | 
					
						
							|  |  |  |   var uptime = ms; | 
					
						
							|  |  |  |   var uptimed = uptime / 1000; | 
					
						
							|  |  |  |   var minute = 60; | 
					
						
							|  |  |  |   var hour = 60 * minute; | 
					
						
							|  |  |  |   var day = 24 * hour; | 
					
						
							|  |  |  |   var days = 0; | 
					
						
							|  |  |  |   var times = []; | 
					
						
							|  |  |  |   while (uptimed > day) { | 
					
						
							|  |  |  |     uptimed -= day; | 
					
						
							|  |  |  |     days += 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   times.push(days + " days "); | 
					
						
							|  |  |  |   var hours = 0; | 
					
						
							|  |  |  |   while (uptimed > hour) { | 
					
						
							|  |  |  |     uptimed -= hour; | 
					
						
							|  |  |  |     hours += 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   times.push(hours.toString().padStart(2, "0") + " h "); | 
					
						
							|  |  |  |   var minutes = 0; | 
					
						
							|  |  |  |   while (uptimed > minute) { | 
					
						
							|  |  |  |     uptimed -= minute; | 
					
						
							|  |  |  |     minutes += 1; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   times.push(minutes.toString().padStart(2, "0") + " m "); | 
					
						
							|  |  |  |   var seconds = Math.round(uptimed); | 
					
						
							|  |  |  |   times.push(seconds.toString().padStart(2, "0") + " s "); | 
					
						
							|  |  |  |   return times.join(''); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | new Vue({ | 
					
						
							|  |  |  |   el: ".v-app" | 
					
						
							|  |  |  | , data: appData | 
					
						
							| 
									
										
										
										
											2018-10-22 22:36:46 -06:00
										 |  |  | , computed: { | 
					
						
							|  |  |  |     statusProctime: function () { | 
					
						
							|  |  |  |       return msToHumanReadable(this.status.proctime); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   , statusRuntime: function () { | 
					
						
							|  |  |  |       return msToHumanReadable(this.status.runtime); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   , statusUptime: function () { | 
					
						
							|  |  |  |       return msToHumanReadable(this.status.uptime); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | , methods: appMethods | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-11 02:17:12 -06:00
										 |  |  | function run(key) { | 
					
						
							|  |  |  |   // 1. Get ACME directory
 | 
					
						
							|  |  |  |   // 2. Fetch ACME account
 | 
					
						
							|  |  |  |   // 3. Test if account has access
 | 
					
						
							|  |  |  |   // 4. Show command line auth instructions to auth
 | 
					
						
							|  |  |  |   // 5. Sign requests / use JWT
 | 
					
						
							|  |  |  |   // 6. Enforce token required for config, status, etc
 | 
					
						
							|  |  |  |   // 7. Move admin interface to standard ports (admin.foo-bar-123.telebit.xyz)
 | 
					
						
							|  |  |  |   api.config().then(function (config) { | 
					
						
							|  |  |  |     telebitState.config = config; | 
					
						
							|  |  |  |     if (config.greenlock) { | 
					
						
							|  |  |  |       appData.init.acmeServer = config.greenlock.server; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (config.relay) { | 
					
						
							|  |  |  |       appData.init.relay = config.relay; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (config.email) { | 
					
						
							|  |  |  |       appData.init.email = config.email; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (config.agreeTos) { | 
					
						
							|  |  |  |       appData.init.letos = config.agreeTos; | 
					
						
							|  |  |  |       appData.init.teletos = config.agreeTos; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (config._otp) { | 
					
						
							|  |  |  |       appData.init.otp = config._otp; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-20 23:25:14 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-11 02:17:12 -06:00
										 |  |  |     telebitState.pollUrl = config._pollUrl || localStorage.getItem('poll_url'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((!config.token && !config._otp) || !config.relay || !config.email || !config.agreeTos) { | 
					
						
							|  |  |  |       changeState('setup'); | 
					
						
							|  |  |  |       setState(); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!config.token && config._otp) { | 
					
						
							|  |  |  |       changeState('otp'); | 
					
						
							|  |  |  |       setState(); | 
					
						
							|  |  |  |       // this will skip ahead as necessary
 | 
					
						
							|  |  |  |       return Telebit.authorize(telebitState, showOtp).then(function () { | 
					
						
							|  |  |  |         return changeState('status'); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // TODO handle default state
 | 
					
						
							|  |  |  |     changeState('status'); | 
					
						
							|  |  |  |   }).catch(function (err) { | 
					
						
							|  |  |  |     appData.views.flash.error = err.message || JSON.stringify(err, null, 2); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-11 02:17:12 -06:00
										 |  |  | // TODO protect key with passphrase (or QR code?)
 | 
					
						
							|  |  |  | function getKey() { | 
					
						
							| 
									
										
										
										
											2019-05-11 14:00:17 -06:00
										 |  |  |   var jwk; | 
					
						
							| 
									
										
										
										
											2019-05-11 02:17:12 -06:00
										 |  |  |   try { | 
					
						
							| 
									
										
										
										
											2019-05-11 14:00:17 -06:00
										 |  |  |     jwk = JSON.parse(localStorage.getItem('key')); | 
					
						
							| 
									
										
										
										
											2019-05-11 02:17:12 -06:00
										 |  |  |   } catch(e) { | 
					
						
							|  |  |  |     // ignore
 | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-05-11 14:00:17 -06:00
										 |  |  |   if (jwk && jwk.kid && jwk.d) { | 
					
						
							|  |  |  |     return Promise.resolve(jwk); | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-05-11 02:17:12 -06:00
										 |  |  |   return Keypairs.generate().then(function (pair) { | 
					
						
							| 
									
										
										
										
											2019-05-11 14:00:17 -06:00
										 |  |  |     jwk = pair.private; | 
					
						
							|  |  |  |     localStorage.setItem('key', JSON.stringify(jwk)); | 
					
						
							|  |  |  |     return jwk; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function getEmail() { | 
					
						
							|  |  |  |   return Promise.resolve().then(function () { | 
					
						
							|  |  |  |     var email = localStorage.getItem('email'); | 
					
						
							|  |  |  |     if (email) { return email; } | 
					
						
							|  |  |  |     while (!email) { | 
					
						
							|  |  |  |       email = window.prompt("Email address (device owner)?"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return email; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | function requestAccount() { | 
					
						
							|  |  |  |   return getKey().then(function (jwk) { | 
					
						
							|  |  |  |     return getEmail().then(function(email) { | 
					
						
							|  |  |  |       // creates new or returns existing
 | 
					
						
							|  |  |  |       var acme = ACME.create({}); | 
					
						
							|  |  |  |       var url = window.location.protocol + '//' + window.location.host + '/acme/directory'; | 
					
						
							|  |  |  |       return acme.init(url).then(function () { | 
					
						
							|  |  |  |         return acme.accounts.create({ | 
					
						
							|  |  |  |           agreeToTerms: function (tos) { return tos; } | 
					
						
							|  |  |  |         , accountKeypair: { privateKeyJwk: jwk } | 
					
						
							|  |  |  |         , email: email | 
					
						
							|  |  |  |         }).then(function (account) { | 
					
						
							|  |  |  |           console.log('account:'); | 
					
						
							|  |  |  |           console.log(account); | 
					
						
							|  |  |  |           if (account.id) { | 
					
						
							|  |  |  |             localStorage.setItem('email', email); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           return jwk; | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-05-11 02:17:12 -06:00
										 |  |  |   }); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | window.api = api; | 
					
						
							| 
									
										
										
										
											2019-05-11 14:00:17 -06:00
										 |  |  | requestAccount().then(function (jwk) { | 
					
						
							|  |  |  |   run(jwk); | 
					
						
							| 
									
										
										
										
											2019-05-11 02:17:12 -06:00
										 |  |  |   setTimeout(function () { | 
					
						
							|  |  |  |     document.body.hidden = false; | 
					
						
							|  |  |  |   }, 50); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2018-10-22 00:17:49 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-15 20:37:07 -06:00
										 |  |  | }()); |