@small-tech/auto-encrypt 5.0.0 → 5.1.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/index.d.ts CHANGED
@@ -20,6 +20,9 @@ import { Server, ServerOptions } from 'node:https'
20
20
  import { SecureContext } from 'node:tls'
21
21
  import { IncomingMessage, ServerResponse } from 'node:http'
22
22
 
23
+ import IPAddresses from './lib/IPAddresses.js'
24
+ export { IPAddresses }
25
+
23
26
  /**
24
27
  Options for creating an AutoEncrypt server. Extends Node’s https.ServerOptions.
25
28
  */
package/index.js CHANGED
@@ -16,9 +16,10 @@
16
16
  @license AGPLv3 or later.
17
17
  */
18
18
 
19
- import os from 'os'
20
- import util from 'util'
21
- import https from 'https'
19
+ import os from 'node:os'
20
+ import util from 'node:util'
21
+ import net from 'node:net'
22
+ import https from 'node:https'
22
23
  import monkeyPatchTls from './lib/staging/monkeyPatchTls.js'
23
24
  import LetsEncryptServer from './lib/LetsEncryptServer.js'
24
25
  import Configuration from './lib/Configuration.js'
@@ -28,11 +29,9 @@ import Pluralise from './lib/util/Pluralise.js'
28
29
  import Throws from './lib/util/Throws.js'
29
30
  import HttpServer from './lib/HttpServer.js'
30
31
  import IPAddresses from './lib/IPAddresses.js'
32
+ export { IPAddresses }
31
33
  import log from './lib/util/log.js'
32
34
 
33
- // Use module-level await to ensure we have the IP address information we need.
34
- const ipAddresses = await IPAddresses.getInstanceAsync()
35
-
36
35
  // Custom errors thrown by the autoEncrypt function.
