Initial curated CertScope source from fe2bbe3ca5c98bf64be26a09c6c58ee805a7f87e
This commit is contained in:
commit
7348faf6c0
65 files changed
+12509
No files matched your search
@@ -0,0 +1,118 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { EventEmitter } from "node:events";
|
||||
import tls from "node:tls";
|
||||
import { certificateDaysRemaining } from "./tls";
|
||||
import { collectTls, type TlsConnector } from "./tls";
|
||||
|
||||
describe("TLS certificate date handling", () => {
|
||||
it("returns whole days remaining from a supplied clock", () => {
|
||||
const now = Date.parse("2026-01-01T12:00:00.000Z");
|
||||
expect(certificateDaysRemaining("Jan 11 12:00:00 2026 GMT", now)).toBe(10);
|
||||
expect(certificateDaysRemaining("Dec 31 12:00:00 2025 GMT", now)).toBe(-1);
|
||||
});
|
||||
|
||||
it("does not turn an invalid certificate date into a score deduction", () => {
|
||||
expect(certificateDaysRemaining("not-a-certificate-date", Date.now())).toBeNull();
|
||||
expect(certificateDaysRemaining(null, Date.now())).toBeNull();
|
||||
});
|
||||
|
||||
it("tries the next validated address after a failed TLS connection", async () => {
|
||||
const attempted: string[] = [];
|
||||
const connect: TlsConnector = ((options) => {
|
||||
const address = String(options.host);
|
||||
attempted.push(address);
|
||||
const socket = new EventEmitter() as EventEmitter & {
|
||||
authorized: boolean;
|
||||
authorizationError: null;
|
||||
getPeerCertificate: () => Record<string, unknown>;
|
||||
getProtocol: () => string;
|
||||
destroy: () => void;
|
||||
};
|
||||
socket.destroy = () => undefined;
|
||||
if (address === "1.1.1.1") {
|
||||
queueMicrotask(() => socket.emit("error", Object.assign(new Error("refused"), { code: "ECONNREFUSED" })));
|
||||
} else {
|
||||
socket.authorized = true;
|
||||
socket.authorizationError = null;
|
||||
socket.getProtocol = () => "TLSv1.3";
|
||||
socket.getPeerCertificate = () => ({
|
||||
subject: { CN: "example.com" },
|
||||
issuer: { CN: "Example CA" },
|
||||
subjectaltname: "DNS:example.com",
|
||||
valid_from: "Jan 01 00:00:00 2026 GMT",
|
||||
valid_to: "Jan 01 00:00:00 2027 GMT",
|
||||
fingerprint256: "AA:BB",
|
||||
});
|
||||
queueMicrotask(() => socket.emit("secureConnect"));
|
||||
}
|
||||
return socket as unknown as ReturnType<typeof tls.connect>;
|
||||
}) as TlsConnector;
|
||||
|
||||
const result = await collectTls("example.com", ["1.1.1.1", "2.2.2.2"], { connect, now: Date.parse("2026-06-01T00:00:00Z") });
|
||||
expect(result).toMatchObject({ address: "2.2.2.2", protocol: "TLSv1.3", hostnameValid: true, authorized: true });
|
||||
expect(attempted).toEqual(["1.1.1.1", "2.2.2.2"]);
|
||||
expect(result.attempts).toEqual([{ address: "1.1.1.1", error: "TLS probe failed (ECONNREFUSED)." }]);
|
||||
});
|
||||
|
||||
it("reports certificates that are not yet valid", async () => {
|
||||
const connect: TlsConnector = (() => {
|
||||
const socket = new EventEmitter() as EventEmitter & {
|
||||
authorized: boolean;
|
||||
authorizationError: null;
|
||||
getPeerCertificate: () => Record<string, unknown>;
|
||||
getProtocol: () => string;
|
||||
destroy: () => void;
|
||||
};
|
||||
socket.authorized = true;
|
||||
socket.authorizationError = null;
|
||||
socket.getProtocol = () => "TLSv1.3";
|
||||
socket.getPeerCertificate = () => ({
|
||||
subjectaltname: "DNS:example.com",
|
||||
valid_from: "Jul 01 00:00:00 2026 GMT",
|
||||
valid_to: "Jan 01 00:00:00 2027 GMT",
|
||||
});
|
||||
socket.destroy = () => undefined;
|
||||
queueMicrotask(() => socket.emit("secureConnect"));
|
||||
return socket as unknown as ReturnType<typeof tls.connect>;
|
||||
}) as TlsConnector;
|
||||
const result = await collectTls("example.com", ["2.2.2.2"], { connect, now: Date.parse("2026-06-01T00:00:00Z") });
|
||||
expect(result.notYetValid).toBe(true);
|
||||
expect(result.daysRemaining).toBe(214);
|
||||
});
|
||||
|
||||
it("marks malformed or inverted certificate validity dates", async () => {
|
||||
const connect: TlsConnector = (() => {
|
||||
const socket = new EventEmitter() as EventEmitter & {
|
||||
authorized: boolean;
|
||||
authorizationError: null;
|
||||
getPeerCertificate: () => Record<string, unknown>;
|
||||
getProtocol: () => string;
|
||||
destroy: () => void;
|
||||
};
|
||||
socket.authorized = true;
|
||||
socket.authorizationError = null;
|
||||
socket.getProtocol = () => "TLSv1.3";
|
||||
socket.getPeerCertificate = () => ({
|
||||
subjectaltname: "DNS:example.com",
|
||||
valid_from: "Jan 02 00:00:00 2026 GMT",
|
||||
valid_to: "Jan 01 00:00:00 2026 GMT",
|
||||
});
|
||||
socket.destroy = () => undefined;
|
||||
queueMicrotask(() => socket.emit("secureConnect"));
|
||||
return socket as unknown as ReturnType<typeof tls.connect>;
|
||||
}) as TlsConnector;
|
||||
const result = await collectTls("example.com", ["2.2.2.2"], { connect, now: Date.parse("2026-01-01T00:00:00Z") });
|
||||
expect(result).toMatchObject({ validityDatesValid: false, daysRemaining: 0 });
|
||||
});
|
||||
|
||||
it("marks an exhausted address set as a failed collector", async () => {
|
||||
const connect: TlsConnector = (() => {
|
||||
const socket = new EventEmitter() as EventEmitter & { destroy: () => void };
|
||||
socket.destroy = () => undefined;
|
||||
queueMicrotask(() => socket.emit("error", Object.assign(new Error("unreachable"), { code: "ETIMEDOUT" })));
|
||||
return socket as unknown as ReturnType<typeof tls.connect>;
|
||||
}) as TlsConnector;
|
||||
const result = await collectTls("example.com", ["2.2.2.2"], { connect, deadline: Date.now() + 1_000 });
|
||||
expect(result._meta).toMatchObject({ status: "failed" });
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user