wildebeest/backend/src/activitypub/deliver.ts

76 wiersze
2.2 KiB
TypeScript

// https://www.w3.org/TR/activitypub/#delivery
import * as actors from 'wildebeest/backend/src/activitypub/actors'
import type { Activity } from './activities'
import type { Actor } from './actors'
import { generateDigestHeader } from 'wildebeest/backend/src/utils/http-signing-cavage'
import { signRequest } from 'wildebeest/backend/src/utils/http-signing'
import { getFollowers } from 'wildebeest/backend/src/mastodon/follow'
const headers = {
'content-type': 'application/activity+json',
}
export async function deliverToActor(signingKey: CryptoKey, from: Actor, to: Actor, activity: Activity) {
const body = JSON.stringify(activity)
console.log({ body })
let req = new Request(to.inbox, {
method: 'POST',
body,
headers,
})
const digest = await generateDigestHeader(body)
req.headers.set('Digest', digest)
await signRequest(req, signingKey, new URL(from.id))
const res = await fetch(req)
if (!res.ok) {
const body = await res.text()
throw new Error(`delivery to ${to.inbox} returned ${res.status}: ${body}`)
}
{
const body = await res.text()
console.log(`${to.inbox} returned 200: ${body}`)
}
}
export async function deliverFollowers(db: D1Database, signingKey: CryptoKey, from: Actor, activity: Activity) {
const body = JSON.stringify(activity)
const followers = await getFollowers(db, from)
const promises = followers.map(async (id) => {
const follower = new URL(id)
// FIXME: When an actor follows another Actor we should download its object
// locally, so we can retrieve the Actor's inbox without a request.
const targetActor = await actors.getAndCache(follower, db)
if (targetActor === null) {
console.warn(`actor ${follower} not found`)
return
}
const req = new Request(targetActor.inbox, {
method: 'POST',
body,
headers,
})
const digest = await generateDigestHeader(body)
req.headers.set('Digest', digest)
await signRequest(req, signingKey, new URL(from.id))
const res = await fetch(req)
if (!res.ok) {
const body = await res.text()
console.error(`delivery to ${targetActor.inbox} returned ${res.status}: ${body}`)
return
}
{
const body = await res.text()
console.log(`${targetActor.inbox} returned 200: ${body}`)
}
})
await Promise.allSettled(promises)
}