web ui updates
This commit is contained in:
		
							parent
							
								
									b81f0ecede
								
							
						
					
					
						commit
						9e1c9c00ca
					
				| @ -7,7 +7,7 @@ | |||||||
|   <div class="v-app"> |   <div class="v-app"> | ||||||
|     <h1>Telebit (Remote) Setup</h1> |     <h1>Telebit (Remote) Setup</h1> | ||||||
| 
 | 
 | ||||||
|     <section v-if="views.section.create"> |     <section v-if="views.section.setup"> | ||||||
|       <h2>Create Account</h2> |       <h2>Create Account</h2> | ||||||
|       <form v-on:submit.stop.prevent="initialize"> |       <form v-on:submit.stop.prevent="initialize"> | ||||||
| 
 | 
 | ||||||
| @ -43,12 +43,23 @@ | |||||||
|         </small> |         </small> | ||||||
| 
 | 
 | ||||||
|         <details><summary><small>Advanced</small></summary> |         <details><summary><small>Advanced</small></summary> | ||||||
|         <label for="-relay">Relay:</label><input id="-relay" v-model="init.relay" type="text" placeholder="telebit.cloud"> | 
 | ||||||
|  |         <label for="-relay">Relay:</label> | ||||||
|  |           <input id="-relay" v-model="init.relay" type="text" placeholder="telebit.cloud"> | ||||||
|         <br> |         <br> | ||||||
|         <button type="button" v-on:click="defaultRelay">Use Default</button> |         <button type="button" v-on:click="defaultRelay">Use Default</button> | ||||||
|         <button type="button" v-on:click="betaRelay">Use Beta</button> |         <button type="button" v-on:click="betaRelay">Use Beta</button> | ||||||
|         <br> |         <br> | ||||||
|         <br> |         <br> | ||||||
|  | 
 | ||||||
