MAJOR: Updates for Authenticated Web UI and CLI #30
							
								
								
									
										235
									
								
								bin/telebitd.js
									
									
									
									
									
								
							
							
						
						
									
										235
									
								
								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 connectTimes = []; | ||||
| var isConnected = false; | ||||
| var eggspress = require('../lib/eggspress.js'); | ||||
| 
 | ||||
| var TelebitRemote = require('../lib/daemon/index.js').TelebitRemote; | ||||
| 
 | ||||
| @ -112,7 +113,7 @@ function saveConfig(cb) { | ||||
|   fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), cb); | ||||
| } | ||||
| var controllers = {}; | ||||
| controllers.http = function (req, res, opts) { | ||||
| controllers.http = function (req, res) { | ||||
|   function getAppname(pathname) { | ||||
|     // port number
 | ||||
|     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.setHeader('Content-Type', 'application/json'); | ||||
|     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 portOrPath = opts.body.handler || opts.body[0]; | ||||
|   var subdomain = opts.body.name || opts.body[1]; | ||||
|   var indexes = opts.body.indexes; | ||||
|   var portOrPath = req.body.handler || req.body[0]; | ||||
|   var subdomain = req.body.name || req.body[1]; | ||||
|   var indexes = req.body.indexes; | ||||
|   var remoteHost; | ||||
| 
 | ||||
|   if (!portOrPath) { | ||||
| @ -260,8 +261,8 @@ controllers.http = function (req, res, opts) { | ||||
|     })); | ||||
|   }); | ||||
| }; | ||||
| controllers.tcp = function (req, res, opts) { | ||||
|   if (!opts.body) { | ||||
| controllers.tcp = function (req, res) { | ||||
|   if (!req.body) { | ||||
|     res.statusCode = 422; | ||||
|     res.setHeader('Content-Type', 'application/json'); | ||||
|     res.end(JSON.stringify({ error: { message: "module 'tcp' needs more arguments" } })); | ||||
| @ -269,8 +270,8 @@ controllers.tcp = function (req, res, opts) { | ||||
|   } | ||||
| 
 | ||||
|   var active; | ||||
|   var remotePort = opts.body[1]; | ||||
|   var portOrPath = opts.body[0]; | ||||
|   var remotePort = req.body[1]; | ||||
|   var portOrPath = req.body[0]; | ||||
| 
 | ||||
|   // portnum
 | ||||
|   if (remotePort) { | ||||
| @ -309,8 +310,8 @@ controllers.tcp = function (req, res, opts) { | ||||
|     })); | ||||
|   }); | ||||
| }; | ||||
| controllers.ssh = function (req, res, opts) { | ||||
|   if (!opts.body) { | ||||
| controllers.ssh = function (req, res) { | ||||
|   if (!req.body) { | ||||
|     res.statusCode = 422; | ||||
|     res.setHeader('Content-Type', 'application/json'); | ||||
|     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; | ||||
|   if (-1 !== [ -1, 'false', 'none', 'off', 'disable' ].indexOf(sshAuto)) { | ||||
|     state.config.sshAuto = false; | ||||
| @ -358,33 +359,29 @@ controllers.ssh = function (req, res, opts) { | ||||
|   state.config.sshAuto = sshAuto; | ||||
|   sshSuccess(); | ||||
| }; | ||||
| controllers.relay = function (req, res, opts) { | ||||
|   if (!opts.body) { | ||||
| controllers.relay = function (req, res) { | ||||
|   if (!req.body) { | ||||
|     res.statusCode = 422; | ||||
|     res.setHeader('Content-Type', 'application/json'); | ||||
|     res.end(JSON.stringify({"error":{"message":"module \'relay\' needs more arguments"}})); | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   return urequestAsync(opts.body).then(function (resp) { | ||||
|   return urequestAsync(req.body).then(function (resp) { | ||||
|     res.setHeader('Content-Type', 'application/json'); | ||||
|     resp = resp.toJSON(); | ||||
|     res.end(JSON.stringify(resp)); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| var serveStatic = require('serve-static')(path.join(__dirname, '../lib/admin/')); | ||||
| function handleRemoteClient(req, res) { | ||||
|   if (/^\/(rpc|api)\//.test(req.url)) { | ||||
|     return handleApi(req, res); | ||||
|   } | ||||
|   serveStatic(req, res, require('finalhandler')(req, res)); | ||||
| } | ||||
| function handleApi(req, res) { | ||||
| function handleApi() { | ||||
|   var app = eggspress(); | ||||
| 
 | ||||
|   app.use('/', function (req, res, next) { | ||||
|     var opts = url.parse(req.url, true); | ||||
|     if (false && opts.query._body) { | ||||
|       try { | ||||
|       opts.body = JSON.parse(decodeURIComponent(opts.query._body, true)); | ||||
|         req.body = JSON.parse(decodeURIComponent(opts.query._body, true)); | ||||
|       } catch(e) { | ||||
|         res.statusCode = 500; | ||||
|         res.end('{"error":{"message":"?_body={{bad_format}}"}}'); | ||||
| @ -392,7 +389,34 @@ function handleApi(req, res) { | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|   function listSuccess() { | ||||
|     var hasLength = req.headers['content-length'] > 0; | ||||
|     if (!hasLength && !req.headers['content-type']) { | ||||
|       next(); | ||||
|       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 { | ||||
|         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 = { | ||||
|       servernames: state.servernames | ||||
|     , ports: state.ports | ||||
| @ -411,7 +435,7 @@ function handleApi(req, res) { | ||||
|     res.end(JSON.stringify(dumpy)); | ||||
|   } | ||||
| 
 | ||||
|   function getConfigOnly() { | ||||
|   function getConfigOnly(req, res) { | ||||
|     var resp = JSON.parse(JSON.stringify(state.config)); | ||||
|     resp.version = pkg.version; | ||||
|     resp._otp = state.otp; | ||||
| @ -422,7 +446,7 @@ function handleApi(req, res) { | ||||
|   //
 | ||||
|   // without proper config
 | ||||
|   //
 | ||||
|   function saveAndReport() { | ||||
|   function saveAndReport(req, res) { | ||||
|     console.log('[DEBUG] saveAndReport config write', confpath); | ||||
|     console.log(YAML.safeDump(snakeCopy(state.config))); | ||||
|     fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) { | ||||
| @ -438,18 +462,18 @@ function handleApi(req, res) { | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   function initOrConfig() { | ||||
|     function initOrConfig(req, res) { | ||||
|       var conf = {}; | ||||
|     if (!opts.body) { | ||||
|       if (!req.body) { | ||||
|         res.statusCode = 422; | ||||
|         res.end('{"error":{"message":"module \'init\' needs more arguments"}}'); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|     if (Array.isArray(opts.body)) { | ||||
|       if (Array.isArray(req.body)) { | ||||
|         // relay, email, agree_tos, servernames, ports
 | ||||
|         //
 | ||||
|       opts.body.forEach(function (opt) { | ||||
|         req.body.forEach(function (opt) { | ||||
|           var parts = opt.split(/:/); | ||||
|           if ('true' === parts[1]) { | ||||
|             parts[1] = true; | ||||
| @ -463,7 +487,7 @@ function handleApi(req, res) { | ||||
|           conf[parts[0]] = parts[1]; | ||||
|         }); | ||||
|       } else { | ||||
|       conf = opts.body; | ||||
|         conf = req.body; | ||||
|       } | ||||
| 
 | ||||
|       conf = camelCopy(conf); | ||||
| @ -545,7 +569,7 @@ function handleApi(req, res) { | ||||
|           , message: "Missing important config file params" | ||||
|           , _params: JSON.stringify(conf) | ||||
|           , _config: JSON.stringify(state.config) | ||||
|         , _body: JSON.stringify(opts.body) | ||||
|           , _body: JSON.stringify(req.body) | ||||
|           } | ||||
|         })); | ||||
|         return; | ||||
| @ -556,7 +580,7 @@ function handleApi(req, res) { | ||||
|       safeStartTelebitRemote(true).then(saveAndReport).catch(handleError); | ||||
|     } | ||||
| 
 | ||||
|   function restart() { | ||||
|     function restart(req, res) { | ||||
|       console.info("[telebitd.js] server closing..."); | ||||
|       state.keepAlive.state = false; | ||||
|       if (myRemote) { | ||||
| @ -584,7 +608,15 @@ function handleApi(req, res) { | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|   function invalidConfig() { | ||||
|     function mustHaveValidConfig(req, res, next) { | ||||
|       //
 | ||||
|       // Check for proper config
 | ||||
|       //
 | ||||
|       if (state.config.relay && state.config.email && state.config.agreeTos) { | ||||
|         next(); | ||||
|         return; | ||||
|       } | ||||
| 
 | ||||
|       res.statusCode = 400; | ||||
|       res.setHeader('Content-Type', 'application/json'); | ||||
|       res.end(JSON.stringify({ | ||||
| @ -592,7 +624,7 @@ function handleApi(req, res) { | ||||
|       })); | ||||
|     } | ||||
| 
 | ||||
|   function saveAndCommit() { | ||||
|     function saveAndCommit(req, res) { | ||||
|       state.config.servernames = state.servernames; | ||||
|       state.config.ports = state.ports; | ||||
|       fs.writeFile(confpath, YAML.safeDump(snakeCopy(state.config)), function (err) { | ||||
| @ -608,7 +640,7 @@ function handleApi(req, res) { | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|   function handleError(err) { | ||||
|     function handleError(err, req, res) { | ||||
|       res.statusCode = 500; | ||||
|       res.setHeader('Content-Type', 'application/json'); | ||||
|       res.end(JSON.stringify({ | ||||
| @ -616,26 +648,28 @@ function handleApi(req, res) { | ||||
|       })); | ||||
|     } | ||||
| 
 | ||||
|   function enable() { | ||||
|     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); | ||||
|           handleError(err, req, res); | ||||
|           return; | ||||
|         } | ||||
|         // TODO XXX myRemote.active
 | ||||
|         if (myRemote) { | ||||
|         listSuccess(); | ||||
|           listSuccess(req, res); | ||||
|           return; | ||||
|         } | ||||
|       safeStartTelebitRemote(true).then(listSuccess).catch(handleError); | ||||
|         safeStartTelebitRemote(true).then(listSuccess).catch(function () { | ||||
|           handleError(err, req, res); | ||||
|         }); | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|   function disable() { | ||||
|     function disable(req, res) { | ||||
|       state.config.disable = true; | ||||
|       state.keepAlive.state = false; | ||||
| 
 | ||||
| @ -651,7 +685,7 @@ function handleApi(req, res) { | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|   function getStatus() { | ||||
|     function getStatus(req, res) { | ||||
|       var now = Date.now(); | ||||
|       res.setHeader('Content-Type', 'application/json'); | ||||
|       require('../lib/ssh.js').checkSecurity().then(function (ssh) { | ||||
| @ -677,98 +711,45 @@ function handleApi(req, res) { | ||||
|       }); | ||||
|     } | ||||
| 
 | ||||
|   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; | ||||
|     } | ||||
|   // 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
 | ||||
|   //
 | ||||
|     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; | ||||
|     } | ||||
| 
 | ||||
|   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.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() { | ||||
|   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)) { | ||||
|     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" | ||||
|       } | ||||
|     }, | ||||
|     "array-flatten": { | ||||
|       "version": "1.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", | ||||
|       "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" | ||||
|     }, | ||||
|     "asn1js": { | ||||
|       "version": "1.2.12", | ||||
|       "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", | ||||
|       "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": { | ||||
|       "version": "1.2.0", | ||||
|       "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", | ||||
|       "integrity": "sha1-0c2v61YAvvbCjWFElkJWvRLgFnc=" | ||||
|     }, | ||||
|     "bytes": { | ||||
|       "version": "3.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", | ||||
|       "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" | ||||
|     }, | ||||
|     "certpem": { | ||||
|       "version": "1.0.1", | ||||
|       "resolved": "https://registry.npmjs.org/certpem/-/certpem-1.0.1.tgz", | ||||
| @ -141,26 +114,6 @@ | ||||
|         "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": { | ||||
|       "version": "1.0.2", | ||||
|       "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", | ||||
|       "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": { | ||||
|       "version": "1.1.1", | ||||
|       "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", | ||||
| @ -289,11 +205,6 @@ | ||||
|         "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": { | ||||
|       "version": "0.5.2", | ||||
|       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", | ||||
| @ -374,14 +285,6 @@ | ||||
|         "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": { | ||||
|       "version": "2.0.3", | ||||
|       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", | ||||
| @ -395,11 +298,6 @@ | ||||
|         "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": { | ||||
|       "version": "3.2.1", | ||||
|       "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", | ||||
|       "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": { | ||||
|       "version": "1.4.1", | ||||
|       "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", | ||||
|       "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": { | ||||
|       "version": "3.0.0", | ||||
|       "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", | ||||
|       "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": { | ||||
|       "version": "2.0.2", | ||||
|       "resolved": "https://registry.npmjs.org/proxy-packer/-/proxy-packer-2.0.2.tgz", | ||||
| @ -723,11 +592,6 @@ | ||||
|         "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": { | ||||
|       "version": "1.2.0", | ||||
|       "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", | ||||
|       "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": { | ||||
|       "version": "2.3.6", | ||||
|       "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", | ||||
|       "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": { | ||||
|       "version": "1.4.1", | ||||
|       "resolved": "https://registry.npmjs.org/sclient/-/sclient-1.4.1.tgz", | ||||
| @ -985,15 +833,6 @@ | ||||
|         "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": { | ||||
|       "version": "1.0.0", | ||||
|       "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", | ||||
|       "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": { | ||||
|       "version": "6.0.0", | ||||
|       "resolved": "https://registry.npmjs.org/ws/-/ws-6.0.0.tgz", | ||||
|  | ||||
| @ -54,7 +54,6 @@ | ||||
|   "homepage": "https://git.coolaj86.com/coolaj86/telebit.js#readme", | ||||
|   "dependencies": { | ||||
|     "@coolaj86/urequest": "^1.3.5", | ||||
|     "express": "^4.16.4", | ||||
|     "finalhandler": "^1.1.1", | ||||
|     "greenlock": "^2.3.1", | ||||
|     "js-yaml": "^3.11.0", | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user