AqUpd

Untitled

Feb 20th, 2022
200
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 11.73 KB | None | 0 0
  1. /*
  2.  * Decompiled with CFR 0.0.9 (FabricMC cc05e23f).
  3.  */
  4. package net.minecraft.server.filter;
  5.  
  6. import com.google.common.base.Strings;
  7. import com.google.common.collect.ImmutableList;
  8. import com.google.gson.JsonObject;
  9. import com.google.gson.internal.Streams;
  10. import com.google.gson.stream.JsonReader;
  11. import com.google.gson.stream.JsonWriter;
  12. import com.mojang.authlib.GameProfile;
  13. import java.io.IOException;
  14. import java.io.InputStream;
  15. import java.io.InputStreamReader;
  16. import java.io.OutputStreamWriter;
  17. import java.net.HttpURLConnection;
  18. import java.net.MalformedURLException;
  19. import java.net.URI;
  20. import java.net.URL;
  21. import java.nio.charset.StandardCharsets;
  22. import java.util.Base64;
  23. import java.util.List;
  24. import java.util.concurrent.CompletableFuture;
  25. import java.util.concurrent.Executor;
  26. import java.util.concurrent.ExecutorService;
  27. import java.util.concurrent.Executors;
  28. import java.util.concurrent.ThreadFactory;
  29. import java.util.concurrent.atomic.AtomicInteger;
  30. import net.minecraft.SharedConstants;
  31. import net.minecraft.server.filter.TextStream;
  32. import net.minecraft.util.JsonHelper;
  33. import net.minecraft.util.Util;
  34. import net.minecraft.util.thread.TaskExecutor;
  35. import org.apache.logging.log4j.LogManager;
  36. import org.apache.logging.log4j.Logger;
  37. import org.jetbrains.annotations.Nullable;
  38.  
  39. public class TextFilterer
  40. implements AutoCloseable {
  41.     private static final Logger LOGGER = LogManager.getLogger();
  42.     private static final AtomicInteger NEXT_WORKER_ID = new AtomicInteger(1);
  43.     private static final ThreadFactory THREAD_FACTORY = runnable -> {
  44.         Thread thread = new Thread(runnable);
  45.         thread.setName("Chat-Filter-Worker-" + NEXT_WORKER_ID.getAndIncrement());
  46.         return thread;
  47.     };
  48.     private final URL chatEndpoint;
  49.     final URL joinEndpoint;
  50.     final URL leaveEndpoint;
  51.     private final String apiKey;
  52.     private final int ruleId;
  53.     private final String serverId;
  54.     final HashIgnorer ignorer;
  55.     final ExecutorService executor;
  56.  
  57.     private TextFilterer(URI apiUrl, String apiKey, int ruleId, String serverId, HashIgnorer ignorer, int threadsNumber) throws MalformedURLException {
  58.         this.apiKey = apiKey;
  59.         this.ruleId = ruleId;
  60.         this.serverId = serverId;
  61.         this.ignorer = ignorer;
  62.         this.chatEndpoint = apiUrl.resolve("/v1/chat").toURL();
  63.         this.joinEndpoint = apiUrl.resolve("/v1/join").toURL();
  64.         this.leaveEndpoint = apiUrl.resolve("/v1/leave").toURL();
  65.         this.executor = Executors.newFixedThreadPool(threadsNumber, THREAD_FACTORY);
  66.     }
  67.  
  68.     @Nullable
  69.     public static TextFilterer load(String config) {
  70.         if (Strings.isNullOrEmpty(config)) {
  71.             return null;
  72.         }
  73.         try {
  74.             JsonObject jsonObject = JsonHelper.deserialize(config);
  75.             URI uRI = new URI(JsonHelper.getString(jsonObject, "apiServer"));
  76.             String string = JsonHelper.getString(jsonObject, "apiKey");
  77.             if (string.isEmpty()) {
  78.                 throw new IllegalArgumentException("Missing API key");
  79.             }
  80.             int i = JsonHelper.getInt(jsonObject, "ruleId", 1);
  81.             String string2 = JsonHelper.getString(jsonObject, "serverId", "");
  82.             int j = JsonHelper.getInt(jsonObject, "hashesToDrop", -1);
  83.             int k = JsonHelper.getInt(jsonObject, "maxConcurrentRequests", 7);
  84.             HashIgnorer hashIgnorer = HashIgnorer.dropHashes(j);
  85.             return new TextFilterer(uRI, Base64.getEncoder().encodeToString(string.getBytes(StandardCharsets.US_ASCII)), i, string2, hashIgnorer, k);
  86.         }
  87.         catch (Exception jsonObject) {
  88.             LOGGER.warn("Failed to parse chat filter config {}", (Object)config, (Object)jsonObject);
  89.             return null;
  90.         }
  91.     }
  92.  
  93.     void sendJoinOrLeaveRequest(GameProfile gameProfile, URL endpoint, Executor executor) {
  94.         JsonObject jsonObject = new JsonObject();
  95.         jsonObject.addProperty("server", this.serverId);
  96.         jsonObject.addProperty("room", "Chat");
  97.         jsonObject.addProperty("user_id", gameProfile.getId().toString());
  98.         jsonObject.addProperty("user_display_name", gameProfile.getName());
  99.         executor.execute(() -> {
  100.             try {
  101.                 this.sendRequest(jsonObject, endpoint);
  102.             }
  103.             catch (Exception exception) {
  104.                 LOGGER.warn("Failed to send join/leave packet to {} for player {}", (Object)endpoint, (Object)gameProfile, (Object)exception);
  105.             }
  106.         });
  107.     }
  108.  
  109.     CompletableFuture<TextStream.Message> filterMessage(GameProfile gameProfile, String message, HashIgnorer ignorer, Executor executor) {
  110.         if (message.isEmpty()) {
  111.             return CompletableFuture.completedFuture(TextStream.Message.EMPTY);
  112.         }
  113.         JsonObject jsonObject = new JsonObject();
  114.         jsonObject.addProperty("rule", this.ruleId);
  115.         jsonObject.addProperty("server", this.serverId);
  116.         jsonObject.addProperty("room", "Chat");
  117.         jsonObject.addProperty("player", gameProfile.getId().toString());
  118.         jsonObject.addProperty("player_display_name", gameProfile.getName());
  119.         jsonObject.addProperty("text", message);
  120.         return CompletableFuture.supplyAsync(() -> {
  121.             try {
  122.                 JsonObject jsonObject2 = this.sendJsonRequest(jsonObject, this.chatEndpoint);
  123.                 boolean bl = JsonHelper.getBoolean(jsonObject2, "response", false);
  124.                 if (bl) {
  125.                     return TextStream.Message.permitted(message);
  126.                 }
  127.                 String string2 = JsonHelper.getString(jsonObject2, "hashed", null);
  128.                 if (string2 == null) {
  129.                     return TextStream.Message.censored(message);
  130.                 }
  131.                 int i = JsonHelper.getArray(jsonObject2, "hashes").size();
  132.                 return ignorer.shouldIgnore(string2, i) ? TextStream.Message.censored(message) : new TextStream.Message(message, string2);
  133.             }
  134.             catch (Exception jsonObject2) {
  135.                 LOGGER.warn("Failed to validate message '{}'", (Object)message, (Object)jsonObject2);
  136.                 return TextStream.Message.censored(message);
  137.             }
  138.         }, executor);
  139.     }
  140.  
  141.     @Override
  142.     public void close() {
  143.         this.executor.shutdownNow();
  144.     }
  145.  
  146.     private void consumeFully(InputStream inputStream) throws IOException {
  147.         byte[] bs = new byte[1024];
  148.         while (inputStream.read(bs) != -1) {
  149.         }
  150.     }
  151.  
  152.     /*
  153.      * WARNING - Removed try catching itself - possible behaviour change.
  154.      */
  155.     private JsonObject sendJsonRequest(JsonObject payload, URL endpoint) throws IOException {
  156.         HttpURLConnection httpURLConnection = this.createConnection(payload, endpoint);
  157.         try (InputStream inputStream = httpURLConnection.getInputStream();){
  158.             JsonObject jsonObject;
  159.             if (httpURLConnection.getResponseCode() == 204) {
  160.                 JsonObject jsonObject2 = new JsonObject();
  161.                 return jsonObject2;
  162.             }
  163.             try {
  164.                 jsonObject = Streams.parse(new JsonReader(new InputStreamReader(inputStream))).getAsJsonObject();
  165.             }
  166.             catch (Throwable throwable) {
  167.                 this.consumeFully(inputStream);
  168.                 throw throwable;
  169.             }
  170.             this.consumeFully(inputStream);
  171.             return jsonObject;
  172.         }
  173.     }
  174.  
  175.     private void sendRequest(JsonObject payload, URL endpoint) throws IOException {
  176.         HttpURLConnection httpURLConnection = this.createConnection(payload, endpoint);
  177.         try (InputStream inputStream = httpURLConnection.getInputStream();){
  178.             this.consumeFully(inputStream);
  179.         }
  180.     }
  181.  
  182.     private HttpURLConnection createConnection(JsonObject payload, URL endpoint) throws IOException {
  183.         HttpURLConnection httpURLConnection = (HttpURLConnection)endpoint.openConnection();
  184.         httpURLConnection.setConnectTimeout(15000);
  185.         httpURLConnection.setReadTimeout(2000);
  186.         httpURLConnection.setUseCaches(false);
  187.         httpURLConnection.setDoOutput(true);
  188.         httpURLConnection.setDoInput(true);
  189.         httpURLConnection.setRequestMethod("POST");
  190.         httpURLConnection.setRequestProperty("Content-Type", "application/json; charset=utf-8");
  191.         httpURLConnection.setRequestProperty("Accept", "application/json");
  192.         httpURLConnection.setRequestProperty("Authorization", "Basic " + this.apiKey);
  193.         httpURLConnection.setRequestProperty("User-Agent", "Minecraft server" + SharedConstants.getGameVersion().getName());
  194.         try (OutputStreamWriter outputStreamWriter = new OutputStreamWriter(httpURLConnection.getOutputStream(), StandardCharsets.UTF_8);
  195.              JsonWriter jsonWriter = new JsonWriter(outputStreamWriter);){
  196.             Streams.write(payload, jsonWriter);
  197.         }
  198.         int outputStreamWriter2 = httpURLConnection.getResponseCode();
  199.         if (outputStreamWriter2 < 200 || outputStreamWriter2 >= 300) {
  200.             throw new FailedHttpRequestException(outputStreamWriter2 + " " + httpURLConnection.getResponseMessage());
  201.         }
  202.         return httpURLConnection;
  203.     }
  204.  
  205.     public TextStream createFilterer(GameProfile gameProfile) {
  206.         return new Impl(gameProfile);
  207.     }
  208.  
  209.     @FunctionalInterface
  210.     public static interface HashIgnorer {
  211.         public static final HashIgnorer NEVER_IGNORE = (hashes, hashesSize) -> false;
  212.         public static final HashIgnorer IGNORE_IF_MATCHES_ALL = (hashes, hashesSize) -> hashes.length() == hashesSize;
  213.  
  214.         public static HashIgnorer internalDropHashes(int hashesToDrop) {
  215.             return (hashes, hashesSize) -> hashesSize >= hashesToDrop;
  216.         }
  217.  
  218.         public static HashIgnorer dropHashes(int hashesToDrop) {
  219.             switch (hashesToDrop) {
  220.                 case -1: {
  221.                     return NEVER_IGNORE;
  222.                 }
  223.                 case 0: {
  224.                     return IGNORE_IF_MATCHES_ALL;
  225.                 }
  226.             }
  227.             return HashIgnorer.internalDropHashes(hashesToDrop);
  228.         }
  229.  
  230.         public boolean shouldIgnore(String var1, int var2);
  231.     }
  232.  
  233.     public static class FailedHttpRequestException
  234.     extends RuntimeException {
  235.         FailedHttpRequestException(String message) {
  236.             super(message);
  237.         }
  238.     }
  239.  
  240.     class Impl
  241.     implements TextStream {
  242.         private final GameProfile gameProfile;
  243.         private final Executor executor;
  244.  
  245.         Impl(GameProfile gameProfile) {
  246.             this.gameProfile = gameProfile;
  247.             TaskExecutor<Runnable> taskExecutor = TaskExecutor.create(TextFilterer.this.executor, "chat stream for " + gameProfile.getName());
  248.             this.executor = taskExecutor::send;
  249.         }
  250.  
  251.         @Override
  252.         public void onConnect() {
  253.             TextFilterer.this.sendJoinOrLeaveRequest(this.gameProfile, TextFilterer.this.joinEndpoint, this.executor);
  254.         }
  255.  
  256.         @Override
  257.         public void onDisconnect() {
  258.             TextFilterer.this.sendJoinOrLeaveRequest(this.gameProfile, TextFilterer.this.leaveEndpoint, this.executor);
  259.         }
  260.  
  261.         @Override
  262.         public CompletableFuture<List<TextStream.Message>> filterTexts(List<String> texts) {
  263.             List list = texts.stream().map(string -> TextFilterer.this.filterMessage(this.gameProfile, (String)string, TextFilterer.this.ignorer, this.executor)).collect(ImmutableList.toImmutableList());
  264.             return Util.combine(list).exceptionally(throwable -> ImmutableList.of());
  265.         }
  266.  
  267.         @Override
  268.         public CompletableFuture<TextStream.Message> filterText(String text) {
  269.             return TextFilterer.this.filterMessage(this.gameProfile, text, TextFilterer.this.ignorer, this.executor);
  270.         }
  271.     }
  272. }
  273.  
  274.  
Add Comment
Please, Sign In to add comment