|  |         <label for="-acme-server">ACME (Let's Encrypt) Server:</label> | ||||||
|  |           <input id="-acme-server" v-model="init.acmeServer" type="text" placeholder="https://acme-v02.api.letsencrypt.org/directory"> | ||||||
|  |         <br> | ||||||
|  |         <button type="button" v-on:click="productionAcme">Use Production</button> | ||||||
|  |         <button type="button" v-on:click="stagingAcme">Use Staging</button> | ||||||
|  |         <br> | ||||||
|  |         <br> | ||||||
|  | 
 | ||||||
|         </details> |         </details> | ||||||
| 
 | 
 | ||||||
|         <button type="submit">Accept & Continue</button> |         <button type="submit">Accept & Continue</button> | ||||||
| @ -58,22 +69,32 @@ | |||||||
|     </section> |     </section> | ||||||
| 
 | 
 | ||||||
|     <section v-if="views.section.advanced"> |     <section v-if="views.section.advanced"> | ||||||
|       <h2>Advanced Setup</h2> |       <h2>Advanced Setup for {{ init.relay }}</h2> | ||||||
|       <form v-on:submit.stop.prevent="initialize"> |       <form v-on:submit.stop.prevent="advance"> | ||||||
| 
 | 
 | ||||||
|         <label for="-secret">Relay Secret:</label> |         <strong><label for="-secret">Relay Shared Secret:</label></strong> | ||||||
|         <input id="-secret" v-model="init.secret" type="text" placeholder="ex: xxxxxxxxxxxx"> |         <input id="-secret" v-model="init.secret" type="text" placeholder="ex: xxxxxxxxxxxx"> | ||||||
|         <br> |         <br> | ||||||
| 
 | 
 | ||||||
|  |         <strong><label for="-domains">Domains:</label></strong> | ||||||
|  |         <br> | ||||||
|  |         <small>(comma separated list of domains to use for http, tls, https, etc)</small> | ||||||
|  |         <br> | ||||||
|  |         <input id="-domains" v-model="init.domains" type="text" placeholder="ex: whatever.com, example.com"> | ||||||
|  |         <br> | ||||||
|  | 
 | ||||||
|  |         <strong><label for="-ports">TCP Ports:</label></strong> | ||||||
|  |         <br> | ||||||
|  |         <small>(comman separated list of ports, excluding 80 and 443, typically port over 1024)</small> | ||||||
|  |         <br> | ||||||
|  |         <input id="-ports" v-model="init.ports" type="text" placeholder="ex: 5050, 3000, 8080"> | ||||||
|  |         <br> | ||||||
|  | 
 | ||||||
|         <label for="-telemetry"><input id="-telemetry" v-model="init.telemetry" type="checkbox"> |         <label for="-telemetry"><input id="-telemetry" v-model="init.telemetry" type="checkbox"> | ||||||
|           Contribute to Telebit by sharing telemetry</label> |           Contribute to Telebit by sharing telemetry</label> | ||||||
|         <br> |         <br> | ||||||
| 
 | 
 | ||||||
|         <label for="-relay">[Advanced] Relay:</label> |         <button type="submit">Finish</button> | ||||||
|         <input id="-relay" v-model="init.relay" type="text" placeholder="telebit.cloud"> |  | ||||||
|         <br> |  | ||||||
| 
 |  | ||||||
|         <button type="submit">Accept & Continue</button> |  | ||||||
| 
 | 
 | ||||||
|       </form> |       </form> | ||||||
|       <pre><code>{{ init }}</code></pre> |       <pre><code>{{ init }}</code></pre> | ||||||
|  | |||||||
| @ -1,14 +1,29 @@ | |||||||
| ;(function () { | ;(function () { | ||||||
| 'use strict'; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| console.log("hello"); |  | ||||||
| 
 |  | ||||||
| var Vue = window.Vue; | var Vue = window.Vue; | ||||||
| var Telebit = window.TELEBIT; | var Telebit = window.TELEBIT; | ||||||
| var api = {}; | var api = {}; | ||||||
| 
 | 
 | ||||||
|  | /*globals AbortController*/ | ||||||
|  | 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); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| api.config = function apiConfig() { | api.config = function apiConfig() { | ||||||
|   return window.fetch("/api/config", { method: "GET" }).then(function (resp) { |   return safeFetch("/api/config", { | ||||||
|  |     method: "GET" | ||||||
|  |   }).then(function (resp) { | ||||||
|     return resp.json().then(function (json) { |     return resp.json().then(function (json) { | ||||||
|       appData.config = json; |       appData.config = json; | ||||||
|       return json; |       return json; | ||||||
| @ -16,17 +31,43 @@ api.config = function apiConfig() { | |||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| api.status = function apiStatus() { | api.status = function apiStatus() { | ||||||
|   return window.fetch("/api/status", { method: "GET" }).then(function (resp) { |   return safeFetch("/api/status", { method: "GET" }).then(function (resp) { | ||||||
|     return resp.json().then(function (json) { |     return resp.json().then(function (json) { | ||||||
|       appData.status = json; |       appData.status = json; | ||||||
|       return json; |       return json; | ||||||
|     }); |     }); | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  | api.initialize = function apiInitialize() { | ||||||
|  |   var opts = { | ||||||
|  |     method: "POST" | ||||||
|  |   , headers: { | ||||||
|  |       'Content-Type': 'application/json' | ||||||
|  |     } | ||||||
|  |   , body: JSON.stringify({ | ||||||
|  |       foo: 'bar' | ||||||
|  |     }) | ||||||
|  |   }; | ||||||
|  |   return safeFetch("/api/init", opts).then(function (resp) { | ||||||
|  |     return resp.json().then(function (json) { | ||||||
|  |       appData.initResult = json; | ||||||
|  |       window.alert("Error: [success] " + JSON.stringify(json, null, 2)); | ||||||
|  |       return json; | ||||||
|  |     }).catch(function (err) { | ||||||
|  |       window.alert("Error: [init] " + (err.message || JSON.stringify(err, null, 2))); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| // TODO test for internet connectivity (and telebit connectivity)
 | // TODO test for internet connectivity (and telebit connectivity)
 | ||||||
| var DEFAULT_RELAY = 'telebit.cloud'; | var DEFAULT_RELAY = 'telebit.cloud'; | ||||||
| var BETA_RELAY = 'telebit.ppl.family'; | var BETA_RELAY = 'telebit.ppl.family'; | ||||||
|  | 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'; | ||||||
| var appData = { | var appData = { | ||||||
|   config: null |   config: null | ||||||
| , status: null | , status: null | ||||||
| @ -35,40 +76,93 @@ var appData = { | |||||||
|   , letos: true |   , letos: true | ||||||
|   , notifications: "important" |   , notifications: "important" | ||||||
|   , relay: DEFAULT_RELAY |   , relay: DEFAULT_RELAY | ||||||
|  |   , telemetry: true | ||||||
|  |   , acmeServer: PRODUCTION_ACME | ||||||
|   } |   } | ||||||
| , http: null | , http: null | ||||||
| , tcp: null | , tcp: null | ||||||
| , ssh: null | , ssh: null | ||||||
| , views: { | , views: { | ||||||
|     section: { |     section: { | ||||||
|       create: true |       setup: false | ||||||
|  |     , advanced: false | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | var telebitState = {}; | ||||||
| var appMethods = { | var appMethods = { | ||||||
|   initialize: function () { |   initialize: function () { | ||||||
|     console.log("call initialize"); |     console.log("call initialize"); | ||||||
|     if (!appData.init.relay) { |     if (!appData.init.relay) { | ||||||
|       appData.init.relay = DEFAULT_RELAY; |       appData.init.relay = DEFAULT_RELAY; | ||||||
|     } |     } | ||||||
|     if (DEFAULT_RELAY !== appData.init.relay) { |     appData.init.relay = appData.init.relay.toLowerCase(); | ||||||
|       window.alert("TODO: Custom Relay Not Implemented Yet"); |     telebitState = { relay: appData.init.relay }; | ||||||
|     } |     return Telebit.api.directory(telebitState).then(function (dir) { | ||||||
|     Telebit.api.directory({ relay: appData.init.relay }, function (err, dir) { |       if (!dir.api_host) { | ||||||
|       if (err) { |         window.alert("Error: '" + telebitState.relay + "' does not appear to be a valid telebit service"); | ||||||
|         window.alert("Error:" + (err.message || JSON.stringify(err, null, 2))); |  | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|       window.alert("Success:" + JSON.stringify(dir, null, 2)); |       if (-1 !== TELEBIT_RELAYS.indexOf(appData.init.relay)) { | ||||||
|  |         return api.initialize(); | ||||||
|  |       } else { | ||||||
|  |         changeState('advanced'); | ||||||
|  |       } | ||||||
|  |     }).catch(function (err) { | ||||||
|  |       window.alert("Error: [directory] " + (err.message || JSON.stringify(err, null, 2))); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  | , advance: function () { | ||||||
|  |     return api.initialize(); | ||||||
|  |   } | ||||||
|  | , 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); | ||||||
|  |   } | ||||||
| , defaultRelay: function () { | , defaultRelay: function () { | ||||||
|     appData.init.relay = DEFAULT_RELAY; |     appData.init.relay = DEFAULT_RELAY; | ||||||
|   } |   } | ||||||
| , betaRelay: function () { | , betaRelay: function () { | ||||||
|     appData.init.relay = BETA_RELAY; |     appData.init.relay = BETA_RELAY; | ||||||
|   } |   } | ||||||
|  | , defaultRhubarb: function () { | ||||||
|  |     appData.init.rhubarb = DEFAULT_RELAY; | ||||||
|  |   } | ||||||
|  | , betaRhubarb: function () { | ||||||
|  |     appData.init.rhubarb = BETA_RELAY; | ||||||
|  |   } | ||||||
| }; | }; | ||||||
|  | var appStates = { | ||||||
|  |   setup: function () { | ||||||
|  |     appData.views.section = { setup: true }; | ||||||
|  |   } | ||||||
|  | , advanced: function () { | ||||||
|  |     appData.views.section = { advanced: true }; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | function changeState(newstate) { | ||||||
|  |   location.hash = '#/' + newstate + '/'; | ||||||
|  | } | ||||||
|  | window.addEventListener('hashchange', setState, false); | ||||||
|  | function setState(/*ev*/) { | ||||||
|  |   //ev.oldURL
 | ||||||
|  |   //ev.newURL
 | ||||||
|  |   var parts = location.hash.substr(1).replace(/^\//, '').replace(/\/$/, '').split('/'); | ||||||
|  |   var fn = appStates; | ||||||
|  |   parts.forEach(function (s) { | ||||||
|  |     console.log("state:", s); | ||||||
|  |     fn = fn[s]; | ||||||
|  |   }); | ||||||
|  |   fn(); | ||||||
|  |   //appMethods.states[newstate]();
 | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| new Vue({ | new Vue({ | ||||||
|   el: ".v-app" |   el: ".v-app" | ||||||
| @ -76,8 +170,12 @@ new Vue({ | |||||||
| , methods: appMethods | , methods: appMethods | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| api.config(); | api.config(); | ||||||
| api.status(); | api.status().then(function () { | ||||||
|  |   changeState('setup'); | ||||||
|  |   setState(); | ||||||
|  | }); | ||||||
| 
 | 
 | ||||||
| window.api = api; | window.api = api; | ||||||
| }()); | }()); | ||||||
|  | |||||||
| @ -11,6 +11,7 @@ if ('undefined' !== typeof Promise) { | |||||||
|   throw new Error("no Promise implementation defined"); |   throw new Error("no Promise implementation defined"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*globals AbortController*/ | ||||||
| if ('undefined' !== typeof fetch) { | if ('undefined' !== typeof fetch) { | ||||||
|   common.requestAsync = function (opts) { |   common.requestAsync = function (opts) { | ||||||
|     /* |     /* | ||||||
| @ -37,7 +38,16 @@ if ('undefined' !== typeof fetch) { | |||||||
|       } |       } | ||||||
|     , body: JSON.stringify(opts) |     , body: JSON.stringify(opts) | ||||||
|     }; |     }; | ||||||
|  |     var controller = new AbortController(); | ||||||
|  |     var tok = setTimeout(function () { | ||||||
|  |       controller.abort(); | ||||||
|  |     }, 4000); | ||||||
|  |     if (!relayOpts) { | ||||||
|  |       relayOpts = {}; | ||||||
|  |     } | ||||||
|  |     relayOpts.signal = controller.signal; | ||||||
|     return window.fetch(relayOpts.url, relayOpts).then(function (resp) { |     return window.fetch(relayOpts.url, relayOpts).then(function (resp) { | ||||||
|  |       clearTimeout(tok); | ||||||
|       return resp.json().then(function (json) { |       return resp.json().then(function (json) { | ||||||
|         /* |         /* | ||||||
|         var headers = {}; |         var headers = {}; | ||||||
| @ -100,17 +110,20 @@ common.signToken = function (state) { | |||||||
|   return jwt.sign(tokenData, state.config.secret); |   return jwt.sign(tokenData, state.config.secret); | ||||||
| }; | }; | ||||||
| common.api = {}; | common.api = {}; | ||||||
| common.api.directory = function (state, next) { | common.api.directory = function (state) { | ||||||
|   console.log('state:'); |   console.log('[DEBUG] state:'); | ||||||
|   console.log(state); |   console.log(state); | ||||||
|   state._relayUrl = common.parseUrl(state.relay); |   state._relayUrl = common.parseUrl(state.relay); | ||||||
|   common.requestAsync({ url: state._relayUrl + common.apiDirectory, json: true }).then(function (resp) { |   if (!state._relays) { state._relays = {}; } | ||||||
|  |   if (state._relays[state._relayUrl]) { | ||||||
|  |     return PromiseA.resolve(state._relays[state._relayUrl]); | ||||||
|  |   } | ||||||
|  |   return common.requestAsync({ url: state._relayUrl + common.apiDirectory, json: true }).then(function (resp) { | ||||||
|     var dir = resp.body; |     var dir = resp.body; | ||||||
|     if (!dir) { dir = { api_host: ':hostname', tunnel: { method: "wss", pathname: "" } }; } |     state._relays[state._relayUrl] = dir; | ||||||
|     state._apiDirectory = dir; |     return dir; | ||||||
|     next(null, dir); |  | ||||||
|   }).catch(function (err) { |   }).catch(function (err) { | ||||||
|     next(err); |     return PromiseA.reject(err); | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| common.api._parseWss = function (state, dir) { | common.api._parseWss = function (state, dir) { | ||||||
| @ -121,153 +134,159 @@ common.api._parseWss = function (state, dir) { | |||||||
|   return dir.tunnel.method + '://' + dir.api_host.replace(/:hostname/g, state._relayHostname) + dir.tunnel.pathname; |   return dir.tunnel.method + '://' + dir.api_host.replace(/:hostname/g, state._relayHostname) + dir.tunnel.pathname; | ||||||
| }; | }; | ||||||
| common.api.wss = function (state, cb) { | common.api.wss = function (state, cb) { | ||||||
|   common.api.directory(state, function (err, dir) { |   common.api.directory(state).then(function (dir) { | ||||||
|     cb(err, common.api._parseWss(state, dir)); |     cb(null, common.api._parseWss(state, dir)); | ||||||
|   }); |   }).catch(cb); | ||||||
| }; | }; | ||||||
| common.api.token = function (state, handlers) { | common.api.token = function (state, handlers) { | ||||||
|   common.api.directory(state, function (err, dir) { |   // directory, requested, connect, tunnelUrl, offer, granted, end
 | ||||||
|     // directory, requested, connect, tunnelUrl, offer, granted, end
 |   function afterDir(err, dir) { | ||||||
|     function afterDir() { |     if (common.debug) { console.log('[debug] after dir'); } | ||||||
|       if (common.debug) { console.log('[debug] after dir'); } |     state.wss = common.api._parseWss(state, dir); | ||||||
|       state.wss = common.api._parseWss(state, dir); |  | ||||||
| 
 | 
 | ||||||
|       handlers.tunnelUrl(state.wss, function () { |     handlers.tunnelUrl(state.wss, function () { | ||||||
|         if (common.debug) { console.log('[debug] after tunnelUrl'); } |       if (common.debug) { console.log('[debug] after tunnelUrl'); } | ||||||
|         if (state.config.secret /* && !state.config.token */) { |       if (state.config.secret /* && !state.config.token */) { | ||||||
|           state.config._token = common.signToken(state); |         state.config._token = common.signToken(state); | ||||||
|         } |       } | ||||||
|         state.token = state.token || state.config.token || state.config._token; |       state.token = state.token || state.config.token || state.config._token; | ||||||
|         if (state.token) { |       if (state.token) { | ||||||
|           if (common.debug) { console.log('[debug] token via token or secret'); } |         if (common.debug) { console.log('[debug] token via token or secret'); } | ||||||
|           // { token, pretoken }
 |         // { token, pretoken }
 | ||||||
|           handlers.connect(state.token, function () { |         handlers.connect(state.token, function () { | ||||||
|             handlers.end(null, function () {}); |           handlers.end(null, function () {}); | ||||||
|           }); |         }); | ||||||
|           return; |         return; | ||||||
|         } |       } | ||||||
| 
 | 
 | ||||||
|         // backwards compat (TODO remove)
 |       // backwards compat (TODO remove)
 | ||||||
|         if (err || !dir || !dir.pair_request) { |       if (err || !dir || !dir.pair_request) { | ||||||
|           if (common.debug) { console.log('[debug] no dir, connect'); } |         if (common.debug) { console.log('[debug] no dir, connect'); } | ||||||
|           handlers.error(new Error("No token found or generated, and no pair_request api found.")); |         handlers.error(new Error("No token found or generated, and no pair_request api found.")); | ||||||
|           return; |         return; | ||||||
|         } |       } | ||||||
| 
 | 
 | ||||||
|         // TODO sign token with own private key, including public key and thumbprint
 |       // TODO sign token with own private key, including public key and thumbprint
 | ||||||
|         //      (much like ACME JOSE account)
 |       //      (much like ACME JOSE account)
 | ||||||
|         var otp = state.config._otp; // common.otp();
 |       var otp = state.config._otp; // common.otp();
 | ||||||
|         var authReq = { |       var authReq = { | ||||||
|           subject: state.config.email |         subject: state.config.email | ||||||
|         , subject_scheme: 'mailto' |       , subject_scheme: 'mailto' | ||||||
|           // TODO create domains list earlier
 |         // TODO create domains list earlier
 | ||||||
|         , scope: (state.config._servernames || Object.keys(state.config.servernames || {})) |       , scope: (state.config._servernames || Object.keys(state.config.servernames || {})) | ||||||
|             .concat(state.config._ports || Object.keys(state.config.ports || {})).join(',') |           .concat(state.config._ports || Object.keys(state.config.ports || {})).join(',') | ||||||
|         , otp: otp |       , otp: otp | ||||||
|         // TODO make call to daemon for this info beforehand
 |       // TODO make call to daemon for this info beforehand
 | ||||||
|         /* |       /* | ||||||
|         , hostname: os.hostname() |       , hostname: os.hostname() | ||||||
|           // Used for User-Agent
 |         // Used for User-Agent
 | ||||||
|         , os_type: os.type() |       , os_type: os.type() | ||||||
|         , os_platform: os.platform() |       , os_platform: os.platform() | ||||||
|         , os_release: os.release() |       , os_release: os.release() | ||||||
|         , os_arch: os.arch() |       , os_arch: os.arch() | ||||||
|         */ |       */ | ||||||
|         }; |       }; | ||||||
|         var pairRequestUrl = new URL(dir.pair_request.pathname, 'https://' + dir.api_host.replace(/:hostname/g, state._relayHostname)); |       var pairRequestUrl = new URL(dir.pair_request.pathname, 'https://' + dir.api_host.replace(/:hostname/g, state._relayHostname)); | ||||||
|         var req = { |       var req = { | ||||||
|           url: pairRequestUrl |         url: pairRequestUrl | ||||||
|         , method: dir.pair_request.method |       , method: dir.pair_request.method | ||||||
|         , json: authReq |       , json: authReq | ||||||
|         }; |       }; | ||||||
|         var firstReq = true; |       var firstReq = true; | ||||||
|         var firstReady = true; |       var firstReady = true; | ||||||
| 
 | 
 | ||||||
|         function gotoNext(req) { |       function gotoNext(req) { | ||||||
|           if (common.debug) { console.log('[debug] gotoNext called'); } |         if (common.debug) { console.log('[debug] gotoNext called'); } | ||||||
|           if (common.debug) { console.log(req); } |         if (common.debug) { console.log(req); } | ||||||
|           common.requestAsync(req).then(function (resp) { |         common.requestAsync(req).then(function (resp) { | ||||||
|             var body = resp.body; |           var body = resp.body; | ||||||
| 
 | 
 | ||||||
|             function checkLocation() { |           function checkLocation() { | ||||||
|               if (common.debug) { console.log('[debug] checkLocation'); } |             if (common.debug) { console.log('[debug] checkLocation'); } | ||||||
|               if (common.debug) { console.log(body); } |             if (common.debug) { console.log(body); } | ||||||
|               // pending, try again
 |             // pending, try again
 | ||||||
|               if ('pending' === body.status && resp.headers.location) { |             if ('pending' === body.status && resp.headers.location) { | ||||||
|                 if (common.debug) { console.log('[debug] pending'); } |               if (common.debug) { console.log('[debug] pending'); } | ||||||
|                 setTimeout(gotoNext, 2 * 1000, { url: resp.headers.location, json: true }); |               setTimeout(gotoNext, 2 * 1000, { url: resp.headers.location, json: true }); | ||||||
|                 return; |  | ||||||
|               } |  | ||||||
| 
 |  | ||||||
|               if ('ready' === body.status) { |  | ||||||
|                 if (common.debug) { console.log('[debug] ready'); } |  | ||||||
|                 if (firstReady) { |  | ||||||
|                   if (common.debug) { console.log('[debug] first ready'); } |  | ||||||
|                   firstReady = false; |  | ||||||
|                   state.token = body.access_token; |  | ||||||
|                   state.config.token = state.token; |  | ||||||
|                   handlers.offer(body.access_token, function () { |  | ||||||
|                     /*ignore*/ |  | ||||||
|                   }); |  | ||||||
|                 } |  | ||||||
|                 setTimeout(gotoNext, 2 * 1000, req); |  | ||||||
|                 return; |  | ||||||
|               } |  | ||||||
| 
 |  | ||||||
|               if ('complete' === body.status) { |  | ||||||
|                 if (common.debug) { console.log('[debug] complete'); } |  | ||||||
|                 handlers.granted(null, function () { |  | ||||||
|                   handlers.end(null, function () {}); |  | ||||||
|                 }); |  | ||||||
|                 return; |  | ||||||
|               } |  | ||||||
| 
 |  | ||||||
|               if (common.debug) { console.log('[debug] bad status'); } |  | ||||||
|               var err = new Error("Bad State:" + body.status); |  | ||||||
|               err._request = req; |  | ||||||
|               handlers.error(err, function () {}); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (firstReq) { |  | ||||||
|               if (common.debug) { console.log('[debug] first req'); } |  | ||||||
|               handlers.requested(authReq, function () { |  | ||||||
|                 handlers.connect(body.access_token || body.jwt, function () { |  | ||||||
|                   var err; |  | ||||||
|                   if (!resp.headers.location) { |  | ||||||
|                     err = new Error("bad authentication request response"); |  | ||||||
|                     err._resp = resp.toJSON && resp.toJSON(); |  | ||||||
|                     handlers.error(err, function () {}); |  | ||||||
|                     return; |  | ||||||
|                   } |  | ||||||
|                   setTimeout(gotoNext, 2 * 1000, { url: resp.headers.location, json: true }); |  | ||||||
|                 }); |  | ||||||
|               }); |  | ||||||
|               firstReq = false; |  | ||||||
|               return; |               return; | ||||||
|             } else { |  | ||||||
|               if (common.debug) { console.log('[debug] other req'); } |  | ||||||
|               checkLocation(); |  | ||||||
|             } |             } | ||||||
|           }).catch(function (err) { | 
 | ||||||
|             if (common.debug) { console.log('[debug] gotoNext error'); } |             if ('ready' === body.status) { | ||||||
|  |               if (common.debug) { console.log('[debug] ready'); } | ||||||
|  |               if (firstReady) { | ||||||
|  |                 if (common.debug) { console.log('[debug] first ready'); } | ||||||
|  |                 firstReady = false; | ||||||
|  |                 state.token = body.access_token; | ||||||
|  |                 state.config.token = state.token; | ||||||
|  |                 handlers.offer(body.access_token, function () { | ||||||
|  |                   /*ignore*/ | ||||||
|  |                 }); | ||||||
|  |               } | ||||||
|  |               setTimeout(gotoNext, 2 * 1000, req); | ||||||
|  |               return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if ('complete' === body.status) { | ||||||
|  |               if (common.debug) { console.log('[debug] complete'); } | ||||||
|  |               handlers.granted(null, function () { | ||||||
|  |                 handlers.end(null, function () {}); | ||||||
|  |               }); | ||||||
|  |               return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (common.debug) { console.log('[debug] bad status'); } | ||||||
|  |             var err = new Error("Bad State:" + body.status); | ||||||
|             err._request = req; |             err._request = req; | ||||||
|             err._hint = '[telebitd.js] pair request'; |  | ||||||
|             handlers.error(err, function () {}); |             handlers.error(err, function () {}); | ||||||
|           }); |           } | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         gotoNext(req); |           if (firstReq) { | ||||||
|  |             if (common.debug) { console.log('[debug] first req'); } | ||||||
|  |             handlers.requested(authReq, function () { | ||||||
|  |               handlers.connect(body.access_token || body.jwt, function () { | ||||||
|  |                 var err; | ||||||
|  |                 if (!resp.headers.location) { | ||||||
|  |                   err = new Error("bad authentication request response"); | ||||||
|  |                   err._resp = resp.toJSON && resp.toJSON(); | ||||||
|  |                   handlers.error(err, function () {}); | ||||||
|  |                   return; | ||||||
|  |                 } | ||||||
|  |                 setTimeout(gotoNext, 2 * 1000, { url: resp.headers.location, json: true }); | ||||||
|  |               }); | ||||||
|  |             }); | ||||||
|  |             firstReq = false; | ||||||
|  |             return; | ||||||
|  |           } else { | ||||||
|  |             if (common.debug) { console.log('[debug] other req'); } | ||||||
|  |             checkLocation(); | ||||||
|  |           } | ||||||
|  |         }).catch(function (err) { | ||||||
|  |           if (common.debug) { console.log('[debug] gotoNext error'); } | ||||||
|  |           err._request = req; | ||||||
|  |           err._hint = '[telebitd.js] pair request'; | ||||||
|  |           handlers.error(err, function () {}); | ||||||
|  |         }); | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|       }); |       gotoNext(req); | ||||||
|     } | 
 | ||||||
| 
 |     }); | ||||||
|     if (dir && dir.api_host) { |   } | ||||||
|       handlers.directory(dir, afterDir); | 
 | ||||||
|     } else { |   // backwards compat (TODO verify we can remove this)
 | ||||||
|       // backwards compat
 |   var failoverDir = '{ "api_host": ":hostname", "tunnel": { "method": "wss", "pathname": "" } }'; | ||||||
|       dir = { api_host: ':hostname', tunnel: { method: "wss", pathname: "" } }; |   common.api.directory(state).then(function (dir) { | ||||||
|       afterDir(); |     if (!dir.api_host) { | ||||||
|  |       dir = JSON.parse(failoverDir); | ||||||
|  |       return afterDir(null, dir); | ||||||
|     } |     } | ||||||
|  |     handlers.directory(dir).then(function (dir) { | ||||||
|  |       return afterDir(null, dir); | ||||||
|  |     }).catch(function (err) { | ||||||
|  |       return PromiseA.reject(err); | ||||||
|  |     }); | ||||||
|  |   }).catch(function (err) { | ||||||
|  |     return afterDir(err, JSON.parse(failoverDir)); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
| }; | }; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user