UNPKG

@fedify/fedify

Version:

An ActivityPub server framework

44 lines (43 loc) 1.6 kB
import * as dntShim from "../_dnt.shims.js"; import { encodeHex } from "../deps/jsr.io/@std/encoding/1.0.7/hex.js"; /** * 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. */ export async function digest(uris) { const processed = 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 dntShim.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. */ export 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}/`); const hash = encodeHex(await digest(actorIds)); return `collectionId="${collectionId}", url="${url}", digest="${hash}"`; }