From a876ef9ad2c96feca49cce6a4c4cb82bf32c81fe Mon Sep 17 00:00:00 2001 From: Sven Sauleau Date: Thu, 23 Feb 2023 14:25:24 +0000 Subject: [PATCH] add Actor cache to webfinger --- backend/src/accounts/getAccount.ts | 6 +++--- backend/src/mastodon/status.ts | 4 ++-- backend/src/webfinger/index.ts | 4 ++-- backend/test/mastodon/accounts.spec.ts | 10 +++++----- backend/test/mastodon/statuses.spec.ts | 20 +++++++++++++------- backend/test/wildebeest/settings.spec.ts | 1 + functions/api/v1/accounts/[id]/unfollow.ts | 2 +- functions/api/v1/statuses.ts | 2 +- functions/api/v2/search.ts | 2 +- functions/api/wb/settings/account/alias.ts | 2 +- 10 files changed, 30 insertions(+), 23 deletions(-) diff --git a/backend/src/accounts/getAccount.ts b/backend/src/accounts/getAccount.ts index 569160b..304ba8a 100644 --- a/backend/src/accounts/getAccount.ts +++ b/backend/src/accounts/getAccount.ts @@ -18,17 +18,17 @@ export async function getAccount(domain: string, accountId: string, db: Database } else if (handle.domain !== null) { // Retrieve the statuses of a remote actor const acct = `${handle.localPart}@${handle.domain}` - return getRemoteAccount(handle, acct) + return getRemoteAccount(handle, acct, db) } else { return null } } -async function getRemoteAccount(handle: Handle, acct: string): Promise { +async function getRemoteAccount(handle: Handle, acct: string, db: D1Database): Promise { // TODO: using webfinger isn't the optimal implementation. We could cache // the object in D1 and directly query the remote API, indicated by the actor's // url field. For now, let's keep it simple. - const actor = await queryAcct(handle.domain!, acct) + const actor = await queryAcct(handle.domain!, db, acct) if (actor === null) { return null } diff --git a/backend/src/mastodon/status.ts b/backend/src/mastodon/status.ts index ff088ec..ccbc532 100644 --- a/backend/src/mastodon/status.ts +++ b/backend/src/mastodon/status.ts @@ -19,7 +19,7 @@ import type { APObject } from 'wildebeest/backend/src/activitypub/objects' import type { Actor } from 'wildebeest/backend/src/activitypub/actors' import { type Database } from 'wildebeest/backend/src/database' -export async function getMentions(input: string, instanceDomain: string): Promise> { +export async function getMentions(input: string, instanceDomain: string, db: Database): Promise> { const mentions: Array = [] for (let i = 0, len = input.length; i < len; i++) { @@ -34,7 +34,7 @@ export async function getMentions(input: string, instanceDomain: string): Promis const handle = parseHandle(buffer) const domain = handle.domain ? handle.domain : instanceDomain const acct = `${handle.localPart}@${domain}` - const targetActor = await queryAcct(domain!, acct) + const targetActor = await queryAcct(domain!, db, acct) if (targetActor === null) { console.warn(`actor ${acct} not found`) continue diff --git a/backend/src/webfinger/index.ts b/backend/src/webfinger/index.ts index 8f65d9e..e0f8502 100644 --- a/backend/src/webfinger/index.ts +++ b/backend/src/webfinger/index.ts @@ -11,12 +11,12 @@ const headers = { accept: 'application/jrd+json', } -export async function queryAcct(domain: string, acct: string): Promise { +export async function queryAcct(domain: string, db: D1Database, acct: string): Promise { const url = await queryAcctLink(domain, acct) if (url === null) { return null } - return actors.get(url) + return actors.getAndCache(url, db) } export async function queryAcctLink(domain: string, acct: string): Promise { diff --git a/backend/test/mastodon/accounts.spec.ts b/backend/test/mastodon/accounts.spec.ts index f29df60..6ab1640 100644 --- a/backend/test/mastodon/accounts.spec.ts +++ b/backend/test/mastodon/accounts.spec.ts @@ -976,24 +976,24 @@ describe('Mastodon APIs', () => { { rel: 'self', type: 'application/activity+json', - href: 'https://social.com/sven', + href: `https://${domain}/ap/users/actor`, }, ], }) ) } - if (request.url === 'https://social.com/sven') { + if (request.url === `https://${domain}/ap/users/actor`) { return new Response( JSON.stringify({ id: `https://${domain}/ap/users/actor`, type: 'Person', - inbox: 'https://example.com/inbox', + inbox: `https://${domain}/ap/users/actor/inbox`, }) ) } - if (request.url === 'https://example.com/inbox') { + if (request.url === `https://${domain}/ap/users/actor/inbox`) { assert.equal(request.method, 'POST') receivedActivity = await request.json() return new Response('') @@ -1040,7 +1040,7 @@ describe('Mastodon APIs', () => { const connectedActor = actor - const req = new Request('https://example.com', { method: 'POST' }) + const req = new Request('https://' + domain, { method: 'POST' }) const res = await accounts_unfollow.handleRequest(req, db, 'actor@' + domain, connectedActor, userKEK) assert.equal(res.status, 200) assertCORS(res) diff --git a/backend/test/mastodon/statuses.spec.ts b/backend/test/mastodon/statuses.spec.ts index 41f64a2..d260292 100644 --- a/backend/test/mastodon/statuses.spec.ts +++ b/backend/test/mastodon/statuses.spec.ts @@ -202,6 +202,7 @@ describe('Mastodon APIs', () => { return new Response( JSON.stringify({ id: 'https://social.com/users/sven', + type: 'Person', inbox: 'https://social.com/sven/inbox', }) ) @@ -404,6 +405,7 @@ describe('Mastodon APIs', () => { }) test('get mentions from status', async () => { + const db = await makeDB() globalThis.fetch = async (input: RequestInfo) => { if (input.toString() === 'https://instance.horse/.well-known/webfinger?resource=acct%3Asven%40instance.horse') { return new Response( @@ -467,6 +469,7 @@ describe('Mastodon APIs', () => { return new Response( JSON.stringify({ id: 'https://instance.horse/users/sven', + type: 'Person', }) ) } @@ -474,6 +477,7 @@ describe('Mastodon APIs', () => { return new Response( JSON.stringify({ id: 'https://cloudflare.com/users/sven', + type: 'Person', }) ) } @@ -481,6 +485,7 @@ describe('Mastodon APIs', () => { return new Response( JSON.stringify({ id: 'https://cloudflare.com/users/a', + type: 'Person', }) ) } @@ -488,6 +493,7 @@ describe('Mastodon APIs', () => { return new Response( JSON.stringify({ id: 'https://cloudflare.com/users/b', + type: 'Person', }) ) } @@ -496,42 +502,42 @@ describe('Mastodon APIs', () => { } { - const mentions = await getMentions('test status', domain) + const mentions = await getMentions('test status', domain, db) assert.equal(mentions.length, 0) } { - const mentions = await getMentions('no-json@actor.com', domain) + const mentions = await getMentions('no-json@actor.com', domain, db) assert.equal(mentions.length, 0) } { - const mentions = await getMentions('@sven@instance.horse test status', domain) + const mentions = await getMentions('@sven@instance.horse test status', domain, db) assert.equal(mentions.length, 1) assert.equal(mentions[0].id.toString(), 'https://instance.horse/users/sven') } { - const mentions = await getMentions('@sven test status', domain) + const mentions = await getMentions('@sven test status', domain, db) assert.equal(mentions.length, 1) assert.equal(mentions[0].id.toString(), 'https://' + domain + '/users/sven') } { - const mentions = await getMentions('@a @b', domain) + const mentions = await getMentions('@a @b', domain, db) assert.equal(mentions.length, 2) assert.equal(mentions[0].id.toString(), 'https://' + domain + '/users/a') assert.equal(mentions[1].id.toString(), 'https://' + domain + '/users/b') } { - const mentions = await getMentions('

@sven

', domain) + const mentions = await getMentions('

@sven

', domain, db) assert.equal(mentions.length, 1) assert.equal(mentions[0].id.toString(), 'https://' + domain + '/users/sven') } { - const mentions = await getMentions('

@unknown

', domain) + const mentions = await getMentions('

@unknown

', domain, db) assert.equal(mentions.length, 0) } }) diff --git a/backend/test/wildebeest/settings.spec.ts b/backend/test/wildebeest/settings.spec.ts index 3dc923a..fb14004 100644 --- a/backend/test/wildebeest/settings.spec.ts +++ b/backend/test/wildebeest/settings.spec.ts @@ -31,6 +31,7 @@ describe('Wildebeest', () => { return new Response( JSON.stringify({ id: 'https://social.com/someone', + type: 'Person', }) ) } diff --git a/functions/api/v1/accounts/[id]/unfollow.ts b/functions/api/v1/accounts/[id]/unfollow.ts index 7a8cf28..693022b 100644 --- a/functions/api/v1/accounts/[id]/unfollow.ts +++ b/functions/api/v1/accounts/[id]/unfollow.ts @@ -35,7 +35,7 @@ export async function handleRequest( } const acct = `${handle.localPart}@${handle.domain}` - const targetActor = await webfinger.queryAcct(handle.domain!, acct) + const targetActor = await webfinger.queryAcct(handle.domain!, db, acct) if (targetActor === null) { return new Response('', { status: 404 }) } diff --git a/functions/api/v1/statuses.ts b/functions/api/v1/statuses.ts index 8f9dbac..a0f1f9e 100644 --- a/functions/api/v1/statuses.ts +++ b/functions/api/v1/statuses.ts @@ -112,7 +112,7 @@ export async function handleRequest( const hashtags = getHashtags(body.status) - const mentions = await getMentions(body.status, domain) + const mentions = await getMentions(body.status, domain, db) if (mentions.length > 0) { extraProperties.tag = mentions.map(newMention) } diff --git a/functions/api/v2/search.ts b/functions/api/v2/search.ts index 7bde6f8..019e54c 100644 --- a/functions/api/v2/search.ts +++ b/functions/api/v2/search.ts @@ -50,7 +50,7 @@ export async function handleRequest(db: Database, request: Request): Promise