@gjsify/tls 0.4.0 → 0.4.3

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/package.json CHANGED
@@ -1,44 +1,47 @@
1
1
  {
2
- "name": "@gjsify/tls",
3
- "version": "0.4.0",
4
- "description": "Node.js tls module for Gjs",
5
- "type": "module",
6
- "module": "lib/esm/index.js",
7
- "types": "lib/types/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./lib/types/index.d.ts",
11
- "default": "./lib/esm/index.js"
2
+ "name": "@gjsify/tls",
3
+ "version": "0.4.3",
4
+ "description": "Node.js tls module for Gjs",
5
+ "type": "module",
6
+ "module": "lib/esm/index.js",
7
+ "types": "lib/types/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/types/index.d.ts",
11
+ "default": "./lib/esm/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "lib"
16
+ ],
17
+ "scripts": {
18
+ "clear": "rm -rf lib tsconfig.tsbuildinfo tsconfig.types.tsbuildinfo test.gjs.mjs test.node.mjs || exit 0",
19
+ "check": "tsc --noEmit",
20
+ "build": "gjsify run build:gjsify && gjsify run build:types",
21
+ "build:gjsify": "gjsify build --library 'src/**/*.{ts,js}' --exclude 'src/**/*.spec.{mts,ts}' 'src/test.{mts,ts}'",
22
+ "build:types": "tsc",
23
+ "build:test": "gjsify run build:test:gjs && gjsify run build:test:node",
24
+ "build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
25
+ "build:test:node": "gjsify build src/test.mts --app node --outfile test.node.mjs",
26
+ "test": "gjsify run build:gjsify && gjsify run build:test && gjsify run test:node && gjsify run test:gjs",
27
+ "test:gjs": "gjsify run test.gjs.mjs",
28
+ "test:node": "node test.node.mjs"
29
+ },
30
+ "keywords": [
31
+ "gjs",
32
+ "node",
33
+ "tls"
34
+ ],
35
+ "devDependencies": {
36
+ "@gjsify/cli": "workspace:^",
37
+ "@gjsify/unit": "workspace:^",
38
+ "@types/node": "^25.6.2",
39
+ "typescript": "^6.0.3"
40
+ },
41
+ "dependencies": {
42
+ "@girs/gio-2.0": "2.88.0-4.0.0-rc.15",
43
+ "@girs/glib-2.0": "2.88.0-4.0.0-rc.15",
44
+ "@gjsify/net": "workspace:^",
45
+ "@gjsify/utils": "workspace:^"
12
46
  }
