Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions src/core/directory-admission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ export interface DirectoryAdmissionDeps {
}

interface Verdict {
proof: string;
ok: boolean;
/** When a refusal stops being remembered (epoch ms). */
until: number;
Expand All @@ -65,7 +64,7 @@ export function directoryAdmission(
deps: Readonly<DirectoryAdmissionDeps>,
): (entries: readonly DirectoryEntry[]) => Promise<DirectoryEntry[]> {
const { gatewayTrust, verifyMembership } = deps;
/** Keyed by kind and device, since a device can carry one proof of each kind. */
/** Keyed by kind, device and proof. A directory event can carry several proofs for one device at once, a stale copy beside a fresh one, so a slot per device would be overwritten by each in turn and every event would verify them all again. */
const verdicts = new Map<string, Verdict>();

const remember = (key: string, verdict: Readonly<Verdict>): void => {
Expand Down Expand Up @@ -123,9 +122,9 @@ export function directoryAdmission(
const proof = readMembershipProof(entry.advert, field);
if (proof === undefined) continue;

const key = `${kind}:${deviceHex}`;
const key = `${kind}:${deviceHex}:${proof}`;
const known = verdicts.get(key);
if (known?.proof === proof) {
if (known !== undefined) {
if (known.ok && gatewayTrust.isVouchedBy(deviceHex, kind)) {
vouched = true;
continue;
Expand All @@ -137,7 +136,6 @@ export function directoryAdmission(

const vouch = await vouchedFor(proof, deviceHex, kind);
remember(key, {
proof,
ok: vouch !== undefined,
until: Date.now() + NEGATIVE_VERDICT_TTL_MS,
});
Expand Down
22 changes: 22 additions & 0 deletions src/test/directory-admission.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,28 @@ describe("directoryAdmission", () => {
expect(verifyMembership).toHaveBeenCalledTimes(1);
});

it("does not re-verify either of two proofs for one device that arrive in alternation", async () => {
const trust = new GatewayTrust();
trust.addPrincipal(PRINCIPAL);
const verifyMembership = verifier(false);
const admit = directoryAdmission({ gatewayTrust: trust, verifyMembership });

await admit([
entry("alternating", "proof-a"),
entry("alternating", "proof-b"),
]);
await admit([
entry("alternating", "proof-a"),
entry("alternating", "proof-b"),
]);
await admit([
entry("alternating", "proof-b"),
entry("alternating", "proof-a"),
]);

expect(verifyMembership).toHaveBeenCalledTimes(2);
});

it("verifies a device's new proof even while its old one is still good, so its trust is renewed before the old one lapses", async () => {
const trust = new GatewayTrust();
trust.addPrincipal(PRINCIPAL);
Expand Down
Loading