LoChat/TODO.md
loki5512344 689ab1a9ae
feat: anti-swear obfuscation bypass + filter statistics
- SwearNormalizer: expanded leet/lookalike map (q→р, digits), strips separators inside
  words, collapses repeated letters; single source of truth for AhoCorasick
- SwearFilter: detects obfuscated profanity on normalized text, masks tolerant matches
  in replace mode via tolerant word patterns
- FilterStatistics: per-filter block counters -> /lochat filterstats subcommand
- tests: SwearNormalizerTest, FilterStatisticsTest
2026-08-09 21:17:18 +02:00

128 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# LoChat Development TODO
> Last updated: 2026-08-04
---
## ✅ CRITICAL FIXES (blocking release — from code review 2026-08-04, all DONE)
### 1. Translation: async + bounded cache, no String.intern(), out of render() ✅
- `renderer/EnhancedChatRenderer.java` — removed blocking `applyTranslation()` from `render()` (zero network I/O in render path). Translation is now delivered via async action bar (`sendTranslationAsync` → `translateAsync().thenAccept`).
- `translate/TranslationService.java` — no more `String.intern()`; bounded LRU cache (2000 entries, synchronized LinkedHashMap); `translateAsync` runs on a dedicated 2-thread daemon executor; failures return original text, never throw.
### 2. Atomic file writes (temp + rename, per-file lock) for all persistence ✅
- `utils/persistence/FilePersistence.java` — `saveYaml`/`saveJson` now write `<name>.tmp` + `Files.move(ATOMIC_MOVE, REPLACE_EXISTING)` under a per-file `ReentrantLock`.
- `core/service/PlayerServiceImpl.java` — `statsLock` serializes async `persistPlayerMessages` and main-thread `saveAll()`.
- `core/service/PunishmentServiceImpl.java` — removed `saveAsync()` from `isBanned()` read path.
- `core/service/mute/MuteDataStorage.java` — uses `FilePersistence.saveJson` (atomic), dropped raw FileWriter.
- `core/service/mute/MuteHistoryManager.java` — atomic temp+rename write under per-file lock, no `e.printStackTrace()`.
### 3. Route /g and /l through the same filter pipeline + escape MiniMessage ✅
- `core/service/ChatServiceImpl.java` — `String` messages now run length check → `MessageService.processMessage` (mute/cooldown) → `AdvancedMessageFilter` → `MiniMessage.escapeTags()` → component (colors only with `lochat.chat.colors`). `Component` messages bypass (trusted internal). Local radius from `AppearanceConfig`.
- `commands/chat/GlobalChatCommand.java`, `LocalChatCommand.java` — pass plain `String`, no more `MM.deserialize(raw input)`.
- `LoChat.java`/`PluginInitializer.java` — filter instance stored on plugin; `ServiceRegistry` builds `MessageService` before `ChatService`.
### 4. Remove duplicate Discord send; single global/local detection ✅
- `listener/DiscordEventListener.java` — deleted the `onChat(AsyncChatEvent)` handler; `ChatEventListener` is now the single send path with correct `isGlobal`.
### 5. Fix config key mismatches (underscore vs dash / nesting) ✅
- `config/AppearanceConfig.java` — `chat.local-radius`, `chat.clear-lines`, `chat.min-message-length`, `chat.max-message-length`, `chat.colors.*` (dash), `prefixes.*.separator` (string), `discord.avatar-urls.*`, `discord.event-titles.*` (+ `_`→`-` normalization).
- `integrations/discord/DiscordConfig.java` — `webhook.avatar-url`, `chat.global-only`, `chat.use-embed`, `chat.embed-color`, `filter.*` (dash), `performance.retry-*`.
- `config/MuteConfig.java` — `settings.*`, `notifications.*`.
- `config/SoundsConfig.java` — `messages.mention.*`, `messages.private-message.*`, `commands.success.*`.
- `config/FiltersConfig.java` + filters — `config/filters.yml` is now the single source of truth (`caps.max-caps-percent`, `swear.replace`, `hidden-urls.*`, `spam.max-repeating-chars`, `flood.max-same-messages`).
- `gradient/config/GradientConfig.java` — nested keys `gradient.limits.*`, `gradient.pricing.*`, `gradient.cooldowns.*`, `gradient.formatting.*`, `gradient.storage.type` → **SQLite now detected**.
- `managers/AutoMessageManager.java` + `config.yml` — reads `automessages.messages` (new `automessages:` section added to config.yml), honors `automessages.random`.
---
## ✅ COMPLETED THIS SESSION
### Architecture (SOLID/KISS/DRY)
- [x] `AppearanceConfig` — fixed double-call bug
- [x] `config/` — 9→3 files per folder (subfolders: chat/, filter/, mute/, manager/)
- [x] `api/service/` + `core/service/` — 8→3 files per folder (subfolders: chat/, player/, moderation/, pm/, spy/, ignore/)
- [x] `ConfigManager` — god class → facade + 6 managers (Chat/Pm/Mention/ClearChat/CustomMessages/Filters)
- [x] `MessagingService` — fat interface → 3 services (PrivateMessageService/SpyService/IgnoreService)
- [x] `AdvancedMessageFilter` — hardcoded pipeline → `FilterPipeline` with dynamic registration
- [x] 25 commands → `BaseCommand`/`AdminCommand`/`PlayerCommand` hierarchy
- [x] `MuteCommand` — decomposed into helper methods (KISS fix)
### Encapsulation
- [x] `ChatEventListener` — removed instanceof cast to `PlayerServiceImpl`
- [x] `PunishmentSnapshot` — mutable fields → private + getters
- [x] `BaseConfig` — protected fields → private + protected getters
- [x] 29 files with `import.*` → explicit imports
### Checkstyle
- [x] Config: 4-space indent, 140-char lines, Google-style naming/quality
- [x] Warnings: **520 → 0** (both main and test)
- [x] Wired into `build.gradle.kts`
### Configs
- [x] All rewritten: clean, English comments, no Spacelegacy palette
---
## 🟡 NEXT: NEW FEATURES
### 1. Channels (like VentureChat / Carbon)
- `/join`, `/leave`, `/channel` — full channel system: global, local, staff, trade, party.
- Per-channel colors, aliases, permissions, cooldowns, spy mode.
- Party chat: private groups `/party`.
- Network channels (Bungee/Velocity) sync.
### 2. Anti-swear hardening + filter statistics ✅
- Obfuscation bypass: `SwearNormalizer` (q→р / leet-подстановки, повторы букв «сууука», разделители внутри слова «с.у.к.а» / «с у к а») + tolerant-маскирование в replace-режиме. Single source of truth для Aho-Corasick.
- Filter stats: `FilterStatistics` считает блокировки по каждому фильтру → `/lochat filterstats`.
### 3. Stable plugin API + API events
- Publish `api/` modules to a repo so third-party plugins can depend on it.
- Add `api-version` hint / `provides` in `plugin.yml` for dependency resolution.
- Dedicated API events: `LoChatMessageEvent`, `LoChatFilterEvent`, `LoChatPunishEvent` etc.
### 4. DiscordSRV-style 2-way bridge (Discord → chat)
- Read messages from a Discord channel (bot or webhook listener) and relay into Minecraft chat.
- Channel ↔ Discord channel mapping.
### 5. Full spy + auto-mute for spam
- PM spy + command spy with custom formats (like VentureChat).
- Auto-mute repeat offenders (spam/flood) with configurable threshold and duration.
---
## 🔵 LOWER PRIORITY (carry-over)
### 1. Shared Persistence Utility
5 services repeat load/save/ensureDir pattern:
- `NickServiceImpl`, `PlayerServiceImpl`, `ChatServiceImpl`, `PunishmentServiceImpl`, `IgnoreServiceImpl`
**Fix:** Extract `FilePersistenceUtil` or base class
### 2. Persist nicknames on change ✅
`NickServiceImpl` now saves asynchronously (`FoliaUtil.runAsync → save()`) on every `setNickname`/`resetNickname` — nicknames survive crashes.
### 3. DIP: Service Locator Anti-Pattern
`ServiceRegistry.get(Xxx.class)` used everywhere instead of constructor DI. Big refactor.
### 4. DRY: PM Send Logic ✅
PM cooldown + actual send centralized in `PrivateMessageServiceImpl.sendPrivateMessage`; both `/msg` and `/reply` delegate to it.
### 5. Fix cooldown map collision ✅
`PlayerServiceImpl` now keeps a separate `ConcurrentHashMap` per chat type (`global`, `local`, `rp_me`, `rp_do`, `rp_try`, `pm`) — no more cross-blocking. Covered by `PlayerServiceCooldownTest`.
### 6. Thread-safe flood/spam deques ✅
`FloodFilter`/`SpamFilter` now use `ConcurrentLinkedDeque` instead of plain `ArrayDeque`.
### 7. Tests
Only 11 test files for 155 main files. Very low coverage (JaCoCo wired, CI uploads report).
### 8. No PM cooldown ✅
`chat.pm.cooldown` (default 2s) is now enforced in `PrivateMessageServiceImpl.sendPrivateMessage`, honoring `chat.bypass.cooldown`.
---
## 📋 KNOWN ISSUES
- Gradients may not display correctly on clients < 1.16
- Some filters may block legitimate messages (configurable in `config/filters.yml`)