13
- },
14
- "scripts": {
15
- "clear": "rm -rf lib tsconfig.tsbuildinfo tsconfig.types.tsbuildinfo test.gjs.mjs test.node.mjs || exit 0",
16
- "check": "tsc --noEmit",
17
- "build": "yarn build:gjsify && yarn build:types",
18
- "build:gjsify": "gjsify build --library 'src/**/*.{ts,js}' --exclude 'src/**/*.spec.{mts,ts}' 'src/test.{mts,ts}'",
19
- "build:types": "tsc",
20
- "build:test": "yarn build:test:gjs && yarn build:test:node",
21
- "build:test:gjs": "gjsify build src/test.mts --app gjs --outfile test.gjs.mjs",
22
- "build:test:node": "gjsify build src/test.mts --app node --outfile test.node.mjs",
23
- "test": "yarn build:gjsify && yarn build:test && yarn test:node && yarn test:gjs",
24
- "test:gjs": "gjsify run test.gjs.mjs",
25
- "test:node": "node test.node.mjs"
26
- },
27
- "keywords": [
28
- "gjs",
29
- "node",
30
- "tls"
31
- ],
32
- "devDependencies": {
33
- "@gjsify/cli": "^0.4.0",
34
- "@gjsify/unit": "^0.4.0",
35
- "@types/node": "^25.6.2",
36
- "typescript": "^6.0.3"
37
- },
38
- "dependencies": {
39
- "@girs/gio-2.0": "2.88.0-4.0.0-rc.15",
40
- "@girs/glib-2.0": "2.88.0-4.0.0-rc.15",
41
- "@gjsify/net": "^0.4.0",
42
- "@gjsify/utils": "^0.4.0"
43
- }
44
- }
47
+ }
package/src/cert.spec.ts DELETED
@@ -1,230 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- // Ported from refs/node-test/parallel/test-tls-check-server-identity.js,
3
- // refs/node-test/parallel/test-tls-canonical-ip.js,
4
- // refs/node-test/parallel/test-tls-checkserveridentity-no-altnames.js.
5
- // Original: Copyright (c) Node.js contributors. MIT.
6
- // Rewritten for @gjsify/unit — behavior preserved, assertion dialect adapted.
7
- //
8
- // Focused coverage of RFC 6125 (§6.4.3) hostname matching + getPeerCertificate
9
- // shape + createSecureContext PEM acceptance. Complements index.spec.ts.
10
-
11
- import { describe, it, expect, on } from '@gjsify/unit';
12
- import {
13
- checkServerIdentity,
14
- createSecureContext,
15
- } from 'node:tls';
16
- import type { PeerCertificate } from 'node:tls';
17
-
18
- function fakeCert(parts: Record<string, unknown>): PeerCertificate {
19
- return parts as unknown as PeerCertificate;
20
- }
21
-
22
- // Self-signed PEM (cert + key) minted with `openssl req -x509 -newkey rsa:2048
23
- // -keyout key.pem -out cert.pem -days 3650 -nodes -subj /CN=test.example`.
24
- // 2048-bit RSA, SHA256, no SAN. Used only for parser smoke-tests — never
25
- // trusted as a CA. Inlined so tests stay hermetic (no fixtures).
26
- const SAMPLE_CERT_PEM = `-----BEGIN CERTIFICATE-----
27
- MIIDDzCCAfegAwIBAgIUO9v7luuPxFHsLdVr//dOTh474OQwDQYJKoZIhvcNAQEL
28
- BQAwFzEVMBMGA1UEAwwMdGVzdC5leGFtcGxlMB4XDTI2MDUwOTA2NDIyMVoXDTM2
29
- MDUwNjA2NDIyMVowFzEVMBMGA1UEAwwMdGVzdC5leGFtcGxlMIIBIjANBgkqhkiG
30
- 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtnMdp3rW+bkeYoW9at2aRt70gub5siMsNOYw
31
- 0obCo1LOkJokEOX2+9kaOUwaCmntcJdU3+JYQe7MGYwI+H9OWxnLRYJUneYB81a8
32
- CfJ7Uk+5FVNzQQFnYvL0G5NSq2w8K6UwV0jgXXFLEfTZOqdFdVVcwAOgCrc4LbpX
33
- E+5IflPoIuwBW2brYx/fIyJu2gH0uRG92R5m/3UxOqlVzIerL3YM3UTSepDtyCek
34
- ooD03UwLl3fYuza2iuMnxJAPshaSwiHbAopnaBSEvKMGHkLyl4zTmaioGXVRObtZ
35
- XAorC7ujI4F8edcmPRwAaNToHS8cRlGQJjXACfAodwNKWpbHYwIDAQABo1MwUTAd
36
- BgNVHQ4EFgQULhAoOyRjZxBRF8FlwTySSAXnFo0wHwYDVR0jBBgwFoAULhAoOyRj
37
- ZxBRF8FlwTySSAXnFo0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
38
- AQEAiePCYXf6PAF/m3SE9PYNLiq+ALeJ+kQgXUYp5S4vsfk2T+XmbtP0uNnTQpsT
39
- 4GaytjMFIQiNO6mHww8SFnrEr9btcNGCg17gyK7T3XukbsXIgOYvYjJboxb6Ww1T
40
- YFEXqPv55of/I5+UPH88WOYR1JsPE6lR4s3MfaMMRXTIZwpob2sxEfqHfti1DrHV
41
- nmzZpIvZi3II+gpx6aYE8m3DjgPrxbXw78Ular/VyYAyy9XVFpcl2nrAQgpErZIr
42
- kweGVVMKE8qMF9SO1/pER4T7A9ZBJol00hMCL+5Rw0Pw4lCLXgGX1J9VyZ+ScLxz
43
- aNy5t6tyGuGk0sol4dLG8nzHGA==
44
- -----END CERTIFICATE-----`;
45
-
46
- const SAMPLE_KEY_PEM = `-----BEGIN PRIVATE KEY-----
47
- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC2cx2netb5uR5i
48
- hb1q3ZpG3vSC5vmyIyw05jDShsKjUs6QmiQQ5fb72Ro5TBoKae1wl1Tf4lhB7swZ
49
- jAj4f05bGctFglSd5gHzVrwJ8ntST7kVU3NBAWdi8vQbk1KrbDwrpTBXSOBdcUsR
50
- 9Nk6p0V1VVzAA6AKtzgtulcT7kh+U+gi7AFbZutjH98jIm7aAfS5Eb3ZHmb/dTE6
51
- qVXMh6svdgzdRNJ6kO3IJ6SigPTdTAuXd9i7NraK4yfEkA+yFpLCIdsCimdoFIS8
52
- owYeQvKXjNOZqKgZdVE5u1lcCisLu6MjgXx51yY9HABo1OgdLxxGUZAmNcAJ8Ch3
53
- A0palsdjAgMBAAECggEADTZAcBYmjSAWDpjHguT+cAiWXwhU2pm1CmhrVRBD9fz5
54
- tZT3IAlXHYO2/dRmw/KwKnAUlr9wS4EvlhLPvEotWJsa+JlogT3cgRktz4nLDmBB
55
- jRH+9AOJaUWIq2dVHDhfq+I8oh8TFREumEoWLpFZ9Hya+9I6lUWq5smdcEI+gHWs
56
- yWhq4auR2/zkhvgsjLKPK8P2M8tmm8IPecE74NSBZqxoqb4upUHpMTxasAE2UJpK
57
- 0slvxiZtk3LT/rflco04twIqK/KmH7phrPzmoSl+Lp1Zh9y4iNznTQKBdImsGl+g
58
- 9FWL7pdxKjVNGQsrKVvB1A78VhhteAuaebT5MicIwQKBgQDtmYfyrlGoYGkArmNL
59
- tGBc5afGx/mL/8BGTQfIx4b11OEr+G4hppLh/WGLUksfMfprL0YU3BM+FOsECsY0
60
- 5AJB6oQuSE8vCIS7yCxV00V+I6n2bEMxZkDwdDuF9rHhGODFx4pPz1nJqScAa23T
61
- 48c+hNSBLRHTSuDAi2DcuxLn4QKBgQDElDjmB/kpW50ya2M2hO5LpwMcAlTJ3nPv
62
- 000eTfzdtDNzesvRClYZWGWs7zSkNsf/F+G0tCg4slzvHPkRJN53hHF0Kwug2aj5
63
- 1BPuDbn3EumDO6quykz6S9vZGcPAMuNm+qtkf+42KE5Sqj3NTf6aiu4tEZbH69me
64
- av1sbfkHwwKBgQC5cb5g1FuZjn4F8RZBDSy09O4pQQVtlpSsigzMUabtklSY7BKR
65
- IyC7T/dlNTq6w1hPdhs9xrMiHlN72SjwORHl/rNiKD/dVsm6grbP2dEAbbeHROKA
66
- 2O1Qf3fBzFTzemZdF6vFNPJAakytkCutWLe2/RebJuElx+h5f49/WGeeIQKBgQC0
67
- mcCUharB9ms7kTF7OzF6y5utte6T8A3vvd9SAjBYt1+1rpFmIersKixvbuycGcAw
68
- eo5gaEuzmxqKi8G/oHHKuCFLquhqBM6bh94vjOjXN8bVTJIJN870/ZCjqmoPQDFv
69
- wMiJ8oa1tt4OUF2rKwbIkO809L3kOqiaRI1Det2Z5QKBgGp4JS3OqzeIMQbUa8e8
70
- tOYnML+RFpo2cZ9rCQAQitm/w5P6lAnG9vv4cXAu94RbtITEuGmqEhYDMhSC2i8e
71
- kjwRLp5R+/pynUdTckRP8buwRSDRlPz3x8GI2Dm0z8fb/uZ8AJK/iITtsOoJtyPx
72
- fUZ521uRyKXnpzj1HTz5WVp0
73
- -----END PRIVATE KEY-----`;
74
-
75
- export default async () => {
76
- await describe('tls — RFC 6125 + cert extraction', async () => {
77
-
78
- // ---------------- RFC 6125 wildcard depth rules ----------------
79
- await describe('RFC 6125 wildcard depth', async () => {
80
- await it('rejects two-label wildcard *.com', async () => {
81
- const err = checkServerIdentity('foo.com', fakeCert({
82
- subject: {},
83
- subjectaltname: 'DNS:*.com',
84
- }));
85
- expect(err instanceof Error).toBe(true);
86
- });
87
-
88
- await it('rejects single-label wildcard *', async () => {
89
- const err = checkServerIdentity('foo', fakeCert({
90
- subject: {},
91
- subjectaltname: 'DNS:*',
92
- }));
93
- expect(err instanceof Error).toBe(true);
94
- });
95
-
96
- await it('accepts three-label wildcard *.example.com matching foo.example.com', async () => {
97
- const ok = checkServerIdentity('foo.example.com', fakeCert({
98
- subject: {},
99
- subjectaltname: 'DNS:*.example.com',
100
- }));
101
- expect(ok).toBeUndefined();
102
- });
103
-
104
- await it('rejects empty wildcard label .x.example.com', async () => {
105
- const err = checkServerIdentity('foo.x.example.com', fakeCert({
106
- subject: {},
107
- subjectaltname: 'DNS:.x.example.com',
108
- }));
109
- expect(err instanceof Error).toBe(true);
110
- });
111
- });
112
-
113
- // ---------------- RFC 6125 wildcard prefix/suffix ----------------
114
- await describe('RFC 6125 wildcard prefix/suffix', async () => {
115
- await it('matches f*.example.com against foo.example.com', async () => {
116
- const ok = checkServerIdentity('foo.example.com', fakeCert({
117
- subject: {},
118
- subjectaltname: 'DNS:f*.example.com',
119
- }));
120
- expect(ok).toBeUndefined();
121
- });
122
-
123
- await it('rejects f*.example.com against bar.example.com', async () => {
124
- const err = checkServerIdentity('bar.example.com', fakeCert({
125
- subject: {},
126
- subjectaltname: 'DNS:f*.example.com',
127
- }));
128
- expect(err instanceof Error).toBe(true);
129
- });
130
-
131
- await it('matches *foo.example.com against barfoo.example.com', async () => {
132
- const ok = checkServerIdentity('barfoo.example.com', fakeCert({
133
- subject: {},
134
- subjectaltname: 'DNS:*foo.example.com',
135
- }));
136
- expect(ok).toBeUndefined();
137
- });
138
-
139
- await it('rejects f*r.example.com against bar.example.com (prefix mismatch)', async () => {
140
- const err = checkServerIdentity('bar.example.com', fakeCert({
141
- subject: {},
142
- subjectaltname: 'DNS:f*r.example.com',
143
- }));
144
- expect(err instanceof Error).toBe(true);
145
- });
146
- });
147
-
148
- // ---------------- IDN / xn-- handling ----------------
149
- await describe('Punycode / IDN', async () => {
150
- await it('treats xn-- labels as exact-match (no wildcard expansion)', async () => {
151
- // pattern is the punycoded form; hostname must match exactly.
152
- const ok = checkServerIdentity('xn--bcher-kva.example.com', fakeCert({
153
- subject: {},
154
- subjectaltname: 'DNS:xn--bcher-kva.example.com',
155
- }));
156
- expect(ok).toBeUndefined();
157
- });
158
-
159
- await it('rejects wildcard expansion against xn-- A-label leftmost', async () => {
160
- // *xn--bcher-kva matched against bcher-kva: per RFC 6125 the wildcard
161
- // is not allowed to expand into A-label content.
162
- const err = checkServerIdentity('foo.example.com', fakeCert({
163
- subject: {},
164
- subjectaltname: 'DNS:xn--*.example.com',
165
- }));
166
- expect(err instanceof Error).toBe(true);
167
- });
168
- });
169
-
170
- // ---------------- Error code shape (Node-compat) ----------------
171
- await describe('error.code', async () => {
172
- await it('returns ERR_TLS_CERT_ALTNAME_INVALID code on mismatch', async () => {
173
- const err = checkServerIdentity('a.com', fakeCert({
174
- subject: { CN: 'b.com' },
175
- }));
176
- expect(err instanceof Error).toBe(true);
177
- const e = err as { code?: string };
178
- // Node: ERR_TLS_CERT_ALTNAME_INVALID. Our impl: same.
179
- expect(e.code).toBe('ERR_TLS_CERT_ALTNAME_INVALID');
180
- });
181
- });
182
-
183
- // ---------------- createSecureContext PEM acceptance ----------------
184
- await describe('createSecureContext', async () => {
185
- await it('accepts string PEM material (cert + key)', async () => {
186
- const ctx = createSecureContext({ cert: SAMPLE_CERT_PEM, key: SAMPLE_KEY_PEM });
187
- expect(ctx).toBeDefined();
188
- });
189
-
190
- await it('accepts Buffer PEM material', async () => {
191
- const Buffer = (globalThis as { Buffer?: { from(s: string): unknown } }).Buffer;
192
- if (!Buffer) return; // skip if Buffer unavailable
193
- const ctx = createSecureContext({
194
- cert: Buffer.from(SAMPLE_CERT_PEM) as never,
195
- key: Buffer.from(SAMPLE_KEY_PEM) as never,
196
- });
197
- expect(ctx).toBeDefined();
198
- });
199
-
200
- await it('accepts array of PEM blocks for ca', async () => {
201
- const ctx = createSecureContext({ ca: [SAMPLE_CERT_PEM, SAMPLE_CERT_PEM] });
202
- expect(ctx).toBeDefined();
203
- });
204
-
205
- await it('returns ctx.context self-reference (Node-compat)', async () => {
206
- const ctx = createSecureContext();
207
- const ref = (ctx as unknown as { context?: unknown }).context;
208
- expect(ref !== undefined).toBe(true);
209
- });
210
-
211
- // Our impl preserves the user-supplied options on the SecureContext;
212
- // Node does not, so this is a GJS-specific guarantee we lean on for
213
- // diagnostics + integration debugging.
214
- await on('Gjs', async () => {
215
- await it('preserves passed-through options (ciphers/minVersion/maxVersion)', async () => {
216
- const ctx = createSecureContext({
217
- ciphers: 'TLS_AES_128_GCM_SHA256',
218
- minVersion: 'TLSv1.2',
219
- maxVersion: 'TLSv1.3',
220
- });
221
- const o = (ctx as unknown as { options?: { ciphers?: string; minVersion?: string; maxVersion?: string } }).options;
222
- expect(o).toBeDefined();
223
- expect(o!.ciphers).toBe('TLS_AES_128_GCM_SHA256');
224
- expect(o!.minVersion).toBe('TLSv1.2');
225
- expect(o!.maxVersion).toBe('TLSv1.3');
226
- });
227
- });
228
- });
229
- });
230
- };