From 1aa22606b2acb8f9b34dc9cd00d11848bbf416fe Mon Sep 17 00:00:00 2001 From: Colbster937 Date: Fri, 9 Jan 2026 19:49:51 -0600 Subject: [PATCH] add discord webhook support --- README.md | 5 +- build.gradle.kts | 2 +- .../originblacklist/base/OriginBlacklist.java | 109 +++++++++++++++++- .../base/enums/EnumBlacklistType.java | 2 +- .../originblacklist/base/util/OPlayer.java | 23 +++- .../base/util/UpdateChecker.java | 4 +- .../bukkit/OriginBlacklistBukkit.java | 4 +- .../bungee/OriginBlacklistBungee.java | 6 +- .../velocity/OriginBlacklistVelocity.java | 6 +- 9 files changed, 140 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 1d9ec75..4a9bde9 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,13 @@ - [x] Client brand based blacklisting - [x] Username based blacklisting - [x] IP based blacklisting -- [x] Json5 based configuration +- [x] JSON5 based configuration - [x] Kick message customization - [x] Blacklist MOTD customization - [x] MiniMessage and legacy formattings supported - [x] Plugin update checker -- [ ] Send blacklist logs to a webhook +- [x] Send blacklist logs to a webhook +- [ ] Ingame blacklist management command - [ ] Subscribe to an auto-updating blacklist - [ ] Reverse blacklist (whitelist) diff --git a/build.gradle.kts b/build.gradle.kts index 2b0f607..0725d3f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -11,7 +11,7 @@ val PLUGIN_NAME = "OriginBlacklist" val PLUGIN_IDEN = "originblacklist" val PLUGIN_DOMN = "xyz.webmc" val PLUGIN_DESC = "An eaglercraft client blacklist plugin." -val PLUGIN_VERS = "2.0.0" +val PLUGIN_VERS = "2.0.1" val PLUGIN_SITE = "https://github.com/WebMCDevelopment/$PLUGIN_IDEN" val PLUGIN_DEPA = listOf("EaglercraftXServer") val PLUGIN_DEPB = listOf("EaglercraftXServer") diff --git a/src/main/java/xyz/webmc/originblacklist/base/OriginBlacklist.java b/src/main/java/xyz/webmc/originblacklist/base/OriginBlacklist.java index 1911ee7..344c9a8 100644 --- a/src/main/java/xyz/webmc/originblacklist/base/OriginBlacklist.java +++ b/src/main/java/xyz/webmc/originblacklist/base/OriginBlacklist.java @@ -2,6 +2,7 @@ package xyz.webmc.originblacklist.base; import xyz.webmc.originblacklist.base.config.OriginBlacklistConfig; import xyz.webmc.originblacklist.base.enums.EnumBlacklistType; +import xyz.webmc.originblacklist.base.enums.EnumConnectionType; import xyz.webmc.originblacklist.base.enums.EnumLogLevel; import xyz.webmc.originblacklist.base.events.OriginBlacklistLoginEvent; import xyz.webmc.originblacklist.base.events.OriginBlacklistMOTDEvent; @@ -9,9 +10,13 @@ import xyz.webmc.originblacklist.base.util.IOriginBlacklistPlugin; import xyz.webmc.originblacklist.base.util.OPlayer; import xyz.webmc.originblacklist.base.util.UpdateChecker; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.ArrayList; import java.util.Base64; import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import org.semver4j.Semver; @@ -25,12 +30,14 @@ import inet.ipaddr.IPAddressString; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.lax1dude.eaglercraft.backend.server.api.EnumWebSocketHeader; +import net.lax1dude.eaglercraft.backend.server.api.IEaglerLoginConnection; import net.lax1dude.eaglercraft.backend.server.api.query.IMOTDConnection; public final class OriginBlacklist { public static final Semver REQUIRED_API_VER = new Semver("1.0.2"); - public static final String GENERIC_STR = "generic"; - public static final String UNKNOWN_STR = "unknown"; + public static final String GENERIC_STR = "GENERIC"; + public static final String UNKNOWN_STR = "UNKNOWN"; public static final String PLUGIN_REPO = "WebMCDevelopment/originblacklist"; public static final int BSTATS_ID = 28776; @@ -66,6 +73,7 @@ public final class OriginBlacklist { this.plugin.kickPlayer(this.getBlacklistedComponent("kick", blacklisted.getArrayString(), blacklisted.getAltString(), blacklisted.getString(), "not allowed", "not allowed on the server", blacklisted_value, blacklisted.getActionString()), event); + this.sendWebhooks(event, blacklisted); final String name = player.getName(); if (isNonNull(name)) { this.plugin.log(EnumLogLevel.INFO, "Prevented blacklisted player " + name + " from joining."); @@ -94,7 +102,7 @@ public final class OriginBlacklist { public final boolean isDebugEnabled() { return this.config.get("debug").getAsBoolean(); } - + public final boolean isMetricsEnabled() { return this.config.get("bStats").getAsBoolean(); } @@ -185,14 +193,105 @@ public final class OriginBlacklist { return MiniMessage.miniMessage().deserialize(str); } + private final void sendWebhooks(final OriginBlacklistLoginEvent event, final EnumBlacklistType type) { + Json5Element element = this.config.get("discord.enabled"); + if (element.getAsBoolean()) { + final OPlayer player = event.getPlayer(); + final EnumConnectionType connType = event.getConnectionType(); + final String userAgent; + if (connType == EnumConnectionType.EAGLER) { + final IEaglerLoginConnection loginConn = event.getEaglerEvent().getLoginConnection(); + userAgent = loginConn.getWebSocketHeader(EnumWebSocketHeader.HEADER_USER_AGENT); + } else { + userAgent = UNKNOWN_STR; + } + final byte[] payload = String.format( + """ + { + "content": "Blocked a blacklisted %s from joining", + "embeds": [ + { + "title": "-------- Player Information --------", + "description": "**→ Name:** %s\\n**→ Origin:** %s\\n**→ Brand:** %s\\n**→ IP Address:** %s\\n**→ Protocol Version:** %s\\n**→ User Agent:** %s\\n**→ Rewind:** %s\\n**→ Player Type:** %s", + "color": 15801922, + "fields": [], + "footer": { + "text": "OriginBlacklist v%s", + "icon_url": "https://raw.githubusercontent.com/%s/refs/heads/main/icon.png" + } + } + ], + "components": [ + { + "type": 1, + "components": [ + { + "type": 2, + "style": 5, + "label": "Get the Plugin", + "url": "https://github.com/%s", + "emoji": { + "name": "🌐" + } + } + ] + } + ] + } + """, + type.getAltString(), + player.getName().replaceAll("_", "\\_"), + player.getOrigin(), + player.getBrand(), + player.getAddr(), + player.getPVN(), + userAgent, + player.isRewind() ? "YES" : "NO", + connType.toString(), + this.plugin.getPluginVersion(), + PLUGIN_REPO, + PLUGIN_REPO + ).getBytes(); + element = this.config.get("discord.webhook_urls"); + if (element instanceof Json5Array) { + for (final Json5Element _element : element.getAsJson5Array()) { + CompletableFuture.runAsync(() -> { + try { + final URL url = new URL(_element.getAsString()); + final HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + conn.setRequestProperty("Content-Type", "application/json"); + conn.setDoOutput(true); + conn.setConnectTimeout(5000); + conn.setReadTimeout(5000); + conn.connect(); + final OutputStream os = conn.getOutputStream(); + os.write(payload); + os.close(); + + final int code = conn.getResponseCode(); + if (code < 200 || code >= 300) { + this.plugin.log(EnumLogLevel.WARN, "Webhook failed (HTTP " + code + ")"); + } + + conn.disconnect(); + } catch (Throwable t) { + t.printStackTrace(); + } + }); + } + } + } + } + private final void checkForUpdate() { - (new Thread(() -> { + CompletableFuture.runAsync(() -> { this.updateAvailable = UpdateChecker.checkForUpdate(PLUGIN_REPO, this.plugin.getPluginVersion(), this.config.get("update_checker.allow_snapshots").getAsBoolean()); if (this.updateAvailable) { this.plugin.log(EnumLogLevel.INFO, "Update Available! Download at https://github.com/" + PLUGIN_REPO + ".git"); } - })).run(); + }); } public static final String getComponentString(final Component comp) { diff --git a/src/main/java/xyz/webmc/originblacklist/base/enums/EnumBlacklistType.java b/src/main/java/xyz/webmc/originblacklist/base/enums/EnumBlacklistType.java index 1342572..9ddbd96 100644 --- a/src/main/java/xyz/webmc/originblacklist/base/enums/EnumBlacklistType.java +++ b/src/main/java/xyz/webmc/originblacklist/base/enums/EnumBlacklistType.java @@ -18,7 +18,7 @@ public enum EnumBlacklistType { this.str = str; this.alt = alt; this.arr = arr; - this.act = OriginBlacklist.isNonNull(act) ? act : OriginBlacklist.GENERIC_STR; + this.act = OriginBlacklist.isNonNull(act) ? act : OriginBlacklist.GENERIC_STR.toLowerCase(); } public final String getString() { diff --git a/src/main/java/xyz/webmc/originblacklist/base/util/OPlayer.java b/src/main/java/xyz/webmc/originblacklist/base/util/OPlayer.java index f82c1c6..d252c93 100644 --- a/src/main/java/xyz/webmc/originblacklist/base/util/OPlayer.java +++ b/src/main/java/xyz/webmc/originblacklist/base/util/OPlayer.java @@ -16,28 +16,37 @@ public final class OPlayer { private final String name; private final UUID uuid; private final String brand; + private final boolean rewind; + private final int pvn; public OPlayer(final IEaglerConnection conn, final String name, final UUID uuid, final String addr, - final String brand) { + final String brand, final int pvn) { this.name = name; this.uuid = uuid; if (conn != null) { this.origin = conn.getWebSocketHeader(EnumWebSocketHeader.HEADER_ORIGIN); this.addr = formatSocketAddress(conn.getSocketAddress()); if (conn instanceof IEaglerLoginConnection) { - this.brand = ((IEaglerLoginConnection) conn).getEaglerBrandString(); + final IEaglerLoginConnection loginConn = (IEaglerLoginConnection) conn; + this.brand = loginConn.getEaglerBrandString(); + this.rewind = loginConn.isEaglerXRewindPlayer(); + this.pvn = this.rewind ? loginConn.getRewindProtocolVersion() : loginConn.getMinecraftProtocol(); } else { this.brand = OriginBlacklist.UNKNOWN_STR; + this.rewind = false; + this.pvn = pvn; } } else { this.origin = OriginBlacklist.UNKNOWN_STR; this.addr = formatIPAddress(addr); this.brand = brand; + this.rewind = false; + this.pvn = pvn; } } public OPlayer(final IEaglerConnection conn, final String name, final UUID uuid) { - this(conn, name, uuid, null, null); + this(conn, name, uuid, null, null, -1); } public final String getOrigin() { @@ -60,6 +69,14 @@ public final class OPlayer { return this.brand; } + public final boolean isRewind() { + return this.rewind; + } + + public final int getPVN() { + return this.pvn; + } + private static final String formatIPAddress(String addr) { if (addr.startsWith("/")) { addr = addr.substring(1); diff --git a/src/main/java/xyz/webmc/originblacklist/base/util/UpdateChecker.java b/src/main/java/xyz/webmc/originblacklist/base/util/UpdateChecker.java index f11ad5f..daae979 100644 --- a/src/main/java/xyz/webmc/originblacklist/base/util/UpdateChecker.java +++ b/src/main/java/xyz/webmc/originblacklist/base/util/UpdateChecker.java @@ -22,8 +22,9 @@ public class UpdateChecker { conn.setRequestMethod("GET"); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); + conn.connect(); final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - Json5Element element = json5.parse(reader); + Json5Element element = json5.parse(reader); if (element instanceof Json5Array) { final Json5Array arr = element.getAsJson5Array(); if (arr.size() > 0) { @@ -38,6 +39,7 @@ public class UpdateChecker { } } } + conn.disconnect(); return false; } catch (final Throwable t) { t.printStackTrace(); diff --git a/src/main/java/xyz/webmc/originblacklist/bukkit/OriginBlacklistBukkit.java b/src/main/java/xyz/webmc/originblacklist/bukkit/OriginBlacklistBukkit.java index 855b1f9..9c05317 100644 --- a/src/main/java/xyz/webmc/originblacklist/bukkit/OriginBlacklistBukkit.java +++ b/src/main/java/xyz/webmc/originblacklist/bukkit/OriginBlacklistBukkit.java @@ -106,14 +106,14 @@ public final class OriginBlacklistBukkit extends JavaPlugin implements Listener, @EventHandler(priority = EventPriority.LOWEST) public final void onJavaLogin(final AsyncPlayerPreLoginEvent event) { final OPlayer player = new OPlayer(null, event.getName(), event.getUniqueId(), - event.getAddress() != null ? event.getAddress().toString() : null, null); + event.getAddress() != null ? event.getAddress().toString() : null, OriginBlacklist.UNKNOWN_STR, -1); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, player)); } @EventHandler(priority = EventPriority.HIGHEST) public final void onJavaMOTD(final ServerListPingEvent event) { final OPlayer player = new OPlayer(null, null, null, - event.getAddress() != null ? event.getAddress().toString() : null, null); + event.getAddress() != null ? event.getAddress().toString() : null, null, -1); this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player)); } diff --git a/src/main/java/xyz/webmc/originblacklist/bungee/OriginBlacklistBungee.java b/src/main/java/xyz/webmc/originblacklist/bungee/OriginBlacklistBungee.java index 852dca4..a70b7e5 100644 --- a/src/main/java/xyz/webmc/originblacklist/bungee/OriginBlacklistBungee.java +++ b/src/main/java/xyz/webmc/originblacklist/bungee/OriginBlacklistBungee.java @@ -104,19 +104,19 @@ public final class OriginBlacklistBungee extends Plugin implements Listener, IOr public final void onJavaLogin(final PostLoginEvent event) { final ProxiedPlayer aPlayer = event.getPlayer(); final OPlayer bPlayer = new OPlayer(null, aPlayer.getName(), aPlayer.getUniqueId(), - aPlayer.getAddress().toString(), aPlayer.getClientBrand()); + aPlayer.getAddress().toString(), aPlayer.getClientBrand(), event.getPlayer().getPendingConnection().getVersion()); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, bPlayer)); } @EventHandler(priority = EventPriority.HIGHEST) public final void onJavaHandshake(final PreLoginEvent event) { - final OPlayer player = new OPlayer(null, null, null, event.getConnection().getAddress().toString(), null); + final OPlayer player = new OPlayer(null, null, null, event.getConnection().getAddress().toString(), OriginBlacklist.UNKNOWN_STR, event.getConnection().getVersion()); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, player)); } @EventHandler(priority = EventPriority.LOWEST) public final void onJavaMOTD(final ProxyPingEvent event) { - final OPlayer player = new OPlayer(null, null, null, event.getConnection().getAddress().toString(), null); + final OPlayer player = new OPlayer(null, null, null, event.getConnection().getAddress().toString(), null, -1); this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player)); } diff --git a/src/main/java/xyz/webmc/originblacklist/velocity/OriginBlacklistVelocity.java b/src/main/java/xyz/webmc/originblacklist/velocity/OriginBlacklistVelocity.java index 3ee40dc..514842a 100644 --- a/src/main/java/xyz/webmc/originblacklist/velocity/OriginBlacklistVelocity.java +++ b/src/main/java/xyz/webmc/originblacklist/velocity/OriginBlacklistVelocity.java @@ -120,7 +120,7 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin { @Subscribe(order = PostOrder.FIRST) public final void onJavaLogin(final PreLoginEvent event) { final OPlayer player = new OPlayer(null, event.getUsername(), event.getUniqueId(), - event.getConnection().getRemoteAddress().toString(), null); + event.getConnection().getRemoteAddress().toString(), OriginBlacklist.UNKNOWN_STR, event.getConnection().getProtocolVersion().getProtocol()); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, player)); } @@ -128,14 +128,14 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin { public final void onJavaHandshake(final PlayerClientBrandEvent event) { final Player aPlayer = (Player) event.getPlayer(); final OPlayer bPlayer = new OPlayer(null, aPlayer.getUsername(), aPlayer.getUniqueId(), - aPlayer.getRemoteAddress().getAddress().toString(), event.getBrand()); + aPlayer.getRemoteAddress().getAddress().toString(), event.getBrand(), event.getPlayer().getProtocolVersion().getProtocol()); this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, bPlayer)); } @Subscribe(order = PostOrder.LAST) public final void onJavaMOTD(final ProxyPingEvent event) { final OPlayer player = new OPlayer(null, null, null, event.getConnection().getRemoteAddress().getHostString(), - null); + null, -1); this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player)); }