MAJOR: Updates for Authenticated Web UI and CLI #30
| @ -4,9 +4,19 @@ | ||||
|   <title>Telebit Setup</title> | ||||
| </head> | ||||
| <body> | ||||
|   <script>document.body.hidden = true;</script> | ||||
| 
 | ||||
|   <div class="v-app"> | ||||
|     <h1>Telebit (Remote) Setup</h1> | ||||
| 
 | ||||
|     <section v-if="views.flash.error"> | ||||
|       {{ views.flash.error }} | ||||
|     </section> | ||||
| 
 | ||||
|     <section v-if="views.section.loading"> | ||||
|       Loading... | ||||
|     </section> | ||||
| 
 | ||||
|     <section v-if="views.section.setup"> | ||||
|       <h2>Create Account</h2> | ||||
|       <form v-on:submit.stop.prevent="initialize"> | ||||
| @ -100,6 +110,14 @@ | ||||
|       <pre><code>{{ init }}</code></pre> | ||||
|     </section> | ||||
| 
 | ||||
|     <section v-if="views.section.otp"> | ||||
|       <pre><code><h2>{{ init.otp }}</h2></code></pre> | ||||
|     </section> | ||||
| 
 | ||||
|     <section v-if="views.section.status"> | ||||
|       <pre><code>{{ status }}</code></pre> | ||||
|     </section> | ||||
| 
 | ||||
|   </div> | ||||
| 
 | ||||
