diff --git a/packages/backend/src/misc/convert-host.ts b/packages/backend/src/misc/convert-host.ts index 856ce3c127..65cc3ca1f5 100644 --- a/packages/backend/src/misc/convert-host.ts +++ b/packages/backend/src/misc/convert-host.ts @@ -1,6 +1,10 @@ import { URL } from "node:url"; import config from "@/config/index.js"; import { toASCII } from "punycode"; +import Logger from "@/services/logger.js"; +import { inspect } from "node:util"; + +const logger = new Logger("convert-host"); export function getFullApAccount(username: string, host: string | null) { return host @@ -13,6 +17,20 @@ export function isSelfHost(host: string) { return toPuny(config.host) === toPuny(host); } +export function isSameOrigin(src: unknown): boolean | null { + if (typeof src !== "string") { + logger.debug(`unknown origin: ${inspect(src)}`); + return null; + } + try { + const u = new URL(src); + return u.origin === config.url; + } catch (e) { + logger.debug(inspect(e)); + return false; + } +} + export function extractDbHost(uri: string) { const url = new URL(uri); return toPuny(url.hostname); diff --git a/packages/backend/src/remote/activitypub/models/note.ts b/packages/backend/src/remote/activitypub/models/note.ts index 19b8fe49e7..3dc54e1fb5 100644 --- a/packages/backend/src/remote/activitypub/models/note.ts +++ b/packages/backend/src/remote/activitypub/models/note.ts @@ -1,6 +1,5 @@ import promiseLimit from "promise-limit"; import * as mfm from "mfm-js"; -import config from "@/config/index.js"; import Resolver from "../resolver.js"; import post from "@/services/note/create.js"; import { extractMentionedUsers } from "@/services/note/create.js"; @@ -14,7 +13,7 @@ import { extractPollFromQuestion } from "./question.js"; import vote from "@/services/note/polls/vote.js"; import { apLogger } from "../logger.js"; import { DriveFile } from "@/models/entities/drive-file.js"; -import { extractDbHost, toPuny } from "@/misc/convert-host.js"; +import { extractDbHost, isSameOrigin, toPuny } from "@/misc/convert-host.js"; import { Emojis, Polls, @@ -234,7 +233,7 @@ export async function createNote( .catch(async (e) => { // トークだったらinReplyToのエラーは無視 const uri = getApId(note.inReplyTo); - if (uri.startsWith(`${config.url}/`)) { + if (isSameOrigin(uri)) { const id = uri.split("/").pop(); const talk = await MessagingMessages.findOneBy({ id }); if (talk) { @@ -439,7 +438,7 @@ export async function resolveNote( } //#endregion - if (uri.startsWith(config.url)) { + if (isSameOrigin(uri)) { throw new StatusError( "cannot resolve local note", 400, @@ -556,7 +555,7 @@ export async function updateNote(value: string | IObject, resolver?: Resolver) { if (!uri) throw new Error("Missing note uri"); // Skip if URI points to this server - if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local"); + if (isSameOrigin(uri)) throw new Error("uri points local"); // A new resolver is created if not specified if (resolver == null) resolver = new Resolver(); diff --git a/packages/backend/src/remote/activitypub/models/person.ts b/packages/backend/src/remote/activitypub/models/person.ts index 1b7bd41bbf..6546f041b8 100644 --- a/packages/backend/src/remote/activitypub/models/person.ts +++ b/packages/backend/src/remote/activitypub/models/person.ts @@ -19,7 +19,7 @@ import { UserNotePining } from "@/models/entities/user-note-pining.js"; import { genId } from "@/misc/gen-id.js"; import { UserPublickey } from "@/models/entities/user-publickey.js"; import { isDuplicateKeyValueError } from "@/misc/is-duplicate-key-value-error.js"; -import { toPuny } from "@/misc/convert-host.js"; +import { isSameOrigin, toPuny } from "@/misc/convert-host.js"; import { UserProfile } from "@/models/entities/user-profile.js"; import { toArray } from "@/prelude/array.js"; import { fetchInstanceMetadata } from "@/services/fetch-instance-metadata.js"; @@ -138,7 +138,7 @@ export async function fetchPerson( if (cached) return cached; // Fetch from the database if the URI points to this server - if (uri.startsWith(`${config.url}/`)) { + if (isSameOrigin(uri)) { const id = uri.split("/").pop(); const u = await Users.findOneBy({ id }); if (u) await uriPersonCache.set(uri, u); @@ -166,7 +166,7 @@ export async function createPerson( ): Promise { if (typeof uri !== "string") throw new Error("uri is not string"); - if (uri.startsWith(config.url)) { + if (isSameOrigin(uri)) { throw new StatusError( "cannot resolve local user", 400, @@ -419,7 +419,7 @@ export async function updatePerson( if (typeof uri !== "string") throw new Error("uri is not string"); // Skip if the URI points to this server - if (uri.startsWith(`${config.url}/`)) { + if (isSameOrigin(uri)) { return; } diff --git a/packages/backend/src/remote/activitypub/models/question.ts b/packages/backend/src/remote/activitypub/models/question.ts index 39963fddbf..59818654fd 100644 --- a/packages/backend/src/remote/activitypub/models/question.ts +++ b/packages/backend/src/remote/activitypub/models/question.ts @@ -1,10 +1,10 @@ -import config from "@/config/index.js"; import Resolver from "../resolver.js"; import type { IObject, IQuestion } from "../type.js"; import { getApId, isQuestion } from "../type.js"; import { apLogger } from "../logger.js"; import { Notes, Polls } from "@/models/index.js"; import type { IPoll } from "@/models/entities/poll.js"; +import { isSameOrigin } from "@/misc/convert-host.js"; export async function extractPollFromQuestion( source: string | IObject, @@ -57,7 +57,7 @@ export async function updateQuestion( const uri = typeof value === "string" ? value : getApId(value); // Skip if URI points to this server - if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local"); + if (isSameOrigin(uri)) throw new Error("uri points local"); //#region Already registered with this server? const note = await Notes.findOneBy({ uri });