Define strict TLS trust plugin API
This commit is contained in:
1 parent
f1fcef9b85
commit
1eeb8bac05
17 files changed
+834
-194
No files matched your search
+39
-26
@@ -3,40 +3,53 @@ import { TrustRunner } from "../src/index.js";
|
||||
|
||||
const villagePlugin = {
|
||||
manifest: {
|
||||
manifestVersion: 1,
|
||||
trustApiVersion: "0.1",
|
||||
id: "community.village.trust",
|
||||
name: "Village community trust",
|
||||
role: "decision-authority",
|
||||
version: "0.0.0",
|
||||
supportedModes: ["decision-authority"],
|
||||
capabilities: {},
|
||||
},
|
||||
collectEvidence({ facts }) {
|
||||
if (facts.hostname !== "library.village") return;
|
||||
return {
|
||||
entries: [
|
||||
{
|
||||
kind: "evidence",
|
||||
code: "known-community-key",
|
||||
message: "The community has previously observed this certificate.",
|
||||
hooks: {
|
||||
collectEvidence({ facts }) {
|
||||
if (facts.hostname !== "library.village") return;
|
||||
return {
|
||||
entries: [
|
||||
{
|
||||
kind: "evidence",
|
||||
code: "known-community-key",
|
||||
message: "The community has previously observed this certificate.",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
async onTlsFailure({ facts, journal }) {
|
||||
const known = journal.entries.some(
|
||||
(entry) => entry.code === "known-community-key",
|
||||
);
|
||||
if (!known) return;
|
||||
return {
|
||||
trusted: true,
|
||||
scope: {
|
||||
kind: "certificate-for-host",
|
||||
hostname: facts.hostname,
|
||||
port: facts.port,
|
||||
certificateSha256: facts.presentedChain[0].sha256,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
decide({ facts, journal }) {
|
||||
const known = journal.entries.some(
|
||||
(entry) => entry.code === "known-community-key",
|
||||
);
|
||||
if (!known) return;
|
||||
return {
|
||||
trusted: true,
|
||||
scope: { hostname: facts.hostname, port: facts.port },
|
||||
reasonEntryIds: journal.entries
|
||||
.filter((entry) => entry.code === "known-community-key")
|
||||
.map((entry) => entry.id),
|
||||
};
|
||||
lifetime: { kind: "connection" },
|
||||
reasonEntryIds: journal.entries
|
||||
.filter((entry) => entry.code === "known-community-key")
|
||||
.map((entry) => entry.id),
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = await new TrustRunner({ plugins: [villagePlugin] }).evaluate(
|
||||
const result = await new TrustRunner({
|
||||
plugins: [{ plugin: villagePlugin, mode: "decision-authority" }],
|
||||
}).evaluate(
|
||||
unknownLocalAuthority,
|
||||
);
|
||||
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
defineTrustPlugin,
|
||||
exactCertificateScope,
|
||||
} from "../sdk/plugin-api.js";
|
||||
|
||||
export default defineTrustPlugin({
|
||||
manifest: {
|
||||
manifestVersion: 1,
|
||||
trustApiVersion: "0.1",
|
||||
id: "community.village.strict-example",
|
||||
name: "Village strict example",
|
||||
version: "1.0.0",
|
||||
supportedModes: ["advisor", "decision-authority"],
|
||||
capabilities: { interactiveUi: true },
|
||||
},
|
||||
|
||||
hooks: {
|
||||
collectEvidence({ facts }) {
|
||||
if (facts.hostname !== "library.village") return undefined;
|
||||
return {
|
||||
entries: [
|
||||
{
|
||||
kind: "evidence",
|
||||
code: "known-community-certificate",
|
||||
message: "The configured community recognizes this certificate.",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
|
||||
async onTlsFailure({ facts, journal, ui }) {
|
||||
const trusted = await ui.requestDecision({
|
||||
title: "Unknown village authority",
|
||||
summary: "Firefox does not recognize this authority. The community recognizes the exact certificate.",
|
||||
proposedScope: exactCertificateScope(facts),
|
||||
evidenceEntryIds: journal.entries.map((entry) => entry.id),
|
||||
});
|
||||
if (trusted === undefined) return undefined;
|
||||
|
||||
return {
|
||||
trusted,
|
||||
scope: exactCertificateScope(facts),
|
||||
lifetime: { kind: "session" },
|
||||
reasonEntryIds: journal.entries.map((entry) => entry.id),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import type {
|
||||
PluginContribution,
|
||||
TrustPluginHooks,
|
||||
TrustVerdict,
|
||||
} from "../sdk/plugin-api.js";
|
||||
|
||||
// These intentionally invalid declarations are compiler assertions: the build
|
||||
// fails if TypeScript ever stops rejecting them.
|
||||
|
||||
const asynchronousFastHook: TrustPluginHooks = {
|
||||
// @ts-expect-error onBeforeTlsAccept must never return a Promise.
|
||||
async onBeforeTlsAccept() {
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-expect-error Every terminal verdict requires an explicit lifetime.
|
||||
const verdictWithoutLifetime: TrustVerdict = {
|
||||
trusted: true,
|
||||
scope: {
|
||||
kind: "certificate-for-host",
|
||||
hostname: "example.test",
|
||||
port: 443,
|
||||
certificateSha256: "leaf-sha256",
|
||||
},
|
||||
reasonEntryIds: [],
|
||||
};
|
||||
|
||||
const voteWithoutBoolean: PluginContribution = {
|
||||
entries: [
|
||||
// @ts-expect-error A vote must state its Boolean recommendation.
|
||||
{
|
||||
kind: "vote",
|
||||
code: "ambiguous-vote",
|
||||
message: "This vote deliberately omits data.trusted.",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
void asynchronousFastHook;
|
||||
void verdictWithoutLifetime;
|
||||
void voteWithoutBoolean;
|
||||
|
||||
Reference in new issue
Block a user