Files
gunshiz 20c52fac04
CI / Verify (push) Successful in 1m41s
CI / Build immutable images and deploy (push) Successful in 2m30s
feat(comments) : filter abusive language and prevent spam
2026-10-08 04:45:45 +07:00

27 lines
1.4 KiB
TypeScript

import { HttpError } from "@/lib/security/http";
// Keep the list focused: broad substring matches reject ordinary game discussion.
const englishTerms = ["fuck", "fucking", "fucker", "motherfucker", "shit", "bullshit", "bitch", "cunt", "asshole", "nigger", "nigga", "faggot"];
const substitutions: Record<string, string> = { a: "[a@4]", e: "[e3]", i: "[i1!]", o: "[o0]", s: "[s$5]", t: "[t7]" };
const abusiveEnglish = new RegExp(
`(?<![\\p{L}\\p{N}])(?:${englishTerms.map((term) => [...term].map((letter) => substitutions[letter] ?? letter).join("[\\s\\p{P}\\p{S}]*")).join("|")})(?![\\p{L}\\p{N}])`,
"u",
);
const abusiveThai = /(?:ไอ้เหี้ย|อีเหี้ย|ไอ้สัส|อีสัส|เย็ดแม่|ควย)/u;
export function normalizeCommentText(text: string) {
return text.normalize("NFKC").toLowerCase().replace(/\p{Cf}/gu, "").replace(/\s+/gu, " ").trim();
}
export function checkCommentContent(text: string) {
const normalized = normalizeCommentText(text);
if (text && !normalized) throw new HttpError(400, "empty-comment");
if (abusiveEnglish.test(normalized) || abusiveThai.test(normalized))
throw new HttpError(400, "comment-abusive-language");
if ((normalized.match(/(?:https?:\/\/|www\.)[^\s]+/gu)?.length ?? 0) > 3 ||
/(.)\1{19,}/u.test(normalized) ||
/(?:^|\s)(\S+(?:\s+\S+){0,4})(?:\s+\1){7,}(?=\s|$)/u.test(normalized))
throw new HttpError(400, "comment-spam");
return normalized;
}