[backend] Strengthen checks against local object resolution

This commit addresses disclosed primitives 26-29 & 31-33
This commit is contained in:
Laura Hausmann 2024-10-29 17:44:40 +01:00
parent ca331d2406
commit 065590279e
No known key found for this signature in database
GPG Key ID: D044E84C5BE01605
4 changed files with 15 additions and 13 deletions

View File

@ -19,6 +19,7 @@ import type { IObject } from "./type.js";
import { getApId } from "./type.js"; import { getApId } from "./type.js";
import { resolvePerson, updatePerson } from "./models/person.js"; import { resolvePerson, updatePerson } from "./models/person.js";
import {redisClient, subscriber} from "@/db/redis.js"; import {redisClient, subscriber} from "@/db/redis.js";
import { extractDbHost, toPuny } from "@/misc/convert-host.js";
const publicKeyCache = new Cache<UserPublickey | null>("publicKey", 60 * 30); const publicKeyCache = new Cache<UserPublickey | null>("publicKey", 60 * 30);
const publicKeyByUserIdCache = new Cache<UserPublickey | null>( const publicKeyByUserIdCache = new Cache<UserPublickey | null>(
@ -46,15 +47,15 @@ export type UriParseResult =
export function parseUri(value: string | IObject): UriParseResult { export function parseUri(value: string | IObject): UriParseResult {
const uri = getApId(value); const uri = getApId(value);
const parsed = new URL(uri);
// the host part of a URL is case insensitive, so use the 'i' flag. if (toPuny(parsed.host) === toPuny(config.host)) {
const localRegex = new RegExp( const localRegex = new RegExp(`^.*?/(\\w+)/(\\w+)(?:/(.+))?`);
`^${escapeRegexp(config.url)}/(\\w+)/(\\w+)(?:/(.+))?`,
"i",
);
const matchLocal = uri.match(localRegex); const matchLocal = uri.match(localRegex);
if (matchLocal == null) {
throw new Error(`Failed to parse local URI: ${uri}`);
}
if (matchLocal) {
return { return {
local: true, local: true,
type: matchLocal[1], type: matchLocal[1],

View File

@ -455,7 +455,7 @@ export async function resolveNote(
} }
//#endregion //#endregion
if (uri.startsWith(config.url)) { if (extractDbHost(uri) === toPuny(config.host)) {
throw new StatusError( throw new StatusError(
"cannot resolve local note", "cannot resolve local note",
400, 400,
@ -572,7 +572,7 @@ export async function updateNote(value: string | IObject, actor: CacheableRemote
if (!uri) throw new Error("Missing note uri"); if (!uri) throw new Error("Missing note uri");
// Skip if URI points to this server // Skip if URI points to this server
if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local"); if (extractDbHost(uri) === toPuny(config.host)) throw new Error("uri points local");
// A new resolver is created if not specified // A new resolver is created if not specified
if (resolver == null) resolver = new Resolver(); if (resolver == null) resolver = new Resolver();

View File

@ -174,7 +174,7 @@ export async function fetchPerson(
if (cached) return cached; if (cached) return cached;
// Fetch from the database if the URI points to this server // Fetch from the database if the URI points to this server
if (uri.startsWith(`${config.url}/`)) { if (extractDbHost(uri) === toPuny(config.host)) {
const id = uri.split("/").pop(); const id = uri.split("/").pop();
const u = await Users.findOneBy({ id }); const u = await Users.findOneBy({ id });
if (u) await uriPersonCache.set(uri, u); if (u) await uriPersonCache.set(uri, u);
@ -204,7 +204,7 @@ export async function createPerson(
): Promise<User> { ): Promise<User> {
if (typeof uri !== "string") throw new Error("uri is not string"); if (typeof uri !== "string") throw new Error("uri is not string");
if (uri.startsWith(config.url)) { if (extractDbHost(uri) === toPuny(config.host)) {
throw new StatusError( throw new StatusError(
"cannot resolve local user", "cannot resolve local user",
400, 400,
@ -507,7 +507,7 @@ export async function updatePerson(
if (typeof uri !== "string") throw new Error("uri is not string"); if (typeof uri !== "string") throw new Error("uri is not string");
// Skip if the URI points to this server // Skip if the URI points to this server
if (uri.startsWith(`${config.url}/`)) { if (extractDbHost(uri) === toPuny(config.host)) {
return; return;
} }

View File

@ -5,6 +5,7 @@ import { getApId, isQuestion } from "../type.js";
import { apLogger } from "../logger.js"; import { apLogger } from "../logger.js";
import { Notes, Polls } from "@/models/index.js"; import { Notes, Polls } from "@/models/index.js";
import type { IPoll } from "@/models/entities/poll.js"; import type { IPoll } from "@/models/entities/poll.js";
import { extractDbHost, toPuny } from "@/misc/convert-host.js";
export async function extractPollFromQuestion( export async function extractPollFromQuestion(
source: string | IObject, source: string | IObject,
@ -55,7 +56,7 @@ export async function updateQuestion(
const uri = typeof value === "string" ? value : getApId(value); const uri = typeof value === "string" ? value : getApId(value);
// Skip if URI points to this server // Skip if URI points to this server
if (uri.startsWith(`${config.url}/`)) throw new Error("uri points local"); if (extractDbHost(uri) === toPuny(config.host)) throw new Error("uri points local");
//#region Already registered with this server? //#region Already registered with this server?
const note = await Notes.findOneBy({ uri }); const note = await Notes.findOneBy({ uri });