add basic key handling to server
This commit is contained in:
		
							parent
							
								
									58dab177da
								
							
						
					
					
						commit
						53cc3ccaba
					
				@ -763,11 +763,31 @@ var parsers = {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var keystore = require('../lib/keystore.js').create(state);
 | 
					var keystore = require('../lib/keystore.js').create(state);
 | 
				
			||||||
var keyname = 'telebit-remote';
 | 
					 | 
				
			||||||
state.keystore = keystore;
 | 
					state.keystore = keystore;
 | 
				
			||||||
state.keystoreSecure = !keystore.insecure;
 | 
					state.keystoreSecure = !keystore.insecure;
 | 
				
			||||||
keystore.get(keyname).then(function (key) {
 | 
					keystore.all().then(function (list) {
 | 
				
			||||||
  if (key && key.kty && key.kid) {
 | 
					  var keyext = '.key.jwk.json';
 | 
				
			||||||
 | 
					  var key;
 | 
				
			||||||
 | 
					  var convert;
 | 
				
			||||||
 | 
					  // TODO create map by account and index into that map to get the master key
 | 
				
			||||||
 | 
					  // and sort keys in the process
 | 
				
			||||||
 | 
					  list.some(function (el) {
 | 
				
			||||||
 | 
					    if (keyext === el.account.slice(-keyext.length)
 | 
				
			||||||
 | 
					      && el.password.kty && el.password.kid) {
 | 
				
			||||||
 | 
					      key = el.password;
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  if (!key) {
 | 
				
			||||||
 | 
					    list.some(function (el) {
 | 
				
			||||||
 | 
					      if (el.password.kty) {
 | 
				
			||||||
 | 
					        convert = el.password;
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (key) {
 | 
				
			||||||
    state.key = key;
 | 
					    state.key = key;
 | 
				
			||||||
    state.pub = keypairs.neuter({ jwk: key });
 | 
					    state.pub = keypairs.neuter({ jwk: key });
 | 
				
			||||||
    fs.readFile(confpath, 'utf8', parseConfig);
 | 
					    fs.readFile(confpath, 'utf8', parseConfig);
 | 
				
			||||||
@ -776,9 +796,10 @@ keystore.get(keyname).then(function (key) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  return keypairs.generate().then(function (pair) {
 | 
					  return keypairs.generate().then(function (pair) {
 | 
				
			||||||
    var jwk = pair.private;
 | 
					    var jwk = pair.private;
 | 
				
			||||||
    return keypairs.thumbprint({ jwk: pair.public }).then(function (kid) {
 | 
					    if (convert) { jwk = convert; }
 | 
				
			||||||
 | 
					    return keypairs.thumbprint({ jwk: jwk }).then(function (kid) {
 | 
				
			||||||
      jwk.kid = kid;
 | 
					      jwk.kid = kid;
 | 
				
			||||||
      return keystore.set(keyname, jwk).then(function () {
 | 
					      return keystore.set(kid + keyext, jwk).then(function () {
 | 
				
			||||||
        var size = (jwk.crv || Buffer.from(jwk.n, 'base64').byteLength * 8);
 | 
					        var size = (jwk.crv || Buffer.from(jwk.n, 'base64').byteLength * 8);
 | 
				
			||||||
        console.info("Generated new %s %s private key with thumbprint %s", jwk.kty, size, kid);
 | 
					        console.info("Generated new %s %s private key with thumbprint %s", jwk.kty, size, kid);
 | 
				
			||||||
        state.key = jwk;
 | 
					        state.key = jwk;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										130
									
								
								bin/telebitd.js
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								bin/telebitd.js
									
									
									
									
									
								
							@ -73,14 +73,11 @@ if (!confpath || /^--/.test(confpath)) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
state._confpath = confpath;
 | 
					state._confpath = confpath;
 | 
				
			||||||
var tokenpath = path.join(path.dirname(state._confpath), 'access_token.txt');
 | 
					var keystore = require('../lib/keystore.js').create({
 | 
				
			||||||
var token;
 | 
					  name: "Telebit Daemon"
 | 
				
			||||||
try {
 | 
					, configDir: path.basename(confpath)
 | 
				
			||||||
  token = fs.readFileSync(tokenpath, 'ascii').trim();
 | 
					});
 | 
				
			||||||
  //console.log('[DEBUG] access_token', typeof token, token);
 | 
					
 | 
				
			||||||
} catch(e) {
 | 
					 | 
				
			||||||
  // ignore
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
var controlServer;
 | 
					var controlServer;
 | 
				
			||||||
var myRemote;
 | 
					var myRemote;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -442,14 +439,12 @@ function jwtEggspress(req, res, next) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
function verifyJws(jwk, jws) {
 | 
					function verifyJws(jwk, jws) {
 | 
				
			||||||
  return require('keypairs').export({ jwk: jwk }).then(function (pem) {
 | 
					  return require('keypairs').export({ jwk: jwk }).then(function (pem) {
 | 
				
			||||||
    var alg = 'RSA-SHA' + jws.header.alg.replace(/[^\d]+/i, '');
 | 
					    var alg = 'SHA' + jws.header.alg.replace(/[^\d]+/i, '');
 | 
				
			||||||
    // XXX
 | 
					    var sig = ecdsaAsn1SigToJwtSig(jws.header.alg, jws.signature);
 | 
				
			||||||
    // TODO check for public key in keytar
 | 
					 | 
				
			||||||
    // XXX
 | 
					 | 
				
			||||||
    return require('crypto')
 | 
					    return require('crypto')
 | 
				
			||||||
      .createVerify(alg)
 | 
					      .createVerify(alg)
 | 
				
			||||||
      .update(jws.protected + '.' + jws.payload)
 | 
					      .update(jws.protected + '.' + jws.payload)
 | 
				
			||||||
      .verify(pem, jws.signature, 'base64');
 | 
					      .verify(pem, sig, 'base64');
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -465,16 +460,31 @@ function jwsEggspress(req, res, next) {
 | 
				
			|||||||
  if ('{'.charCodeAt(0) === req.body[0] || '['.charCodeAt(0) === req.body[0]) {
 | 
					  if ('{'.charCodeAt(0) === req.body[0] || '['.charCodeAt(0) === req.body[0]) {
 | 
				
			||||||
    req.body = JSON.parse(req.body);
 | 
					    req.body = JSON.parse(req.body);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (req.jws.header.jwk) {
 | 
					
 | 
				
			||||||
    verifyJws(req.jws.header.jwk, req.jws).then(function (verified) {
 | 
					  var vjwk;
 | 
				
			||||||
      req.jws.selfVerified = verified;
 | 
					  jwks.some(function (jwk) {
 | 
				
			||||||
      next();
 | 
					    if (jwk.kid === req.jws.header.kid) {
 | 
				
			||||||
 | 
					      vjwk = jwk;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
    return;
 | 
					  if ((0 === jwks.length && req.jws.header.jwk)) {
 | 
				
			||||||
 | 
					    vjwk = req.jws.header.jwk;
 | 
				
			||||||
 | 
					    if (!vjwk.kid) { throw Error("Impossible: no key id"); }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // TODO verify if possible
 | 
					  return verifyJws(vjwk, req.jws).then(function (verified) {
 | 
				
			||||||
 | 
					    if (true !== verified) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    req.jws.verified = verified;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (0 !== jwks.length) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return keystore.set(vjwk.kid + '.pub.jwk.json', vjwk);
 | 
				
			||||||
 | 
					  }).then(function () {
 | 
				
			||||||
    next();
 | 
					    next();
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function handleApi() {
 | 
					function handleApi() {
 | 
				
			||||||
@ -883,7 +893,9 @@ function serveControlsHelper() {
 | 
				
			|||||||
        // nada
 | 
					        // nada
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      setTimeout(function () {
 | 
					      setTimeout(function () {
 | 
				
			||||||
        console.log("trying again");
 | 
					        console.log("Could not start control server (%s), trying again...", err.code);
 | 
				
			||||||
 | 
					        console.log(portFile);
 | 
				
			||||||
 | 
					        console.log(serverOpts);
 | 
				
			||||||
        serveControlsHelper();
 | 
					        serveControlsHelper();
 | 
				
			||||||
      }, 1000);
 | 
					      }, 1000);
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
@ -1313,15 +1325,19 @@ state.handlers = {
 | 
				
			|||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    state.token = opts.jwt || opts.access_token;
 | 
					    state.token = opts.jwt || opts.access_token;
 | 
				
			||||||
 | 
					    // TODO don't put token in config
 | 
				
			||||||
    state.config.token = opts.jwt || opts.access_token;
 | 
					    state.config.token = opts.jwt || opts.access_token;
 | 
				
			||||||
    console.info("Updating '" + tokenpath + "' with new token:");
 | 
					    console.info("Placing new token in keystore.");
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      fs.writeFileSync(tokenpath, opts.jwt);
 | 
					 | 
				
			||||||
      fs.writeFileSync(confpath, YAML.safeDump(snakeCopy(state.config)));
 | 
					      fs.writeFileSync(confpath, YAML.safeDump(snakeCopy(state.config)));
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      console.error("Token not saved:");
 | 
					      console.error("Token not saved:");
 | 
				
			||||||
      console.error(e);
 | 
					      console.error(e);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    return keystore.set("access_token.jwt", opts.jwt || opts.access_token).catch(function (e) {
 | 
				
			||||||
 | 
					      console.error("Token not saved:");
 | 
				
			||||||
 | 
					      console.error(e);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1358,6 +1374,72 @@ state.net = state.net || {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fs.readFile(confpath, 'utf8', parseConfig);
 | 
					var token;
 | 
				
			||||||
 | 
					var tokenname = "access_token.jwt";
 | 
				
			||||||
 | 
					// backwards-compatibility shim
 | 
				
			||||||
 | 
					try {
 | 
				
			||||||
 | 
					  var tokenpath = path.join(path.dirname(state._confpath), 'access_token.txt');
 | 
				
			||||||
 | 
					  token = fs.readFileSync(tokenpath, 'ascii').trim();
 | 
				
			||||||
 | 
					  keystore.set(tokenname, token).then(onKeystore).catch(function (err) {
 | 
				
			||||||
 | 
					    console.error('keystore failure:');
 | 
				
			||||||
 | 
					    console.error(err);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					} catch(e) {
 | 
				
			||||||
 | 
					  onKeystore();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					var jwks = [];
 | 
				
			||||||
 | 
					function onKeystore() {
 | 
				
			||||||
 | 
					  return keystore.all().then(function (list) {
 | 
				
			||||||
 | 
					    list.forEach(function (el) {
 | 
				
			||||||
 | 
					      if (tokenname === el.account) {
 | 
				
			||||||
 | 
					        token = el.password;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // these are secret because just adding the
 | 
				
			||||||
 | 
					      // willy-nilly to the fs can allow arbitrary tokens
 | 
				
			||||||
 | 
					      if (/\.pub\.jwk\.json$/.test(el.account)) {
 | 
				
			||||||
 | 
					        // pre-parsed
 | 
				
			||||||
 | 
					        jwks.push(el.password);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    fs.readFile(confpath, 'utf8', parseConfig);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
}());
 | 
					}());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function ecdsaAsn1SigToJwtSig(alg, b64sig) {
 | 
				
			||||||
 | 
					  // ECDSA JWT signatures differ from "normal" ECDSA signatures
 | 
				
			||||||
 | 
					  // https://tools.ietf.org/html/rfc7518#section-3.4
 | 
				
			||||||
 | 
					  if (!/^ES/i.test(alg)) { return b64sig; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var bufsig = Buffer.from(b64sig, 'base64');
 | 
				
			||||||
 | 
					  var hlen = bufsig.byteLength / 2; // should be even
 | 
				
			||||||
 | 
					  var r = bufsig.slice(0, hlen);
 | 
				
			||||||
 | 
					  var s = bufsig.slice(hlen);
 | 
				
			||||||
 | 
					  // unpad positive ints less than 32 bytes wide
 | 
				
			||||||
 | 
					  while (!r[0]) { r = r.slice(1); }
 | 
				
			||||||
 | 
					  while (!s[0]) { s = s.slice(1); }
 | 
				
			||||||
 | 
					  // pad (or re-pad) ambiguously non-negative BigInts to 33 bytes wide
 | 
				
			||||||
 | 
					  if (0x80 & r[0]) { r = Buffer.concat([Buffer.from([0]), r]); }
 | 
				
			||||||
 | 
					  if (0x80 & s[0]) { s = Buffer.concat([Buffer.from([0]), s]); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var len = 2 + r.byteLength + 2 + s.byteLength;
 | 
				
			||||||
 | 
					  var head = [0x30];
 | 
				
			||||||
 | 
					  // hard code 0x80 + 1 because it won't be longer than
 | 
				
			||||||
 | 
					  // two SHA512 plus two pad bytes (130 bytes <= 256)
 | 
				
			||||||
 | 
					  if (len >= 0x80) { head.push(0x81); }
 | 
				
			||||||
 | 
					  head.push(len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  var buf = Buffer.concat([
 | 
				
			||||||
 | 
					    Buffer.from(head)
 | 
				
			||||||
 | 
					  , Buffer.from([0x02, r.byteLength]), r
 | 
				
			||||||
 | 
					  , Buffer.from([0x02, s.byteLength]), s
 | 
				
			||||||
 | 
					  ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return buf.toString('base64')
 | 
				
			||||||
 | 
					    .replace(/-/g, '+')
 | 
				
			||||||
 | 
					    .replace(/_/g, '/')
 | 
				
			||||||
 | 
					    .replace(/=/g, '')
 | 
				
			||||||
 | 
					  ;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -34,14 +34,21 @@ module.exports = function eggspress() {
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      try {
 | 
					      function fail(e) {
 | 
				
			||||||
        //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("[eggspress] error", todo[2], todo[0], req.url);
 | 
				
			||||||
        console.error(e);
 | 
					        console.error(e);
 | 
				
			||||||
        // TODO make a nice error message
 | 
					        // TODO make a nice error message
 | 
				
			||||||
        res.end(e.message);
 | 
					        res.end(e.message);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        console.log("[eggspress] matched pattern", todo[0], req.url);
 | 
				
			||||||
 | 
					        var p = todo[1](req, res, next);
 | 
				
			||||||
 | 
					        if (p && p.catch) {
 | 
				
			||||||
 | 
					          p.catch(fail);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } catch(e) {
 | 
				
			||||||
 | 
					        fail(e);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,12 +1,14 @@
 | 
				
			|||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					/*global Promise*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var fs = require('fs').promises;
 | 
					var fs = require('fs').promises;
 | 
				
			||||||
var path = require('path');
 | 
					var path = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports.create = function (opts) {
 | 
					module.exports.create = function (opts) {
 | 
				
			||||||
 | 
					  var keyext = '.key';
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    getPassword: function (service, name) {
 | 
					    getPassword: function (service, name) {
 | 
				
			||||||
      var f = path.join(opts.configDir, name + '.key');
 | 
					      var f = path.join(opts.configDir, name + keyext);
 | 
				
			||||||
      return fs.readFile(f, 'utf8').catch(function (err) {
 | 
					      return fs.readFile(f, 'utf8').catch(function (err) {
 | 
				
			||||||
        if ('ENOEXIST' === err.code) {
 | 
					        if ('ENOEXIST' === err.code) {
 | 
				
			||||||
          return;
 | 
					          return;
 | 
				
			||||||
@ -14,13 +16,22 @@ module.exports.create = function (opts) {
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  , setPassword: function (service, name, key) {
 | 
					  , setPassword: function (service, name, key) {
 | 
				
			||||||
      var f = path.join(opts.configDir, name + '.key');
 | 
					      var f = path.join(opts.configDir, name + keyext);
 | 
				
			||||||
      return fs.writeFile(f, key, 'utf8');
 | 
					      return fs.writeFile(f, key, 'utf8');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  , deletePassword: function (service, name) {
 | 
					  , deletePassword: function (service, name) {
 | 
				
			||||||
      var f = path.join(opts.configDir, name + '.key');
 | 
					      var f = path.join(opts.configDir, name + keyext);
 | 
				
			||||||
      return fs.unlink(f);
 | 
					      return fs.unlink(f);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  , findCredentials: function (/*service*/) {
 | 
				
			||||||
 | 
					      return fs.readDir(opts.configDir).then(function (nodes) {
 | 
				
			||||||
 | 
					        return Promise.all(nodes.filter(function (node) {
 | 
				
			||||||
 | 
					          return keyext === node.slice(-4);
 | 
				
			||||||
 | 
					        }).map(function (node) {
 | 
				
			||||||
 | 
					          return fs.readFile(path.join(opts.configDir, node + keyext));
 | 
				
			||||||
 | 
					        }));
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  , insecure: true
 | 
					  , insecure: true
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -1,10 +1,11 @@
 | 
				
			|||||||
'use strict';
 | 
					'use strict';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports.create = function (opts) {
 | 
					module.exports.create = function (opts) {
 | 
				
			||||||
  var service = "Telebit";
 | 
					  var service = opts.name || "Telebit";
 | 
				
			||||||
  var keytar;
 | 
					  var keytar;
 | 
				
			||||||
  try {
 | 
					  try {
 | 
				
			||||||
    keytar = require('keytar');
 | 
					    keytar = require('keytar');
 | 
				
			||||||
 | 
					    // TODO test that long "passwords" (JWTs and JWKs) can be stored in all OSes
 | 
				
			||||||
  } catch(e) {
 | 
					  } catch(e) {
 | 
				
			||||||
    console.warn("Could not load native key management. Keys will be stored in plain text.");
 | 
					    console.warn("Could not load native key management. Keys will be stored in plain text.");
 | 
				
			||||||
    keytar = require('./keystore-fallback.js').create(opts);
 | 
					    keytar = require('./keystore-fallback.js').create(opts);
 | 
				
			||||||
@ -21,6 +22,14 @@ module.exports.create = function (opts) {
 | 
				
			|||||||
  , delete: function (name) {
 | 
					  , delete: function (name) {
 | 
				
			||||||
      return keytar.deletePassword(service, name);
 | 
					      return keytar.deletePassword(service, name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  , all: function () {
 | 
				
			||||||
 | 
					      return keytar.findCredentials(service).then(function (list) {
 | 
				
			||||||
 | 
					        return list.map(function (el) {
 | 
				
			||||||
 | 
					          el.password = maybeParse(el.password);
 | 
				
			||||||
 | 
					          return el;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  , insecure: keytar.insecure
 | 
					  , insecure: keytar.insecure
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										36
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										36
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -38,8 +38,7 @@
 | 
				
			|||||||
    "ansi-regex": {
 | 
					    "ansi-regex": {
 | 
				
			||||||
      "version": "2.1.1",
 | 
					      "version": "2.1.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
 | 
				
			||||||
      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
 | 
					      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
 | 
				
			||||||
      "optional": true
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "aproba": {
 | 
					    "aproba": {
 | 
				
			||||||
      "version": "1.2.0",
 | 
					      "version": "1.2.0",
 | 
				
			||||||
@ -137,14 +136,12 @@
 | 
				
			|||||||
    "code-point-at": {
 | 
					    "code-point-at": {
 | 
				
			||||||
      "version": "1.1.0",
 | 
					      "version": "1.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
 | 
				
			||||||
      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
 | 
					      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
 | 
				
			||||||
      "optional": true
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "console-control-strings": {
 | 
					    "console-control-strings": {
 | 
				
			||||||
      "version": "1.1.0",
 | 
					      "version": "1.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
 | 
				
			||||||
      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
 | 
					      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
 | 
				
			||||||
      "optional": true
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "core-util-is": {
 | 
					    "core-util-is": {
 | 
				
			||||||
      "version": "1.0.2",
 | 
					      "version": "1.0.2",
 | 
				
			||||||
@ -236,7 +233,6 @@
 | 
				
			|||||||
      "version": "1.4.1",
 | 
					      "version": "1.4.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
 | 
				
			||||||
      "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
 | 
					      "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
 | 
				
			||||||
      "optional": true,
 | 
					 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "once": "^1.4.0"
 | 
					        "once": "^1.4.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -400,7 +396,6 @@
 | 
				
			|||||||
      "version": "1.0.0",
 | 
					      "version": "1.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
 | 
				
			||||||
      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
 | 
					      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
 | 
				
			||||||
      "optional": true,
 | 
					 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "number-is-nan": "^1.0.0"
 | 
					        "number-is-nan": "^1.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -429,10 +424,20 @@
 | 
				
			|||||||
      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
 | 
				
			||||||
      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
 | 
					      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "keyfetch": {
 | 
				
			||||||
 | 
					      "version": "1.1.8",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/keyfetch/-/keyfetch-1.1.8.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-a8E1E25mHiv2zZnrBM6WNfQi4hG43TgVg1JG/D61WiTBAM07OJzSuy3j00H2pWPF6MCofBmA+KTzSu145nZWuA==",
 | 
				
			||||||
 | 
					      "requires": {
 | 
				
			||||||
 | 
					        "@coolaj86/urequest": "^1.3.6",
 | 
				
			||||||
 | 
					        "eckles": "^1.4.0",
 | 
				
			||||||
 | 
					        "rasha": "^1.2.1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "keypairs": {
 | 
					    "keypairs": {
 | 
				
			||||||
      "version": "1.2.6",
 | 
					      "version": "1.2.12",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/keypairs/-/keypairs-1.2.6.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/keypairs/-/keypairs-1.2.12.tgz",
 | 
				
			||||||
      "integrity": "sha512-sJDaZvJqHWUawJjrOGKJvKGLfPh0eo2WV7td4RSL88w3BjPYCYI9PkqBn0hLqc6uw0HFSqZMikhGn/jgPpcWnQ==",
 | 
					      "integrity": "sha512-zYjYdDvo7G4AIkkZVM3WEJBTRUIrFzYswYNqCxcCPHUsgbBBdewSHAH1CiaQ+VA6Yb7BLEPIv8gFrRz5wJrgsw==",
 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "eckles": "^1.4.1",
 | 
					        "eckles": "^1.4.1",
 | 
				
			||||||
        "rasha": "^1.2.4"
 | 
					        "rasha": "^1.2.4"
 | 
				
			||||||
@ -597,8 +602,7 @@
 | 
				
			|||||||
    "number-is-nan": {
 | 
					    "number-is-nan": {
 | 
				
			||||||
      "version": "1.0.1",
 | 
					      "version": "1.0.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
 | 
				
			||||||
      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
 | 
					      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
 | 
				
			||||||
      "optional": true
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "object-assign": {
 | 
					    "object-assign": {
 | 
				
			||||||
      "version": "4.1.1",
 | 
					      "version": "4.1.1",
 | 
				
			||||||
@ -617,7 +621,6 @@
 | 
				
			|||||||
      "version": "1.4.0",
 | 
					      "version": "1.4.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
 | 
				
			||||||
      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
 | 
					      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
 | 
				
			||||||
      "optional": true,
 | 
					 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "wrappy": "1"
 | 
					        "wrappy": "1"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -951,7 +954,6 @@
 | 
				
			|||||||
      "version": "1.0.2",
 | 
					      "version": "1.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
 | 
				
			||||||
      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
 | 
					      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
 | 
				
			||||||
      "optional": true,
 | 
					 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "code-point-at": "^1.0.0",
 | 
					        "code-point-at": "^1.0.0",
 | 
				
			||||||
        "is-fullwidth-code-point": "^1.0.0",
 | 
					        "is-fullwidth-code-point": "^1.0.0",
 | 
				
			||||||
@ -970,7 +972,6 @@
 | 
				
			|||||||
      "version": "3.0.1",
 | 
					      "version": "3.0.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
 | 
				
			||||||
      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
 | 
					      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
 | 
				
			||||||
      "optional": true,
 | 
					 | 
				
			||||||
      "requires": {
 | 
					      "requires": {
 | 
				
			||||||
        "ansi-regex": "^2.0.0"
 | 
					        "ansi-regex": "^2.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -1104,8 +1105,7 @@
 | 
				
			|||||||
    "wrappy": {
 | 
					    "wrappy": {
 | 
				
			||||||
      "version": "1.0.2",
 | 
					      "version": "1.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
 | 
				
			||||||
      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
 | 
					      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
 | 
				
			||||||
      "optional": true
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "ws": {
 | 
					    "ws": {
 | 
				
			||||||
      "version": "6.0.0",
 | 
					      "version": "6.0.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -57,7 +57,8 @@
 | 
				
			|||||||
    "finalhandler": "^1.1.1",
 | 
					    "finalhandler": "^1.1.1",
 | 
				
			||||||
    "greenlock": "^2.6.7",
 | 
					    "greenlock": "^2.6.7",
 | 
				
			||||||
    "js-yaml": "^3.11.0",
 | 
					    "js-yaml": "^3.11.0",
 | 
				
			||||||
    "keypairs": "^1.2.6",
 | 
					    "keyfetch": "^1.1.8",
 | 
				
			||||||
 | 
					    "keypairs": "^1.2.12",
 | 
				
			||||||
    "mkdirp": "^0.5.1",
 | 
					    "mkdirp": "^0.5.1",
 | 
				
			||||||
    "proxy-packer": "^2.0.2",
 | 
					    "proxy-packer": "^2.0.2",
 | 
				
			||||||
    "ps-list": "^5.0.0",
 | 
					    "ps-list": "^5.0.0",
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user