MAJOR: Updates for Authenticated Web UI and CLI #30
							
								
								
									
										645
									
								
								bin/telebitd.js
									
									
									
									
									
								
							
							
						
						
									
										645
									
								
								bin/telebitd.js
									
									
									
									
									
								
							| @ -28,6 +28,7 @@ var TPLS = TOML.parse(fs.readFileSync(path.join(__dirname, "../lib/en-us.toml"), | |||||||
| var startTime = Date.now(); | var startTime = Date.now(); | ||||||
| var connectTimes = []; | var connectTimes = []; | ||||||
| var isConnected = false; | var isConnected = false; | ||||||
|  | var eggspress = require('../lib/eggspress.js'); | ||||||
| 
 | 
 | ||||||
| var TelebitRemote = require('../lib/daemon/index.js').TelebitRemote; | var TelebitRemote = require('../lib/daemon/index.js').TelebitRemote; | ||||||
| 
 | 
 | ||||||
| @ -112,7 +113,7 @@ function saveConfig(cb) { | |||||||
|   fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), cb); |   fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), cb); | ||||||
| } | } | ||||||
| var controllers = {}; | var controllers = {}; | ||||||
| controllers.http = function (req, res, opts) { | controllers.http = function (req, res) { | ||||||
|   function getAppname(pathname) { |   function getAppname(pathname) { | ||||||
|     // port number
 |     // port number
 | ||||||
|     if (String(pathname) === String(parseInt(pathname, 10))) { |     if (String(pathname) === String(parseInt(pathname, 10))) { | ||||||
| @ -138,7 +139,7 @@ controllers.http = function (req, res, opts) { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (!opts.body) { |   if (!req.body) { | ||||||
|     res.statusCode = 422; |     res.statusCode = 422; | ||||||
|     res.setHeader('Content-Type', 'application/json'); |     res.setHeader('Content-Type', 'application/json'); | ||||||
|     res.end(JSON.stringify({"error":{"message":"module \'http\' needs some arguments"}})); |     res.end(JSON.stringify({"error":{"message":"module \'http\' needs some arguments"}})); | ||||||
| @ -146,9 +147,9 @@ controllers.http = function (req, res, opts) { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   var active = true; |   var active = true; | ||||||
|   var portOrPath = opts.body.handler || opts.body[0]; |   var portOrPath = req.body.handler || req.body[0]; | ||||||
|   var subdomain = opts.body.name || opts.body[1]; |   var subdomain = req.body.name || req.body[1]; | ||||||
|   var indexes = opts.body.indexes; |   var indexes = req.body.indexes; | ||||||
|   var remoteHost; |   var remoteHost; | ||||||
| 
 | 
 | ||||||
|   if (!portOrPath) { |   if (!portOrPath) { | ||||||
| @ -260,8 +261,8 @@ controllers.http = function (req, res, opts) { | |||||||
|     })); |     })); | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| controllers.tcp = function (req, res, opts) { | controllers.tcp = function (req, res) { | ||||||
|   if (!opts.body) { |   if (!req.body) { | ||||||
|     res.statusCode = 422; |     res.statusCode = 422; | ||||||
|     res.setHeader('Content-Type', 'application/json'); |     res.setHeader('Content-Type', 'application/json'); | ||||||
|     res.end(JSON.stringify({ error: { message: "module 'tcp' needs more arguments" } })); |     res.end(JSON.stringify({ error: { message: "module 'tcp' needs more arguments" } })); | ||||||
| @ -269,8 +270,8 @@ controllers.tcp = function (req, res, opts) { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   var active; |   var active; | ||||||
|   var remotePort = opts.body[1]; |   var remotePort = req.body[1]; | ||||||
|   var portOrPath = opts.body[0]; |   var portOrPath = req.body[0]; | ||||||
| 
 | 
 | ||||||
|   // portnum
 |   // portnum
 | ||||||
|   if (remotePort) { |   if (remotePort) { | ||||||
| @ -309,8 +310,8 @@ controllers.tcp = function (req, res, opts) { | |||||||
|     })); |     })); | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| controllers.ssh = function (req, res, opts) { | controllers.ssh = function (req, res) { | ||||||
|   if (!opts.body) { |   if (!req.body) { | ||||||
|     res.statusCode = 422; |     res.statusCode = 422; | ||||||
|     res.setHeader('Content-Type', 'application/json'); |     res.setHeader('Content-Type', 'application/json'); | ||||||
|     res.end(JSON.stringify({"error":{"message":"module 'ssh' needs more arguments"}})); |     res.end(JSON.stringify({"error":{"message":"module 'ssh' needs more arguments"}})); | ||||||
| @ -336,7 +337,7 @@ controllers.ssh = function (req, res, opts) { | |||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   var rawSshAuto = opts.body.port || opts.body[0]; |   var rawSshAuto = req.body.port || req.body[0]; | ||||||
|   var sshAuto = rawSshAuto; |   var sshAuto = rawSshAuto; | ||||||
|   if (-1 !== [ -1, 'false', 'none', 'off', 'disable' ].indexOf(sshAuto)) { |   if (-1 !== [ -1, 'false', 'none', 'off', 'disable' ].indexOf(sshAuto)) { | ||||||
|     state.config.sshAuto = false; |     state.config.sshAuto = false; | ||||||
| @ -358,41 +359,64 @@ controllers.ssh = function (req, res, opts) { | |||||||
|   state.config.sshAuto = sshAuto; |   state.config.sshAuto = sshAuto; | ||||||
|   sshSuccess(); |   sshSuccess(); | ||||||
| }; | }; | ||||||
| controllers.relay = function (req, res, opts) { | controllers.relay = function (req, res) { | ||||||
|   if (!opts.body) { |   if (!req.body) { | ||||||
|     res.statusCode = 422; |     res.statusCode = 422; | ||||||
|     res.setHeader('Content-Type', 'application/json'); |     res.setHeader('Content-Type', 'application/json'); | ||||||
|     res.end(JSON.stringify({"error":{"message":"module \'relay\' needs more arguments"}})); |     res.end(JSON.stringify({"error":{"message":"module \'relay\' needs more arguments"}})); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   return urequestAsync(opts.body).then(function (resp) { |   return urequestAsync(req.body).then(function (resp) { | ||||||
|     res.setHeader('Content-Type', 'application/json'); |     res.setHeader('Content-Type', 'application/json'); | ||||||
|     resp = resp.toJSON(); |     resp = resp.toJSON(); | ||||||
|     res.end(JSON.stringify(resp)); |     res.end(JSON.stringify(resp)); | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| var serveStatic = require('serve-static')(path.join(__dirname, '../lib/admin/')); | function handleApi() { | ||||||
| function handleRemoteClient(req, res) { |   var app = eggspress(); | ||||||
|   if (/^\/(rpc|api)\//.test(req.url)) { | 
 | ||||||
|     return handleApi(req, res); |   app.use('/', function (req, res, next) { | ||||||
|   } |     var opts = url.parse(req.url, true); | ||||||
|   serveStatic(req, res, require('finalhandler')(req, res)); |     if (false && opts.query._body) { | ||||||
| } |       try { | ||||||
| function handleApi(req, res) { |         req.body = JSON.parse(decodeURIComponent(opts.query._body, true)); | ||||||
|   var opts = url.parse(req.url, true); |       } catch(e) { | ||||||
|   if (false && opts.query._body) { |         res.statusCode = 500; | ||||||
|     try { |         res.end('{"error":{"message":"?_body={{bad_format}}"}}'); | ||||||
|       opts.body = JSON.parse(decodeURIComponent(opts.query._body, true)); |         return; | ||||||
|     } catch(e) { |       } | ||||||
|       res.statusCode = 500; |     } | ||||||
|       res.end('{"error":{"message":"?_body={{bad_format}}"}}'); | 
 | ||||||
|  |     var hasLength = req.headers['content-length'] > 0; | ||||||
|  |     if (!hasLength && !req.headers['content-type']) { | ||||||
|  |       next(); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   function listSuccess() { |     var body = ''; | ||||||
|  |     req.on('readable', function () { | ||||||
|  |       var data; | ||||||
|  |       while (true) { | ||||||
|  |         data = req.read(); | ||||||
|  |         if (!data) { break; } | ||||||
|  |         body += data.toString(); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     req.on('end', function () { | ||||||
|  |       try { | ||||||
|  |         req.body = JSON.parse(body); | ||||||
|  |       } catch(e) { | ||||||
|  |         res.statusCode = 400; | ||||||
|  |         res.end('{"error":{"message":"POST body is not valid json"}}'); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |       next(); | ||||||
|  |     }); | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   function listSuccess(req, res) { | ||||||
|     var dumpy = { |     var dumpy = { | ||||||
|       servernames: state.servernames |       servernames: state.servernames | ||||||
|     , ports: state.ports |     , ports: state.ports | ||||||
| @ -411,7 +435,7 @@ function handleApi(req, res) { | |||||||
|     res.end(JSON.stringify(dumpy)); |     res.end(JSON.stringify(dumpy)); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function getConfigOnly() { |   function getConfigOnly(req, res) { | ||||||
|     var resp = JSON.parse(JSON.stringify(state.config)); |     var resp = JSON.parse(JSON.stringify(state.config)); | ||||||
|     resp.version = pkg.version; |     resp.version = pkg.version; | ||||||
|     resp._otp = state.otp; |     resp._otp = state.otp; | ||||||
| @ -422,7 +446,7 @@ function handleApi(req, res) { | |||||||
|   //
 |   //
 | ||||||
|   // without proper config
 |   // without proper config
 | ||||||
|   //
 |   //
 | ||||||
|   function saveAndReport() { |   function saveAndReport(req, res) { | ||||||
|     console.log('[DEBUG] saveAndReport config write', confpath); |     console.log('[DEBUG] saveAndReport config write', confpath); | ||||||
|     console.log(YAML.safeDump(snakeCopy(state.config))); |     console.log(YAML.safeDump(snakeCopy(state.config))); | ||||||
|     fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) { |     fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) { | ||||||
| @ -438,337 +462,294 @@ function handleApi(req, res) { | |||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function initOrConfig() { |     function initOrConfig(req, res) { | ||||||
|     var conf = {}; |       var conf = {}; | ||||||
|     if (!opts.body) { |       if (!req.body) { | ||||||
|       res.statusCode = 422; |         res.statusCode = 422; | ||||||
|       res.end('{"error":{"message":"module \'init\' needs more arguments"}}'); |         res.end('{"error":{"message":"module \'init\' needs more arguments"}}'); | ||||||
|       return; |         return; | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (Array.isArray(opts.body)) { |  | ||||||
|       // relay, email, agree_tos, servernames, ports
 |  | ||||||
|       //
 |  | ||||||
|       opts.body.forEach(function (opt) { |  | ||||||
|         var parts = opt.split(/:/); |  | ||||||
|         if ('true' === parts[1]) { |  | ||||||
|           parts[1] = true; |  | ||||||
|         } else if ('false' === parts[1]) { |  | ||||||
|           parts[1] = false; |  | ||||||
|         } else if ('null' === parts[1]) { |  | ||||||
|           parts[1] = null; |  | ||||||
|         } else if ('undefined' === parts[1]) { |  | ||||||
|           parts[1] = undefined; |  | ||||||
|         } |  | ||||||
|         conf[parts[0]] = parts[1]; |  | ||||||
|       }); |  | ||||||
|     } else { |  | ||||||
|       conf = opts.body; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     conf = camelCopy(conf); |  | ||||||
| 
 |  | ||||||
|     // TODO deep merge
 |  | ||||||
|     // greenlock config
 |  | ||||||
|     if (!state.config.greenlock) { state.config.greenlock = {}; } |  | ||||||
|     if (conf.greenlock) { |  | ||||||
|       if ('undefined' !== typeof conf.greenlock.agree) { |  | ||||||
|         state.config.greenlock.agree = conf.greenlock.agree; |  | ||||||
|       } |       } | ||||||
|       if (conf.greenlock.server) { state.config.greenlock.server = conf.greenlock.server; } |  | ||||||
|       if (conf.greenlock.version) { state.config.greenlock.version = conf.greenlock.version; } |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // main config
 |       if (Array.isArray(req.body)) { | ||||||
|     if (conf.email) { state.config.email = conf.email; } |         // relay, email, agree_tos, servernames, ports
 | ||||||
|     if (conf.relay) { state.config.relay = conf.relay; } |         //
 | ||||||
|     if (conf.token) { state.config.token = conf.token; } |         req.body.forEach(function (opt) { | ||||||
|     if (conf.secret) { state.config.secret = conf.secret; } |           var parts = opt.split(/:/); | ||||||
|     if ('undefined' !== typeof conf.agreeTos) { |           if ('true' === parts[1]) { | ||||||
|       state.config.agreeTos = conf.agreeTos; |             parts[1] = true; | ||||||
|     } |           } else if ('false' === parts[1]) { | ||||||
|  |             parts[1] = false; | ||||||
|  |           } else if ('null' === parts[1]) { | ||||||
|  |             parts[1] = null; | ||||||
|  |           } else if ('undefined' === parts[1]) { | ||||||
|  |             parts[1] = undefined; | ||||||
|  |           } | ||||||
|  |           conf[parts[0]] = parts[1]; | ||||||
|  |         }); | ||||||
|  |       } else { | ||||||
|  |         conf = req.body; | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|     // to state
 |       conf = camelCopy(conf); | ||||||
|     if (conf.pretoken) { state.pretoken = conf.pretoken; } |  | ||||||
|     if (conf._otp) { |  | ||||||
|       state.otp = conf._otp; // TODO should this only be done on the client side?
 |  | ||||||
|       delete conf._otp; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     console.log(); |       // TODO deep merge
 | ||||||
|     console.log('conf.token', typeof conf.token, conf.token); |       // greenlock config
 | ||||||
|     console.log('state.config.token', typeof state.config.token, state.config.token); |       if (!state.config.greenlock) { state.config.greenlock = {}; } | ||||||
| 
 |       if (conf.greenlock) { | ||||||
|     if (state.secret) { console.log('state.secret'); state.token = common.signToken(state); } |         if ('undefined' !== typeof conf.greenlock.agree) { | ||||||
|     if (!state.token) { console.log('!state.token'); state.token = conf._token; } |           state.config.greenlock.agree = conf.greenlock.agree; | ||||||
| 
 |  | ||||||
|     console.log(); |  | ||||||
|     console.log('JSON.stringify(conf)'); |  | ||||||
|     console.log(JSON.stringify(conf)); |  | ||||||
|     console.log(); |  | ||||||
|     console.log('JSON.stringify(state)'); |  | ||||||
|     console.log(JSON.stringify(state)); |  | ||||||
|     console.log(); |  | ||||||
|     if ('undefined' !== typeof conf.newsletter) { |  | ||||||
|       state.config.newsletter = conf.newsletter; |  | ||||||
|     } |  | ||||||
|     if ('undefined' !== typeof conf.communityMember |  | ||||||
|       || 'undefined' !== typeof conf.community_member) { |  | ||||||
|       state.config.communityMember = conf.communityMember || conf.community_member; |  | ||||||
|     } |  | ||||||
|     if ('undefined' !== typeof conf.telemetry) { |  | ||||||
|       state.config.telemetry = conf.telemetry; |  | ||||||
|     } |  | ||||||
|     if (conf._servernames) { |  | ||||||
|       (conf._servernames||'').split(/,/g).forEach(function (key) { |  | ||||||
|         if (!state.config.servernames[key]) { |  | ||||||
|           state.config.servernames[key] = { sub: undefined }; |  | ||||||
|         } |         } | ||||||
|       }); |         if (conf.greenlock.server) { state.config.greenlock.server = conf.greenlock.server; } | ||||||
|     } |         if (conf.greenlock.version) { state.config.greenlock.version = conf.greenlock.version; } | ||||||
|     if (conf._ports) { |       } | ||||||
|       (conf._ports||'').split(/,/g).forEach(function (key) { |  | ||||||
|         if (!state.config.ports[key]) { |  | ||||||
|           state.config.ports[key] = {}; |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     if (!state.config.relay || !state.config.email || !state.config.agreeTos) { |       // main config
 | ||||||
|       console.warn('missing config'); |       if (conf.email) { state.config.email = conf.email; } | ||||||
|       res.statusCode = 400; |       if (conf.relay) { state.config.relay = conf.relay; } | ||||||
|  |       if (conf.token) { state.config.token = conf.token; } | ||||||
|  |       if (conf.secret) { state.config.secret = conf.secret; } | ||||||
|  |       if ('undefined' !== typeof conf.agreeTos) { | ||||||
|  |         state.config.agreeTos = conf.agreeTos; | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|       res.setHeader('Content-Type', 'application/json'); |       // to state
 | ||||||
|       res.end(JSON.stringify({ |       if (conf.pretoken) { state.pretoken = conf.pretoken; } | ||||||
|         error: { |       if (conf._otp) { | ||||||
|           code: "E_INIT" |         state.otp = conf._otp; // TODO should this only be done on the client side?
 | ||||||
|         , message: "Missing important config file params" |         delete conf._otp; | ||||||
|         , _params: JSON.stringify(conf) |       } | ||||||
|         , _config: JSON.stringify(state.config) |  | ||||||
|         , _body: JSON.stringify(opts.body) |  | ||||||
|         } |  | ||||||
|       })); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // init also means enable
 |       console.log(); | ||||||
|     delete state.config.disable; |       console.log('conf.token', typeof conf.token, conf.token); | ||||||
|     safeStartTelebitRemote(true).then(saveAndReport).catch(handleError); |       console.log('state.config.token', typeof state.config.token, state.config.token); | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   function restart() { |       if (state.secret) { console.log('state.secret'); state.token = common.signToken(state); } | ||||||
|     console.info("[telebitd.js] server closing..."); |       if (!state.token) { console.log('!state.token'); state.token = conf._token; } | ||||||
|     state.keepAlive.state = false; |  | ||||||
|     if (myRemote) { |  | ||||||
|       myRemote.end(); |  | ||||||
|       myRemote.on('end', respondAndClose); |  | ||||||
|       // failsafe
 |  | ||||||
|       setTimeout(function () { |  | ||||||
|         console.info("[telebitd.js] closing too slowly, force quit"); |  | ||||||
|         respondAndClose(); |  | ||||||
|       }, 5 * 1000); |  | ||||||
|     } else { |  | ||||||
|       respondAndClose(); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     function respondAndClose() { |       console.log(); | ||||||
|       res.setHeader('Content-Type', 'application/json'); |       console.log('JSON.stringify(conf)'); | ||||||
|       res.end(JSON.stringify({ success: true })); |       console.log(JSON.stringify(conf)); | ||||||
|       controlServer.close(function () { |       console.log(); | ||||||
|         console.info("[telebitd.js] server closed"); |       console.log('JSON.stringify(state)'); | ||||||
|         setTimeout(function () { |       console.log(JSON.stringify(state)); | ||||||
|           // system daemon will restart the process
 |       console.log(); | ||||||
|           process.exit(22); // use non-success exit code
 |       if ('undefined' !== typeof conf.newsletter) { | ||||||
|         }, 100); |         state.config.newsletter = conf.newsletter; | ||||||
|       }); |       } | ||||||
|     } |       if ('undefined' !== typeof conf.communityMember | ||||||
|   } |         || 'undefined' !== typeof conf.community_member) { | ||||||
|  |         state.config.communityMember = conf.communityMember || conf.community_member; | ||||||
|  |       } | ||||||
|  |       if ('undefined' !== typeof conf.telemetry) { | ||||||
|  |         state.config.telemetry = conf.telemetry; | ||||||
|  |       } | ||||||
|  |       if (conf._servernames) { | ||||||
|  |         (conf._servernames||'').split(/,/g).forEach(function (key) { | ||||||
|  |           if (!state.config.servernames[key]) { | ||||||
|  |             state.config.servernames[key] = { sub: undefined }; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |       if (conf._ports) { | ||||||
|  |         (conf._ports||'').split(/,/g).forEach(function (key) { | ||||||
|  |           if (!state.config.ports[key]) { | ||||||
|  |             state.config.ports[key] = {}; | ||||||
|  |           } | ||||||
|  |         }); | ||||||
|  |       } | ||||||
| 
 | 
 | ||||||
|   function invalidConfig() { |       if (!state.config.relay || !state.config.email || !state.config.agreeTos) { | ||||||
|     res.statusCode = 400; |         console.warn('missing config'); | ||||||
|     res.setHeader('Content-Type', 'application/json'); |         res.statusCode = 400; | ||||||
|     res.end(JSON.stringify({ |  | ||||||
|       error: { code: "E_CONFIG", message: "Invalid config file. Please run 'telebit init'" } |  | ||||||
|     })); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   function saveAndCommit() { |  | ||||||
|     state.config.servernames = state.servernames; |  | ||||||
|     state.config.ports = state.ports; |  | ||||||
|     fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) { |  | ||||||
|       if (err) { |  | ||||||
|         res.statusCode = 500; |  | ||||||
|         res.setHeader('Content-Type', 'application/json'); |         res.setHeader('Content-Type', 'application/json'); | ||||||
|         res.end(JSON.stringify({ |         res.end(JSON.stringify({ | ||||||
|           "error":{"message":"Could not save config file. Perhaps you're not running as root?"} |           error: { | ||||||
|  |             code: "E_INIT" | ||||||
|  |           , message: "Missing important config file params" | ||||||
|  |           , _params: JSON.stringify(conf) | ||||||
|  |           , _config: JSON.stringify(state.config) | ||||||
|  |           , _body: JSON.stringify(req.body) | ||||||
|  |           } | ||||||
|         })); |         })); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|       listSuccess(); |  | ||||||
|     }); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   function handleError(err) { |       // init also means enable
 | ||||||
|     res.statusCode = 500; |       delete state.config.disable; | ||||||
|     res.setHeader('Content-Type', 'application/json'); |       safeStartTelebitRemote(true).then(saveAndReport).catch(handleError); | ||||||
|     res.end(JSON.stringify({ |     } | ||||||
|       error: { message: err.message, code: err.code } |  | ||||||
|     })); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   function enable() { |     function restart(req, res) { | ||||||
|     delete state.config.disable;// = undefined;
 |       console.info("[telebitd.js] server closing..."); | ||||||
|     state.keepAlive.state = true; |       state.keepAlive.state = false; | ||||||
| 
 |  | ||||||
|     fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) { |  | ||||||
|       if (err) { |  | ||||||
|         err.message = "Could not save config file. Perhaps you're user doesn't have permission?"; |  | ||||||
|         handleError(err); |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|       // TODO XXX myRemote.active
 |  | ||||||
|       if (myRemote) { |       if (myRemote) { | ||||||
|         listSuccess(); |         myRemote.end(); | ||||||
|  |         myRemote.on('end', respondAndClose); | ||||||
|  |         // failsafe
 | ||||||
|  |         setTimeout(function () { | ||||||
|  |           console.info("[telebitd.js] closing too slowly, force quit"); | ||||||
|  |           respondAndClose(); | ||||||
|  |         }, 5 * 1000); | ||||||
|  |       } else { | ||||||
|  |         respondAndClose(); | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       function respondAndClose() { | ||||||
|  |         res.setHeader('Content-Type', 'application/json'); | ||||||
|  |         res.end(JSON.stringify({ success: true })); | ||||||
|  |         controlServer.close(function () { | ||||||
|  |           console.info("[telebitd.js] server closed"); | ||||||
|  |           setTimeout(function () { | ||||||
|  |             // system daemon will restart the process
 | ||||||
|  |             process.exit(22); // use non-success exit code
 | ||||||
|  |           }, 100); | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function mustHaveValidConfig(req, res, next) { | ||||||
|  |       //
 | ||||||
|  |       // Check for proper config
 | ||||||
|  |       //
 | ||||||
|  |       if (state.config.relay && state.config.email && state.config.agreeTos) { | ||||||
|  |         next(); | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|       safeStartTelebitRemote(true).then(listSuccess).catch(handleError); |  | ||||||
|     }); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   function disable() { |       res.statusCode = 400; | ||||||
|     state.config.disable = true; |  | ||||||
|     state.keepAlive.state = false; |  | ||||||
| 
 |  | ||||||
|     if (myRemote) { myRemote.end(); myRemote = null; } |  | ||||||
|     fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) { |  | ||||||
|       res.setHeader('Content-Type', 'application/json'); |       res.setHeader('Content-Type', 'application/json'); | ||||||
|       if (err) { |       res.end(JSON.stringify({ | ||||||
|         err.message = "Could not save config file. Perhaps you're user doesn't have permission?"; |         error: { code: "E_CONFIG", message: "Invalid config file. Please run 'telebit init'" } | ||||||
|         handleError(err); |       })); | ||||||
|         return; |     } | ||||||
|       } |  | ||||||
|       res.end('{"success":true}'); |  | ||||||
|     }); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   function getStatus() { |     function saveAndCommit(req, res) { | ||||||
|     var now = Date.now(); |       state.config.servernames = state.servernames; | ||||||
|     res.setHeader('Content-Type', 'application/json'); |       state.config.ports = state.ports; | ||||||
|     require('../lib/ssh.js').checkSecurity().then(function (ssh) { |       fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) { | ||||||
|       res.end(JSON.stringify( |         if (err) { | ||||||
|         { module: 'status' |           res.statusCode = 500; | ||||||
|         , version: pkg.version |           res.setHeader('Content-Type', 'application/json'); | ||||||
|         , port: (state.config.ipc && state.config.ipc.port || state._ipc.port || undefined) |           res.end(JSON.stringify({ | ||||||
|         , enabled: !state.config.disable |             "error":{"message":"Could not save config file. Perhaps you're not running as root?"} | ||||||
|         , active: !!myRemote |           })); | ||||||
|         , initialized: (state.config.relay && state.config.token && state.config.agreeTos) ? true : false |           return; | ||||||
|         , connected: isConnected |  | ||||||
|         //, proctime: Math.round(process.uptime() * 1000)
 |  | ||||||
|         , uptime: now - startTime |  | ||||||
|         , runtime: isConnected && connectTimes.length && (now - connectTimes[0]) || 0 |  | ||||||
|         , reconnects: connectTimes.length |  | ||||||
|         , servernames: state.servernames |  | ||||||
|         , ssh: state.config.sshAuto |  | ||||||
|         , ssh_permit_root_login: ssh.permit_root_login |  | ||||||
|         , ssh_password_authentication: ssh.password_authentication |  | ||||||
|         , ssh_requests_password: ssh.requests_password |  | ||||||
|         } |         } | ||||||
|       )); |         listSuccess(); | ||||||
|     }); |       }); | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   function route() { |  | ||||||
|     if (/\b(relay)\b/.test(opts.pathname)) { |  | ||||||
|       controllers.relay(req, res, opts); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (/\b(config)\b/.test(opts.pathname) && /get/i.test(req.method)) { |  | ||||||
|       getConfigOnly(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (/\b(init|config)\b/.test(opts.pathname)) { |  | ||||||
|       initOrConfig(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (/restart/.test(opts.pathname)) { |  | ||||||
|       restart(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     //
 |  | ||||||
|     // Check for proper config
 |  | ||||||
|     //
 |  | ||||||
|     if (!state.config.relay || !state.config.email || !state.config.agreeTos) { |  | ||||||
|       invalidConfig(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     //
 |  | ||||||
|     // With proper config
 |  | ||||||
|     //
 |  | ||||||
|     if (/http/.test(opts.pathname)) { |  | ||||||
|       controllers.http(req, res, opts); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (/tcp/.test(opts.pathname)) { |  | ||||||
|       controllers.tcp(req, res, opts); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (/save|commit/.test(opts.pathname)) { |  | ||||||
|       saveAndCommit(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (/ssh/.test(opts.pathname)) { |  | ||||||
|       controllers.ssh(req, res, opts); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (/enable/.test(opts.pathname)) { |  | ||||||
|       enable(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (/disable/.test(opts.pathname)) { |  | ||||||
|       disable(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (/status/.test(opts.pathname)) { |  | ||||||
|       getStatus(); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     if (/list/.test(opts.pathname)) { |  | ||||||
|       listSuccess(); |  | ||||||
|       return; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     function handleError(err, req, res) { | ||||||
|  |       res.statusCode = 500; | ||||||
|  |       res.setHeader('Content-Type', 'application/json'); | ||||||
|  |       res.end(JSON.stringify({ | ||||||
|  |         error: { message: err.message, code: err.code } | ||||||
|  |       })); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function enable(req, res) { | ||||||
|  |       delete state.config.disable;// = undefined;
 | ||||||
|  |       state.keepAlive.state = true; | ||||||
|  | 
 | ||||||
|  |       fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) { | ||||||
|  |         if (err) { | ||||||
|  |           err.message = "Could not save config file. Perhaps you're user doesn't have permission?"; | ||||||
|  |           handleError(err, req, res); | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |         // TODO XXX myRemote.active
 | ||||||
|  |         if (myRemote) { | ||||||
|  |           listSuccess(req, res); | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |         safeStartTelebitRemote(true).then(listSuccess).catch(function () { | ||||||
|  |           handleError(err, req, res); | ||||||
|  |         }); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function disable(req, res) { | ||||||
|  |       state.config.disable = true; | ||||||
|  |       state.keepAlive.state = false; | ||||||
|  | 
 | ||||||
|  |       if (myRemote) { myRemote.end(); myRemote = null; } | ||||||
|  |       fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) { | ||||||
|  |         res.setHeader('Content-Type', 'application/json'); | ||||||
|  |         if (err) { | ||||||
|  |           err.message = "Could not save config file. Perhaps you're user doesn't have permission?"; | ||||||
|  |           handleError(err); | ||||||
|  |           return; | ||||||
|  |         } | ||||||
|  |         res.end('{"success":true}'); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     function getStatus(req, res) { | ||||||
|  |       var now = Date.now(); | ||||||
|  |       res.setHeader('Content-Type', 'application/json'); | ||||||
|  |       require('../lib/ssh.js').checkSecurity().then(function (ssh) { | ||||||
|  |         res.end(JSON.stringify( | ||||||
|  |           { module: 'status' | ||||||
|  |           , version: pkg.version | ||||||
|  |           , port: (state.config.ipc && state.config.ipc.port || state._ipc.port || undefined) | ||||||
|  |           , enabled: !state.config.disable | ||||||
|  |           , active: !!myRemote | ||||||
|  |           , initialized: (state.config.relay && state.config.token && state.config.agreeTos) ? true : false | ||||||
|  |           , connected: isConnected | ||||||
|  |           //, proctime: Math.round(process.uptime() * 1000)
 | ||||||
|  |           , uptime: now - startTime | ||||||
|  |           , runtime: isConnected && connectTimes.length && (now - connectTimes[0]) || 0 | ||||||
|  |           , reconnects: connectTimes.length | ||||||
|  |           , servernames: state.servernames | ||||||
|  |           , ssh: state.config.sshAuto | ||||||
|  |           , ssh_permit_root_login: ssh.permit_root_login | ||||||
|  |           , ssh_password_authentication: ssh.password_authentication | ||||||
|  |           , ssh_requests_password: ssh.requests_password | ||||||
|  |           } | ||||||
|  |         )); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   // TODO turn strings into regexes to match beginnings
 | ||||||
|  |   app.use(/\b(relay)\b/, controllers.relay); | ||||||
|  |   app.get(/\b(config)\b/, getConfigOnly); | ||||||
|  |   app.use(/\b(init|config)\b/, initOrConfig); | ||||||
|  |   app.use(/\b(restart)\b/, restart); | ||||||
|  | 
 | ||||||
|  |   // Position is important with eggspress
 | ||||||
|  |   // This should stay here, right before the other methods
 | ||||||
|  |   app.use('/', mustHaveValidConfig); | ||||||
|  | 
 | ||||||
|  |   //
 | ||||||
|  |   // With proper config
 | ||||||
|  |   //
 | ||||||
|  |   app.use(/\b(http)\b/, controllers.http); | ||||||
|  |   app.use(/\b(tcp)\b/, controllers.tcp); | ||||||
|  |   app.use(/\b(save|commit)\b/, saveAndCommit); | ||||||
|  |   app.use(/\b(ssh)\b/, controllers.ssh); | ||||||
|  |   app.use(/\b(enable)\b/, enable); | ||||||
|  |   app.use(/\b(disable)\b/, disable); | ||||||
|  |   app.use(/\b(status)\b/, getStatus); | ||||||
|  |   app.use(/\b(list)\b/, listSuccess); | ||||||
|  |   app.use('/', function (req, res) { | ||||||
|     res.setHeader('Content-Type', 'application/json'); |     res.setHeader('Content-Type', 'application/json'); | ||||||
|     res.end(JSON.stringify({"error":{"message":"unrecognized rpc"}})); |     res.end(JSON.stringify({"error":{"message":"unrecognized rpc"}})); | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   var hasLength = req.headers['content-length'] > 0; |  | ||||||
|   if (!hasLength && !req.headers['content-type']) { |  | ||||||
|     route(); |  | ||||||
|     return; |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   var body = ''; |  | ||||||
|   req.on('readable', function () { |  | ||||||
|     var data; |  | ||||||
|     while (true) { |  | ||||||
|       data = req.read(); |  | ||||||
|       if (!data) { break; } |  | ||||||
|       body += data.toString(); |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
|   req.on('end', function () { |  | ||||||
|     try { |  | ||||||
|       opts.body = JSON.parse(body); |  | ||||||
|     } catch(e) { |  | ||||||
|       res.statusCode = 400; |  | ||||||
|       res.end('{"error":{"message":"POST body is not valid json"}}'); |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
|     route(); |  | ||||||
|   }); |   }); | ||||||
|  | 
 | ||||||
|  |   return app; | ||||||
| } | } | ||||||
|  | 
 | ||||||
| function serveControlsHelper() { | function serveControlsHelper() { | ||||||
|   controlServer = http.createServer(handleRemoteClient); |   var app = eggspress(); | ||||||
|  |   var serveStatic = require('serve-static')(path.join(__dirname, '../lib/admin/')); | ||||||
|  |   var apiHandler = handleApi(); | ||||||
|  | 
 | ||||||
|  |   app.use('/rpc/', apiHandler); | ||||||
|  |   app.use('/api/', apiHandler); | ||||||
|  |   app.use('/', serveStatic); | ||||||
|  | 
 | ||||||
|  |   controlServer = http.createServer(app); | ||||||
| 
 | 
 | ||||||
|   if (fs.existsSync(state._ipc.path)) { |   if (fs.existsSync(state._ipc.path)) { | ||||||
|     fs.unlinkSync(state._ipc.path); |     fs.unlinkSync(state._ipc.path); | ||||||
|  | |||||||
							
								
								
									
										78
									
								
								lib/eggspress.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								lib/eggspress.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,78 @@ | |||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | module.exports = function eggspress() { | ||||||
|  |   //var patternsMap = {};
 | ||||||
|  |   var allPatterns = []; | ||||||
|  |   var app = function (req, res) { | ||||||
|  |     var patterns = allPatterns.slice(0).reverse(); | ||||||
|  |     function next() { | ||||||
|  |       var todo = patterns.pop(); | ||||||
|  |       if (!todo) { | ||||||
|  |         console.log('[eggspress] Did not match any patterns', req.url); | ||||||
|  |         require('finalhandler')(req, res)(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       // '', GET, POST, DELETE
 | ||||||
|  |       if (todo[2] && req.method.toLowerCase() !== todo[2]) { | ||||||
|  |         //console.log("[eggspress] HTTP method doesn't match", req.url);
 | ||||||
|  |         next(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       if (!req.url.match(todo[0])) { | ||||||
|  |         //console.log("[eggspress] pattern doesn't match", todo[0], req.url);
 | ||||||
|  |         next(); | ||||||
|  |         return; | ||||||
|  |       } else if ('string' === typeof todo[0] && 0 !== req.url.match(todo[0]).index) { | ||||||
|  |         //console.log("[eggspress] string pattern is not the start", todo[0], req.url);
 | ||||||
|  |         next(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       try { | ||||||
|  |         //console.log("[eggspress] matched pattern", todo[0], req.url);
 | ||||||
|  |         todo[1](req, res, next); | ||||||
|  |       } catch(e) { | ||||||
|  |         console.error("[eggspress] error", todo[2], todo[0], req.url); | ||||||
|  |         console.error(e); | ||||||
|  |         // TODO make a nice error message
 | ||||||
|  |         res.end(e.message); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     next(); | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   app.use = function (pattern, fn) { | ||||||
|  |     return app._use('', pattern, fn); | ||||||
|  |   }; | ||||||
|  |   [ 'GET', 'POST', 'DELETE' ].forEach(function (method) { | ||||||
|  |     app[method.toLowerCase()] = function (pattern, fn) { | ||||||
|  |       return app._use(method, pattern, fn); | ||||||
|  |     }; | ||||||
|  |   }); | ||||||
|  | 
 | ||||||
|  |   app.post = function (pattern, fn) { | ||||||
|  |     return app._use('POST', pattern, fn); | ||||||
|  |   }; | ||||||
|  |   app._use = function (method, pattern, fn) { | ||||||
|  |     // always end in a slash, for now
 | ||||||
|  |     if ('string' === typeof pattern) { | ||||||
|  |       pattern = pattern.replace(/\/$/, '')  + '/'; | ||||||
|  |     } | ||||||
|  |     /* | ||||||
|  |     if (!patternsMap[pattern]) { | ||||||
|  |       patternsMap[pattern] = []; | ||||||
|  |     } | ||||||
|  |     patternsMap[pattern].push(fn); | ||||||
|  |     patterns = Object.keys(patternsMap).sort(function (a, b) { | ||||||
|  |       return b.length - a.length; | ||||||
|  |     }); | ||||||
|  |     */ | ||||||
|  |     allPatterns.push([pattern, fn, method.toLowerCase()]); | ||||||
|  |     return app; | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   return app; | ||||||
|  | }; | ||||||
							
								
								
									
										171
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										171
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -49,11 +49,6 @@ | |||||||
|         "sprintf-js": "~1.0.2" |         "sprintf-js": "~1.0.2" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "array-flatten": { |  | ||||||
|       "version": "1.1.1", |  | ||||||
|       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", |  | ||||||
|       "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" |  | ||||||
|     }, |  | ||||||
|     "asn1js": { |     "asn1js": { | ||||||
|       "version": "1.2.12", |       "version": "1.2.12", | ||||||
|       "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-1.2.12.tgz", |       "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-1.2.12.tgz", | ||||||
| @ -74,23 +69,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", |       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", | ||||||
|       "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" |       "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" | ||||||
|     }, |     }, | ||||||
|     "body-parser": { |  | ||||||
|       "version": "1.18.3", |  | ||||||
|       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", |  | ||||||
|       "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", |  | ||||||
|       "requires": { |  | ||||||
|         "bytes": "3.0.0", |  | ||||||
|         "content-type": "~1.0.4", |  | ||||||
|         "debug": "2.6.9", |  | ||||||
|         "depd": "~1.1.2", |  | ||||||
|         "http-errors": "~1.6.3", |  | ||||||
|         "iconv-lite": "0.4.23", |  | ||||||
|         "on-finished": "~2.3.0", |  | ||||||
|         "qs": "6.5.2", |  | ||||||
|         "raw-body": "2.3.3", |  | ||||||
|         "type-is": "~1.6.16" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "buffer-alloc": { |     "buffer-alloc": { | ||||||
|       "version": "1.2.0", |       "version": "1.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", |       "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", | ||||||
| @ -125,11 +103,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/buffer-v6-polyfill/-/buffer-v6-polyfill-1.0.5.tgz", |       "resolved": "https://registry.npmjs.org/buffer-v6-polyfill/-/buffer-v6-polyfill-1.0.5.tgz", | ||||||
|       "integrity": "sha1-0c2v61YAvvbCjWFElkJWvRLgFnc=" |       "integrity": "sha1-0c2v61YAvvbCjWFElkJWvRLgFnc=" | ||||||
|     }, |     }, | ||||||
|     "bytes": { |  | ||||||
|       "version": "3.0.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", |  | ||||||
|       "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" |  | ||||||
|     }, |  | ||||||
|     "certpem": { |     "certpem": { | ||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/certpem/-/certpem-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/certpem/-/certpem-1.0.1.tgz", | ||||||
| @ -141,26 +114,6 @@ | |||||||
|         "pkijs": "^1.3.27" |         "pkijs": "^1.3.27" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "content-disposition": { |  | ||||||
|       "version": "0.5.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", |  | ||||||
|       "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" |  | ||||||
|     }, |  | ||||||
|     "content-type": { |  | ||||||
|       "version": "1.0.4", |  | ||||||
|       "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", |  | ||||||
|       "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" |  | ||||||
|     }, |  | ||||||
|     "cookie": { |  | ||||||
|       "version": "0.3.1", |  | ||||||
|       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", |  | ||||||
|       "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" |  | ||||||
|     }, |  | ||||||
|     "cookie-signature": { |  | ||||||
|       "version": "1.0.6", |  | ||||||
|       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", |  | ||||||
|       "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" |  | ||||||
|     }, |  | ||||||
|     "core-util-is": { |     "core-util-is": { | ||||||
|       "version": "1.0.2", |       "version": "1.0.2", | ||||||
|       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", |       "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", | ||||||
| @ -238,43 +191,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", |       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", | ||||||
|       "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" |       "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" | ||||||
|     }, |     }, | ||||||
|     "express": { |  | ||||||
|       "version": "4.16.4", |  | ||||||
|       "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", |  | ||||||
|       "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", |  | ||||||
|       "requires": { |  | ||||||
|         "accepts": "~1.3.5", |  | ||||||
|         "array-flatten": "1.1.1", |  | ||||||
|         "body-parser": "1.18.3", |  | ||||||
|         "content-disposition": "0.5.2", |  | ||||||
|         "content-type": "~1.0.4", |  | ||||||
|         "cookie": "0.3.1", |  | ||||||
|         "cookie-signature": "1.0.6", |  | ||||||
|         "debug": "2.6.9", |  | ||||||
|         "depd": "~1.1.2", |  | ||||||
|         "encodeurl": "~1.0.2", |  | ||||||
|         "escape-html": "~1.0.3", |  | ||||||
|         "etag": "~1.8.1", |  | ||||||
|         "finalhandler": "1.1.1", |  | ||||||
|         "fresh": "0.5.2", |  | ||||||
|         "merge-descriptors": "1.0.1", |  | ||||||
|         "methods": "~1.1.2", |  | ||||||
|         "on-finished": "~2.3.0", |  | ||||||
|         "parseurl": "~1.3.2", |  | ||||||
|         "path-to-regexp": "0.1.7", |  | ||||||
|         "proxy-addr": "~2.0.4", |  | ||||||
|         "qs": "6.5.2", |  | ||||||
|         "range-parser": "~1.2.0", |  | ||||||
|         "safe-buffer": "5.1.2", |  | ||||||
|         "send": "0.16.2", |  | ||||||
|         "serve-static": "1.13.2", |  | ||||||
|         "setprototypeof": "1.1.0", |  | ||||||
|         "statuses": "~1.4.0", |  | ||||||
|         "type-is": "~1.6.16", |  | ||||||
|         "utils-merge": "1.0.1", |  | ||||||
|         "vary": "~1.1.2" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "finalhandler": { |     "finalhandler": { | ||||||
|       "version": "1.1.1", |       "version": "1.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", |       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", | ||||||
| @ -289,11 +205,6 @@ | |||||||
|         "unpipe": "~1.0.0" |         "unpipe": "~1.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "forwarded": { |  | ||||||
|       "version": "0.1.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", |  | ||||||
|       "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" |  | ||||||
|     }, |  | ||||||
|     "fresh": { |     "fresh": { | ||||||
|       "version": "0.5.2", |       "version": "0.5.2", | ||||||
|       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", |       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", | ||||||
| @ -374,14 +285,6 @@ | |||||||
|         "statuses": ">= 1.4.0 < 2" |         "statuses": ">= 1.4.0 < 2" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "iconv-lite": { |  | ||||||
|       "version": "0.4.23", |  | ||||||
|       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", |  | ||||||
|       "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", |  | ||||||
|       "requires": { |  | ||||||
|         "safer-buffer": ">= 2.1.2 < 3" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "inherits": { |     "inherits": { | ||||||
|       "version": "2.0.3", |       "version": "2.0.3", | ||||||
|       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", |       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", | ||||||
| @ -395,11 +298,6 @@ | |||||||
|         "from2": "^2.1.1" |         "from2": "^2.1.1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "ipaddr.js": { |  | ||||||
|       "version": "1.8.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", |  | ||||||
|       "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" |  | ||||||
|     }, |  | ||||||
|     "is": { |     "is": { | ||||||
|       "version": "3.2.1", |       "version": "3.2.1", | ||||||
|       "resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz", |       "resolved": "https://registry.npmjs.org/is/-/is-3.2.1.tgz", | ||||||
| @ -525,21 +423,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", |       "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", | ||||||
|       "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" |       "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" | ||||||
|     }, |     }, | ||||||
|     "media-typer": { |  | ||||||
|       "version": "0.3.0", |  | ||||||
|       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", |  | ||||||
|       "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" |  | ||||||
|     }, |  | ||||||
|     "merge-descriptors": { |  | ||||||
|       "version": "1.0.1", |  | ||||||
|       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", |  | ||||||
|       "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" |  | ||||||
|     }, |  | ||||||
|     "methods": { |  | ||||||
|       "version": "1.1.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", |  | ||||||
|       "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" |  | ||||||
|     }, |  | ||||||
|     "mime": { |     "mime": { | ||||||
|       "version": "1.4.1", |       "version": "1.4.1", | ||||||
|       "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", |       "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", | ||||||
| @ -659,11 +542,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", |       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", | ||||||
|       "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" |       "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" | ||||||
|     }, |     }, | ||||||
|     "path-to-regexp": { |  | ||||||
|       "version": "0.1.7", |  | ||||||
|       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", |  | ||||||
|       "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" |  | ||||||
|     }, |  | ||||||
|     "pify": { |     "pify": { | ||||||
|       "version": "3.0.0", |       "version": "3.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", |       "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", | ||||||
| @ -692,15 +570,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", |       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", | ||||||
|       "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" |       "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" | ||||||
|     }, |     }, | ||||||
|     "proxy-addr": { |  | ||||||
|       "version": "2.0.4", |  | ||||||
|       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", |  | ||||||
|       "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", |  | ||||||
|       "requires": { |  | ||||||
|         "forwarded": "~0.1.2", |  | ||||||
|         "ipaddr.js": "1.8.0" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "proxy-packer": { |     "proxy-packer": { | ||||||
|       "version": "2.0.2", |       "version": "2.0.2", | ||||||
|       "resolved": "https://registry.npmjs.org/proxy-packer/-/proxy-packer-2.0.2.tgz", |       "resolved": "https://registry.npmjs.org/proxy-packer/-/proxy-packer-2.0.2.tgz", | ||||||
| @ -723,11 +592,6 @@ | |||||||
|         "safe-replace": "^1.0.2" |         "safe-replace": "^1.0.2" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "qs": { |  | ||||||
|       "version": "6.5.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", |  | ||||||
|       "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" |  | ||||||
|     }, |  | ||||||
|     "range-parser": { |     "range-parser": { | ||||||
|       "version": "1.2.0", |       "version": "1.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", |       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", | ||||||
| @ -738,17 +602,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.1.tgz", |       "resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.1.tgz", | ||||||
|       "integrity": "sha512-cs4Hu/rVF3/Qucq+V7lxSz449VfHNMVXJaeajAHno9H5FC1PWlmS4NM6IAX5jPKFF0IC2rOdHdf7iNxQuIWZag==" |       "integrity": "sha512-cs4Hu/rVF3/Qucq+V7lxSz449VfHNMVXJaeajAHno9H5FC1PWlmS4NM6IAX5jPKFF0IC2rOdHdf7iNxQuIWZag==" | ||||||
|     }, |     }, | ||||||
|     "raw-body": { |  | ||||||
|       "version": "2.3.3", |  | ||||||
|       "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", |  | ||||||
|       "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", |  | ||||||
|       "requires": { |  | ||||||
|         "bytes": "3.0.0", |  | ||||||
|         "http-errors": "1.6.3", |  | ||||||
|         "iconv-lite": "0.4.23", |  | ||||||
|         "unpipe": "1.0.0" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "readable-stream": { |     "readable-stream": { | ||||||
|       "version": "2.3.6", |       "version": "2.3.6", | ||||||
|       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", |       "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", | ||||||
| @ -801,11 +654,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.0.2.tgz", |       "resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.0.2.tgz", | ||||||
|       "integrity": "sha1-sYGrQJWs32qwqPhAUXSRyoqZIro=" |       "integrity": "sha1-sYGrQJWs32qwqPhAUXSRyoqZIro=" | ||||||
|     }, |     }, | ||||||
|     "safer-buffer": { |  | ||||||
|       "version": "2.1.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", |  | ||||||
|       "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" |  | ||||||
|     }, |  | ||||||
|     "sclient": { |     "sclient": { | ||||||
|       "version": "1.4.1", |       "version": "1.4.1", | ||||||
|       "resolved": "https://registry.npmjs.org/sclient/-/sclient-1.4.1.tgz", |       "resolved": "https://registry.npmjs.org/sclient/-/sclient-1.4.1.tgz", | ||||||
| @ -985,15 +833,6 @@ | |||||||
|         "hoek": "2.x.x" |         "hoek": "2.x.x" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     "type-is": { |  | ||||||
|       "version": "1.6.16", |  | ||||||
|       "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", |  | ||||||
|       "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", |  | ||||||
|       "requires": { |  | ||||||
|         "media-typer": "0.3.0", |  | ||||||
|         "mime-types": "~2.1.18" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     "unpipe": { |     "unpipe": { | ||||||
|       "version": "1.0.0", |       "version": "1.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", |       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", | ||||||
| @ -1004,16 +843,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", |       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", | ||||||
|       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" |       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" | ||||||
|     }, |     }, | ||||||
|     "utils-merge": { |  | ||||||
|       "version": "1.0.1", |  | ||||||
|       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", |  | ||||||
|       "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" |  | ||||||
|     }, |  | ||||||
|     "vary": { |  | ||||||
|       "version": "1.1.2", |  | ||||||
|       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", |  | ||||||
|       "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" |  | ||||||
|     }, |  | ||||||
|     "ws": { |     "ws": { | ||||||
|       "version": "6.0.0", |       "version": "6.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/ws/-/ws-6.0.0.tgz", |       "resolved": "https://registry.npmjs.org/ws/-/ws-6.0.0.tgz", | ||||||
|  | |||||||
| @ -54,7 +54,6 @@ | |||||||
|   "homepage": "https://git.coolaj86.com/coolaj86/telebit.js#readme", |   "homepage": "https://git.coolaj86.com/coolaj86/telebit.js#readme", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@coolaj86/urequest": "^1.3.5", |     "@coolaj86/urequest": "^1.3.5", | ||||||
|     "express": "^4.16.4", |  | ||||||
|     "finalhandler": "^1.1.1", |     "finalhandler": "^1.1.1", | ||||||
|     "greenlock": "^2.3.1", |     "greenlock": "^2.3.1", | ||||||
|     "js-yaml": "^3.11.0", |     "js-yaml": "^3.11.0", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user