37
36
  const throws = new Throws({
38
37
  [Symbol.for('BusyProvisioningCertificateError')]:
@@ -152,37 +151,56 @@ export default class AutoEncrypt {
152
151
  defaultPebbleDomains.push('pebble')
153
152
  }
154
153
 
155
- if (options.ipv4 === true) {
156
- if (letsEncryptServer.type === LetsEncryptServer.type.PEBBLE) {
157
- const localIPv4Address = '127.0.0.1'
158
- defaultPebbleDomains.push(localIPv4Address)
159
- log(` 📍 ❨auto-encrypt❩ Will provision TLS certificate from Pebble server for local IPv4 address (${localIPv4Address})`)
160
- } else {
161
- if (ipAddresses.hasIPv4Address) {
162
- const ipv4Address = ipAddresses.ipv4Address
163
- defaultStagingAndProductionDomains.push(ipv4Address)
164
- log(` 📍 ❨auto-encrypt❩ Will provision TLS certificate for detected IPv4 address: ${ipv4Address}`)
154
+ // Check if the passed list of domains contains an IP address. If it does, we can skip our automatic IP address detection and use the provides ones.
155
+ let domainsListContainsAtLeastOneIPAddress = false
156
+ if (options.domains) {
157
+ const ip = options.domains.find(domain => net.isIP(domain) !== 0)
158
+ if (ip !== undefined) {
159
+ domainsListContainsAtLeastOneIPAddress = true
160
+ }
161
+ }
162
+
163
+ if (!domainsListContainsAtLeastOneIPAddress) {
164
+ // Domains list does not contain any IP addresses, if auto detection is requested, auto detect the requested IP types.
165
+
166
+ /** @type { IPAddresses } */
167
+ let ipAddresses
168
+ if (options.ipv4 === true || options.ipv6 === true) {
169
+ ipAddresses = await IPAddresses.getInstanceAsync()
170
+ }
171
+
172
+ if (options.ipv4 === true) {
173
+ if (letsEncryptServer.type === LetsEncryptServer.type.PEBBLE) {
174
+ const localIPv4Address = '127.0.0.1'
175
+ defaultPebbleDomains.push(localIPv4Address)
176
+ log(` 📍 ❨auto-encrypt❩ Will provision TLS certificate from Pebble server for local IPv4 address (${localIPv4Address})`)
165
177
  } else {
166
- throws.error(Symbol.for('IPv4AddressNotFound'))
178
+ if (ipAddresses.hasIPv4Address) {
179
+ const ipv4Address = ipAddresses.ipv4Address
180
+ defaultStagingAndProductionDomains.push(ipv4Address)
181
+ log(` 📍 ❨auto-encrypt❩ Will provision TLS certificate for detected IPv4 address: ${ipv4Address}`)
182
+ } else {
183
+ throws.error(Symbol.for('IPv4AddressNotFound'))
184
+ }
167
185
  }
168
186
  }
169
- }
170
187
 
171
- if (options.ipv6 === true) {
172
- if (letsEncryptServer.type === LetsEncryptServer.type.PEBBLE) {
173
- // IPv6: Pebble.
174
- const localIPv6Address = '::1'
175
- defaultPebbleDomains.push(localIPv6Address)
176
- log(` 📍 ❨auto-encrypt❩ Will provision TLS certificate from Pebble server for local IPv6 address (${localIPv6Address})`)
177
- } else {
178
- // IPv6: Staging and production.
179
- const ipv6Addresses = ipAddresses.ipv6Addresses
180
- if (ipv6Addresses.length > 0) {
181
- defaultStagingAndProductionDomains = defaultStagingAndProductionDomains.concat(ipv6Addresses)
182
- ipv6Addresses.forEach(ipv6Address => defaultPebbleDomains.push(ipv6Address))
183
- log(` 📍 ❨auto-encrypt❩ Will provision TLS certificate for detected stable IPv6 address${ipv6Addresses.length > 1 ? 'es' : ''}: ${ipv6Addresses}`)
188
+ if (options.ipv6 === true) {
189
+ if (letsEncryptServer.type === LetsEncryptServer.type.PEBBLE) {
190
+ // IPv6: Pebble.
191
+ const localIPv6Address = '::1'
192
+ defaultPebbleDomains.push(localIPv6Address)
193
+ log(` 📍 ❨auto-encrypt❩ Will provision TLS certificate from Pebble server for local IPv6 address (${localIPv6Address})`)
184
194
  } else {
185
- throws.error(Symbol.for('IPv6AddressNotFound'))
195
+ // IPv6: Staging and production.
196
+ const ipv6Addresses = ipAddresses.ipv6Addresses
197
+ if (ipv6Addresses.length > 0) {
198
+ defaultStagingAndProductionDomains = defaultStagingAndProductionDomains.concat(ipv6Addresses)
199
+ ipv6Addresses.forEach(ipv6Address => defaultPebbleDomains.push(ipv6Address))
200
+ log(` 📍 ❨auto-encrypt❩ Will provision TLS certificate for detected stable IPv6 address${ipv6Addresses.length > 1 ? 'es' : ''}: ${ipv6Addresses}`)
201
+ } else {
202
+ throws.error(Symbol.for('IPv6AddressNotFound'))
203
+ }
186
204
  }
187
205
  }
188
206
  }
@@ -11,6 +11,10 @@ import Throws from './util/Throws.js'
11
11
 
12
12
  const throws = new Throws()
13
13
 
14
+ /**
15
+ @typedef {{ ip: string }} IpAddressApiResponse
16
+ */
17
+
14
18
  export default class IPAddresses {
15
19
  /** @type {IPAddresses} */
16
20
  static instance
@@ -82,7 +86,7 @@ export default class IPAddresses {
82
86
  try {
83
87
  const response = await fetch('https://ip.small-web.org/json/')
84
88
  if (response.status === 200) {
85
- const ip = (await response.json()).ip
89
+ const ip = /** @type { IpAddressApiResponse } */ (await response.json()).ip
86
90
  if (ip !== '::1') {
87
91
  this.ipv4Address = ip
88
92
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@small-tech/auto-encrypt",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
4
4
  "description": "Automatically provisions and renews Let’s Encrypt TLS certificates on Node.js https servers (including Kitten, Polka, Express.js, etc.)",
5
5
  "engines": {
6
6
  "node": ">=18.20.0"
@@ -35,11 +35,11 @@
35
35
  "type": "foundation",
36
36
  "url": "https://small-tech.org/fund-us/"
37
37
  },
38
- "homepage": "https://github.com/small-tech/auto-encrypt",
39
- "bugs": "https://github.com/small-tech/auto-encrypt/issues",
38
+ "homepage": "https://codeberg.org/small-tech/auto-encrypt#readme",
39
+ "bugs": "https://codeberg.org/small-tech/auto-encrypt/issues",
40
40
  "repository": {
41
41
  "type": "git",
42
- "url": "https://github.com/small-tech/auto-encrypt.git"
42
+ "url": "https://codeberg.org/small-tech/auto-encrypt.git"
43
43
  },
44
44
  "scripts": {
45
45
  "test": "PEBBLE_VA_NOSLEEP=1 PEBBLE_WFE_NONCEREJECT=0 QUIET=true esm-tape-runner 'test/**/*.js' | tap-monkey",