UNPKG

@fedify/fedify

Version:

An ActivityPub server framework

45 lines (44 loc) 1.6 kB
import "@js-temporal/polyfill"; import "urlpattern-polyfill"; globalThis.addEventListener = () => {}; import { encodeHex } from "byte-encodings/hex"; //#region src/federation/collection.ts /** * Calculates the [partial follower collection digest][1]. * * [1]: https://w3id.org/fep/8fcf#partial-follower-collection-digest * @param uris The URIs to calculate the digest. Duplicate URIs are ignored. * @returns The digest. */ async function digest(uris) { const processed = /* @__PURE__ */ new Set(); const encoder = new TextEncoder(); const result = new Uint8Array(32); for (const uri of uris) { const u = uri instanceof URL ? uri.href : uri; if (processed.has(u)) continue; processed.add(u); const encoded = encoder.encode(u); const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", encoded)); for (let i = 0; i < 32; i++) result[i] ^= digest[i]; } return result; } /** * Builds [`Collection-Synchronization`][1] header content. * * [1]: https://w3id.org/fep/8fcf#the-collection-synchronization-http-header * * @param collectionId The sender's followers collection URI. * @param actorIds The actor URIs to digest. * @returns The header content. */ async function buildCollectionSynchronizationHeader(collectionId, actorIds) { const [anyActorId] = actorIds; const baseUrl = new URL(anyActorId); const url = new URL(collectionId); url.searchParams.set("base-url", `${baseUrl.origin}/`); return `collectionId="${collectionId}", url="${url}", digest="${encodeHex(await digest(actorIds))}"`; } //#endregion export { digest as n, buildCollectionSynchronizationHeader as t };