From 9fc45f166c033ce1ef21724e61d888407b25f3ea Mon Sep 17 00:00:00 2001 From: Laura Hausmann Date: Fri, 16 Feb 2024 18:22:38 +0100 Subject: [PATCH] [backend] Verify response content type when fetching remote activities --- packages/backend/src/misc/fetch.ts | 26 +++++++++++++++++++ .../backend/src/remote/activitypub/request.ts | 4 +++ .../src/remote/activitypub/resolver.ts | 4 +-- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/misc/fetch.ts b/packages/backend/src/misc/fetch.ts index ff9cf6e0c..1cbaa78c4 100644 --- a/packages/backend/src/misc/fetch.ts +++ b/packages/backend/src/misc/fetch.ts @@ -28,6 +28,32 @@ export async function getJson( return await res.json(); } +export async function getJsonActivity( + url: string, + accept = "application/activity+json, application/ld+json", + timeout = 10000, + headers?: Record, +) { + const res = await getResponse({ + url, + method: "GET", + headers: Object.assign( + { + "User-Agent": config.userAgent, + Accept: accept, + }, + headers || {}, + ), + timeout, + }); + + const contentType = res.headers.get('content-type'); + if (contentType == null || (contentType !== 'application/activity+json' && !contentType.startsWith('application/activity+json;') && contentType !== 'application/ld+json' && !contentType.startsWith('application/ld+json;'))) + throw new Error(`getJsonActivity response had unexpected content-type: ${contentType}`); + + return await res.json(); +} + export async function getHtml( url: string, accept = "text/html, */*", diff --git a/packages/backend/src/remote/activitypub/request.ts b/packages/backend/src/remote/activitypub/request.ts index ef35fd45d..d4996c5db 100644 --- a/packages/backend/src/remote/activitypub/request.ts +++ b/packages/backend/src/remote/activitypub/request.ts @@ -65,5 +65,9 @@ export async function signedGet(url: string, user: { id: User["id"] }, redirects return signedGet(newUrl, user, false); } + const contentType = res.headers.get('content-type'); + if (contentType == null || (contentType !== 'application/activity+json' && !contentType.startsWith('application/activity+json;') && contentType !== 'application/ld+json' && !contentType.startsWith('application/ld+json;'))) + throw new Error(`signedGet response had unexpected content-type: ${contentType}`); + return await res.json(); } diff --git a/packages/backend/src/remote/activitypub/resolver.ts b/packages/backend/src/remote/activitypub/resolver.ts index 223350cae..1da888dd2 100644 --- a/packages/backend/src/remote/activitypub/resolver.ts +++ b/packages/backend/src/remote/activitypub/resolver.ts @@ -1,5 +1,5 @@ import config from "@/config/index.js"; -import { getJson } from "@/misc/fetch.js"; +import { getJsonActivity } from "@/misc/fetch.js"; import type { ILocalUser } from "@/models/entities/user.js"; import { getInstanceActor } from "@/services/instance-actor.js"; import { fetchMeta } from "@/misc/fetch-meta.js"; @@ -124,7 +124,7 @@ export default class Resolver { const object = ( this.user ? await signedGet(value, this.user) - : await getJson(value, "application/activity+json, application/ld+json") + : await getJsonActivity(value) ) as IObject; if (