export function createFirefoxValidationPlugin() { return { manifest: pluginManifest( "org.browsec.firefox-validation", "Firefox validation", ["advisor"], ), hooks: { collectEvidence({ facts }) { if (facts.validation === "success") { return { entries: [ { kind: "vote", code: "firefox-validation-succeeded", message: "Firefox constructed a valid path to a configured trust anchor.", data: { trusted: true }, }, ], }; } return { entries: facts.errors.map((error) => ({ kind: "warning", code: error, message: explainValidationError(error), })), }; }, }, }; } export function createVillageCommunityPlugin() { return { manifest: pluginManifest( "community.village.observer", "Village community observer", ["advisor"], ), hooks: { collectEvidence({ facts }) { if (facts.hostname !== "library.village") return; return { entries: [ { kind: "evidence", code: "community-key-continuity", message: "This certificate has appeared in the synthetic community record for 184 days.", data: { observers: 7, independentOperators: 3, ageDays: 184 }, }, { kind: "vote", code: "community-recommends-trust", message: "The configured community recommends trusting this exact host certificate.", data: { trusted: true }, }, ], }; }, }, }; } export function createCommunityAdvicePlugin({ id, name, trusted, message, }) { return { manifest: pluginManifest(id, name, ["advisor"]), hooks: { collectEvidence() { return { entries: [ { kind: "vote", code: trusted ? "community-votes-trusted" : "community-votes-not-trusted", message, data: { trusted }, }, ], }; }, }, }; } export function createUserDecisionPlugin(decision, options = {}) { if (decision !== true && decision !== false) return undefined; const decide = ({ facts, journal }) => ({ trusted: decision, scope: options.target === "authority" ? authorityForHostScope(facts, options) : exactCertificateScope(facts), lifetime: { kind: options.lifetime ?? "connection" }, reasonEntryIds: journal.entries .filter((entry) => entry.kind === "evidence" || entry.kind === "warning") .map((entry) => entry.id), overriddenErrors: decision ? [...facts.errors] : [], }); return { manifest: pluginManifest( "local.user.decision", "Local user decision", ["decision-authority"], ), hooks: { onBeforeTlsAccept: decide, async onTlsFailure(context) { return decide(context); }, }, }; } function authorityForHostScope(facts, options) { const authorities = [...facts.constructedChain].filter( (certificate) => certificate.isCa && certificate.keyUsages.includes("keyCertSign"), ); const authority = options.authorityCertificateSha256 ? authorities.find( (certificate) => certificate.sha256 === options.authorityCertificateSha256, ) : authorities.at(-1); if (!authority) throw new TypeError("No usable CA certificate is present"); return { kind: "authority-for-host", hostname: facts.hostname, port: "any", authorityCertificateSha256: authority.sha256, includeSubdomains: Boolean(options.includeSubdomains), }; } function exactCertificateScope(facts) { return { kind: "certificate-for-host", hostname: facts.hostname, port: facts.port, certificateSha256: facts.presentedChain[0].sha256, }; } function pluginManifest(id, name, supportedModes) { return { manifestVersion: 1, trustApiVersion: "0.1", id, name, version: "0.0.0", supportedModes, capabilities: {}, }; } function explainValidationError(error) { const explanations = { "unknown-issuer": "Firefox cannot construct a path from this certificate to a configured trust anchor.", expired: "At least one certificate in the validation path is outside its validity period.", "hostname-mismatch": "The leaf certificate does not identify the requested hostname.", "explicitly-distrusted-authority": "The chain reaches an authority rejected by an explicit local Browsec rule.", }; return explanations[error] ?? `Firefox reported certificate error: ${error}.`; }