diff --git a/package-lock.json b/package-lock.json
index 2065998f..46c60bfa 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"@tanstack/react-query": "^5.90.5",
"@tanstack/react-query-devtools": "^5.90.2",
"axios": "^1.13.1",
+ "badwords-ko": "^1.0.4",
"clsx": "^2.1.1",
"framer-motion": "^12.23.24",
"jotai": "^2.15.1",
@@ -6400,6 +6401,12 @@
"@babel/core": "^7.11.0 || ^8.0.0-beta.1"
}
},
+ "node_modules/badwords-ko": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/badwords-ko/-/badwords-ko-1.0.4.tgz",
+ "integrity": "sha512-l2gJiVkIXd1nyyRI6aXEujq+aCiMfCyREUdK68mUnH6iZy8+mvXvkvOLO6Nv6MXiRKgvdUQEmSeuVno38MX+wA==",
+ "license": "MIT"
+ },
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
diff --git a/package.json b/package.json
index c947c29b..502435ad 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"@tanstack/react-query": "^5.90.5",
"@tanstack/react-query-devtools": "^5.90.2",
"axios": "^1.13.1",
+ "badwords-ko": "^1.0.4",
"clsx": "^2.1.1",
"framer-motion": "^12.23.24",
"jotai": "^2.15.1",
diff --git a/src/app/(auth)/signup/page.tsx b/src/app/(auth)/signup/page.tsx
index 342cc978..287d1b06 100644
--- a/src/app/(auth)/signup/page.tsx
+++ b/src/app/(auth)/signup/page.tsx
@@ -1,6 +1,6 @@
"use client";
-import React, { useEffect, useState } from "react";
+import React, { useState } from "react";
import SingUpInFormWrapper from "../_components/form_wrapper";
import { useForm } from "react-hook-form";
import {
@@ -12,6 +12,7 @@ import { Button, Icon, TextInput, LoadingSpinner } from "@/components";
import { useSignupQuery } from "@/hooks/auth/use-signup-query";
import type { SignupRequest } from "@/api/auth/signup-action";
import SimpleSignUpIn from "../_components/simple-signUpIn";
+import { hasProfanity } from "@/utils/profanityFilter";
const Page = () => {
const [showPassword, setShowPassword] = useState(false);
@@ -57,6 +58,10 @@ const Page = () => {
aria-describedby={errors.nickname ? "nickname-error" : undefined}
{...register("nickname", {
required: "닉네임을 입력해주세요.",
+ validate: {
+ noProfanity: (value) =>
+ !hasProfanity(value) || "부적절한 닉네임입니다.",
+ },
})}
/>
@@ -75,6 +80,15 @@ const Page = () => {
value: EMAIL_REGEX,
message: "이메일 형식이 올바르지 않습니다.",
},
+ validate: {
+ noProfanityInEmail: (value) => {
+ const localPart = value.split("@")[0];
+ return (
+ !hasProfanity(localPart) ||
+ "이메일에 부적절한 단어가 포함되어 있습니다."
+ );
+ },
+ },
})}
/>
diff --git a/src/app/boards/[articleId]/_components/article-comments/article-comments.tsx b/src/app/boards/[articleId]/_components/article-comments/article-comments.tsx
index fc0bf951..6c820181 100644
--- a/src/app/boards/[articleId]/_components/article-comments/article-comments.tsx
+++ b/src/app/boards/[articleId]/_components/article-comments/article-comments.tsx
@@ -13,6 +13,7 @@ import usePatchArticleComment from "@/hooks/api/articles/use-patch-article-comme
import useDeleteArticleComment from "@/hooks/api/articles/use-delete-article-comment";
import LikeButton from "@/components/lottie/LikeButton";
import DefaultProfile from "@/assets/icons/ic-user.svg";
+import { filterProfanity } from "@/utils/profanityFilter";
interface ArticleCommentsProps {
article: Article;
@@ -61,10 +62,12 @@ const ArticleComments = ({ article }: ArticleCommentsProps) => {
}, [fetchNextPage, hasNextPage, isFetchingNextPage]);
const handleCommentSubmit = (content: string) => {
+ const filteredContent = filterProfanity(content);
+
mutate({
articleId: article.id,
data: {
- content,
+ content: filteredContent,
},
});
};
@@ -135,9 +138,10 @@ const ArticleComments = ({ article }: ArticleCommentsProps) => {
- patchComment({ commentId, content })
- }
+ onEdit={(commentId, content) => {
+ const filteredContent = filterProfanity(content);
+ patchComment({ commentId, content: filteredContent });
+ }}
onDelete={(commentId) =>
deleteComment({ commentId, articleId: article.id })
}
diff --git a/src/app/boards/[articleId]/edit/_components/article-edit-contents/article-edit-contents.tsx b/src/app/boards/[articleId]/edit/_components/article-edit-contents/article-edit-contents.tsx
index f9fc0d23..db5f54ea 100644
--- a/src/app/boards/[articleId]/edit/_components/article-edit-contents/article-edit-contents.tsx
+++ b/src/app/boards/[articleId]/edit/_components/article-edit-contents/article-edit-contents.tsx
@@ -12,6 +12,7 @@ import {
} from "@/components/index";
import usePatchArticle from "@/hooks/api/articles/use-patch-article";
import { Article } from "@/types/article";
+import { filterProfanity } from "@/utils/profanityFilter";
interface ArticleEditContentsProps {
article: Article;
@@ -44,12 +45,15 @@ const ArticleEditContents = ({ article }: ArticleEditContentsProps) => {
}, []);
const onSubmit = (data: EditFormData) => {
+ const filteredTitle = filterProfanity(data.title);
+ const filteredContent = filterProfanity(data.content);
+
mutate(
{
articleId: article.id,
data: {
- title: data.title,
- content: data.content,
+ title: filteredTitle,
+ content: filteredContent,
image: images[0] || undefined,
},
},
diff --git a/src/app/boards/page.tsx b/src/app/boards/page.tsx
index 534de692..e2faa787 100644
--- a/src/app/boards/page.tsx
+++ b/src/app/boards/page.tsx
@@ -24,8 +24,8 @@ const Page = () => {
-