Files
sori.studio/lib/signup-blocked-usernames.js
zenn b77f37a94e v1.3.1: 어나운스 바·가입 금지 닉네임·설정 UI 개선
공개 상단 어나운스 바와 관리자 맞춤 설정을 추가하고, 스팸 필터에서 가입 금지 닉네임을 관리·검증한다. POST 설정 읽기 모드 비활성 토글과 설정 내비 아이콘 틀을 반영한다.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 15:50:47 +09:00

111 lines
2.9 KiB
JavaScript

/** @type {readonly string[]} 가입 금지 닉네임 기본값 */
export const DEFAULT_SIGNUP_BLOCKED_USERNAMES = Object.freeze([
'admin',
'master',
'zenn',
'sori',
'sori.studio'
])
/** @type {number} 금지 닉네임 최대 개수 */
export const MAX_SIGNUP_BLOCKED_USERNAME_COUNT = 100
/** @type {number} 금지 닉네임 한 항목 최대 길이 */
export const MAX_SIGNUP_BLOCKED_USERNAME_LENGTH = 60
/**
* 금지 닉네임 목록을 정리한다.
* @param {unknown} value - 원본 값
* @returns {string[]} 정리된 목록
*/
export const normalizeSignupBlockedUsernames = (value) => {
const source = Array.isArray(value) ? value : []
const seen = new Set()
const result = []
for (const item of source) {
const term = String(item || '').trim()
if (!term) {
continue
}
const key = term.toLowerCase()
if (seen.has(key)) {
continue
}
seen.add(key)
result.push(term.slice(0, MAX_SIGNUP_BLOCKED_USERNAME_LENGTH))
if (result.length >= MAX_SIGNUP_BLOCKED_USERNAME_COUNT) {
break
}
}
return result.length > 0 ? result : [...DEFAULT_SIGNUP_BLOCKED_USERNAMES]
}
/**
* DB에 저장된 금지 닉네임 JSON 문자열을 파싱한다.
* @param {unknown} raw - DB 값
* @returns {string[]} 정리된 목록
*/
export const parseSignupBlockedUsernamesFromDb = (raw) => {
if (Array.isArray(raw)) {
return normalizeSignupBlockedUsernames(raw)
}
if (typeof raw === 'string' && raw.trim()) {
try {
return normalizeSignupBlockedUsernames(JSON.parse(raw))
} catch {
return [...DEFAULT_SIGNUP_BLOCKED_USERNAMES]
}
}
return [...DEFAULT_SIGNUP_BLOCKED_USERNAMES]
}
/**
* 줄 단위 텍스트를 금지 닉네임 배열로 변환한다.
* @param {string} text - 줄바꿈 구분 입력
* @returns {string[]} 정리된 목록
*/
export const parseSignupBlockedUsernamesFromText = (text) => {
const lines = String(text || '').split(/\r?\n/)
return normalizeSignupBlockedUsernames(lines)
}
/**
* 닉네임에 금지 단어가 포함되는지 확인한다.
* @param {string} username - 닉네임
* @param {string[]} blockedList - 금지 목록
* @returns {string | null} 매칭된 금지 단어(표시용)
*/
export const getSignupBlockedUsernameMatch = (username, blockedList) => {
const normalized = username.trim().toLowerCase()
if (!normalized) {
return null
}
const terms = normalizeSignupBlockedUsernames(blockedList)
.slice()
.sort((left, right) => right.length - left.length)
for (const term of terms) {
const key = term.toLowerCase()
if (normalized === key || normalized.includes(key)) {
return term
}
}
return null
}
/**
* 금지 닉네임 안내 문구를 만든다.
* @param {string} matchedTerm - 매칭된 금지 단어
* @returns {string} 안내 문구
*/
export const formatSignupBlockedUsernameMessage = (matchedTerm) => `${matchedTerm}은 사용할 수 없는 단어입니다.`