100 lines
3.5 KiB
JavaScript
100 lines
3.5 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { readFile } from "node:fs/promises";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
explicitlyDistrustedAuthority,
|
|
expiredLeafCertificate,
|
|
hostnameMismatch,
|
|
unknownLocalAuthority,
|
|
} from "../fixtures/tls.js";
|
|
import {
|
|
createCommunityAdvicePlugin,
|
|
createFirefoxValidationPlugin,
|
|
createUserDecisionPlugin,
|
|
createVillageCommunityPlugin,
|
|
} from "../plugins/demo-plugins.js";
|
|
import { TrustRunner } from "../src/index.js";
|
|
import { chainRows, subjectName, verdictCopy } from "../ui/model.js";
|
|
|
|
test("UI model identifies the failed end of an unknown-authority chain", () => {
|
|
const rows = chainRows(unknownLocalAuthority);
|
|
assert.equal(rows.length, 2);
|
|
assert.equal(rows[0].name, "library.village");
|
|
assert.equal(rows.at(-1).failed, true);
|
|
assert.match(rows.at(-1).edge, /Not anchored/);
|
|
});
|
|
|
|
test("UI model locates leaf and root policy failures precisely", () => {
|
|
const expired = chainRows(expiredLeafCertificate);
|
|
assert.equal(expired[0].failed, true);
|
|
assert.match(expired[0].edge, /validity period/);
|
|
assert.equal(expired.at(-1).failed, false);
|
|
|
|
const mismatch = chainRows(hostnameMismatch);
|
|
assert.equal(mismatch[0].failed, true);
|
|
assert.match(mismatch[0].edge, /records\.village/);
|
|
|
|
const distrusted = chainRows(explicitlyDistrustedAuthority);
|
|
assert.equal(distrusted.at(-1).failed, true);
|
|
assert.match(distrusted.at(-1).edge, /Explicitly distrusted/);
|
|
});
|
|
|
|
test("certificate display names prefer the common name", () => {
|
|
assert.equal(subjectName("O=Village,CN=Library CA,C=GE"), "Library CA");
|
|
assert.equal(subjectName("O=Nameless"), "O=Nameless");
|
|
});
|
|
|
|
test("UI plugins produce attributed evidence and a local Boolean verdict", async () => {
|
|
const plugins = [
|
|
configure(createFirefoxValidationPlugin(), "advisor"),
|
|
configure(createVillageCommunityPlugin(), "advisor"),
|
|
configure(createUserDecisionPlugin(true), "decision-authority"),
|
|
];
|
|
const result = await new TrustRunner({ plugins }).evaluate(unknownLocalAuthority);
|
|
|
|
assert.equal(result.verdict.trusted, true);
|
|
assert.ok(result.journal.entries.some((entry) => entry.code === "unknown-issuer"));
|
|
assert.ok(
|
|
result.journal.entries.some((entry) => entry.code === "community-key-continuity"),
|
|
);
|
|
assert.equal(verdictCopy(result, true).title, "You trust this connection");
|
|
});
|
|
|
|
test("conflicting community advice remains visible without becoming a verdict", async () => {
|
|
const plugins = [
|
|
configure(createCommunityAdvicePlugin({
|
|
id: "community.yes",
|
|
name: "Community Yes",
|
|
trusted: true,
|
|
message: "Known key",
|
|
}), "advisor"),
|
|
configure(createCommunityAdvicePlugin({
|
|
id: "community.no",
|
|
name: "Community No",
|
|
trusted: false,
|
|
message: "Unexpected change",
|
|
}), "advisor"),
|
|
];
|
|
const result = await new TrustRunner({ plugins }).evaluate(unknownLocalAuthority);
|
|
|
|
assert.equal(result.verdict.trusted, false);
|
|
assert.deepEqual(
|
|
result.journal.entries.map((entry) => entry.data?.trusted),
|
|
[true, false],
|
|
);
|
|
assert.ok(result.journal.entries.every((entry) => entry.kind === "vote"));
|
|
});
|
|
|
|
function configure(plugin, mode) {
|
|
return { plugin, mode };
|
|
}
|
|
|
|
test("security surface contains immutable-frame and simulation labels", async () => {
|
|
const html = await readFile(new URL("../ui/index.html", import.meta.url), "utf8");
|
|
assert.match(html, /Browsec security decision/);
|
|
assert.match(html, /Browser-owned test surface/);
|
|
assert.match(html, /TRUSTLAB · SYNTHETIC/);
|
|
assert.match(html, /It cannot alter browser trust/);
|
|
});
|