@small-tech/auto-encrypt 3.0.1 → 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
 
@@ -266,7 +271,7 @@ We exist in part thanks to patronage by people like you. If you share [our visio
266
271
 
267
272
  ## Copyright
268
273
 
269
- © 2020-2021 [Aral Balkan](https://ar.al), [Small Technology Foundation](https://small-tech.org).
274
+ © 2020-present [Aral Balkan](https://ar.al), [Small Technology Foundation](https://small-tech.org).
270
275
 
271
276
  Let’s Encrypt is a trademark of the Internet Security Research Group (ISRG). All rights reserved. Node.js is a trademark of Joyent, Inc. and is used with its permission. We are not endorsed by or affiliated with Joyent or ISRG.
272
277
 
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
  }
package/lib/acmeCsr.js CHANGED
@@ -62,7 +62,7 @@ function csrAsPem (domains, key) {
62
62
  }]
63
63
  }])
64
64
 
65
- csr.sign(keys.private)
65
+ csr.sign(keys.private, forge.md.sha256.create())
66
66
 
67
67
  const pem = forge.pki.certificationRequestToPem(csr)
68
68
  return pem
@@ -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.0.1",
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",
67
- "node-forge": "^0.10.0",
68
- "ocsp": "^1.2.0",
69
- "server-destroy": "^1.0.1"
69
+ "jose": "^1.28.2",
70
+ "moment": "^2.29.4",
71
+ "node-forge": "^1.3.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.6.0",
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
  }
package/CHANGELOG.md DELETED
@@ -1,120 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
-
7
- ## [3.0.1] - 2021-03-21
8
-
9
- Fixes regression on Windows introduced in 3.x branch.
10
-
11
- ### Fixed
12
-
13
- - Make `__dirname` declaration cross-platform (was previously failing on Windows). See https://github.com/nodejs/node/issues/37845
14
- - Introduce small delay in request fail check test while certificate is being provisioned to ensure tests pass with Let’s Encrypt staging server.
15
-
16
- ## [3.0.0] - 2021-03-08
17
-
18
- ### Changed
19
-
20
- - __Breaking change:__ Is now an ECMAScript Modules (ESM) project.
21
- - Now includes the latest Let’s Encrypt certificate authority root certificate for the staging environment. (This is automatically injected into your Node.js environment when running the server in staging mode and is used during testing.)
22
- - Dev: now using @small-tech/esm-tape-runner.
23
- - Dev: replaced tap-spec and tap-nyc with @small-tech/tap-monkey.
24
-
25
- ### Fixed
26
-
27
- - No longer crashes when checking for certificate renewal. (#34)
28
- - Tests now run properly in staging mode.
29
-
30
- ### Improved
31
-
32
- - npm package size is now 193.1kb (down from 345kb previously).
33
-
34
- ## [2.1.0 and 2.1.1] - Do not use these versions.
35
-
36
- These accidentally included the breaking change from 3.0.0 in a semver minor update.
37
-
38
- _The CommonJS version of Auto Encrypt now lives in the 2.x branch and the first release from it is version 2.2.0 which has the bug fix and the root certificate update from version 3.0.0 backported. For future 2.x release info, please see the changelog in the 2.x branch._
39
-
40
- ## [2.0.6] - 2021-02-16
41
-
42
- ### Fixed
43
-
44
- - Assignment to constant. This would have caused a crash when a `Retry-After` header was received from Let’s Encrypt.
45
-
46
- ### Improved
47
-
48
- - Developer documentation. Now lists value to be added to hosts files to run local tests.
49
-
50
- ## [2.0.5] - 2020-10-29
51
-
52
- ### Improved
53
-
54
- - Update dependencies to remove npm vulnerability warnings.
55
-
56
- ## [2.0.4] - 2020-07-10
57
-
58
- ### Fixed
59
-
60
- - HTTP to HTTPS redirects now start up and work as they should (they weren’t previously).
61
-
62
- ## [2.0.3] - 2020-07-10
63
-
64
- ### Changed
65
-
66
- - Update source code repository in npm package to point to GitHub mirror. (The GitHub mirror is the public repository where we can accept issues and pull requests. [The canonical repository](https://source.small-tech.org/site.js/lib/auto-encrypt) is on our own server where we do not accept sign ups as we don’t want it to become yet another centralised host.)
67
-
68
- ## [2.0.2] - 2020-07-10
69
-
70
- ### Fixed
71
-
72
- - Links to developer documentation now work everywhere, not just on source code repository web interfaces.
73
-
74
- ### Changed
75
-
76
- - Replaced outdated coverage message in readme and linked to developer documentation for information on tests and coverage.
77
-
78
- ## [2.0.1] - 2020-07-03
79
-
80
- ### Added
81
-
82
- - HTTP to HTTPS redirects are now logged.
83
-
84
- ## [2.0.0] - 2020-07-03
85
-
86
- ### Changed
87
-
88
- - Breaking change: you no longer have to call AutoEncrypt.shutdown() manually. Closing your server will do it automatically (#33).
89
-
90
- ### Added
91
-
92
- - Automatic HTTP to HTTPS redirection. An HTTP server is now kept running for the lifetime of your HTTPS server and, when it is not responding to Let’s Encrypt challenges, it redirects HTTP calls on port 80 to your HTTPS server (#32).
93
-
94
- ## [1.0.3] - 2020-06-20
95
-
96
- ### Fixed
97
-
98
- - Carriage returns are now stripped from Certificate Signing Requests (CSRs) (#31).
99
-
100
- ## [1.0.2] - 2020-06-16
101
-
102
- ### Fixed
103
-
104
- - No longer crashes if OCSP request received before certificate created.
105
- - Cosmetic: format certificate details nicely in log message.
106
- - Minor: fix capitalisation in log message.
107
-
108
- ## [1.0.1] - 2020-06-15
109
-
110
- ### Changed
111
-
112
- - Update log format to match Site.js output.
113
-
114
- ### Fixed
115
-
116
- - Remove debug output.
117
-
118
- ## [1.0.0] - 2020-04-15
119
-
120
- Initial release.