[17.8k Lines] Started working on the chat filter

This commit is contained in:
Rainnny7 2021-02-20 22:55:47 -05:00
parent 4d2a8369d9
commit 6803133935
9 changed files with 240 additions and 17 deletions

@ -11,6 +11,7 @@ import zone.themcgamer.api.model.ModelSerializer;
import zone.themcgamer.api.model.impl.*; import zone.themcgamer.api.model.impl.*;
import zone.themcgamer.api.repository.AccountRepository; import zone.themcgamer.api.repository.AccountRepository;
import zone.themcgamer.api.route.AccountRoute; import zone.themcgamer.api.route.AccountRoute;
import zone.themcgamer.api.route.ChatRoute;
import zone.themcgamer.api.route.PlayerStatusRoute; import zone.themcgamer.api.route.PlayerStatusRoute;
import zone.themcgamer.api.route.ServersRoute; import zone.themcgamer.api.route.ServersRoute;
import zone.themcgamer.data.APIAccessLevel; import zone.themcgamer.data.APIAccessLevel;
@ -63,6 +64,7 @@ public class API {
addRoute(new ServersRoute()); addRoute(new ServersRoute());
addRoute(new AccountRoute(accountRepository)); addRoute(new AccountRoute(accountRepository));
addRoute(new PlayerStatusRoute()); addRoute(new PlayerStatusRoute());
addRoute(new ChatRoute());
// 404 Handling // 404 Handling
Spark.notFound((request, response) -> { Spark.notFound((request, response) -> {

@ -0,0 +1,70 @@
package zone.themcgamer.api.route;
import com.google.common.base.Strings;
import spark.Request;
import spark.Response;
import zone.themcgamer.api.APIException;
import zone.themcgamer.api.APIVersion;
import zone.themcgamer.api.RestPath;
import zone.themcgamer.common.EnumUtils;
import zone.themcgamer.data.APIAccessLevel;
import zone.themcgamer.data.ChatFilterLevel;
import zone.themcgamer.data.jedis.data.APIKey;
import java.util.*;
import java.util.stream.Collectors;
/**
* This route handles everything associated with the chat
*
* @author Braydon
*/
public class ChatRoute {
private static final Map<ChatFilterLevel, List<String>> filteredWords = new HashMap<>() {{
put(ChatFilterLevel.LOW, Arrays.asList(
"ass"
));
put(ChatFilterLevel.MEDIUM, Arrays.asList(
"fuck", "shit"
));
put(ChatFilterLevel.HIGH, Arrays.asList(
"nigger"
));
}};
/**
* This path handles filtering the provided text with the provided {@link ChatFilterLevel}
*/
@RestPath(path = "/filter/:text/:level", version = APIVersion.V1, accessLevel = APIAccessLevel.DEV)
public String filterText(Request request, Response response, APIKey apiKey) throws APIException {
String text = request.params(":text");
ChatFilterLevel chatFilterLevel = EnumUtils.fromString(ChatFilterLevel.class, request.params(":level").toUpperCase());
if (chatFilterLevel == null)
throw new APIException("Invalid filter level, valid options: " + Arrays.stream(ChatFilterLevel.values()).map(ChatFilterLevel::name).collect(Collectors.joining(", ")));
String filteredMessage = text;
text = text.replace("{dot}", ".");
if (chatFilterLevel.isUrls()) {
// TODO: 2/20/21 filter urls with regex patterns
}
if (chatFilterLevel.isIps()) {
// TODO: 2/20/21 filter ips with regex patterns
}
List<String> filteredWords = new ArrayList<>();
for (ChatFilterLevel filterLevel : ChatFilterLevel.values()) {
if (chatFilterLevel.ordinal() >= filterLevel.ordinal()) {
List<String> list = ChatRoute.filteredWords.getOrDefault(filterLevel, new ArrayList<>());
if (list.isEmpty())
continue;
filteredWords.addAll(list);
}
}
for (String word : text.split(" ")) {
for (String filteredWord : filteredWords) {
if (word.toLowerCase().contains(filteredWord.toLowerCase())) {
filteredMessage = filteredMessage.replace(word, Strings.repeat("*", word.length()));
}
}
}
return filteredMessage;
}
}

@ -41,7 +41,7 @@ subprojects {
compileOnly("org.slf4j:slf4j-simple:1.7.30") compileOnly("org.slf4j:slf4j-simple:1.7.30")
implementation("com.google.code.gson:gson:2.7") implementation("com.google.code.gson:gson:2.8.5")
implementation("commons-io:commons-io:2.6") implementation("commons-io:commons-io:2.6")

@ -0,0 +1,37 @@
package zone.themcgamer.core.api;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import lombok.NonNull;
import zone.themcgamer.core.api.json.JsonRequest;
import zone.themcgamer.core.api.json.JsonResponse;
import zone.themcgamer.data.ChatFilterLevel;
import java.net.http.HttpClient;
import java.time.Duration;
/**
* @author Braydon
*/
public class WebAPI {
public static final String API_KEY = "406321cc-48f3-454b-900a-972fd88e4882";
private static final String URL = "https://api.mcgamerzone.net/v1";
public static HttpClient HTTP_CLIENT;
static {
HTTP_CLIENT = java.net.http.HttpClient.newBuilder()
.version(java.net.http.HttpClient.Version.HTTP_1_1)
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(30L))
.build();
}
public static String filterText(@NonNull String text, @NonNull ChatFilterLevel chatFilterLevel) {
JsonResponse jsonResponse = new JsonRequest(URL + "/filter/" + text.replaceAll(" ", "%20") + "/" + chatFilterLevel.name()).getResponse();
JsonElement jsonElement = jsonResponse.getJsonElement();
if (!(jsonElement instanceof JsonObject))
return text;
JsonObject jsonObject = (JsonObject) jsonElement;
return jsonObject.get("value").getAsString();
}
}

@ -0,0 +1,64 @@
package zone.themcgamer.core.api.json;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import zone.themcgamer.core.api.WebAPI;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.function.Consumer;
/**
* @author Braydon
*/
@AllArgsConstructor @Slf4j(topic = "Json Request")
public class JsonRequest {
private final String url;
/**
* Get the {@link JsonResponse} from the provided url
*
* @return the response
*/
public JsonResponse getResponse() {
try {
return checkResponse(WebAPI.HTTP_CLIENT.send(buildRequest(), HttpResponse.BodyHandlers.ofString()));
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
return null;
}
/**
* Get the {@link JsonResponse} from the provided url asynchronously
*
* @param consumer the consumer the response will be accepted in
*/
public void getResponseAsync(Consumer<JsonResponse> consumer) {
WebAPI.HTTP_CLIENT.sendAsync(buildRequest(), HttpResponse.BodyHandlers.ofString())
.thenAccept(httpResponse -> consumer.accept(checkResponse(httpResponse)));
}
private JsonResponse checkResponse(HttpResponse<String> httpResponse) {
int statusCode = httpResponse.statusCode();
if (statusCode != 200) {
log.warn("Response from \"" + url + "\" returned status code " + statusCode + ":");
log.warn("Body: " + httpResponse.body());
log.warn("Headers: " + httpResponse.headers().toString());
}
return new JsonResponse(httpResponse);
}
private HttpRequest buildRequest() {
return HttpRequest.newBuilder()
.GET()
.uri(URI.create(url))
.timeout(Duration.ofMinutes(1L))
.header("Content-Type", "application/json")
.header("key", WebAPI.API_KEY)
.build();
}
}

@ -0,0 +1,25 @@
package zone.themcgamer.core.api.json;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import lombok.Getter;
import java.net.http.HttpResponse;
/**
* This class represents a response from a {@link JsonRequest}
*
* @author Braydon
*/
@Getter
public class JsonResponse {
private final HttpResponse<String> httpResponse;
private final String json;
private final JsonElement jsonElement;
public JsonResponse(HttpResponse<String> httpResponse) {
this.httpResponse = httpResponse;
json = httpResponse.body();
jsonElement = new JsonParser().parse(json);
}
}

@ -13,6 +13,7 @@ import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import zone.themcgamer.core.account.Account; import zone.themcgamer.core.account.Account;
import zone.themcgamer.core.account.AccountManager; import zone.themcgamer.core.account.AccountManager;
import zone.themcgamer.core.api.WebAPI;
import zone.themcgamer.core.badSportSystem.BadSportClient; import zone.themcgamer.core.badSportSystem.BadSportClient;
import zone.themcgamer.core.badSportSystem.BadSportSystem; import zone.themcgamer.core.badSportSystem.BadSportSystem;
import zone.themcgamer.core.badSportSystem.Punishment; import zone.themcgamer.core.badSportSystem.Punishment;
@ -26,6 +27,7 @@ import zone.themcgamer.core.common.Style;
import zone.themcgamer.core.cooldown.CooldownHandler; import zone.themcgamer.core.cooldown.CooldownHandler;
import zone.themcgamer.core.module.Module; import zone.themcgamer.core.module.Module;
import zone.themcgamer.core.module.ModuleInfo; import zone.themcgamer.core.module.ModuleInfo;
import zone.themcgamer.data.ChatFilterLevel;
import zone.themcgamer.data.Rank; import zone.themcgamer.data.Rank;
import java.util.*; import java.util.*;
@ -41,19 +43,21 @@ public class ChatManager extends Module {
@Getter private final Map<String, String> emotes = new HashMap<>(); @Getter private final Map<String, String> emotes = new HashMap<>();
{ {
emotes.put("¯\\_(ツ)_/¯", ":shrug:"); emotes.put(":shrug:", "¯\\_(ツ)_/¯");
emotes.put("⊂(´・◡・⊂ )∘˚˳°", ":happyghost:"); emotes.put(":happyghost:", "⊂(´・◡・⊂ )∘˚˳°");
emotes.put("ヽ༼ຈل͜ຈ༽ノ", ":donger:"); emotes.put(":donger:", "ヽ༼ຈل͜ຈ༽ノ");
emotes.put("ಠ_ಠ", ":disapproval:"); emotes.put(":disapproval:", "ಠ_ಠ");
emotes.put("(≖_≖)", ":squint:"); emotes.put(":squint:", "(≖_≖)");
emotes.put("(౮⦦ʖ౮)", ":lenny:"); emotes.put(":lenny:", "(౮⦦ʖ౮)");
emotes.put("┬─┬ ( ゜-゜ノ)", ":unflip:"); emotes.put(":unflip:", "┬─┬ ( ゜-゜ノ)");
emotes.put("(☞゚ヮ゚)☞", ":same:"); emotes.put(":same:", "(☞゚ヮ゚)☞");
emotes.put("ლ(ಥ Д ಥ )ლ", ":why:"); emotes.put(":why:", "ლ(ಥ Д ಥ )ლ");
emotes.put("(╯°□°)╯︵ ┻━┻", ":tableflip:"); emotes.put(":tableflip:", "(╯°□°)╯︵ ┻━┻");
emotes.put("⊂(•̀_•́⊂ )∘˚˳°", ":angryghost:"); emotes.put(":angryghost:", "⊂(•̀_•́⊂ )∘˚˳°");
emotes.put("( ˘ ³˘)♥", ":kiss:"); emotes.put(":kiss:", "( ˘ ³˘)♥");
emotes.put("༼ つ ◕_◕ ༽つ", ":ameno:"); emotes.put(":ameno:", "༼ つ ◕_◕ ༽つ");
emotes.put(":heart:", "");
emotes.put("<3", "");
} }
public ChatManager(JavaPlugin plugin, AccountManager accountManager, BadSportSystem badSportSystem, IChatComponent[] chatComponents) { public ChatManager(JavaPlugin plugin, AccountManager accountManager, BadSportSystem badSportSystem, IChatComponent[] chatComponents) {
@ -88,7 +92,11 @@ public class ChatManager extends Module {
player.sendMessage(Style.error("Bad Sport", PunishmentCategory.format(optionalMute.get()))); player.sendMessage(Style.error("Bad Sport", PunishmentCategory.format(optionalMute.get())));
return; return;
} }
// TODO: 1/26/21 filter message try {
message = WebAPI.filterText(message, ChatFilterLevel.HIGH);
} catch (Exception ex) {
player.sendMessage(Style.error("Chat", "§cProblem filtering chat message: §f" + ex.getLocalizedMessage()));
}
if (message.trim().isEmpty()) { if (message.trim().isEmpty()) {
player.sendMessage(Style.error("Chat", "§cCannot send empty chat message")); player.sendMessage(Style.error("Chat", "§cCannot send empty chat message"));
return; return;
@ -104,7 +112,7 @@ public class ChatManager extends Module {
return; return;
} }
for (Map.Entry<String, String> emote : emotes.entrySet()) for (Map.Entry<String, String> emote : emotes.entrySet())
message = message.replace(emote.getValue(), emote.getKey()); message = message.replace(emote.getKey(), emote.getValue());
List<BaseComponent> components = new ArrayList<>(); List<BaseComponent> components = new ArrayList<>();
for (IChatComponent chatComponent : chatComponents) { for (IChatComponent chatComponent : chatComponents) {
BaseComponent component = chatComponent.getComponent(player); BaseComponent component = chatComponent.getComponent(player);

@ -21,6 +21,6 @@ public class EmotesCommand {
Player player = command.getPlayer(); Player player = command.getPlayer();
player.sendMessage(Style.main("Chat", "Chat Emotes:")); player.sendMessage(Style.main("Chat", "Chat Emotes:"));
for (Map.Entry<String, String> entry : chatManager.getEmotes().entrySet()) for (Map.Entry<String, String> entry : chatManager.getEmotes().entrySet())
player.sendMessage(" §6" + entry.getValue() + " §7-> §b" + entry.getKey()); player.sendMessage(" §6" + entry.getKey() + " §7-> §b" + entry.getValue());
} }
} }

@ -0,0 +1,17 @@
package zone.themcgamer.data;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* @author Braydon
*/
@AllArgsConstructor
@Getter
public enum ChatFilterLevel {
LOW(false, true),
MEDIUM(true, true),
HIGH(true, true);
private final boolean urls, ips;
}