@small-tech/auto-encrypt-localhost
Advanced tools
Comparing version 8.3.2 to 8.4.0
@@ -47,3 +47,3 @@ #!/usr/bin/env node | ||
.describe('Create certificate authority and server certificate if necessary') | ||
.action(_ => { | ||
.action(() => { | ||
AutoEncryptLocalhost.getKeyMaterial() | ||
@@ -62,3 +62,3 @@ console.info('\n🎉 Certificates created and added to local trust stores.\n') | ||
.describe('Run local server and serve certificate authority certificate at http://<local IPs>/.ca') | ||
.action(_ => { | ||
.action(async () => { | ||
console.info() | ||
@@ -106,6 +106,6 @@ const server = AutoEncryptLocalhost.https.createServer((_request, response) => { | ||
server.listen(443, () => { | ||
console.info('\nHTTPS Server running. Please see https://localhost for instructions.') | ||
this.printFooter() | ||
}) | ||
await server.listen(443) | ||
console.info('\nHTTPS Server running. Please see https://localhost for instructions.') | ||
this.printFooter() | ||
}) | ||
@@ -116,3 +116,3 @@ | ||
.describe('Print out certificate authority and server certificate key material') | ||
.action(_ => { | ||
.action(() => { | ||
const keyMaterial = AutoEncryptLocalhost.getKeyMaterial() | ||
@@ -144,3 +144,3 @@ console.info('\nLocal development certificate:\n') | ||
.describe('Alias for --version, -v.') | ||
.action(_ => this.commands._version()) | ||
.action(() => this.commands._version()) | ||
} | ||
@@ -147,0 +147,0 @@ |
124
index.js
@@ -63,3 +63,3 @@ /** | ||
/** | ||
* Automatically provisions trusted development-time (localhost) certificates in Node.js via mkcert. | ||
* Automatically provisions trusted development-time (localhost) certificates in Node.js. | ||
* | ||
@@ -71,3 +71,2 @@ * @static | ||
* Custom path to save the certificate and private key to. | ||
* @returns {https.Server} The server instance returned by Node’s https.createServer() method. | ||
*/ | ||
@@ -92,34 +91,115 @@ static createServer(_options, _listener) { | ||
// Create HTTPS server. | ||
const server = https.createServer(options, listener) | ||
// | ||
// Monkey-patch server. | ||
// | ||
server.__autoEncryptLocalhost__self = this | ||
// Monkey-patch server’s listen method so that we can start up the HTTP | ||
// redirection server at the same time. | ||
server.__autoEncryptLocalhost__originalListen = server.listen | ||
server.listen = function(...args) { | ||
// Start the HTTP server. | ||
HttpServer.getSharedInstance(keyMaterial.certificateAuthority).then(() => { | ||
// Start the HTTPS server. | ||
return this.__autoEncryptLocalhost__originalListen.apply(this, args) | ||
/** | ||
Auto Encrypt Localhost’s patched (async) version of Node’s built-in `https.listen()` method. | ||
You can still use this method with exactly the same signature as Node’s and | ||
with a callback but, ideally, you should be awaiting it and not using the callback. | ||
@param {number|function} [port] | ||
@param {string|function} [host] | ||
@param {number|function} [backlog] | ||
@param {() => void} [callback] | ||
*/ | ||
const patchedListen = async function(port, host, backlog, callback) { | ||
// Start HTTP server. | ||
await HttpServer.getSharedInstance(keyMaterial.certificateAuthority) | ||
// Start HTTPS server. | ||
// We need to support the messy old-school overloaded method signature | ||
// to remain backwards compatible with existing implementations that will be | ||
// using the callback approach. | ||
// | ||
// server.listen([port[, host[, backlog]]][, callback]) | ||
// | ||
// (See https://nodejs.org/api/net.html#serverlistenport-host-backlog-callback) | ||
let originalCallback = () => {} | ||
return await new Promise((resolve, reject) => { | ||
const args = [] | ||
if (typeof port === 'number') { | ||
args.push(port) | ||
if (typeof host === 'string') { | ||
args.push(host) | ||
if (typeof backlog === 'number') { | ||
args.push(backlog) | ||
} else { | ||
if (typeof backlog === 'function') { | ||
originalCallback = backlog | ||
} | ||
} | ||
} else { | ||
if (typeof host === 'function') { | ||
originalCallback = host | ||
} | ||
} | ||
} else { | ||
originalCallback = port | ||
} | ||
const callback = error => { | ||
if (error) { | ||
reject(error) | ||
return | ||
} | ||
originalCallback() | ||
setImmediate(resolve) | ||
} | ||
args.push(callback) | ||
this.__autoEncryptLocalhost__originalListen.apply(this, args) | ||
}) | ||
} | ||
// Monkey-patch server’s close method so that we can perform clean-up and | ||
// shut down the HTTP redirection server transparently when server.close() is called. | ||
server.__autoEncryptLocalhost__originalClose = server.close | ||
server.close = function (...args) { | ||
// Shut down the HTTP redirection server. | ||
HttpServer.destroySharedInstance().then(() => { | ||
// Shut down the HTTPS server. | ||
return this.__autoEncryptLocalhost__originalClose.apply(this, args) | ||
/** | ||
Auto Encrypt Localhost’s patched (async) version of Node’s built-in `https.close()` method. | ||
Unlike Node’s `close()` method, this version also calls `closeAllConnections()` so it | ||
will sever any existing idle and active connections. When `await`ed, this call will | ||
only return once `node:https`’s close callback is called. This is also where your | ||
callback will fire, if you are using Node’s original method signature will callbacks. | ||
You can still use this method with exactly the same signature as Node’s and | ||
with a callback but, ideally, you should be awaiting it and not using the callback. | ||
@param {() => void} [callback] | ||
*/ | ||
const patchedClose = async function (callback) { | ||
// Shut down HTTP redirection server. | ||
await HttpServer.destroySharedInstance() | ||
// Shut down HTTPS server. | ||
await new Promise((resolve, _reject) => { | ||
this.__autoEncryptLocalhost__originalClose(() => { | ||
if (typeof callback === 'function') { | ||
callback() | ||
} | ||
resolve() | ||
}) | ||
// Sever all idle and active connections. | ||
server.closeAllConnections() | ||
}) | ||
} | ||
// Create HTTPS server. | ||
const server = /** @type {{ listen: patchedListen, close: patchedClose } & https.Server} */ (https.createServer(options, listener)) | ||
server.__autoEncryptLocalhost__self = this | ||
// Monkey-patch server’s listen method so we can start up the HTTP | ||
// redirection server at the same time. | ||
// This also means that the listen() method is now async. | ||
server.__autoEncryptLocalhost__originalListen = server.listen | ||
server.listen = patchedListen | ||
// Monkey-patch server’s close method so we can perform clean-up and | ||
// shut down HTTP redirection server transparently when server.close() is called. | ||
// This also means the close() method is now async. | ||
server.__autoEncryptLocalhost__originalClose = server.close.bind(server) | ||
server.close = patchedClose | ||
return server | ||
} | ||
} |
{ | ||
"name": "@small-tech/auto-encrypt-localhost", | ||
"version": "8.3.2", | ||
"version": "8.4.0", | ||
"engines": { | ||
@@ -19,3 +19,3 @@ "node": ">=18.2.0" | ||
"bin": { | ||
"auto-encrypt-localhost": "./bin/index.js" | ||
"auto-encrypt-localhost": "bin/index.js" | ||
}, | ||
@@ -39,3 +39,3 @@ "type": "module", | ||
"coverage-debug": "npm run unlockSudo && c8 tape 'test/**/*.js' | tap-monkey", | ||
"generate-dependency-diagram": "mkdir -p artefacts && node_modules/.bin/depcruise --collapse '^node_modules/[^/]+' --output-type dot index.js | dot -T svg > artefacts/dependency-graph.svg", | ||
"generate-dependency-diagram": "mkdir -p artefacts && node_modules/.bin/depcruise --no-config --collapse '^node_modules/[^/]+' --output-type dot index.js | dot -T svg > artefacts/dependency-graph.svg", | ||
"generate-developer-documentation": "npm run generate-dependency-diagram && node_modules/.bin/jsdoc2md --private --template developer-documentation.hbs --files index.js > developer-documentation.md" | ||
@@ -69,8 +69,7 @@ }, | ||
"@small-tech/tap-monkey": "^1.4.0", | ||
"bent": "^7.3.12", | ||
"c8": "^7.12.0", | ||
"dependency-cruiser": "^12.4.0", | ||
"jsdoc-to-markdown": "^8.0.0", | ||
"tape": "^5.6.1" | ||
"c8": "^9.1.0", | ||
"dependency-cruiser": "^16.2.3", | ||
"jsdoc-to-markdown": "^8.0.1", | ||
"tape": "^5.7.5" | ||
} | ||
} |
@@ -137,7 +137,11 @@ # Auto Encrypt Localhost | ||
server.listen(443, () => { | ||
console.log('Web server is running at https://localhost') | ||
}) | ||
await server.listen(443) | ||
console.log(`Web server is running at https://localhost:${server.address().port}`) | ||
``` | ||
> 💡 Note that unlike Node’s regular `https` server, the `listen()` and `close()` methods are – as of version 8.4.0 – _asynchronous_. To maintain compatibility with earlier versions, you can still pass a callback to the methods and use exactly the same method signatures as Node’s regular methods. Unless you’re creating multiple servers, in normal usage, it should not make a huge difference whether you `await` the results of these methods or not but, for correctness, you should. | ||
> | ||
> Also, note that if you await the `close()` method, it will return only when Node’s own `https` server’s close callback is called. Unlike Node’s native `close()` method, Auto Encrypt Localhost’s method also calls `closeAllConnections()` so it will not wait for active connections to complete but sever them immediately. | ||
On first run, Auto Encrypt Localhost will create your local certificate authority and install it in the system root store and in Firefox. These actions require elevated privileges and you will be prompted for your password unless you have passwordless sudo set up for your system. | ||
@@ -225,6 +229,2 @@ | ||
### On Linux | ||
@@ -231,0 +231,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
64533
5
1003
2