@small-tech/auto-encrypt 3.1.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,12 +2,20 @@
2
2
 
3
3
  Adds automatic provisioning and renewal of [Let’s Encrypt](https://letsencrypt.org) TLS certificates with [OCSP Stapling](https://letsencrypt.org/docs/integration-guide/#implement-ocsp-stapling) to [Node.js](https://nodejs.org) [https](https://nodejs.org/dist/latest-v12.x/docs/api/https.html) servers (including [Express.js](https://expressjs.com/), etc.)
4
4
 
5
+ Implements the subset of RFC 8555 – Automatic Certificate Management Environment (ACME) – necessary for a client to support TLS certificate provisioning from Let’s Encrypt using HTTP-01 challenges.
6
+
5
7
  ## How it works
6
8
 
7
9
  The first time your web site is hit, it will take a couple of seconds to load as your Let’s Encrypt TLS certificates are automatically provisioned for you. From there on, your certificates will be seamlessly renewed 30 days before their expiry date.
8
10
 
9
11
  When not provisioning certificates, Auto Encrypt will also forward HTTP calls to HTTPS on your server.
10
12
 
13
+ ## Compatibility
14
+
15
+ All tests pass on Node.js LTS (18.2+).
16
+
17
+ [Tests fail on Node.js 19 (socket hang up error).](https://codeberg.org/small-tech/auto-encrypt/issues/3)
18
+
11
19
  ## Installation
12
20
 
13
21
  ```sh
@@ -19,31 +27,30 @@ npm i @small-tech/auto-encrypt
19
27
  ### Instructions
20
28
 
21
29
  1. Import the module:
22
-
23
- ```js
24
- import AutoEncrypt from '@small-tech/auto-encrypt'
25
- ```
30
+
31
+ ```js
32
+ import AutoEncrypt from '@small-tech/auto-encrypt'
33
+ ```
26
34
 
27
35
  2. Prefix your server creation code with a reference to the Auto Encrypt class:
28
-
29
- ```js
30
- // const server = https.createServer(…) becomes
31
- const server = AutoEncrypt.https.createServer(…)
32
- ```
36
+
37
+ ```js
38
+ // const server = https.createServer(…) becomes
39
+ const server = AutoEncrypt.https.createServer(…)
40
+ ```
33
41
 
34
42
  3. When done, close your server as you would normally:
35
-
36
- ```js
37
- server.close(() => {
38
- console.log('The server is now closed.')
39
- })
40
- ```
43
+
44
+ ```js
45
+ server.close(() => {
46
+ console.log('The server is now closed.')
47
+ })
48
+ ```
41
49
 
42
50
  ### Example
43
51
 
44
52
  The following code creates an HTTPS server running on port 443 with [OCSP Stapling](https://letsencrypt.org/docs/integration-guide/#implement-ocsp-stapling) that automatically provisions and renews TLS certificates from [Let’s Encrypt](https://letsencrypt.org) for the domains _<hostname>_ and _www.<hostname>_.
45
53
 
46
-
47
54
  ```js
48
55
  import AutoEncrypt from '@small-tech/auto-encrypt'
49
56
 
@@ -94,9 +101,9 @@ const server = AutoEncrypt.https.createServer(options, listener)
94
101
 
95
102
  Here is the full list of Auto Encrypt options (all optional) and their defaults:
96
103
 
97
- - `domains`: the hostname of the current computer and the www subdomain at that hostname.
98
- - `server`: it will use the production server (which has [rate limits](https://letsencrypt.org/docs/rate-limits/)). Valid values are `AutoEncrypt.server.(PEBBLE|STAGING|PRODUCTION)`.
99
- - `settingsPath`: _~/.small-tech.org/auto-encrypt/_
104
+ - `domains`: the hostname of the current computer and the www subdomain at that hostname.
105
+ - `server`: it will use the production server (which has [rate limits](https://letsencrypt.org/docs/rate-limits/)). Valid values are `AutoEncrypt.server.(PEBBLE|STAGING|PRODUCTION)`.
106
+ - `settingsPath`: _~/.small-tech.org/auto-encrypt/_
100
107
 
101
108
  ## Making a graceful exit
102
109
 
@@ -174,10 +181,9 @@ Auto Encrypt does one thing and one thing well: it automatically provisions a Le
174
181
 
175
182
  Auto Encrypt __does not_ and __will not__:
176
183
 
177
- - Implement wildcard certificates. For most [small tech](https://small-tech.org/about/#small-technology) needs (personal web sites and web apps), you will likely need no more than two domains (the root domain and, due to historic and conventional reasons, the www subdomain). You will definitely not need more than the 100 domains that are supported per certificate. If you do, chances are you are looking to use Auto Encrypt in a startup or corporate setting, which is not what its for.
178
-
179
- - Implement DNS-01 or any other methods that cannot be fully automated.
184
+ - Implement wildcard certificates. For most [small tech](https://small-tech.org/about/#small-technology) needs (personal web sites and web apps), you will likely need no more than two domains (the root domain and, due to historic and conventional reasons, the www subdomain). You will definitely not need more than the 100 domains that are supported per certificate. If you do, chances are you are looking to use Auto Encrypt in a startup or corporate setting, which is not what its for.
180
185
 
186
+ - Implement DNS-01 or any other methods that cannot be fully automated.
181
187
 
182
188
  ## Staging and production server behaviour and rate limits
183
189
 
@@ -191,29 +197,28 @@ If you do use the staging environment, be aware that browsers will reject the st
191
197
 
192
198
  Needless to say, do not add the fake certificate root to the same trust store you use for your everyday browsing.
193
199
 
194
-
195
200
  ## Related projects
196
201
 
197
202
  From lower-level to higher-level:
198
203
 
199
204
  ### Auto Encrypt Localhost
200
205
 
201
- - Source: https://source.small-tech.org/site.js/lib/auto-encrypt-localhost
202
- - Package: [@small-tech/auto-encrypt-localhost](https://www.npmjs.com/package/@small-tech/auto-encrypt-localhost)
206
+ - Source: https://source.small-tech.org/site.js/lib/auto-encrypt-localhost
207
+ - Package: [@small-tech/auto-encrypt-localhost](https://www.npmjs.com/package/@small-tech/auto-encrypt-localhost)
203
208
 
204
209
  Automatically provisions and installs locally-trusted TLS certificates for Node.js https servers (including Express.js, etc.) using [mkcert](https://github.com/FiloSottile/mkcert/).
205
210
 
206
211
  ### HTTPS
207
212
 
208
- - Source: https://source.small-tech.org/site.js/lib/https
209
- - Package: [@small-tech/https](https://www.npmjs.com/package/@small-tech/https)
213
+ - Source: https://source.small-tech.org/site.js/lib/https
214
+ - Package: [@small-tech/https](https://www.npmjs.com/package/@small-tech/https)
210
215
 
211
216
  A drop-in [standard Node.js HTTPS module](https://nodejs.org/dist/latest-v12.x/docs/api/https.html) replacement with both automatic development-time (localhost) certificates via Auto Encrypt Localhost and automatic production certificates via Auto Encrypt.
212
217
 
213
218
  ### Site.js
214
219
 
215
- - Web site: https://sitejs.org
216
- - Source: https://source.small-tech.org/site.js/app
220
+ - Web site: https://sitejs.org
221
+ - Source: https://source.small-tech.org/site.js/app
217
222
 
218
223
  A complete [small technology](https://small-tech.org/about/#small-technology) tool for developing, testing, and deploying a secure static or dynamic personal web site or app with zero configuration.
219
224
 
package/index.js CHANGED
@@ -24,6 +24,11 @@ import Throws from './lib/util/Throws.js'
24
24
  import HttpServer from './lib/HttpServer.js'
25
25
  import log from './lib/util/log.js'
26
26
 
27
+ // This reverts IP address sort order to pre-Node 17 behaviour.
28
+ // See https://github.com/nodejs/node/issues/40537
29
+ import dns from 'node:dns'
30
+ dns.setDefaultResultOrder('ipv4first')
31
+
27
32
  // Custom errors thrown by the autoEncrypt function.
28
33
  const throws = new Throws({
29
34
  [Symbol.for('BusyProvisioningCertificateError')]:
package/lib/HttpServer.js CHANGED
@@ -18,7 +18,7 @@
18
18
  // B. At all other times:
19
19
  // ======================
20
20
  //
21
- // Forwards http requests to https requests using a 302 redirect.
21
+ // Forwards http requests to https requests using a 307 redirect.
22
22
  //
23
23
  // Copyright © 2020 Aral Balkan, Small Technology Foundation.
24
24
  // License: AGPLv3 or later.
@@ -27,7 +27,6 @@
27
27
 
28
28
  import http from 'http'
29
29
  import encodeUrl from 'encodeurl'
30
- import enableDestroy from 'server-destroy'
31
30
  import log from './util/log.js'
32
31
 
33
32
  export default class HttpServer {
@@ -120,18 +119,13 @@ export default class HttpServer {
120
119
  response.end()
121
120
  }
122
121
  })
123
-
124
- // Enable server to be destroyed without waiting for any existing connections to close.
125
- // (While there shouldn’t be any existing connections and while the likelihood of someone
126
- // trying to denial-of-service this very low, it’s still the right thing to do.)
127
- enableDestroy(this.server)
128
122
  }
129
123
 
130
124
  set challengeServer (state) {
131
125
  if (state) {
132
126
  log(` 🔒 ❨auto-encrypt❩ HTTP server is now only responding to Let’s Encrypt challenges.`)
133
127
  } else {
134
- log(` 🔒 ❨auto-encrypt❩ HTTP server is now forwarding HTTP requests to HTTPS (302).`)
128
+ log(` 🔒 ❨auto-encrypt❩ HTTP server is now forwarding HTTP requests to HTTPS (307).`)
135
129
  }
136
130
  this.#isChallengeServer = state
137
131
  }
@@ -156,16 +150,16 @@ export default class HttpServer {
156
150
 
157
151
  async destroy () {
158
152
  // Starts killing all connections and closes the server.
159
- this.server.destroy()
153
+ this.server.closeAllConnections()
160
154
 
161
- // Wait until the server is closed before returning.
162
155
  await new Promise((resolve, reject) => {
163
- this.server.on('close', () => {
156
+ this.server.close(error => {
157
+ if (error) {
158
+ console.error(error)
159
+ reject(error)
160
+ }
164
161
  resolve()
165
162
  })
166
- this.server.on('error', (error) => {
167
- reject(error)
168
- })
169
163
  })
170
164
  }
171
165
  }
@@ -8,7 +8,6 @@ import fs from 'fs'
8
8
  import os from 'os'
9
9
  import path from 'path'
10
10
  import http from 'http'
11
- import enableServerDestroy from 'server-destroy'
12
11
  import Configuration from '../Configuration.js'
13
12
  import LetsEncryptServer from '../LetsEncryptServer.js'
14
13
  import Throws from '../util/Throws.js'
@@ -19,7 +18,7 @@ import log from '../util/log.js'
19
18
  //
20
19
 
21
20
  const throws = new Throws({
22
- [Symbol.for('MockServerCouldNotBeStartedError')]: details => `Mock server could not be started (${error})`
21
+ [Symbol.for('MockServerCouldNotBeStartedError')]: error => `Mock server could not be started (${error})`
23
22
  })
24
23
 
25
24
  export class MockServer {
@@ -45,7 +44,6 @@ export class MockServer {
45
44
 
46
45
  async create () {
47
46
  const server = http.createServer(this.#responseHandler)
48
- enableServerDestroy(server)
49
47
  this.#server = server
50
48
  await new Promise((resolve, reject) => {
51
49
  try {
@@ -60,12 +58,21 @@ export class MockServer {
60
58
  }
61
59
 
62
60
  async destroy () {
63
- this.#server.destroy()
61
+ this.#server.closeAllConnections()
62
+ return new Promise((resolve, reject) => {
63
+ this.#server.close(error => {
64
+ if (error) {
65
+ console.error(error)
66
+ reject(error)
67
+ }
68
+ resolve()
69
+ })
70
+ })
64
71
  }
65
72
  }
66
73
 
67
74
  export async function httpServerWithResponse (mockResponse) {
68
- return new Promise((resolve, reject) => {
75
+ return new Promise((resolve, _reject) => {
69
76
  const server = http.createServer((request, response) => {
70
77
  response.statusCode = mockResponse.statusCode
71
78
  response.end(mockResponse.body)
package/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "@small-tech/auto-encrypt",
3
- "version": "3.1.0",
3
+ "version": "4.0.0",
4
4
  "description": "Adds automatic provisioning and renewal of Let’s Encrypt TLS certificates with OCSP Stapling to Node.js https servers (including Express.js, etc.)",
5
+ "engines": {
6
+ "node": ">=18.2.0"
7
+ },
5
8
  "keywords": [
6
9
  "let's encrypt",
7
10
  "acme",
@@ -10,6 +13,7 @@
10
13
  "tls",
11
14
  "auto encrypt",
12
15
  "small tech",
16
+ "small web",
13
17
  "automatic"
14
18
  ],
15
19
  "author": {
@@ -60,24 +64,20 @@
60
64
  ]
61
65
  },
62
66
  "dependencies": {
63
- "bent": "aral/bent#errors-with-response-headers",
67
+ "bent": "^7.3.12",
64
68
  "encodeurl": "^1.0.2",
65
- "jose": "^1.24.0",
66
- "moment": "^2.24.0",
69
+ "jose": "^1.28.2",
70
+ "moment": "^2.29.4",
67
71
  "node-forge": "^1.3.1",
68
- "ocsp": "^1.2.0",
69
- "server-destroy": "^1.0.1"
72
+ "ocsp": "^1.2.0"
70
73
  },
71
74
  "devDependencies": {
72
75
  "@small-tech/esm-tape-runner": "^1.0.3",
73
76
  "@small-tech/node-pebble": "^4.2.4",
74
77
  "@small-tech/tap-monkey": "^1.3.0",
75
- "c8": "^7.11.3",
76
- "dependency-cruiser": "^9.15.1",
77
- "esbuild": "^0.8.53",
78
- "jsdoc": "^3.6.6",
78
+ "c8": "^7.12.0",
79
+ "dependency-cruiser": "^12.3.0",
79
80
  "jsdoc-to-markdown": "^6.0.1",
80
- "tape": "^5.2.1",
81
- "wtfnode": "^0.8.1"
81
+ "tape": "^5.2.1"
82
82
  }
83
83
  }