@small-tech/https 5.4.0 → 6.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.
Files changed (3) hide show
  1. package/README.md +18 -13
  2. package/index.js +48 -50
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -12,7 +12,7 @@ Simply replace Node’s `https` module with `@small-tech/https` and get:
12
12
 
13
13
  That’s it.
14
14
 
15
- ___Note:__ This is a standard ECMAScript Modules (ESM; es6 modules) project. If you need to use legacy CommonJS, [please see the 2.x branch](https://github.com/small-tech/https/tree/2.x) which is deprecated but still receives bug fixes._
15
+ ***Note:** This is a standard ECMAScript Modules (ESM; es6 modules) project. If you need to use legacy CommonJS, [please see the 2.x branch](https://github.com/small-tech/https/tree/2.x) which is deprecated but still receives bug fixes.*
16
16
 
17
17
  ## System requirements
18
18
 
@@ -24,11 +24,12 @@ __Tested and supported on:__
24
24
 
25
25
  - Linux (tested on Fedora Silverblue 37 and Ubuntu 22.04)
26
26
  - macOS (tested on Intel: Monterey, M1: Ventura, M4: Sequoia)
27
- - Windows (10 and 11 under Windows Terminal and with Windows PowerShell)
28
27
 
29
28
  > 💡 On macOS, if you’re using a third-party terminal application like iTerm, you must give it Full Disk Access rights or @small-tech/https will fail to install the policy file inside Firefox when creating local development servers. You can do this on the latest version of the operating system by adding iTerm to the list at System Settings → Privacy & Security → Full Disk Access.
30
29
 
31
- > 💡 On Windows, @small-tech/https will also run under WSL 2 but this is not recommended when creating local development servers as local development certificates will not be automatically installed in your Windows browsers for you since your guest Linux system knows nothing about and cannot configure your host Windows environment.
30
+ > 💡 Windows support has been removed as [Microsoft is complicit in Israel’s genocide of the Palestinian people](https://www.bdsmovement.net/microsoft) and [Small Technology Foundation](https://small-tech.org/) stands in solidarity with the [Boycott, Divestment, and Sanctions (BDS) movement](https://www.bdsmovement.net/). **Windows is an ad-infested and surveillance-ridden dumpster fire of an operating system and, alongside supporting genocide, you are putting both yourself and others at risk by using it.**
31
+ >
32
+ > 🇵🇸 To support families facing genocide in Gaza, consider [donating to them via Gaza Verified](https://gaza-verified.org/donate/).
32
33
 
33
34
  ## Testing
34
35
 
@@ -81,19 +82,21 @@ npm i @small-tech/https
81
82
  ```js
82
83
  import https from '@small-tech/https'
83
84
 
84
- const server = https.createServer((request, response) => {
85
+ const server = await https.createServer((request, response) => {
85
86
  response.end('Hello, world!')
86
87
  })
87
88
 
88
- server.listen(443, () => {
89
- console.log(' 🎉 Server running at https://localhost.')
90
- })
89
+ await server.listen(443)
90
+
91
+ console.info(' 🎉 Server running at https://localhost.')
91
92
  ```
92
93
 
93
94
  Hit `https://localhost` and you should see your site with locally-trusted TLS certificates.
94
95
 
95
96
  > 💡 As of version 5.2.0, you can also use the localhost aliases _place1.localhost_ - _place4.localhost_ when testing the peer-to-peer features of [Small Web](https://ar.al/2020/08/07/what-is-the-small-web/) apps.
96
97
 
98
+ > 💡 You can have a maximum of one server per Node process.
99
+
97
100
  @small-tech/https uses [Auto Encrypt Localhost](https://codeberg.org/small-tech/auto-encrypt-localhost) to create a local Certificate Authority (cA) and add it to the various trust stores. It then uses that CA to create locally-trusted TLS certificates that are automatically used by your server.
98
101
 
99
102
  ### At hostname with automatically-provisioned Let’s Encrypt certificates.
@@ -105,18 +108,20 @@ import os form 'os'
105
108
  const hostname = os.hostname()
106
109
  const options = { domains: [hostname] }
107
110
 
108
- const server = https.createServer((request, response) => {
111
+ const server = await https.createServer((request, response) => {
109
112
  response.end('Hello, world!')
110
113
  })
111
114
 
112
- server.listen(443, () => {
113
- console.log(` 🎉 Server running at https://${hostname}.`)
114
- })
115
+ await server.listen(443)
116
+
117
+ console.info(` 🎉 Server running at https://${hostname}.`)
115
118
  ```
116
119
 
117
120
  To provision globally-trusted Let’s Encrypt certificates, we additionally create an `options` object containing the domain(s) we want to support, and pass it as the first argument in the `createServer()` method.
118
121
 
119
- @small-tech/https automatically provisions Let’s Encrypt certificates for you the first time your server is hit using [Auto Encrypt](https://codeberg.org/small-tech/auto-encrypt) (this first load will take longer than future ones). During this initial load, other requests are ignored. This module will also automatically renew your certificates as necessary in plenty of time before they expire.
122
+ > 💡 As of version 6, you can also pass the options `ipv4:true` and `ipv6:true` to automatically provision certificates for your server’s externally-reachable IPv4 address (as determined by hitting https://ip.small-web.org) and any locally-detected stable IPv6 addresses, respectively. You can also pass `ipOnly:true` to _only_ provision certificates for IP addresses (and ignore the automatically-detected hostname or any domains passed in the `domains` array).
123
+
124
+ @small-tech/https automatically provisions Let’s Encrypt certificates for you when your server starts using [Auto Encrypt](https://codeberg.org/small-tech/auto-encrypt) This module will also automatically renew your certificates as necessary in plenty of time before they expire.
120
125
 
121
126
  You can find a version of this example in the `/example` folder. To download and run that version:
122
127
 
@@ -150,7 +155,7 @@ Or, if you want to cling to ancient historic relics like a conservative to a rac
150
155
  sudo setcap cap_net_bind_service=+ep $(which node)
151
156
  ```
152
157
 
153
- If you are wrapping your Node app into an executable binary using a module like [Nexe](https://github.com/nexe/nexe), you will have to ensure that every build of your app has that capability set. For an example of how we do this in [Site.js](https://sitejs.org), [see this listing](https://source.ind.ie/site.js/app/blob/master/bin/lib/ensure.js#L124).
158
+ If you are wrapping your Node app into an executable binary using a module like [Nexe](https://github.com/nexe/nexe), you will have to ensure that every build of your app has that capability set. For an example of how we do this in [Site.js](https://sitejs.org), [see this listing](https://codeberg.org/site.js/app/src/branch/main/bin/lib/ensure.js#L127).
154
159
 
155
160
  ## Related projects
156
161
 
package/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import os from 'node:os'
2
2
  import process from 'node:process'
3
3
  import path from 'node:path'
4
- import https from 'node:https'
5
4
  import EventEmitter from 'node:events'
6
5
 
7
6
  import AutoEncrypt from '@small-tech/auto-encrypt'
@@ -26,56 +25,55 @@ const DATA_HOME = path.join(
26
25
  export const SMALL_TECH_HOME_PATH = path.join(DATA_HOME, 'small-tech.org')
27
26
  export const DEFAULT_SETTINGS_PATH = path.join(SMALL_TECH_HOME_PATH, 'https')
28
27
 
29
- // Only modify this instance of the https module with our own createServer method.
30
- const smallTechHttps = Object.assign({}, https)
31
-
32
- smallTechHttps.createServer = function (options, listener) {
33
- // The first parameter is optional. If omitted, listener should be passed as the first argument.
34
- if (typeof options === 'function') {
35
- listener = options
36
- options = {}
37
- }
38
-
39
- const localDomains = ['localhost', 'place1.localhost', 'place2.localhost', 'place3.localhost', 'place4.localhost']
40
- const isLocal = options.domains == undefined || options.domains.some(domain => localDomains.includes(domain))
41
- const serverScope = isLocal ? 'local' : 'global'
42
- const settingsPath = options.settingsPath ? path.join(path.resolve(options.settingsPath), serverScope) : path.join(DEFAULT_SETTINGS_PATH, serverScope)
43
- options.settingsPath = settingsPath
44
-
45
- if (options.staging) { options.serverType = AUTO_ENCRYPT_STAGING_SERVER_TYPE }
46
- delete options.staging
47
-
48
- const autoEncryptScope = {
49
- local: AutoEncryptLocalhost,
50
- global: AutoEncrypt
51
- }
52
-
53
- const messageSuffix = {
54
- local: 'at localhost with locally-trusted certificates',
55
- global: 'with globally-trusted Let’s Encrypt certificates'
56
- }
57
- events.emit(events.CREATING_SERVER, `Creating server ${messageSuffix[serverScope]}.`)
58
-
59
- const server = autoEncryptScope[serverScope].https.createServer(options, listener)
60
-
61
- function emitCloseEvent() {
62
- events.emit(events.SERVER_CLOSED, 'Server closed.')
63
- }
64
-
65
- if (serverScope === 'global') {
66
- // Allow AutoEncrypt to perform clean-up (e.g., remove interval timer for renewal check, etc.)
67
- server.on('close', () => {
68
- AutoEncrypt.shutdown()
69
- emitCloseEvent()
70
- })
71
- } else {
72
- // No additional clean-up required for Auto Encrypt Localhost.
28
+ export default class https {
29
+ /** @type { import('@small-tech/auto-encrypt-localhost').AutoEncryptedLocalhostServer| import('@small-tech/auto-encrypt').AutoEncryptedServer} */
30
+ static server = null
31
+
32
+ /**
33
+ Creates new AutoEncryped or AutoEncrypedLocalhost https server (asynchronous).
34
+
35
+ @param {import('./index.d.ts').SmallTechHttpsOptions | import('node:http').RequestListener} [options]
36
+ @param {import('node:http').RequestListener} [listener]
37
+ */
38
+ static async createServer (options = {}, listener) {
39
+ // There can be only server per node process. Enforce that here.
40
+ if (this.server !== null) {
41
+ console.warn('Create server called when server already exists for this process. Returning existing server instance.')
42
+ return this.server
43
+ }
44
+
45
+ // The first parameter is optional. If omitted, listener should be passed as the first argument.
46
+ if (typeof options === 'function') {
47
+ listener = /** @type {import('node:http').RequestListener} */ (options)
48
+ options = {}
49
+ }
50
+
51
+ const localDomains = ['localhost', 'place1.localhost', 'place2.localhost', 'place3.localhost', 'place4.localhost']
52
+ const isLocal = (options.domains == undefined || options.domains.some(domain => localDomains.includes(domain))) && !options.ipv4 && !options.ipv6 && !options.ipOnly
53
+ const serverScope = isLocal ? 'local' : 'global'
54
+ const settingsPath = options.settingsPath ? path.join(path.resolve(options.settingsPath), serverScope) : path.join(DEFAULT_SETTINGS_PATH, serverScope)
55
+ options.settingsPath = settingsPath
56
+
57
+ if (options.staging) { options.serverType = AUTO_ENCRYPT_STAGING_SERVER_TYPE }
58
+ delete options.staging
59
+
60
+ const messageSuffix = {
61
+ local: 'at localhost with locally-trusted certificates',
62
+ global: 'with globally-trusted Let’s Encrypt certificates'
63
+ }
64
+ events.emit(events.CREATING_SERVER, `Creating server ${messageSuffix[serverScope]}.`)
65
+
66
+ const server = await (serverScope === 'local'
67
+ ? AutoEncryptLocalhost.https.createServer(options, listener)
68
+ : AutoEncrypt.https.createServer(options, listener))
69
+
70
+ function emitCloseEvent() {
71
+ events.emit(events.SERVER_CLOSED, 'Server closed.')
72
+ }
73
73
  server.on('close', emitCloseEvent)
74
- }
75
74
 
76
- events.emit(events.SERVER_CREATED, 'Created HTTPS server.')
75
+ events.emit(events.SERVER_CREATED, 'Created HTTPS server.')
77
76
 
78
- return server
77
+ return server
78
+ }
79
79
  }
80
-
81
- export default smallTechHttps
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@small-tech/https",
3
- "version": "5.4.0",
3
+ "version": "6.0.0",
4
4
  "description": "A drop-in standard Node.js HTTPS module replacement with both automatic development-time (localhost) certificates via Auto Encrypt Localhost and automatic production certificates via Auto Encrypt.",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -49,13 +49,13 @@
49
49
  },
50
50
  "license": "AGPL-3.0",
51
51
  "dependencies": {
52
- "@small-tech/auto-encrypt": "^4.3.0",
53
- "@small-tech/auto-encrypt-localhost": "^8.3.2"
52
+ "@small-tech/auto-encrypt": "^5.0.0",
53
+ "@small-tech/auto-encrypt-localhost": "^10.0.0"
54
54
  },
55
55
  "devDependencies": {
56
- "@small-tech/cross-platform-hostname": "^1.0.0",
57
56
  "@small-tech/esm-tape-runner": "^1.0.3",
58
57
  "@small-tech/tap-monkey": "^1.3.0",
58
+ "@types/node": "^25.0.9",
59
59
  "bent": "^7.3.12",
60
60
  "c8": "^7.6.0",
61
61
  "tape": "^5.2.2"