@fedify/fedify
Version:
An ActivityPub server framework
44 lines (43 loc) • 1.6 kB
JavaScript
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}"`;
}