import { readFileSync, realpathSync } from "fs"; import { tls as cert1 } from "harness"; import { AddressInfo } from "net"; import { createTest } from "node-harness"; import { once } from "node:events"; import { tmpdir } from "os"; import { join } from "path"; import type { PeerCertificate } from "tls"; import tls, { connect, createServer, rootCertificates, Server, TLSSocket } from "tls"; const { describe, expect, it, createCallCheckCtx } = createTest(import.meta.path); const passKeyFile = join(import.meta.dir, "fixtures", "rsa_private_encrypted.pem"); const passKey = readFileSync(passKeyFile); const rawKeyFile = join(import.meta.dir, "fixtures", "rsa_private.pem"); const rawKey = readFileSync(rawKeyFile); const certFile = join(import.meta.dir, "fixtures", "rsa_cert.crt"); const cert = readFileSync(certFile); const COMMON_CERT = { ...cert1 }; const socket_domain = join(realpathSync(tmpdir()), "node-tls-server.sock"); describe("tls.createServer listen", () => { it("should throw when no port or path when using options", done => { expect(() => createServer(COMMON_CERT).listen({ exclusive: true })).toThrow( 'The argument \'options\' must have the property "port" or "path". Received {"exclusive":true}', ); done(); }); it("should listen on IPv6 by default", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const server: Server = createServer(COMMON_CERT); let timeout: Timer; const closeAndFail = () => { clearTimeout(timeout); server.close(); mustNotCall()(); }; server.on("error", closeAndFail); timeout = setTimeout(closeAndFail, 100); server.listen( 0, mustCall(() => { const address = server.address() as AddressInfo; expect(address.address).toStrictEqual("::"); //system should provide an port when 0 or no port is passed expect(address.port).toBeGreaterThan(100); expect(address.family).toStrictEqual("IPv6"); server.close(); done(); }), ); }); it("should listen on IPv4", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const server: Server = createServer(COMMON_CERT); let timeout: Timer; const closeAndFail = () => { clearTimeout(timeout); server.close(); mustNotCall()(); }; server.on("error", closeAndFail); timeout = setTimeout(closeAndFail, 100); server.listen( 0, "0.0.0.0", mustCall(() => { const address = server.address() as AddressInfo; expect(address.address).toStrictEqual("0.0.0.0"); //system should provide an port when 0 or no port is passed expect(address.port).toBeGreaterThan(100); expect(address.family).toStrictEqual("IPv4"); server.close(); done(); }), ); }); it("should call listening", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const server: Server = createServer(COMMON_CERT); let timeout: Timer; const closeAndFail = () => { clearTimeout(timeout); server.close(); mustNotCall()(); }; server.on("error", closeAndFail).on( "listening", mustCall(() => { clearTimeout(timeout); server.close(); done(); }), ); timeout = setTimeout(closeAndFail, 100); server.listen(0, "0.0.0.0"); }); it("should listen on localhost", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const server: Server = createServer(COMMON_CERT); let timeout: Timer; const closeAndFail = () => { clearTimeout(timeout); server.close(); mustNotCall()(); }; server.on("error", closeAndFail); timeout = setTimeout(closeAndFail, 100); server.listen( 0, "::1", mustCall(() => { const address = server.address() as AddressInfo; expect(address.address).toStrictEqual("::1"); //system should provide an port when 0 or no port is passed expect(address.port).toBeGreaterThan(100); expect(address.family).toStrictEqual("IPv6"); server.close(); done(); }), ); }); it("should listen on localhost", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const server: Server = createServer(COMMON_CERT); let timeout: Timer; const closeAndFail = () => { clearTimeout(timeout); server.close(); mustNotCall()(); }; server.on("error", closeAndFail); timeout = setTimeout(closeAndFail, 100); server.listen( 0, "::1", mustCall(() => { const address = server.address() as AddressInfo; expect(address.address).toStrictEqual("::1"); expect(address.family).toStrictEqual("IPv6"); server.close(); done(); }), ); }); it("should listen without port or host", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const server: Server = createServer(COMMON_CERT); let timeout: Timer; const closeAndFail = () => { clearTimeout(timeout); server.close(); mustNotCall()(); }; server.on("error", closeAndFail); timeout = setTimeout(closeAndFail, 100); server.listen( mustCall(() => { const address = server.address() as AddressInfo; expect(address.address).toStrictEqual("::"); //system should provide an port when 0 or no port is passed expect(address.port).toBeGreaterThan(100); expect(address.family).toStrictEqual("IPv6"); server.close(); done(); }), ); }); it("should listen on unix domain socket", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const server: Server = createServer(COMMON_CERT); let timeout: Timer; const closeAndFail = () => { clearTimeout(timeout); server.close(); mustNotCall()(); }; server.on("error", closeAndFail); timeout = setTimeout(closeAndFail, 100); server.listen( socket_domain, mustCall(() => { const address = server.address(); expect(address).toStrictEqual(socket_domain); server.close(); done(); }), ); }); it("should not listen with wrong password", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const server: Server = createServer({ key: passKey, passphrase: "invalid", cert: cert, }); server.on("error", mustCall()); let timeout: Timer; function closeAndFail() { clearTimeout(timeout); server.close(); mustNotCall()(); } timeout = setTimeout(closeAndFail, 100); server.listen(0, "0.0.0.0", closeAndFail); }); it("should not listen without cert", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const server: Server = createServer({ key: passKey, passphrase: "invalid", }); server.on("error", mustCall()); let timeout: Timer; function closeAndFail() { clearTimeout(timeout); server.close(); mustNotCall()(); } timeout = setTimeout(closeAndFail, 100); server.listen(0, "0.0.0.0", closeAndFail); }); it("should not listen without password", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const server: Server = createServer({ key: passKey, cert: cert, }); server.on("error", mustCall()); let timeout: Timer; function closeAndFail() { clearTimeout(timeout); server.close(); mustNotCall()(); } timeout = setTimeout(closeAndFail, 100); server.listen(0, "0.0.0.0", closeAndFail); }); }); describe("tls.createServer", () => { it("should work with getCertificate", done => { let timeout: Timer; let client: TLSSocket | null = null; const server: Server = createServer(COMMON_CERT, socket => { socket.on("secure", () => { try { expect(socket).toBeDefined(); const cert = socket.getCertificate() as PeerCertificate; expect(cert).toBeDefined(); expect(cert.subject).toBeDefined(); expect(cert.subject).toMatchObject({ C: "US", CN: "server-bun", L: "San Francisco", O: "Oven", OU: "Team Bun", ST: "CA", }); expect(cert.issuer).toBeDefined(); expect(cert.issuer).toMatchObject({ C: "US", CN: "server-bun", L: "San Francisco", O: "Oven", OU: "Team Bun", ST: "CA", }); expect(cert.ca).toBe(true); expect(cert.bits).toBe(2048); expect(cert.modulus).toBe( "e5633a2c8118171cbeaf321d55d0444586cbe566bb51a234b0ead69faf7490069854efddffac68986652ff949f472252e4c7d24c6ee4e3366e54d9e4701e24d021e583e1a088112c0f96475a558b42f883a3e796c937cc4d6bb8791b227017b3e73deb40b0ac84f033019f580a3216888acec71ce52d938fcadd8e29794e38774e33d323ede89b58e526ef8b513ba465fa4ffd9cf6c1ec7480de0dcb569dec295d7b3cce40256b428d5907e90e7a52e77c3101f4ad4c0e254ab03d75ac42ee1668a5094bc4521b264fb404b6c4b17b6b279e13e6282e1e4fb6303540cb830ea8ff576ca57b7861e4ef797af824b0987c870718780a1c5141e4f904fd0c5139f5", ); expect(cert.exponent).toBe("0x10001"); expect(cert.pubkey).toBeInstanceOf(Buffer); // yes these spaces are intentional expect(cert.valid_from).toBe("Sep 6 03:00:49 2025 GMT"); expect(cert.valid_to).toBe("Sep 4 03:00:49 2035 GMT"); expect(cert.fingerprint).toBe("D2:5E:B9:AD:8B:48:3B:7A:35:D3:1A:45:BD:32:AC:AD:55:4A:BA:AD"); expect(cert.fingerprint256).toBe( "85:F4:47:0C:6D:D8:DE:C8:68:77:7C:5E:3F:9B:56:A6:D3:69:C7:C2:1A:E8:B8:F8:1C:16:1D:04:78:A0:E9:91", ); expect(cert.fingerprint512).toBe( "CE:00:17:97:29:5E:1C:7E:59:86:8D:1F:F0:F4:AF:A0:B0:10:F2:2E:0E:79:D1:32:D0:44:F9:B4:3A:DE:D5:83:A9:15:0E:E4:47:24:D4:2A:10:FB:21:BE:3A:38:21:FC:40:20:B3:BC:52:64:F7:38:93:EF:C9:3F:C8:57:89:31", ); expect(cert.serialNumber).toBe("71a46ae89fd817ef81a34d5973e1de42f09b9d63"); expect(cert.raw).toBeInstanceOf(Buffer); client?.end(); server.close(); done(); } catch (err) { client?.end(); server.close(); done(err); } }); }); const closeAndFail = (err: any) => { clearTimeout(timeout); server.close(); client?.end(); done(err || "Timeout"); }; server.on("error", closeAndFail); timeout = setTimeout(closeAndFail, 1000); server.listen(0, () => { const address = server.address() as AddressInfo; client = connect({ port: address.port, host: address.address, secureContext: tls.createSecureContext(COMMON_CERT), rejectUnauthorized: false, }); }); }); }); describe("tls.createServer events", () => { it("should receive data", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); let timeout: Timer; let client: any = null; let is_done = false; const onData = mustCall(data => { is_done = true; clearTimeout(timeout); server.close(); expect(data.byteLength).toBe(5); expect(data.toString("utf8")).toBe("Hello"); done(); }); const server: Server = createServer(COMMON_CERT, (socket: TLSSocket) => { socket.on("data", onData); }); const closeAndFail = () => { if (is_done) return; clearTimeout(timeout); server.close(); client?.end(); mustNotCall("no data received")(); }; server.on("error", closeAndFail); //should be faster than 100ms timeout = setTimeout(closeAndFail, 100); server.listen( mustCall(async () => { const address = server.address() as AddressInfo; client = await Bun.connect({ tls: true, hostname: address.address, port: address.port, socket: { data(socket) {}, handshake(socket, success, verifyError) { if (socket.write("Hello")) { socket.end(); } }, connectError: closeAndFail, // connection failed }, }).catch(closeAndFail); }), ); }); it("should call end", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); let timeout: Timer; let is_done = false; const onEnd = mustCall(() => { is_done = true; clearTimeout(timeout); server.close(); done(); }); const server: Server = createServer(COMMON_CERT, (socket: TLSSocket) => { socket.on("end", onEnd); socket.end(); }); const closeAndFail = () => { if (is_done) return; clearTimeout(timeout); server.close(); mustNotCall("end not called")(); }; server.on("error", closeAndFail); //should be faster than 100ms timeout = setTimeout(closeAndFail, 100); server.listen( mustCall(async () => { const address = server.address() as AddressInfo; await Bun.connect({ tls: true, hostname: address.address, port: address.port, socket: { data(socket) {}, open(socket) {}, connectError: closeAndFail, // connection failed }, }).catch(closeAndFail); }), ); }); it("should call close", async () => { const { promise, reject, resolve } = Promise.withResolvers(); const server: Server = createServer(COMMON_CERT); server.listen().on("close", resolve).on("error", reject); server.close(); await promise; }); it("should call connection and drop", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); let timeout: Timer; let is_done = false; const server = createServer(COMMON_CERT); let maxClients = 2; server.maxConnections = maxClients - 1; const closeAndFail = () => { if (is_done) return; clearTimeout(timeout); server.close(); mustNotCall("drop not called")(); }; //should be faster than 100ms timeout = setTimeout(closeAndFail, 100); let connection_called = false; server .on( "connection", mustCall(() => { connection_called = true; }), ) .on( "drop", mustCall(data => { is_done = true; server.close(); clearTimeout(timeout); expect(data.localPort).toBeDefined(); expect(data.remotePort).toBeDefined(); expect(data.remoteFamily).toBeDefined(); expect(data.localFamily).toBeDefined(); expect(data.localAddress).toBeDefined(); expect(connection_called).toBe(true); done(); }), ) .listen(async () => { const address = server.address() as AddressInfo; async function spawnClient() { await Bun.connect({ tls: true, port: address?.port, hostname: address?.address, socket: { data(socket) {}, handshake(socket, success, verifyError) {}, open(socket) { socket.end(); }, }, }); } const promises = []; for (let i = 0; i < maxClients; i++) { promises.push(spawnClient()); } await Promise.all(promises).catch(closeAndFail); }); }); it("should error on an invalid port", () => { const server = createServer(COMMON_CERT); expect(() => server.listen(123456)).toThrow( expect.objectContaining({ code: "ERR_SOCKET_BAD_PORT", }), ); }); it("should call abort with signal", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); const controller = new AbortController(); let timeout: Timer; const server = createServer(COMMON_CERT); const closeAndFail = () => { clearTimeout(timeout); server.close(); mustNotCall("close not called")(); }; //should be faster than 100ms timeout = setTimeout(closeAndFail, 100); server .on( "close", mustCall(() => { clearTimeout(timeout); done(); }), ) .listen({ port: 0, signal: controller.signal }, () => { controller.abort(); }); }); it("should echo data", done => { const { mustCall, mustNotCall } = createCallCheckCtx(done); let timeout: Timer; let client: any = null; const server: Server = createServer(COMMON_CERT, (socket: TLSSocket) => { socket.pipe(socket); }); let is_done = false; const closeAndFail = () => { if (is_done) return; clearTimeout(timeout); server.close(); client?.end(); mustNotCall("no data received")(); }; server.on("error", closeAndFail); //should be faster than 100ms timeout = setTimeout(closeAndFail, 100); server.listen( mustCall(async () => { const address = server.address() as AddressInfo; client = await Bun.connect({ tls: true, hostname: address.address, port: address.port, socket: { error(socket, err) { closeAndFail(); }, drain(socket) { socket.write("Hello"); }, data(socket, data) { is_done = true; clearTimeout(timeout); server.close(); socket.end(); expect(data.byteLength).toBe(5); expect(data.toString("utf8")).toBe("Hello"); done(); }, handshake(socket) { socket.write("Hello"); }, connectError: closeAndFail, // connection failed }, }).catch(closeAndFail); }), ); }); }); it("tls.rootCertificates should exists", () => { expect(tls.rootCertificates).toBeDefined(); expect(tls.rootCertificates).toBeInstanceOf(Array); expect(tls.rootCertificates.length).toBeGreaterThan(0); expect(typeof tls.rootCertificates[0]).toBe("string"); expect(rootCertificates).toBeDefined(); expect(rootCertificates).toBeInstanceOf(Array); expect(rootCertificates.length).toBeGreaterThan(0); expect(typeof rootCertificates[0]).toBe("string"); }); it("connectionListener should emit the right amount of times, and with alpnProtocol available", async () => { let count = 0; const promises = []; const server: Server = createServer( { ...COMMON_CERT, ALPNProtocols: ["bun"], }, socket => { count++; expect(socket.alpnProtocol).toBe("bun"); socket.end(); }, ); server.setMaxListeners(100); server.listen(0); await once(server, "listening"); for (let i = 0; i < 50; i++) { const { promise, resolve } = Promise.withResolvers(); promises.push(promise); const socket = connect( { ca: COMMON_CERT.cert, rejectUnauthorized: false, port: server.address().port, host: "127.0.0.1", ALPNProtocols: ["bun"], }, () => { socket.on("close", resolve); socket.resume(); socket.end(); }, ); } await Promise.all(promises); expect(count).toBe(50); });