fix(api): 🔒 Replace bad webfinger regex with good one

This commit is contained in:
Jesse Wierzbinski 2024-05-12 16:27:40 -10:00
parent 9ad0f88ff2
commit 4f070c9b65
No known key found for this signature in database
3 changed files with 33 additions and 16 deletions

View file

@ -1,3 +1,4 @@
import { mentionValidator } from "@api";
import markdownItTaskLists from "@hackmd/markdown-it-task-lists"; import markdownItTaskLists from "@hackmd/markdown-it-task-lists";
import { dualLogger } from "@loggers"; import { dualLogger } from "@loggers";
import { sanitizeHtml, sanitizeHtmlInline } from "@sanitization"; import { sanitizeHtml, sanitizeHtmlInline } from "@sanitization";
@ -365,26 +366,13 @@ export const resolveNote = async (
return createdNote; return createdNote;
}; };
export const createMentionRegExp = () =>
createRegExp(
exactly("@"),
oneOrMore(anyOf(letter.lowercase, digit, charIn("-"))).groupedAs(
"username",
),
maybe(
exactly("@"),
oneOrMore(anyOf(letter, digit, charIn("_-.:"))).groupedAs("domain"),
),
[global],
);
/** /**
* Get people mentioned in the content (match @username or @username@domain.com mentions) * Get people mentioned in the content (match @username or @username@domain.com mentions)
* @param text The text to parse mentions from. * @param text The text to parse mentions from.
* @returns An array of users mentioned in the text. * @returns An array of users mentioned in the text.
*/ */
export const parseTextMentions = async (text: string): Promise<User[]> => { export const parseTextMentions = async (text: string): Promise<User[]> => {
const mentionedPeople = [...text.matchAll(createMentionRegExp())] ?? []; const mentionedPeople = [...text.matchAll(mentionValidator)] ?? [];
if (mentionedPeople.length === 0) return []; if (mentionedPeople.length === 0) return [];
const baseUrlHost = new URL(config.http.base_url).host; const baseUrlHost = new URL(config.http.base_url).host;

View file

@ -1,4 +1,9 @@
import { applyConfig, handleZodError, idValidator } from "@api"; import {
applyConfig,
handleZodError,
idValidator,
webfingerMention,
} from "@api";
import { zValidator } from "@hono/zod-validator"; import { zValidator } from "@hono/zod-validator";
import { errorResponse, jsonResponse } from "@response"; import { errorResponse, jsonResponse } from "@response";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
@ -36,7 +41,7 @@ export default (app: Hono) =>
const { resource } = context.req.valid("query"); const { resource } = context.req.valid("query");
// Check if resource is in the correct format (acct:uuid/username@domain) // Check if resource is in the correct format (acct:uuid/username@domain)
if (!resource.match(/^acct:[a-zA-Z0-9-]+@[a-zA-Z0-9.-:]+$/)) { if (!resource.match(webfingerMention)) {
return errorResponse( return errorResponse(
"Invalid resource (should be acct:(id or username)@domain)", "Invalid resource (should be acct:(id or username)@domain)",
400, 400,

View file

@ -11,7 +11,9 @@ import {
createRegExp, createRegExp,
digit, digit,
exactly, exactly,
global,
letter, letter,
maybe,
oneOrMore, oneOrMore,
} from "magic-regexp"; } from "magic-regexp";
import { parse } from "qs"; import { parse } from "qs";
@ -64,6 +66,28 @@ export const emojiValidatorWithColons = createRegExp(
[caseInsensitive], [caseInsensitive],
); );
export const mentionValidator = createRegExp(
exactly("@"),
oneOrMore(anyOf(letter.lowercase, digit, charIn("-"))).groupedAs(
"username",
),
maybe(
exactly("@"),
oneOrMore(anyOf(letter, digit, charIn("_-.:"))).groupedAs("domain"),
),
[global],
);
export const webfingerMention = createRegExp(
exactly("acct:"),
oneOrMore(anyOf(letter, digit, charIn("-"))).groupedAs("username"),
maybe(
exactly("@"),
oneOrMore(anyOf(letter, digit, charIn("_-.:"))).groupedAs("domain"),
),
[],
);
export const handleZodError = ( export const handleZodError = (
result: result:
| { success: true; data?: object } | { success: true; data?: object }