diff --git a/packages/backend/src/misc/fetch.ts b/packages/backend/src/misc/fetch.ts index b24eecd86..661716e25 100644 --- a/packages/backend/src/misc/fetch.ts +++ b/packages/backend/src/misc/fetch.ts @@ -35,7 +35,7 @@ export async function getHtml(url: string, accept = 'text/html, */*', timeout = return await res.text(); } -export async function getResponse(args: { url: string, method: string, body?: string, headers: Record, timeout?: number, size?: number }) { +export async function getResponse(args: { url: string, method: string, body?: string, headers: Record, timeout?: number, size?: number, redirect: 'follow' | 'manual' | 'error' = 'follow' }) { const timeout = args.timeout || 10 * SECOND; const controller = new AbortController(); @@ -47,8 +47,9 @@ export async function getResponse(args: { url: string, method: string, body?: st method: args.method, headers: args.headers, body: args.body, + redirect: args.redirect, timeout, - size: args.size || 10 * 1024 * 1024, + size: args.size || 10 * 1024 * 1024, // 10 MiB agent: getAgentByUrl, signal: controller.signal, }); diff --git a/packages/backend/src/remote/activitypub/request.ts b/packages/backend/src/remote/activitypub/request.ts index ccdd30a00..dd1aeccea 100644 --- a/packages/backend/src/remote/activitypub/request.ts +++ b/packages/backend/src/remote/activitypub/request.ts @@ -1,3 +1,4 @@ +import { URL } from 'node:url'; import config from '@/config/index.js'; import { getUserKeypair } from '@/misc/keypair-store.js'; import { User } from '@/models/entities/user.js'; @@ -37,22 +38,32 @@ export async function request(user: { id: User['id'] }, url: string, object: any export async function signedGet(url: string, user: { id: User['id'] }): Promise { const keypair = await getUserKeypair(user.id); - const req = createSignedGet({ - key: { - privateKeyPem: keypair.privateKey, - keyId: `${config.url}/users/${user.id}#main-key`, - }, - url, - additionalHeaders: { - 'User-Agent': config.userAgent, - }, - }); + for (let redirects = 0; redirects < 3; redirects++) { + const req = createSignedGet({ + key: { + privateKeyPem: keypair.privateKey, + keyId: `${config.url}/users/${user.id}#main-key`, + }, + url, + additionalHeaders: { + 'User-Agent': config.userAgent, + }, + }); - const res = await getResponse({ - url, - method: req.request.method, - headers: req.request.headers, - }); + const res = await getResponse({ + url, + method: req.request.method, + headers: req.request.headers, + }); - return await res.json(); + if (res.status >= 300 && res.status < 400) { + // Have been redirected, need to make a new signature. + // Use Location header and fetched URL as the base URL. + url = new URL(res.headers.get('Location'), url).href; + } else { + return await res.json(); + } + } + + throw new Error('too many redirects'); }