feat: add IP-based login brute-force protection (#531)
* feat: add IP-based login brute-force protection - Per-IP rate limiting: 3 failed login attempts locks the IP for 1 hour - Separate counters for password login and token auth - Global safety net: 20 req/min, hard lock after 50 total failures - Persistent lock state to ~/.hermes-web-ui/.login-lock.json (survives restarts) - Manual unlock: edit or delete the lock file - Frontend handles 429/503 responses with localized error messages - i18n support for 8 languages * feat: add locked IP management endpoint and UI - GET /api/auth/locked-ips: list all currently locked IPs (protected) - DELETE /api/auth/locked-ips/:ip: unlock a specific IP (protected) - DELETE /api/auth/locked-ips: unlock all IPs (protected) - AccountSettings: shows locked IPs with remaining time, unlock buttons - i18n support for 8 languages - Clean up stale .js artifacts, add .gitignore rule * fix: cross-type IP lock and IPv6-compatible unlock route - Password and token login now share IP lock state: if an IP is locked by either method, ALL auth methods are blocked for that IP - Changed unlock endpoint from path param to query param (?ip=xxx) to support IPv6 addresses containing colons - Merged unlockIp and unlockAll into a single handler * chore: increase global login rate limit from 20 to 100 requests per minute Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: ekko <fqsy1416@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ export default {
|
||||
passwordPlaceholder: '비밀번호',
|
||||
credentialsRequired: '사용자 이름과 비밀번호를 입력해 주세요',
|
||||
invalidCredentials: '사용자 이름 또는 비밀번호가 올바르지 않습니다',
|
||||
tooManyAttempts: '로그인 시도 횟수가 너무 많습니다. 잠시 후 다시 시도해 주세요',
|
||||
passwordMismatch: '비밀번호가 일치하지 않습니다',
|
||||
passwordTooShort: '비밀번호는 6자 이상이어야 합니다',
|
||||
setupSuccess: '비밀번호 로그인이 설정되었습니다',
|
||||
@@ -519,6 +520,16 @@ export default {
|
||||
cors: 'CORS 출처',
|
||||
corsHint: '허용된 교차 출처',
|
||||
},
|
||||
lockedIps: {
|
||||
title: '잠긴 IP 관리',
|
||||
count: '{count}개 잠김',
|
||||
empty: '잠긴 IP 없음',
|
||||
unlock: '잠금 해제',
|
||||
unlockAll: '전체 해제',
|
||||
unlockAllConfirm: '모든 잠긴 IP를 해제하시겠습니까?',
|
||||
unlocked: 'IP 잠금 해제됨',
|
||||
allUnlocked: '{count}개 IP 잠금 해제됨',
|
||||
},
|
||||
},
|
||||
|
||||
// 플랫폼 채널 설정
|
||||
|
||||
Reference in New Issue
Block a user