wip trying to get auth request and token...
This commit is contained in:
		
							parent
							
								
									9e1c9c00ca
								
							
						
					
					
						commit
						e6b7ba575f
					
				@ -338,9 +338,12 @@ controllers.relay = function (req, res, opts) {
 | 
				
			|||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  console.log('POST /api/relay:');
 | 
				
			||||||
 | 
					  console.log(opts.body);
 | 
				
			||||||
 | 
					  console.log();
 | 
				
			||||||
  return urequestAsync(opts.body).then(function (resp) {
 | 
					  return urequestAsync(opts.body).then(function (resp) {
 | 
				
			||||||
    res.setHeader('Content-Type', 'application/json');
 | 
					    res.setHeader('Content-Type', 'application/json');
 | 
				
			||||||
    var resp = resp.toJSON();
 | 
					    resp = resp.toJSON();
 | 
				
			||||||
    res.end(JSON.stringify(resp));
 | 
					    res.end(JSON.stringify(resp));
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -104,6 +104,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  <script src="/js/vue.js"></script>
 | 
					  <script src="/js/vue.js"></script>
 | 
				
			||||||
  <script src="/js/telebit.js"></script>
 | 
					  <script src="/js/telebit.js"></script>
 | 
				
			||||||
 | 
					  <script src="/js/telebit-token.js"></script>
 | 
				
			||||||
  <script src="/js/app.js"></script>
 | 
					  <script src="/js/app.js"></script>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,7 @@ var Vue = window.Vue;
 | 
				
			|||||||
var Telebit = window.TELEBIT;
 | 
					var Telebit = window.TELEBIT;
 | 
				
			||||||
var api = {};
 | 
					var api = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*globals AbortController*/
 | 
					/*
 | 
				
			||||||
function safeFetch(url, opts) {
 | 
					function safeFetch(url, opts) {
 | 
				
			||||||
  var controller = new AbortController();
 | 
					  var controller = new AbortController();
 | 
				
			||||||
  var tok = setTimeout(function () {
 | 
					  var tok = setTimeout(function () {
 | 
				
			||||||
@ -19,28 +19,29 @@ function safeFetch(url, opts) {
 | 
				
			|||||||
    clearTimeout(tok);
 | 
					    clearTimeout(tok);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
api.config = function apiConfig() {
 | 
					api.config = function apiConfig() {
 | 
				
			||||||
  return safeFetch("/api/config", {
 | 
					  return Telebit.reqLocalAsync({
 | 
				
			||||||
    method: "GET"
 | 
					    url: "/api/config"
 | 
				
			||||||
 | 
					  , method: "GET"
 | 
				
			||||||
  }).then(function (resp) {
 | 
					  }).then(function (resp) {
 | 
				
			||||||
    return resp.json().then(function (json) {
 | 
					    var json = resp.body;
 | 
				
			||||||
      appData.config = json;
 | 
					    appData.config = json;
 | 
				
			||||||
      return json;
 | 
					    return json;
 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
api.status = function apiStatus() {
 | 
					api.status = function apiStatus() {
 | 
				
			||||||
  return safeFetch("/api/status", { method: "GET" }).then(function (resp) {
 | 
					  return Telebit.reqLocalAsync({ url: "/api/status", method: "GET" }).then(function (resp) {
 | 
				
			||||||
    return resp.json().then(function (json) {
 | 
					    var json = resp.body;
 | 
				
			||||||
      appData.status = json;
 | 
					    appData.status = json;
 | 
				
			||||||
      return json;
 | 
					    return json;
 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
api.initialize = function apiInitialize() {
 | 
					api.initialize = function apiInitialize() {
 | 
				
			||||||
  var opts = {
 | 
					  var opts = {
 | 
				
			||||||
    method: "POST"
 | 
					    url: "/api/init"
 | 
				
			||||||
 | 
					  , method: "POST"
 | 
				
			||||||
  , headers: {
 | 
					  , headers: {
 | 
				
			||||||
      'Content-Type': 'application/json'
 | 
					      'Content-Type': 'application/json'
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -48,14 +49,13 @@ api.initialize = function apiInitialize() {
 | 
				
			|||||||
      foo: 'bar'
 | 
					      foo: 'bar'
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  return safeFetch("/api/init", opts).then(function (resp) {
 | 
					  return Telebit.reqLocalAsync(opts).then(function (resp) {
 | 
				
			||||||
    return resp.json().then(function (json) {
 | 
					    var json = resp.body;
 | 
				
			||||||
      appData.initResult = json;
 | 
					    appData.initResult = json;
 | 
				
			||||||
      window.alert("Error: [success] " + JSON.stringify(json, null, 2));
 | 
					    window.alert("Error: [success] " + JSON.stringify(json, null, 2));
 | 
				
			||||||
      return json;
 | 
					    return json;
 | 
				
			||||||
    }).catch(function (err) {
 | 
					  }).catch(function (err) {
 | 
				
			||||||
      window.alert("Error: [init] " + (err.message || JSON.stringify(err, null, 2)));
 | 
					    window.alert("Error: [init] " + (err.message || JSON.stringify(err, null, 2)));
 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -104,15 +104,27 @@ var appMethods = {
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (-1 !== TELEBIT_RELAYS.indexOf(appData.init.relay)) {
 | 
					      if (-1 !== TELEBIT_RELAYS.indexOf(appData.init.relay)) {
 | 
				
			||||||
        return api.initialize();
 | 
					        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)));
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        changeState('advanced');
 | 
					        changeState('advanced');
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }).catch(function (err) {
 | 
					    }).catch(function (err) {
 | 
				
			||||||
 | 
					      console.error(err);
 | 
				
			||||||
      window.alert("Error: [directory] " + (err.message || JSON.stringify(err, null, 2)));
 | 
					      window.alert("Error: [directory] " + (err.message || JSON.stringify(err, null, 2)));
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
, advance: function () {
 | 
					, advance: function () {
 | 
				
			||||||
 | 
					    console.log('2 api.init...');
 | 
				
			||||||
    return api.initialize();
 | 
					    return api.initialize();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
, productionAcme: function () {
 | 
					, productionAcme: function () {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										123
									
								
								lib/admin/js/telebit-token.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								lib/admin/js/telebit-token.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,123 @@
 | 
				
			|||||||
 | 
					;(function (exports) {
 | 
				
			||||||
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* global Promise */
 | 
				
			||||||
 | 
					var PromiseA;
 | 
				
			||||||
 | 
					if ('undefined' !== typeof Promise) {
 | 
				
			||||||
 | 
					  PromiseA = Promise;
 | 
				
			||||||
 | 
					} else {
 | 
				
			||||||
 | 
					  throw new Error("no Promise implementation defined");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var common = exports.TELEBIT || require('./lib/common.js');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					common.authorize = common.getToken = function getToken(state) {
 | 
				
			||||||
 | 
					  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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  , directory: function (dir) {
 | 
				
			||||||
 | 
					      //console.log('[directory] Telebit Relay Discovered:');
 | 
				
			||||||
 | 
					      //console.log(dir);
 | 
				
			||||||
 | 
					      state._apiDirectory = dir;
 | 
				
			||||||
 | 
					      return PromiseA.resolve();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  , tunnelUrl: function (tunnelUrl) {
 | 
				
			||||||
 | 
					      //console.log('[tunnelUrl] Telebit Relay Tunnel Socket:', tunnelUrl);
 | 
				
			||||||
 | 
					      state.wss = tunnelUrl;
 | 
				
			||||||
 | 
					      return PromiseA.resolve();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  , requested: function (authReq) {
 | 
				
			||||||
 | 
					      console.log("[requested] Pairing Requested");
 | 
				
			||||||
 | 
					      state.config._otp = state.config._otp = authReq.otp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!state.config.token && state._can_pair) {
 | 
				
			||||||
 | 
					        console.info("0000".replace(/0000/g, state.config._otp));
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return PromiseA.resolve();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  , connect: function (pretoken) {
 | 
				
			||||||
 | 
					      console.log("[connect] Enabling Pairing Locally...");
 | 
				
			||||||
 | 
					      state.config.pretoken = pretoken;
 | 
				
			||||||
 | 
					      state._connecting = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return common.reqLocalAsync({ url: '/api/config', method: 'POST', data: state.config || {} }).then(function () {
 | 
				
			||||||
 | 
					        console.info("waiting...");
 | 
				
			||||||
 | 
					        return PromiseA.resolve();
 | 
				
			||||||
 | 
					      }).catch(function (err) {
 | 
				
			||||||
 | 
					        state._error = err;
 | 
				
			||||||
 | 
					        console.error("Error while initializing config [connect]:");
 | 
				
			||||||
 | 
					        console.error(err);
 | 
				
			||||||
 | 
					        return PromiseA.reject(err);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  , offer: function (token) {
 | 
				
			||||||
 | 
					      //console.log("[offer] Pairing Enabled by Relay");
 | 
				
			||||||
 | 
					      state.config.token = token;
 | 
				
			||||||
 | 
					      if (state._error) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      state._connecting = true;
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        //require('jsonwebtoken').decode(token);
 | 
				
			||||||
 | 
					        token = token.split('.');
 | 
				
			||||||
 | 
					        token[0] = token[0].replace(/_/g, '/').replace(/-/g, '+');
 | 
				
			||||||
 | 
					        while (token[0].length % 4) { token[0] += '='; }
 | 
				
			||||||
 | 
					        btoa(token[0]);
 | 
				
			||||||
 | 
					        token[1] = token[1].replace(/_/g, '/').replace(/-/g, '+');
 | 
				
			||||||
 | 
					        while (token[1].length % 4) { token[1] += '='; }
 | 
				
			||||||
 | 
					        btoa(token[1]);
 | 
				
			||||||
 | 
					        //console.log(require('jsonwebtoken').decode(token));
 | 
				
			||||||
 | 
					      } catch(e) {
 | 
				
			||||||
 | 
					        console.warn("[warning] could not decode token");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return common.reqLocalAsync({ url: '/api/config', method: 'POST', data: state.config }).then(function () {
 | 
				
			||||||
 | 
					        //console.log("Pairing Enabled Locally");
 | 
				
			||||||
 | 
					        return PromiseA.resolve();
 | 
				
			||||||
 | 
					      }).catch(function (err) {
 | 
				
			||||||
 | 
					        state._error = err;
 | 
				
			||||||
 | 
					        console.error("Error while initializing config [offer]:");
 | 
				
			||||||
 | 
					        console.error(err);
 | 
				
			||||||
 | 
					        return PromiseA.reject(err);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  , granted: function (/*_*/) {
 | 
				
			||||||
 | 
					      //console.log("[grant] Pairing complete!");
 | 
				
			||||||
 | 
					      return PromiseA.resolve();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  , end: function () {
 | 
				
			||||||
 | 
					      return common.reqLocalAsync({ url: '/api/enable', method: 'POST', data: [] }).then(function () {
 | 
				
			||||||
 | 
					        console.info("Success");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // workaround for https://github.com/nodejs/node/issues/21319
 | 
				
			||||||
 | 
					        if (state._useTty) {
 | 
				
			||||||
 | 
					          setTimeout(function () {
 | 
				
			||||||
 | 
					            console.info("Some fun things to try first:\n");
 | 
				
			||||||
 | 
					            console.info("    ~/telebit http ~/public");
 | 
				
			||||||
 | 
					            console.info("    ~/telebit tcp 5050");
 | 
				
			||||||
 | 
					            console.info("    ~/telebit ssh auto");
 | 
				
			||||||
 | 
					            console.info();
 | 
				
			||||||
 | 
					            console.info("Press any key to continue...");
 | 
				
			||||||
 | 
					            console.info();
 | 
				
			||||||
 | 
					            process.exit(0);
 | 
				
			||||||
 | 
					          }, 0.5 * 1000);
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // end workaround
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //parseCli(state);
 | 
				
			||||||
 | 
					      }).catch(function (err) {
 | 
				
			||||||
 | 
					        console.error('[end] [error]', err);
 | 
				
			||||||
 | 
					        return PromiseA.reject(err);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}('undefined' === typeof module ? window : module.exports));
 | 
				
			||||||
@ -2,6 +2,7 @@
 | 
				
			|||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var common = exports.TELEBIT = {};
 | 
					var common = exports.TELEBIT = {};
 | 
				
			||||||
 | 
					common.debug = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* global Promise */
 | 
					/* global Promise */
 | 
				
			||||||
var PromiseA;
 | 
					var PromiseA;
 | 
				
			||||||
@ -14,19 +15,6 @@ if ('undefined' !== typeof Promise) {
 | 
				
			|||||||
/*globals AbortController*/
 | 
					/*globals AbortController*/
 | 
				
			||||||
if ('undefined' !== typeof fetch) {
 | 
					if ('undefined' !== typeof fetch) {
 | 
				
			||||||
  common.requestAsync = function (opts) {
 | 
					  common.requestAsync = function (opts) {
 | 
				
			||||||
    /*
 | 
					 | 
				
			||||||
    if (opts.json && true !== opts.json) {
 | 
					 | 
				
			||||||
      opts.body = opts.json;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (opts.json) {
 | 
					 | 
				
			||||||
      if (!opts.headers) { opts.headers = {}; }
 | 
					 | 
				
			||||||
      if (opts.body) {
 | 
					 | 
				
			||||||
        opts.headers['Content-Type'] = 'application/json';
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        opts.headers.Accepts = 'application/json';
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    */
 | 
					 | 
				
			||||||
    // funnel requests through the local server
 | 
					    // funnel requests through the local server
 | 
				
			||||||
    // (avoid CORS, for now)
 | 
					    // (avoid CORS, for now)
 | 
				
			||||||
    var relayOpts = {
 | 
					    var relayOpts = {
 | 
				
			||||||
@ -49,13 +37,6 @@ if ('undefined' !== typeof fetch) {
 | 
				
			|||||||
    return window.fetch(relayOpts.url, relayOpts).then(function (resp) {
 | 
					    return window.fetch(relayOpts.url, relayOpts).then(function (resp) {
 | 
				
			||||||
      clearTimeout(tok);
 | 
					      clearTimeout(tok);
 | 
				
			||||||
      return resp.json().then(function (json) {
 | 
					      return resp.json().then(function (json) {
 | 
				
			||||||
        /*
 | 
					 | 
				
			||||||
        var headers = {};
 | 
					 | 
				
			||||||
        resp.headers.forEach(function (k, v) {
 | 
					 | 
				
			||||||
          headers[k] = v;
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
        return { statusCode: resp.status, headers: headers, body: json };
 | 
					 | 
				
			||||||
        */
 | 
					 | 
				
			||||||
        if (json.error) {
 | 
					        if (json.error) {
 | 
				
			||||||
          return PromiseA.reject(new Error(json.error && json.error.message || JSON.stringify(json.error)));
 | 
					          return PromiseA.reject(new Error(json.error && json.error.message || JSON.stringify(json.error)));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -63,8 +44,38 @@ if ('undefined' !== typeof fetch) {
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					  common.reqLocalAsync = function (opts) {
 | 
				
			||||||
 | 
					    if (!opts) { opts = {}; }
 | 
				
			||||||
 | 
					    if (opts.json && true !== opts.json) {
 | 
				
			||||||
 | 
					      opts.body = opts.json;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (opts.json) {
 | 
				
			||||||
 | 
					      if (!opts.headers) { opts.headers = {}; }
 | 
				
			||||||
 | 
					      if (opts.body) {
 | 
				
			||||||
 | 
					        opts.headers['Content-Type'] = 'application/json';
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        opts.headers.Accepts = 'application/json';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var controller = new AbortController();
 | 
				
			||||||
 | 
					    var tok = setTimeout(function () {
 | 
				
			||||||
 | 
					      controller.abort();
 | 
				
			||||||
 | 
					    }, 4000);
 | 
				
			||||||
 | 
					    opts.signal = controller.signal;
 | 
				
			||||||
 | 
					    return window.fetch(opts.url, opts).then(function (resp) {
 | 
				
			||||||
 | 
					      clearTimeout(tok);
 | 
				
			||||||
 | 
					      return resp.json().then(function (json) {
 | 
				
			||||||
 | 
					        var headers = {};
 | 
				
			||||||
 | 
					        resp.headers.forEach(function (k, v) {
 | 
				
			||||||
 | 
					          headers[k] = v;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return { statusCode: resp.status, headers: headers, body: json };
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
} else {
 | 
					} else {
 | 
				
			||||||
  common.requestAsync = require('util').promisify(require('@coolaj86/urequest'));
 | 
					  common.requestAsync = require('util').promisify(require('@coolaj86/urequest'));
 | 
				
			||||||
 | 
					  common.reqLocalAsync = require('util').promisify(require('@coolaj86/urequest'));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
common.parseUrl = function (hostname) {
 | 
					common.parseUrl = function (hostname) {
 | 
				
			||||||
@ -78,7 +89,12 @@ common.parseUrl = function (hostname) {
 | 
				
			|||||||
  return hostname;
 | 
					  return hostname;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
common.parseHostname = function (hostname) {
 | 
					common.parseHostname = function (hostname) {
 | 
				
			||||||
  var location = new URL(hostname);
 | 
					  var location = {};
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    location = new URL(hostname);
 | 
				
			||||||
 | 
					  } catch(e) {
 | 
				
			||||||
 | 
					    // ignore
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if (!location.protocol || /\./.test(location.protocol)) {
 | 
					  if (!location.protocol || /\./.test(location.protocol)) {
 | 
				
			||||||
    hostname = 'https://' + hostname;
 | 
					    hostname = 'https://' + hostname;
 | 
				
			||||||
    location = new URL(hostname);
 | 
					    location = new URL(hostname);
 | 
				
			||||||
@ -109,6 +125,17 @@ common.signToken = function (state) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return jwt.sign(tokenData, state.config.secret);
 | 
					  return jwt.sign(tokenData, state.config.secret);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					common.promiseTimeout = function (ms) {
 | 
				
			||||||
 | 
					  var x = new PromiseA(function (resolve) {
 | 
				
			||||||
 | 
					    x._tok = setTimeout(function () {
 | 
				
			||||||
 | 
					      resolve();
 | 
				
			||||||
 | 
					    }, ms);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  x.cancel = function () {
 | 
				
			||||||
 | 
					    clearTimeout(x._tok);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return x;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
common.api = {};
 | 
					common.api = {};
 | 
				
			||||||
common.api.directory = function (state) {
 | 
					common.api.directory = function (state) {
 | 
				
			||||||
  console.log('[DEBUG] state:');
 | 
					  console.log('[DEBUG] state:');
 | 
				
			||||||
@ -118,11 +145,14 @@ common.api.directory = function (state) {
 | 
				
			|||||||
  if (state._relays[state._relayUrl]) {
 | 
					  if (state._relays[state._relayUrl]) {
 | 
				
			||||||
    return PromiseA.resolve(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) {
 | 
					  return common.requestAsync({ url: state._relayUrl + common.apiDirectory, json: true }).then(function (resp) {
 | 
				
			||||||
 | 
					    console.error('123aaaaaaaaabsnthsnth');
 | 
				
			||||||
    var dir = resp.body;
 | 
					    var dir = resp.body;
 | 
				
			||||||
    state._relays[state._relayUrl] = dir;
 | 
					    state._relays[state._relayUrl] = dir;
 | 
				
			||||||
    return dir;
 | 
					    return dir;
 | 
				
			||||||
  }).catch(function (err) {
 | 
					  }).catch(function (err) {
 | 
				
			||||||
 | 
					    console.error('bsnthsnth');
 | 
				
			||||||
    return PromiseA.reject(err);
 | 
					    return PromiseA.reject(err);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -133,18 +163,18 @@ common.api._parseWss = function (state, dir) {
 | 
				
			|||||||
  state._relayHostname = common.parseHostname(state.relay);
 | 
					  state._relayHostname = common.parseHostname(state.relay);
 | 
				
			||||||
  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) {
 | 
				
			||||||
  common.api.directory(state).then(function (dir) {
 | 
					  return common.api.directory(state).then(function (dir) {
 | 
				
			||||||
    cb(null, common.api._parseWss(state, dir));
 | 
					    return common.api._parseWss(state, dir);
 | 
				
			||||||
  }).catch(cb);
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
common.api.token = function (state, handlers) {
 | 
					common.api.token = function (state, handlers) {
 | 
				
			||||||
  // directory, requested, connect, tunnelUrl, offer, granted, end
 | 
					  // directory, requested, connect, tunnelUrl, offer, granted, end
 | 
				
			||||||
  function afterDir(err, dir) {
 | 
					  function afterDir(dir) {
 | 
				
			||||||
    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 () {
 | 
					    return PromiseA.resolve(handlers.tunnelUrl(state.wss)).then(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);
 | 
				
			||||||
@ -153,21 +183,19 @@ common.api.token = function (state, handlers) {
 | 
				
			|||||||
      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 () {
 | 
					        return PromiseA.resolve(handlers.connect(state.token)).then(function () {
 | 
				
			||||||
          handlers.end(null, function () {});
 | 
					          return PromiseA.resolve(handlers.end(null));
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // backwards compat (TODO remove)
 | 
					      if (!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."));
 | 
					        return PromiseA.resolve(handlers.error(err || new Error("No token found or generated, and no pair_request api found.")));
 | 
				
			||||||
        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)
 | 
				
			||||||
 | 
					      // TODO handle agree
 | 
				
			||||||
      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
 | 
				
			||||||
@ -187,8 +215,21 @@ common.api.token = function (state, handlers) {
 | 
				
			|||||||
      */
 | 
					      */
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
      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));
 | 
				
			||||||
 | 
					      console.log('pairRequestUrl:', pairRequestUrl);
 | 
				
			||||||
 | 
					      //console.log('pairRequestUrl:', JSON.stringify(pairRequestUrl.toJSON()));
 | 
				
			||||||
      var req = {
 | 
					      var req = {
 | 
				
			||||||
        url: pairRequestUrl
 | 
					        // WHATWG URL defines .toJSON() but, of course, it's not implemented
 | 
				
			||||||
 | 
					        // because... why would we implement JavaScript objects in the DOM
 | 
				
			||||||
 | 
					        // when we can have perfectly incompatible non-JS objects?
 | 
				
			||||||
 | 
					        url: {
 | 
				
			||||||
 | 
					          host: pairRequestUrl.host
 | 
				
			||||||
 | 
					        , hostname: pairRequestUrl.hostname
 | 
				
			||||||
 | 
					        , href: pairRequestUrl.href
 | 
				
			||||||
 | 
					        , pathname: pairRequestUrl.pathname
 | 
				
			||||||
 | 
					        , port: pairRequestUrl.port
 | 
				
			||||||
 | 
					        , protocol: pairRequestUrl.protocol
 | 
				
			||||||
 | 
					        , search: pairRequestUrl.search
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
      , method: dir.pair_request.method
 | 
					      , method: dir.pair_request.method
 | 
				
			||||||
      , json: authReq
 | 
					      , json: authReq
 | 
				
			||||||
      };
 | 
					      };
 | 
				
			||||||
@ -198,7 +239,7 @@ common.api.token = function (state, handlers) {
 | 
				
			|||||||
      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) {
 | 
					        return common.requestAsync(req).then(function (resp) {
 | 
				
			||||||
          var body = resp.body;
 | 
					          var body = resp.body;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          function checkLocation() {
 | 
					          function checkLocation() {
 | 
				
			||||||
@ -207,86 +248,88 @@ common.api.token = function (state, handlers) {
 | 
				
			|||||||
            // 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 });
 | 
					              return common.promiseTimeout(2 * 1000).then(function () {
 | 
				
			||||||
              return;
 | 
					                return gotoNext({ url: resp.headers.location, json: true });
 | 
				
			||||||
            }
 | 
					              });
 | 
				
			||||||
 | 
					            } else if ('ready' === body.status) {
 | 
				
			||||||
            if ('ready' === body.status) {
 | 
					 | 
				
			||||||
              if (common.debug) { console.log('[debug] ready'); }
 | 
					              if (common.debug) { console.log('[debug] ready'); }
 | 
				
			||||||
              if (firstReady) {
 | 
					              if (firstReady) {
 | 
				
			||||||
                if (common.debug) { console.log('[debug] first ready'); }
 | 
					                if (common.debug) { console.log('[debug] first ready'); }
 | 
				
			||||||
                firstReady = false;
 | 
					                firstReady = false;
 | 
				
			||||||
                state.token = body.access_token;
 | 
					                state.token = body.access_token;
 | 
				
			||||||
                state.config.token = state.token;
 | 
					                state.config.token = state.token;
 | 
				
			||||||
                handlers.offer(body.access_token, function () {
 | 
					                // falls through on purpose
 | 
				
			||||||
 | 
					                PromiseA.resolve(handlers.offer(body.access_token)).then(function () {
 | 
				
			||||||
                  /*ignore*/
 | 
					                  /*ignore*/
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
              setTimeout(gotoNext, 2 * 1000, req);
 | 
					              return common.promiseTimeout(2 * 1000).then(function () {
 | 
				
			||||||
              return;
 | 
					                return gotoNext(req);
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ('complete' === body.status) {
 | 
					 | 
				
			||||||
              if (common.debug) { console.log('[debug] complete'); }
 | 
					 | 
				
			||||||
              handlers.granted(null, function () {
 | 
					 | 
				
			||||||
                handlers.end(null, function () {});
 | 
					 | 
				
			||||||
              });
 | 
					              });
 | 
				
			||||||
              return;
 | 
					            } 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 (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 (firstReq) {
 | 
				
			||||||
            if (common.debug) { console.log('[debug] first req'); }
 | 
					            if (common.debug) { console.log('[debug] first req'); }
 | 
				
			||||||
            handlers.requested(authReq, function () {
 | 
					            if (!body.access_token && !body.jwt) {
 | 
				
			||||||
              handlers.connect(body.access_token || body.jwt, function () {
 | 
					              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.connect(body.access_token || body.jwt)).then(function () {
 | 
				
			||||||
                var err;
 | 
					                var err;
 | 
				
			||||||
                if (!resp.headers.location) {
 | 
					                if (!resp.headers.location) {
 | 
				
			||||||
                  err = new Error("bad authentication request response");
 | 
					                  err = new Error("bad authentication request response");
 | 
				
			||||||
                  err._resp = resp.toJSON && resp.toJSON();
 | 
					                  err._resp = resp.toJSON && resp.toJSON();
 | 
				
			||||||
                  handlers.error(err, function () {});
 | 
					                  return PromiseA.resolve(handlers.error(err)).then(function () {});
 | 
				
			||||||
                  return;
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                setTimeout(gotoNext, 2 * 1000, { url: resp.headers.location, json: true });
 | 
					                return common.promiseTimeout(2 * 1000).then(function () {
 | 
				
			||||||
 | 
					                  return gotoNext({ url: resp.headers.location, json: true });
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
              });
 | 
					              });
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            firstReq = false;
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            if (common.debug) { console.log('[debug] other req'); }
 | 
					            if (common.debug) { console.log('[debug] other req'); }
 | 
				
			||||||
            checkLocation();
 | 
					            return checkLocation();
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }).catch(function (err) {
 | 
					        }).catch(function (err) {
 | 
				
			||||||
          if (common.debug) { console.log('[debug] gotoNext error'); }
 | 
					          if (common.debug) { console.log('[debug] gotoNext error'); }
 | 
				
			||||||
          err._request = req;
 | 
					          err._request = req;
 | 
				
			||||||
          err._hint = '[telebitd.js] pair request';
 | 
					          err._hint = '[telebitd.js] pair request';
 | 
				
			||||||
          handlers.error(err, function () {});
 | 
					          return PromiseA.resolve(handlers.error(err)).then(function () {});
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      gotoNext(req);
 | 
					      return gotoNext(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // backwards compat (TODO verify we can remove this)
 | 
					  // backwards compat (TODO verify we can remove this)
 | 
				
			||||||
  var failoverDir = '{ "api_host": ":hostname", "tunnel": { "method": "wss", "pathname": "" } }';
 | 
					  var failoverDir = '{ "api_host": ":hostname", "tunnel": { "method": "wss", "pathname": "" } }';
 | 
				
			||||||
  common.api.directory(state).then(function (dir) {
 | 
					  return common.api.directory(state).then(function (dir) {
 | 
				
			||||||
    if (!dir.api_host) {
 | 
					    console.log('[debug] [directory]', dir);
 | 
				
			||||||
      dir = JSON.parse(failoverDir);
 | 
					    if (!dir.api_host) { dir = JSON.parse(failoverDir); }
 | 
				
			||||||
      return afterDir(null, dir);
 | 
					    return dir;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    handlers.directory(dir).then(function (dir) {
 | 
					 | 
				
			||||||
      return afterDir(null, dir);
 | 
					 | 
				
			||||||
    }).catch(function (err) {
 | 
					 | 
				
			||||||
      return PromiseA.reject(err);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }).catch(function (err) {
 | 
					  }).catch(function (err) {
 | 
				
			||||||
    return afterDir(err, JSON.parse(failoverDir));
 | 
					    console.warn('[warn] [directory] fetch fail, using failover');
 | 
				
			||||||
 | 
					    console.warn(err);
 | 
				
			||||||
 | 
					    return JSON.parse(failoverDir);
 | 
				
			||||||
 | 
					  }).then(function (dir) {
 | 
				
			||||||
 | 
					    return PromiseA.resolve(handlers.directory(dir)).then(function () {
 | 
				
			||||||
 | 
					      console.log('[debug] [directory]', dir);
 | 
				
			||||||
 | 
					      return afterDir(dir);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user