From e6170f0d97c47f420ca9881dcece49f4fc2273aa Mon Sep 17 00:00:00 2001 From: scanash00 Date: Fri, 12 Jun 2026 10:33:27 -0800 Subject: [PATCH] Reconstruct the trusted-verifier set instead of trusting every issuer The earlier verification pass counted any issuer, which would show false badges (e.g. bsky.app had 54 raw verification records, 53 from untrusted accounts). Trust is actually expressed on-network: Bluesky's root DID issues a verification record to each trusted verifier, who can then verify regular users. So a verification of X by issuer I counts only if the root DID verified I. This is a two-hop backlink lookup, fully reconstructable from Constellation with no private allowlist - the only constant is the root DID itself. hydrateVerificationState now filters verifications to trusted issuers and sets the subject's trustedVerifierStatus from whether the root verified it directly. Verified: bsky.app/nytimes/wired each collapse from raw records to exactly 1 trusted verification, all trustedVerifierStatus=valid. --- src/lib/microcosm/hydrate.ts | 90 ++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 19 deletions(-) diff --git a/src/lib/microcosm/hydrate.ts b/src/lib/microcosm/hydrate.ts index 98dce9a..53e0512 100644 --- a/src/lib/microcosm/hydrate.ts +++ b/src/lib/microcosm/hydrate.ts @@ -30,6 +30,40 @@ import {constellation} from '#/lib/microcosm' import {getRecordByUri, resolveMiniDoc} from '#/lib/microcosm/slingshot' import {IMG_CDN_URL} from '#/env' +/** + * The root of trust for verifications. Bluesky designates "trusted verifiers" + * by issuing them a verification record from this DID; those verifiers can in + * turn verify regular users. A verification of X by issuer I therefore only + * counts if Bluesky verified I (i.e. I is a trusted verifier). This mirrors the + * AppView's trusted-verifier filter, reconstructed entirely from records rather + * than a private allowlist. + */ +const VERIFICATION_ROOT_DID = 'did:plc:z72i7hdynmk6r22z27h6tvur' + +/** + * Whether `did` is a trusted verifier: Bluesky's root DID issued a verification + * record for it. Cached because the same issuer recurs across many profiles. + */ +const trustedVerifierCache = new Map>() +function isTrustedVerifier(did: string, signal?: AbortSignal): Promise { + const hit = trustedVerifierCache.get(did) + if (hit) return hit + const p = constellation + .getBacklinks( + { + subject: did, + source: constellation.Sources.verifications, + did: [VERIFICATION_ROOT_DID], + limit: 1, + }, + signal, + ) + .then(r => r.total > 0) + .catch(() => false) + trustedVerifierCache.set(did, p) + return p +} + /** * Image CDN base. Avatars/banners/feed images are blob refs in the raw record; * the AppView rewrites them to CDN URLs and we reconstruct the same scheme @@ -201,33 +235,52 @@ async function hydrateEmbed( * `app.bsky.graph.verification` records whose `subject` points at the verified * DID (a Constellation backlink); each record's repo is the issuer. * - * NOTE on "trusted verifiers": the AppView only surfaces verifications from a - * curated trusted-verifier set, which is Bluesky policy not present in the - * records, so we can't reproduce that filter. We include every issuer and let - * the UI decide. `isValid` is computed structurally: the handle captured in the - * record must still match the subject's current handle (per the lexicon). + * Trust is reconstructed, not assumed: a verification only counts if its issuer + * is a trusted verifier, i.e. Bluesky's root DID verified that issuer (see + * `isTrustedVerifier`). Verifications from untrusted issuers are dropped, matching + * the AppView. `isValid` additionally requires that the handle captured in the + * record still matches the subject's current handle (per the lexicon). + * + * The subject's own `trustedVerifierStatus` is `valid` iff Bluesky verified the + * subject directly (which is how a trusted verifier is designated). */ async function hydrateVerificationState( did: string, currentHandle: string, signal?: AbortSignal, ): Promise { - const page = await constellation - .getBacklinks( - { - subject: did, - source: constellation.Sources.verifications, - limit: 20, - }, - signal, - ) - .catch(() => undefined) - if (!page || page.records.length === 0) return undefined + const [page, subjectIsVerifier] = await Promise.all([ + constellation + .getBacklinks( + { + subject: did, + source: constellation.Sources.verifications, + limit: 20, + }, + signal, + ) + .catch(() => undefined), + isTrustedVerifier(did, signal), + ]) + + const trustedVerifierStatus = subjectIsVerifier ? 'valid' : 'none' + + if (!page || page.records.length === 0) { + if (!subjectIsVerifier) return undefined + return { + $type: 'app.bsky.actor.defs#verificationState', + verifications: [], + verifiedStatus: 'none', + trustedVerifierStatus, + } + } const verifications = ( await Promise.all( page.records.map( async (ref): Promise => { + // Only verifications from trusted verifiers count. + if (!(await isTrustedVerifier(ref.did, signal))) return undefined const uri = `at://${ref.did}/${ref.collection}/${ref.rkey}` const rec = await getRecordByUri(uri, undefined, signal).catch( () => undefined, @@ -259,15 +312,14 @@ async function hydrateVerificationState( ) ).filter(Boolean) as AppBskyActorDefs.VerificationView[] - if (verifications.length === 0) return undefined + if (verifications.length === 0 && !subjectIsVerifier) return undefined const verifiedStatus = verifications.some(v => v.isValid) ? 'valid' : 'none' return { $type: 'app.bsky.actor.defs#verificationState', verifications, verifiedStatus, - // We are not a trusted verifier ourselves; report none. - trustedVerifierStatus: 'none', + trustedVerifierStatus, } } -- 2.51.2