|   <script src="/js/vue.js"></script> | ||||
|  | ||||
| @ -34,20 +34,17 @@ api.config = function apiConfig() { | ||||
| api.status = function apiStatus() { | ||||
|   return Telebit.reqLocalAsync({ url: "/api/status", method: "GET" }).then(function (resp) { | ||||
|     var json = resp.body; | ||||
|     appData.status = json; | ||||
|     return json; | ||||
|   }); | ||||
| }; | ||||
| api.initialize = function apiInitialize() { | ||||
|   var opts = { | ||||
|     url: "/api/init" | ||||
|     url: "/api/xxinitxx" | ||||
|   , method: "POST" | ||||
|   , headers: { | ||||
|       'Content-Type': 'application/json' | ||||
|     } | ||||
|   , body: JSON.stringify({ | ||||
|       foo: 'bar' | ||||
|     }) | ||||
|   , body: JSON.stringify(telebitState.config) | ||||
|   }; | ||||
|   return Telebit.reqLocalAsync(opts).then(function (resp) { | ||||
|     var json = resp.body; | ||||
| @ -59,6 +56,47 @@ api.initialize = function apiInitialize() { | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| 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 () { | ||||
|     console.log('1 api.init...'); | ||||
|     return api.initialize(); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // TODO test for internet connectivity (and telebit connectivity)
 | ||||
| var DEFAULT_RELAY = 'telebit.cloud'; | ||||
| var BETA_RELAY = 'telebit.ppl.family'; | ||||
| @ -83,9 +121,15 @@ var appData = { | ||||
| , tcp: null | ||||
| , ssh: null | ||||
| , views: { | ||||
|     section: { | ||||
|       setup: false | ||||
|     flash: { | ||||
|       error: "" | ||||
|     } | ||||
|   , section: { | ||||
|       loading: true | ||||
|     , setup: false | ||||
|     , advanced: false | ||||
|     , otp: false | ||||
|     , status: false | ||||
|     } | ||||
|   } | ||||
| }; | ||||
| @ -98,34 +142,28 @@ var appMethods = { | ||||
|     } | ||||
|     appData.init.relay = appData.init.relay.toLowerCase(); | ||||
|     telebitState = { relay: appData.init.relay }; | ||||
| 
 | ||||
|     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"); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       telebitState.dir = dir; | ||||
| 
 | ||||
|       // If it's one of the well-known relays
 | ||||
|       if (-1 !== TELEBIT_RELAYS.indexOf(appData.init.relay)) { | ||||
|         if (!telebitState.config) { telebitState.config = {}; } | ||||
|         if (!telebitState.config.relay) { telebitState.config.relay = telebitState.relay; } | ||||
|         telebitState.config.email = appData.init.email; | ||||
|         telebitState.config._otp = Telebit.otp(); | ||||
|         return Telebit.authorize(telebitState).then(function () { | ||||
|           console.log('1 api.init...'); | ||||
|           return api.initialize(); | ||||
|         }).catch(function (err) { | ||||
|           console.error(err); | ||||
|           window.alert("Error: [authorize] " + (err.message || JSON.stringify(err, null, 2))); | ||||
|         }); | ||||
|         return doConfigure(); | ||||
|       } else { | ||||
|         changeState('advanced'); | ||||
|       } | ||||
|     }).catch(function (err) { | ||||
|       console.error(err); | ||||
|       window.alert("Error: [directory] " + (err.message || JSON.stringify(err, null, 2))); | ||||
|       window.alert("Error: [initialize] " + (err.message || JSON.stringify(err, null, 2))); | ||||
|     }); | ||||
|   } | ||||
| , advance: function () { | ||||
|     console.log('2 api.init...'); | ||||
|     return api.initialize(); | ||||
|     return doConfigure(); | ||||
|   } | ||||
| , productionAcme: function () { | ||||
|     console.log("prod acme:"); | ||||
| @ -157,10 +195,26 @@ var appStates = { | ||||
| , advanced: function () { | ||||
|     appData.views.section = { advanced: true }; | ||||
|   } | ||||
| , otp: function () { | ||||
|     appData.views.section = { otp: true }; | ||||
|   } | ||||
| , status: function () { | ||||
|     appData.views.section = { status: true }; | ||||
|     return api.status().then(function (status) { | ||||
|       appData.status = status; | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| function changeState(newstate) { | ||||
|   location.hash = '#/' + newstate + '/'; | ||||
|   var newhash = '#/' + newstate + '/'; | ||||
|   if (location.hash === newhash) { | ||||
|     if (!telebitState.firstState) { | ||||
|       telebitState.firstState = true; | ||||
|       setState(); | ||||
|     } | ||||
|   } | ||||
|   location.hash = newhash; | ||||
| } | ||||
| window.addEventListener('hashchange', setState, false); | ||||
| function setState(/*ev*/) { | ||||
| @ -183,11 +237,52 @@ new Vue({ | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| api.config(); | ||||
| api.status().then(function () { | ||||
| 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; | ||||
|   } | ||||
| 
 | ||||
|   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 () { | ||||
|       console.log('2 api.init...'); | ||||
|       return api.initialize(); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   // TODO handle default state
 | ||||
|   changeState('status'); | ||||
| }).catch(function (err) { | ||||
|   appData.views.flash.error = err.message || JSON.stringify(err, null, 2); | ||||
| }); | ||||
| 
 | ||||
| window.api = api; | ||||
| 
 | ||||
| setTimeout(function () { | ||||
|   document.body.hidden = false; | ||||
| }, 50); | ||||
| 
 | ||||
| }()); | ||||
|  | ||||
| @ -11,19 +11,14 @@ if ('undefined' !== typeof Promise) { | ||||
| 
 | ||||
| var common = exports.TELEBIT || require('./lib/common.js'); | ||||
| 
 | ||||
| common.authorize = common.getToken = function getToken(state) { | ||||
| common.authorize = common.getToken = function getToken(state, showOtp) { | ||||
|   state.relay = state.config.relay; | ||||
| 
 | ||||
|   // { _otp, config: {} }
 | ||||
|   return common.api.token(state, { | ||||
|     error: function (err) { | ||||
|       console.error("[Error] common.api.token handlers.error:"); | ||||
|       console.error(err); | ||||
|       return PromiseA.reject(err); | ||||
|     } | ||||
|     error: function (err) { console.error("[Error] common.api.token handlers.error: \n", err); return PromiseA.reject(err); } | ||||
|   , directory: function (dir) { | ||||
|       //console.log('[directory] Telebit Relay Discovered:');
 | ||||
|       //console.log(dir);
 | ||||
|       /*console.log('[directory] Telebit Relay Discovered:', dir);*/ | ||||
|       state._apiDirectory = dir; | ||||
|       return PromiseA.resolve(); | ||||
|     } | ||||
| @ -32,12 +27,13 @@ common.authorize = common.getToken = function getToken(state) { | ||||
|       state.wss = tunnelUrl; | ||||
|       return PromiseA.resolve(); | ||||
|     } | ||||
|   , requested: function (authReq) { | ||||
|   , requested: function (authReq, pollUrl) { | ||||
|       console.log("[requested] Pairing Requested"); | ||||
|       state.config._otp = state.config._otp = authReq.otp; | ||||
|       state._otp = state._otp = authReq.otp; | ||||
| 
 | ||||
|       if (!state.config.token && state._can_pair) { | ||||
|         console.info("0000".replace(/0000/g, state.config._otp)); | ||||
|         console.info("0000".replace(/0000/g, state._otp)); | ||||
|         showOtp(authReq.otp, pollUrl); | ||||
|       } | ||||
| 
 | ||||
|       return PromiseA.resolve(); | ||||
| @ -47,7 +43,9 @@ common.authorize = common.getToken = function getToken(state) { | ||||
|       state.config.pretoken = pretoken; | ||||
|       state._connecting = true; | ||||
| 
 | ||||
|       return common.reqLocalAsync({ url: '/api/config', method: 'POST', body: state.config }).then(function () { | ||||
|       // This will only be saved to the session
 | ||||
|       state.config._otp = state._otp; | ||||
|       return common.reqLocalAsync({ url: '/api/config', method: 'POST', body: state.config, json: true }).then(function () { | ||||
|         console.info("waiting..."); | ||||
|         return PromiseA.resolve(); | ||||
|       }).catch(function (err) { | ||||
| @ -59,6 +57,7 @@ common.authorize = common.getToken = function getToken(state) { | ||||
|     } | ||||
|   , offer: function (token) { | ||||
|       //console.log("[offer] Pairing Enabled by Relay");
 | ||||
|       state.token = token; | ||||
|       state.config.token = token; | ||||
|       if (state._error) { | ||||
|         return; | ||||
| @ -77,7 +76,7 @@ common.authorize = common.getToken = function getToken(state) { | ||||
|       } catch(e) { | ||||
|         console.warn("[warning] could not decode token"); | ||||
|       } | ||||
|       return common.reqLocalAsync({ url: '/api/config', method: 'POST', body: state.config }).then(function () { | ||||
|       return common.reqLocalAsync({ url: '/api/config', method: 'POST', body: state.config, json: true }).then(function () { | ||||
|         //console.log("Pairing Enabled Locally");
 | ||||
|         return PromiseA.resolve(); | ||||
|       }).catch(function (err) { | ||||
| @ -87,12 +86,9 @@ common.authorize = common.getToken = function getToken(state) { | ||||
|         return PromiseA.reject(err); | ||||
|       }); | ||||
|     } | ||||
|   , granted: function (/*_*/) { | ||||
|       //console.log("[grant] Pairing complete!");
 | ||||
|       return PromiseA.resolve(); | ||||
|     } | ||||
|   , granted: function (/*_*/) { /*console.log("[grant] Pairing complete!");*/ return PromiseA.resolve(); } | ||||
|   , end: function () { | ||||
|       return common.reqLocalAsync({ url: '/api/enable', method: 'POST', body: [] }).then(function () { | ||||
|       return common.reqLocalAsync({ url: '/api/enable', method: 'POST', body: [], json: true }).then(function () { | ||||
|         console.info("Success"); | ||||
| 
 | ||||
|         // workaround for https://github.com/nodejs/node/issues/21319
 | ||||
| @ -112,9 +108,6 @@ common.authorize = common.getToken = function getToken(state) { | ||||
|         // end workaround
 | ||||
| 
 | ||||
|         //parseCli(state);
 | ||||
|       }).catch(function (err) { | ||||
|         console.error('[end] [error]', err); | ||||
|         return PromiseA.reject(err); | ||||
|       }); | ||||
|     } | ||||
|   }); | ||||
|  | ||||
| @ -48,11 +48,15 @@ if ('undefined' !== typeof fetch) { | ||||
|     if (!opts) { opts = {}; } | ||||
|     if (opts.json && true !== opts.json) { | ||||
|       opts.body = opts.json; | ||||
|       opts.json = true; | ||||
|     } | ||||
|     if (opts.json) { | ||||
|       if (!opts.headers) { opts.headers = {}; } | ||||
|       if (opts.body) { | ||||
|         opts.headers['Content-Type'] = 'application/json'; | ||||
|         if ('string' !== typeof opts.body) { | ||||
|           opts.body = JSON.stringify(opts.body); | ||||
|         } | ||||
|       } else { | ||||
|         opts.headers.Accepts = 'application/json'; | ||||
|       } | ||||
| @ -126,15 +130,16 @@ common.signToken = function (state) { | ||||
|   return jwt.sign(tokenData, state.config.secret); | ||||
| }; | ||||
| common.promiseTimeout = function (ms) { | ||||
|   var x = new PromiseA(function (resolve) { | ||||
|     x._tok = setTimeout(function () { | ||||
|   var tok; | ||||
|   var p = new PromiseA(function (resolve) { | ||||
|     tok = setTimeout(function () { | ||||
|       resolve(); | ||||
|     }, ms); | ||||
|   }); | ||||
|   x.cancel = function () { | ||||
|     clearTimeout(x._tok); | ||||
|   p.cancel = function () { | ||||
|     clearTimeout(tok); | ||||
|   }; | ||||
|   return x; | ||||
|   return p; | ||||
| }; | ||||
| common.api = {}; | ||||
| common.api.directory = function (state) { | ||||
| @ -145,15 +150,10 @@ common.api.directory = function (state) { | ||||
|   if (state._relays[state._relayUrl]) { | ||||
|     return PromiseA.resolve(state._relays[state._relayUrl]); | ||||
|   } | ||||
|   console.error('aaaaaaaaabsnthsnth'); | ||||
|   return common.requestAsync({ url: state._relayUrl + common.apiDirectory, json: true }).then(function (resp) { | ||||
|     console.error('123aaaaaaaaabsnthsnth'); | ||||
|     var dir = resp.body; | ||||
|     state._relays[state._relayUrl] = dir; | ||||
|     return dir; | ||||
|   }).catch(function (err) { | ||||
|     console.error('bsnthsnth'); | ||||
|     return PromiseA.reject(err); | ||||
|   }); | ||||
| }; | ||||
| common.api._parseWss = function (state, dir) { | ||||
| @ -169,15 +169,63 @@ common.api.wss = function (state) { | ||||
|   }); | ||||
| }; | ||||
| common.api.token = function (state, handlers) { | ||||
| 
 | ||||
|   var firstReady = true; | ||||
|   function pollStatus(req) { | ||||
|     if (common.debug) { console.log('[debug] pollStatus called'); } | ||||
|     if (common.debug) { console.log(req); } | ||||
|     return common.requestAsync(req).then(function checkLocation(resp) { | ||||
|       var body = resp.body; | ||||
|       if (common.debug) { console.log('[debug] checkLocation'); } | ||||
|       if (common.debug) { console.log(body); } | ||||
|       // pending, try again
 | ||||
|       if ('pending' === body.status && resp.headers.location) { | ||||
|         if (common.debug) { console.log('[debug] pending'); } | ||||
|         return common.promiseTimeout(2 * 1000).then(function () { | ||||
|           return pollStatus({ url: resp.headers.location, json: true }); | ||||
|         }); | ||||
|       } else if ('ready' === body.status) { | ||||
|         if (common.debug) { console.log('[debug] ready'); } | ||||
|         if (firstReady) { | ||||
|           if (common.debug) { console.log('[debug] first ready'); } | ||||
|           firstReady = false; | ||||
|           // falls through on purpose
 | ||||
|           PromiseA.resolve(handlers.offer(body.access_token)).then(function () { | ||||
|             /*ignore*/ | ||||
|           }); | ||||
|         } | ||||
|         return common.promiseTimeout(2 * 1000).then(function () { | ||||
|           return pollStatus(req); | ||||
|         }); | ||||
|       } else if ('complete' === body.status) { | ||||
|         if (common.debug) { console.log('[debug] complete'); } | ||||
|         return PromiseA.resolve(handlers.granted(null)).then(function () { | ||||
|           return PromiseA.resolve(handlers.end(null)).then(function () {}); | ||||
|         }); | ||||
|       } else { | ||||
|         if (common.debug) { console.log('[debug] bad status'); } | ||||
|         var err = new Error("Bad State:" + body.status); | ||||
|         err._request = req; | ||||
|         return PromiseA.reject(err); | ||||
|       } | ||||
|     }).catch(function (err) { | ||||
|       if (common.debug) { console.log('[debug] pollStatus error'); } | ||||
|       err._request = req; | ||||
|       err._hint = '[telebitd.js] pair request'; | ||||
|       return PromiseA.resolve(handlers.error(err)).then(function () {}); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   // directory, requested, connect, tunnelUrl, offer, granted, end
 | ||||
|   function afterDir(dir) { | ||||
|   function requestAuth(dir) { | ||||
|     if (common.debug) { console.log('[debug] after dir'); } | ||||
|     state.wss = common.api._parseWss(state, dir); | ||||
| 
 | ||||
|     return PromiseA.resolve(handlers.tunnelUrl(state.wss)).then(function () { | ||||
|       if (common.debug) { console.log('[debug] after tunnelUrl'); } | ||||
|       if (state.config.secret /* && !state.config.token */) { | ||||
|         state.config._token = common.signToken(state); | ||||
|         // TODO make token here in the browser
 | ||||
|         //state.config._token = common.signToken(state);
 | ||||
|       } | ||||
|       state.token = state.token || state.config.token || state.config._token; | ||||
|       if (state.token) { | ||||
| @ -190,13 +238,13 @@ common.api.token = function (state, handlers) { | ||||
| 
 | ||||
|       if (!dir.pair_request) { | ||||
|         if (common.debug) { console.log('[debug] no dir, connect'); } | ||||
|         return PromiseA.resolve(handlers.error(err || new Error("No token found or generated, and no pair_request api found."))); | ||||
|         return PromiseA.resolve(handlers.error(new Error("No token found or generated, and no pair_request api found."))); | ||||
|       } | ||||
| 
 | ||||
|       // TODO sign token with own private key, including public key and thumbprint
 | ||||
|       //      (much like ACME JOSE account)
 | ||||
|       // TODO handle agree
 | ||||
|       var otp = state.config._otp; // common.otp();
 | ||||
|       var otp = state._otp; // common.otp();
 | ||||
|       var authReq = { | ||||
|         subject: state.config.email | ||||
|       , subject_scheme: 'mailto' | ||||
| @ -236,59 +284,14 @@ common.api.token = function (state, handlers) { | ||||
|       , method: dir.pair_request.method | ||||
|       , json: authReq | ||||
|       }; | ||||
|       var firstReq = true; | ||||
|       var firstReady = true; | ||||
| 
 | ||||
|       function gotoNext(req) { | ||||
|         if (common.debug) { console.log('[debug] gotoNext called'); } | ||||
|         if (common.debug) { console.log(req); } | ||||
|         return common.requestAsync(req).then(function (resp) { | ||||
|       return common.requestAsync(req).then(function doFirst(resp) { | ||||
|         var body = resp.body; | ||||
| 
 | ||||
|           function checkLocation() { | ||||
|             if (common.debug) { console.log('[debug] checkLocation'); } | ||||
|             if (common.debug) { console.log(body); } | ||||
|             // pending, try again
 | ||||
|             if ('pending' === body.status && resp.headers.location) { | ||||
|               if (common.debug) { console.log('[debug] pending'); } | ||||
|               return common.promiseTimeout(2 * 1000).then(function () { | ||||
|                 return gotoNext({ url: resp.headers.location, json: true }); | ||||
|               }); | ||||
|             } else 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; | ||||
|                 // falls through on purpose
 | ||||
|                 PromiseA.resolve(handlers.offer(body.access_token)).then(function () { | ||||
|                   /*ignore*/ | ||||
|                 }); | ||||
|               } | ||||
|               return common.promiseTimeout(2 * 1000).then(function () { | ||||
|                 return gotoNext(req); | ||||
|               }); | ||||
|             } else if ('complete' === body.status) { | ||||
|               if (common.debug) { console.log('[debug] complete'); } | ||||
|               return PromiseA.resolve(handlers.granted(null)).then(function () { | ||||
|                 return PromiseA.resolve(handlers.end(null)).then(function () {}); | ||||
|               }); | ||||
|             } else { | ||||
|               if (common.debug) { console.log('[debug] bad status'); } | ||||
|               var err = new Error("Bad State:" + body.status); | ||||
|               err._request = req; | ||||
|               return PromiseA.resolve(handlers.error(err)); | ||||
|             } | ||||
|           } | ||||
| 
 | ||||
|           if (firstReq) { | ||||
|         if (common.debug) { console.log('[debug] first req'); } | ||||
|         if (!body.access_token && !body.jwt) { | ||||
|           return PromiseA.reject(new Error("something wrong with pre-authorization request")); | ||||
|         } | ||||
|             firstReq = false; | ||||
|             return PromiseA.resolve(handlers.requested(authReq)).then(function () { | ||||
|         return PromiseA.resolve(handlers.requested(authReq, resp.headers.location)).then(function () { | ||||
|           return PromiseA.resolve(handlers.connect(body.access_token || body.jwt)).then(function () { | ||||
|             var err; | ||||
|             if (!resp.headers.location) { | ||||
| @ -297,25 +300,21 @@ common.api.token = function (state, handlers) { | ||||
|               return PromiseA.resolve(handlers.error(err)).then(function () {}); | ||||
|             } | ||||
|             return common.promiseTimeout(2 * 1000).then(function () { | ||||
|                   return gotoNext({ url: resp.headers.location, json: true }); | ||||
|               return pollStatus({ url: resp.headers.location, json: true }); | ||||
|             }); | ||||
|           }); | ||||
|         }); | ||||
|           } else { | ||||
|             if (common.debug) { console.log('[debug] other req'); } | ||||
|             return checkLocation(); | ||||
|           } | ||||
|       }).catch(function (err) { | ||||
|           if (common.debug) { console.log('[debug] gotoNext error'); } | ||||
|         if (common.debug) { console.log('[debug] gotoFirst error'); } | ||||
|         err._request = req; | ||||
|         err._hint = '[telebitd.js] pair request'; | ||||
|         return PromiseA.resolve(handlers.error(err)).then(function () {}); | ||||
|       }); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|       return gotoNext(req); | ||||
| 
 | ||||
|     }); | ||||
|   if (state.pollUrl) { | ||||
|     return pollStatus({ url: state.pollUrl, json: true }); | ||||
|   } | ||||
| 
 | ||||
|   // backwards compat (TODO verify we can remove this)
 | ||||
| @ -331,9 +330,9 @@ common.api.token = function (state, handlers) { | ||||
|   }).then(function (dir) { | ||||
|     return PromiseA.resolve(handlers.directory(dir)).then(function () { | ||||
|       console.log('[debug] [directory]', dir); | ||||
|       return afterDir(dir); | ||||
|       return requestAuth(dir); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| }('undefined' !== typeof module ? module.exports : window)); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user