| 1 |
// A hub with a self-signed certificate: plain fetch refuses it, and the |
| 2 |
// fetch that trusts the remote's CA file reaches it. |
| 3 |
import { test } from "node:test"; |
| 4 |
import assert from "node:assert/strict"; |
| 5 |
import { execFileSync } from "node:child_process"; |
| 6 |
import { mkdtempSync, readFileSync } from "node:fs"; |
| 7 |
import { createServer } from "node:https"; |
| 8 |
import { tmpdir } from "node:os"; |
| 9 |
import { join } from "node:path"; |
| 10 |
import { fetchTrusting, HubClient } from "../out/hub.mjs"; |
| 11 |
|
| 12 |
test("a self-signed hub is reached with its CA file", async () => { |
| 13 |
const dir = mkdtempSync(join(tmpdir(), "hubtls-")); |
| 14 |
const key = join(dir, "key.pem"); |
| 15 |
const cert = join(dir, "cert.pem"); |
| 16 |
execFileSync("openssl", ["req", "-x509", "-newkey", "rsa:2048", "-nodes", "-keyout", key, "-out", cert, "-days", "1", "-subj", "/CN=127.0.0.1", "-addext", "subjectAltName=IP:127.0.0.1"], { stdio: "ignore" }); |
| 17 |
const server = createServer({ key: readFileSync(key), cert: readFileSync(cert) }, (req, res) => { |
| 18 |
let body = ""; |
| 19 |
req.on("data", (c) => (body += c)); |
| 20 |
req.on("end", () => { |
| 21 |
if (req.url === "/api/v1/user") { |
| 22 |
res.writeHead(200, { "content-type": "application/json" }); |
| 23 |
res.end(JSON.stringify({ username: "andy", auth: req.headers.authorization ?? "" })); |
| 24 |
} else if (req.url === "/echo") { |
| 25 |
res.writeHead(201, { "content-type": "application/json" }); |
| 26 |
res.end(JSON.stringify({ method: req.method, body })); |
| 27 |
} else { |
| 28 |
res.writeHead(204); |
| 29 |
res.end(); |
| 30 |
} |
| 31 |
}); |
| 32 |
}); |
| 33 |
await new Promise((r) => server.listen(0, "127.0.0.1", r)); |
| 34 |
const base = `https://127.0.0.1:${server.address().port}`; |
| 35 |
try { |
| 36 |
await assert.rejects(fetch(`${base}/api/v1/user`), "plain fetch does not trust it"); |
| 37 |
const trusting = fetchTrusting(cert); |
| 38 |
const me = await new HubClient(base, "tok", trusting).me(); |
| 39 |
assert.equal(me.username, "andy"); |
| 40 |
assert.equal(me.auth, "Bearer tok", "headers go through"); |
| 41 |
const echo = await trusting(`${base}/echo`, { method: "POST", body: '{"a":1}', headers: { "content-type": "application/json" } }); |
| 42 |
assert.equal(echo.status, 201); |
| 43 |
assert.deepEqual(await echo.json(), { method: "POST", body: '{"a":1}' }); |
| 44 |
assert.equal((await trusting(`${base}/other`)).status, 204); |
| 45 |
await assert.rejects(fetchTrusting(join(dir, "missing.pem"))(`${base}/api/v1/user`), /cannot read the hub's CA file/); |
| 46 |
} finally { |
| 47 |
server.close(); |
| 48 |
} |
| 49 |
}); |