Исправлен фильтр чата: добавлена нормализация сообщений, защита от обхода фильтра, точный поиск слов с word boundaries
This commit is contained in:
parent
d49261988e
commit
2292137986
3 changed files with 126 additions and 10 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package com.loki.lochat.managers;
|
||||
|
||||
import com.loki.lochat.LoChat;
|
||||
import com.loki.lochat.gradient.util.FoliaUtil;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
|
|
@ -61,9 +62,16 @@ public class ChatColorManager {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Асинхронное сохранение данных (для Folia совместимости)
|
||||
*/
|
||||
private void saveDataAsync() {
|
||||
FoliaUtil.runAsync(plugin, this::saveData);
|
||||
}
|
||||
|
||||
public void setChatColor(UUID playerId, String color) {
|
||||
chatColors.put(playerId, color);
|
||||
saveData();
|
||||
saveDataAsync();
|
||||
}
|
||||
|
||||
public String getChatColor(UUID playerId) {
|
||||
|
|
@ -77,7 +85,7 @@ public class ChatColorManager {
|
|||
public void removeChatColor(UUID playerId) {
|
||||
chatColors.remove(playerId);
|
||||
dataConfig.set(playerId.toString(), null);
|
||||
saveData();
|
||||
saveDataAsync();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -20,18 +20,49 @@ public class FilterManager {
|
|||
WARNED
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет сообщение на наличие запрещенных слов
|
||||
*/
|
||||
public FilterResult checkMessage(String message) {
|
||||
if (!plugin.getConfigManager().isFilterEnabled()) {
|
||||
return FilterResult.ALLOWED;
|
||||
}
|
||||
|
||||
if (message == null || message.trim().isEmpty()) {
|
||||
return FilterResult.ALLOWED;
|
||||
}
|
||||
|
||||
List<String> badWords = plugin.getConfigManager().getFilterWords();
|
||||
String lowerMessage = message.toLowerCase();
|
||||
if (badWords == null || badWords.isEmpty()) {
|
||||
return FilterResult.ALLOWED;
|
||||
}
|
||||
|
||||
// Нормализуем сообщение (убираем обход фильтра)
|
||||
String normalizedMessage = normalizeMessage(message);
|
||||
String lowerMessage = normalizedMessage.toLowerCase();
|
||||
|
||||
for (String word : badWords) {
|
||||
if (lowerMessage.contains(word.toLowerCase())) {
|
||||
if (word == null || word.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String lowerWord = word.toLowerCase().trim();
|
||||
|
||||
// Проверяем точное совпадение слова (с границами слов)
|
||||
Pattern wordPattern = Pattern.compile("\\b" + Pattern.quote(lowerWord) + "\\b", Pattern.CASE_INSENSITIVE);
|
||||
if (wordPattern.matcher(normalizedMessage).find()) {
|
||||
String action = plugin.getConfigManager().getFilterAction();
|
||||
return switch (action) {
|
||||
return switch (action.toLowerCase()) {
|
||||
case "block" -> FilterResult.BLOCKED;
|
||||
case "warn" -> FilterResult.WARNED;
|
||||
default -> FilterResult.CENSORED;
|
||||
};
|
||||
}
|
||||
|
||||
// Также проверяем как подстроку (для частичных совпадений типа "пизд")
|
||||
if (lowerMessage.contains(lowerWord)) {
|
||||
String action = plugin.getConfigManager().getFilterAction();
|
||||
return switch (action.toLowerCase()) {
|
||||
case "block" -> FilterResult.BLOCKED;
|
||||
case "warn" -> FilterResult.WARNED;
|
||||
default -> FilterResult.CENSORED;
|
||||
|
|
@ -42,20 +73,89 @@ public class FilterManager {
|
|||
return FilterResult.ALLOWED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Цензурирует сообщение, заменяя запрещенные слова
|
||||
*/
|
||||
public String censorMessage(String message) {
|
||||
if (!plugin.getConfigManager().isFilterEnabled()) {
|
||||
return message;
|
||||
}
|
||||
|
||||
if (message == null || message.trim().isEmpty()) {
|
||||
return message;
|
||||
}
|
||||
|
||||
List<String> badWords = plugin.getConfigManager().getFilterWords();
|
||||
if (badWords == null || badWords.isEmpty()) {
|
||||
return message;
|
||||
}
|
||||
|
||||
String replacement = plugin.getConfigManager().getFilterReplacement();
|
||||
if (replacement == null) {
|
||||
replacement = "***";
|
||||
}
|
||||
|
||||
String result = message;
|
||||
String normalizedMessage = normalizeMessage(message);
|
||||
|
||||
for (String word : badWords) {
|
||||
Pattern pattern = Pattern.compile("(?i)" + Pattern.quote(word));
|
||||
result = pattern.matcher(result).replaceAll(replacement);
|
||||
if (word == null || word.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String lowerWord = word.toLowerCase().trim();
|
||||
|
||||
// Заменяем точные совпадения слов
|
||||
Pattern wordPattern = Pattern.compile("\\b" + Pattern.quote(word) + "\\b", Pattern.CASE_INSENSITIVE);
|
||||
result = wordPattern.matcher(result).replaceAll(replacement);
|
||||
|
||||
// Также заменяем как подстроку (для частичных совпадений)
|
||||
Pattern substringPattern = Pattern.compile("(?i)" + Pattern.quote(word));
|
||||
result = substringPattern.matcher(result).replaceAll(replacement);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Нормализует сообщение, убирая попытки обхода фильтра
|
||||
* Заменяет специальные символы на обычные буквы
|
||||
*/
|
||||
private String normalizeMessage(String message) {
|
||||
if (message == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Заменяем символы обхода на буквы (для обнаружения х*й, х_уй и т.д.)
|
||||
String normalized = message;
|
||||
|
||||
// Заменяем символы обхода на буквы
|
||||
normalized = normalized.replace('*', 'а');
|
||||
normalized = normalized.replace('_', 'а');
|
||||
normalized = normalized.replace('-', 'а');
|
||||
normalized = normalized.replace('.', 'а');
|
||||
normalized = normalized.replace(',', 'а');
|
||||
normalized = normalized.replace('|', 'и');
|
||||
normalized = normalized.replace('1', 'и');
|
||||
normalized = normalized.replace('!', 'и');
|
||||
normalized = normalized.replace('0', 'о');
|
||||
normalized = normalized.replace('3', 'з');
|
||||
normalized = normalized.replace('4', 'ч');
|
||||
normalized = normalized.replace('5', 'с');
|
||||
normalized = normalized.replace('6', 'б');
|
||||
normalized = normalized.replace('7', 'т');
|
||||
normalized = normalized.replace('8', 'в');
|
||||
normalized = normalized.replace('9', 'д');
|
||||
normalized = normalized.replace('@', 'а');
|
||||
normalized = normalized.replace('#', 'х');
|
||||
normalized = normalized.replace('$', 'с');
|
||||
normalized = normalized.replace('%', 'о');
|
||||
normalized = normalized.replace('^', 'х');
|
||||
normalized = normalized.replace('&', 'а');
|
||||
|
||||
// Убираем множественные пробелы
|
||||
normalized = normalized.replaceAll("\\s+", " ");
|
||||
|
||||
return normalized;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.loki.lochat.managers;
|
||||
|
||||
import com.loki.lochat.LoChat;
|
||||
import com.loki.lochat.gradient.util.FoliaUtil;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -69,7 +70,7 @@ public class IgnoreManager {
|
|||
public boolean addIgnore(UUID player, UUID target) {
|
||||
Set<UUID> ignored = ignoreMap.computeIfAbsent(player, k -> ConcurrentHashMap.newKeySet());
|
||||
boolean added = ignored.add(target);
|
||||
if (added) save();
|
||||
if (added) saveAsync();
|
||||
return added;
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +78,7 @@ public class IgnoreManager {
|
|||
Set<UUID> ignored = ignoreMap.get(player);
|
||||
if (ignored == null) return false;
|
||||
boolean removed = ignored.remove(target);
|
||||
if (removed) save();
|
||||
if (removed) saveAsync();
|
||||
return removed;
|
||||
}
|
||||
|
||||
|
|
@ -92,6 +93,13 @@ public class IgnoreManager {
|
|||
|
||||
public void clearIgnores(UUID player) {
|
||||
ignoreMap.remove(player);
|
||||
save();
|
||||
saveAsync();
|
||||
}
|
||||
|
||||
/**
|
||||
* Асинхронное сохранение данных (для Folia совместимости)
|
||||
*/
|
||||
private void saveAsync() {
|
||||
FoliaUtil.runAsync(plugin, this::save);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue