Compare commits

..

No commits in common. "main" and "v1.0.4" have entirely different histories.
main ... v1.0.4

9 changed files with 118 additions and 173 deletions

1
.gitignore vendored
View File

@ -4,6 +4,5 @@
gradle gradle
build build
run run
bin
gradlew gradlew
gradlew.bat gradlew.bat

View File

@ -8,7 +8,6 @@ basically just a reimplementation of originblacklist but for eaglerxserver
### Features ### Features
- [x] Origin Blacklisting - [x] Origin Blacklisting
- [x] Brand Blacklisting - [x] Brand Blacklisting
- [x] Username blacklisting
- [x] Custom kick message - [x] Custom kick message
- [x] Custom blacklist MOTD - [x] Custom blacklist MOTD
- [x] MiniMessage formatting for messages - [x] MiniMessage formatting for messages

View File

@ -8,7 +8,7 @@ plugins {
group = 'dev.colbster937' group = 'dev.colbster937'
version = '1.0.6' version = '1.0.4'
description = 'A reimplementation of OriginBlacklist for EaglerXServer' description = 'A reimplementation of OriginBlacklist for EaglerXServer'
def targetJavaVersion = 17 def targetJavaVersion = 17
@ -64,7 +64,7 @@ java {
} }
processResources { processResources {
filesMatching(['plugin.yml', 'bungee.yml', 'velocity-plugin.json', 'Base.java']) { filesMatching(['plugin.yml', 'bungee.yml', 'velocity-plugin.json']) {
expand( expand(
version: project.version, version: project.version,
description: project.description description: project.description

View File

@ -4,19 +4,21 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import net.lax1dude.eaglercraft.backend.server.api.*; import net.lax1dude.eaglercraft.backend.server.api.*;
import net.lax1dude.eaglercraft.backend.server.api.event.IEaglercraftLoginEvent; import net.lax1dude.eaglercraft.backend.server.api.event.IEaglercraftClientBrandEvent;
import net.lax1dude.eaglercraft.backend.server.api.event.IEaglercraftMOTDEvent; import net.lax1dude.eaglercraft.backend.server.api.event.IEaglercraftMOTDEvent;
import net.lax1dude.eaglercraft.backend.server.api.query.IMOTDConnection; import net.lax1dude.eaglercraft.backend.server.api.query.IMOTDConnection;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.*; import java.io.File;
import java.net.HttpURLConnection; import java.io.IOException;
import java.net.URL; import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class Base { public class Base {
@ -40,68 +42,55 @@ public class Base {
for (int i = 0; i < Math.max(c.length, r.length); i++) { for (int i = 0; i < Math.max(c.length, r.length); i++) {
int c1 = i < c.length ? Integer.parseInt(c[i]) : 0; int c1 = i < c.length ? Integer.parseInt(c[i]) : 0;
int r1 = i < r.length ? Integer.parseInt(r[i]) : 0; int r1 = i < r.length ? Integer.parseInt(r[i]) : 0;
if (c1 < r1) if (c1 < r1) return false;
return false; if (c1 > r1) return true;
if (c1 > r1)
return true;
} }
return true; return true;
} }
public static LoggerAdapter getLogger() { public static LoggerAdapter getLogger() {
if (adapter == null) if (adapter == null) throw new IllegalStateException("Logger not initialized!");
throw new IllegalStateException("Logger not initialized!");
return adapter; return adapter;
} }
public interface LoggerAdapter { public interface LoggerAdapter {
void info(String msg); void info(String msg);
void warn(String msg); void warn(String msg);
void error(String msg); void error(String msg);
} }
public static void handleConnection(IEaglercraftLoginEvent e) { public static void handleConnection(IEaglercraftClientBrandEvent e) {
IEaglerLoginConnection conn = e.getLoginConnection(); IEaglerPendingConnection conn = e.getPendingConnection();
String origin = conn.getWebSocketHeader(EnumWebSocketHeader.HEADER_ORIGIN); String origin = conn.getWebSocketHeader(EnumWebSocketHeader.HEADER_ORIGIN);
String brand = conn.getEaglerBrandString(); String brand = conn.getEaglerBrandString();
String name = conn.getUsername(); if ((origin != "null" || origin != null) && !config.blacklist.missing_origin) {
if (origin != null && !origin.equals("null")) {
for (String origin1 : config.blacklist.origins) { for (String origin1 : config.blacklist.origins) {
if (matches(origin, origin1)) { if (matches(origin, origin1)) {
setKick(e, formatKickMessage("origin", "website", origin, conn.getWebSocketHost())); setKickMessage(e, kick("origin", "website", origin, conn.getWebSocketHost()));
webhook(conn, origin, brand, "origin"); webhook(conn, origin, brand, "origin");
return; return;
} }
} }
} else {
if (origin != "null" || origin != null) {
setKickMessage(e, kick("origin", "website", origin, conn.getWebSocketHost()));
webhook(conn, "null", brand, "origin");
return;
}
} }
if (brand != "null" && brand != null) {
if (brand != null && !brand.equals("null")) {
for (String brand1 : config.blacklist.brands) { for (String brand1 : config.blacklist.brands) {
if (matches(brand, brand1)) { if (matches(brand, brand1)) {
setKick(e, formatKickMessage("brand", "client", brand, conn.getWebSocketHost())); setKickMessage(e, kick("brand", "client", brand, conn.getWebSocketHost()));
webhook(conn, origin, brand, "brand"); webhook(conn, origin, brand, "brand");
return; return;
} }
} }
} }
if (name != null && !name.equals("null")) {
for (String name1 : config.blacklist.players) {
if (matches(name, name1) || (name.length() > 16 || name.length() < 3)) {
setKick(e, formatKickMessage("player", "username", name, conn.getWebSocketHost()));
webhook(conn, origin, name, "player");
return;
}
}
}
} }
public static void setKick(IEaglercraftLoginEvent e, Component msg) { public static void setKickMessage(IEaglercraftClientBrandEvent e, Component msg) {
try { try {
getLogger().info("Kicked " + e.getProfileUsername());
e.setKickMessage(msg); e.setKickMessage(msg);
} catch (Throwable ignored) { } catch (Throwable ignored) {
String msg1 = LegacyComponentSerializer.legacySection().serialize(msg); String msg1 = LegacyComponentSerializer.legacySection().serialize(msg);
@ -115,23 +104,26 @@ public class Base {
String origin = conn.getWebSocketHeader(EnumWebSocketHeader.HEADER_ORIGIN); String origin = conn.getWebSocketHeader(EnumWebSocketHeader.HEADER_ORIGIN);
List<String> m = List.of(config.messages.motd.text.split("\n")).stream() List<String> m = List.of(config.messages.motd.text.split("\n")).stream()
.map(line -> line .map(line -> line
.replaceAll("%blocktype%", "origin") .replaceAll("%blocktype%", "origin")
.replaceAll("%easyblocktype%", "website") .replaceAll("%easyblocktype%", "website")
.replaceAll("%blocked%", origin) .replaceAll("%blocked%", origin)
.replaceAll("%host%", conn.getWebSocketHost())) .replaceAll("%host%", conn.getWebSocketHost()))
.map(line -> LegacyComponentSerializer.legacySection().serialize( .map(line -> LegacyComponentSerializer.legacySection().serialize(
MiniMessage.miniMessage().deserialize(line))) MiniMessage.miniMessage().deserialize(
.collect(Collectors.toList()); line
)
if (origin != null && !origin.equals("null")) { )).collect(Collectors.toList());
if ((origin != "null" || origin != null) && !config.blacklist.missing_origin) {
for (String origin1 : config.blacklist.origins) { for (String origin1 : config.blacklist.origins) {
if (matches(origin, origin1)) { if (matches(origin, origin1)) {
setMOTD(conn, m); setMOTD(conn, m);
return; return;
} }
} }
} else if (origin != null && !origin.equals("null")) { } else {
setMOTD(conn, m); if (origin != "null" || origin != null) {
setMOTD(conn, m);
}
} }
} }
} }
@ -141,15 +133,13 @@ public class Base {
conn.setPlayerTotal(0); conn.setPlayerTotal(0);
conn.setPlayerMax(0); conn.setPlayerMax(0);
conn.setPlayerList(List.of()); conn.setPlayerList(List.of());
if (config.messages.motd.icon != null && !config.messages.motd.icon.isEmpty())
if (config.messages.motd.icon != null && !config.messages.motd.icon.isEmpty()) {
try { try {
BufferedImage img = ImageIO.read(new File(config.messages.motd.icon)); BufferedImage img = ImageIO.read(new File(config.messages.motd.icon));
if (img.getWidth() != 64 || img.getHeight() != 64) { if (img.getWidth() != 64 || img.getHeight() != 64) {
getLogger().warn("Icon must be 64x64"); getLogger().warn("Icon must be 64x64");
return; return;
} }
byte[] bytes = new byte[64 * 64 * 4]; byte[] bytes = new byte[64 * 64 * 4];
for (int y = 0; y < 64; y++) { for (int y = 0; y < 64; y++) {
for (int x = 0; x < 64; x++) { for (int x = 0; x < 64; x++) {
@ -165,74 +155,63 @@ public class Base {
} catch (IOException ex) { } catch (IOException ex) {
getLogger().error(ex.toString()); getLogger().error(ex.toString());
} }
}
} }
public static boolean matches(String text1, String text2) { public static boolean matches(String text1, String text2) {
return text1.toLowerCase().matches(text2.replace(".", "\\.").replaceAll("\\*", ".*").toLowerCase()); return text1.toLowerCase().matches(text2.replace(".", "\\.").replaceAll("\\*", ".*").toLowerCase());
} }
public static Component formatKickMessage(String type, String easytype, String value, String host) { public static Component kick(String type, String easytype, String value, String host) {
String help = "";
if (type != "player") {
help = config.messages.help.generic;
} else {
help = config.messages.help.player;
}
return MiniMessage.miniMessage().deserialize( return MiniMessage.miniMessage().deserialize(
config.messages.kick config.messages.kick
.replaceAll("%help%", help) .replaceAll("%blocktype%", type)
.replaceAll("%blocktype%", type) .replaceAll("%easyblocktype%", easytype)
.replaceAll("%easyblocktype%", easytype) .replaceAll("%blocked%", value)
.replaceAll("%blocked%", value) .replaceAll("%host%", host)
.replaceAll("%host%", host)); );
} }
public static void webhook(IEaglerLoginConnection plr, String origin, String brand, String type) { public static void webhook(IEaglerPendingConnection plr, String origin, String brand, String type) {
String webhook = config.discord.webhook; String webhook = config.discord.webhook;
if (webhook == null || webhook.isBlank()) if (webhook == null || webhook.isBlank()) return;
return;
CompletableFuture.runAsync(() -> { String addr = plr.getPlayerAddress() != null ? plr.getPlayerAddress().toString().substring(1) : "undefined";
String addr = (plr.getPlayerAddress() != null ? plr.getPlayerAddress().toString().substring(1) : "undefined:undefined").split(":")[0]; String protocol = plr.isEaglerXRewindPlayer()
int protocol = !plr.isEaglerXRewindPlayer() ? plr.getMinecraftProtocol() : plr.getRewindProtocolVersion(); ? (String.valueOf(plr.getRewindProtocolVersion()) != null ? String.valueOf(plr.getRewindProtocolVersion()) : "undefined")
String host = plr.getWebSocketHost(); : (String.valueOf(plr.getMinecraftProtocol()) != null ? String.valueOf(plr.getMinecraftProtocol()) : "undefined");
String userAgent = plr.getWebSocketHeader(EnumWebSocketHeader.HEADER_USER_AGENT); String rewind = plr.isEaglerXRewindPlayer() ? "Yes" : "No";
Boolean rewind = plr.isEaglerXRewindPlayer(); String host = plr.getWebSocketHost();
if (userAgent == null || userAgent.isEmpty()) String userAgent = plr.getWebSocketHeader(EnumWebSocketHeader.HEADER_USER_AGENT);
userAgent = "undefined"; if (userAgent == null || userAgent.isEmpty()) userAgent = "undefined";
String payload = String.format( String payload = String.format("""
""" {
{ "content": "Blocked a blacklisted %s from joining",
"content": "Blocked a blacklisted %s from joining", "embeds": [
"embeds": [ {
{ "title": "Player Information",
"title": "Player Information", "description": "🎮 **Name:** %s\\n🏠 **Address:** %s\\n🌄 **PVN:** %s\\n🌐 **Origin:** %s\\n🔋 **Brand:** %s\\n🪑 **Host:** %s\\n🧊 **User Agent:** %s\\n⏪ **Rewind:** %s"
"description": "🎮 **Name:** %s\\n🏠 **IP:** %s\\n🌄 **PVN:** %s\\n🌐 **Origin:** %s\\n🔋 **Brand:** %s\\n🪑 **Host:** %s\\n🧊 **User Agent:** %s\\n⏪ **Rewind:** %s"
}
]
}
""",
type, plr.getUsername(), addr, protocol, origin, brand, plr.isWebSocketSecure() ? "wss://" : "ws://" + host, userAgent, rewind ? "Yes" : "No");
try {
HttpURLConnection conn = (HttpURLConnection) new URL(webhook).openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
try (OutputStream os = conn.getOutputStream()) {
os.write(payload.getBytes());
}
conn.getInputStream().close();
} catch (Exception e) {
getLogger().warn("Failed to send webhook: " + e);
} }
}); ]
}
""", type, plr.getAuthUsername(), addr, protocol, origin, brand, host, userAgent, rewind);
try {
HttpURLConnection conn = (HttpURLConnection) new URL(webhook).openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
try (OutputStream os = conn.getOutputStream()) {
os.write(payload.getBytes());
}
conn.getInputStream().close();
} catch (Exception e) {
getLogger().warn("Failed to send webhook: " + e);
}
} }
public static void init() { public static void init() {

View File

@ -3,73 +3,47 @@ package dev.colbster937.originblacklist.base;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.DumperOptions; import java.io.File;
import java.io.*; import java.io.InputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.StandardCopyOption; import java.nio.file.StandardCopyOption;
import java.util.List; import java.util.List;
import java.util.Map;
public class ConfigManager { public class ConfigManager {
public Messages messages = new Messages(); public Messages messages = new Messages();
public List<String> subscriptions = List.of(); public List<String> subscriptions;
public Blacklist blacklist = new Blacklist(); public Blacklist blacklist = new Blacklist();
public Discord discord = new Discord(); public Discord discord = new Discord();
public static ConfigManager loadConfig(Base.LoggerAdapter logger) { public static ConfigManager loadConfig(Base.LoggerAdapter logger) {
File f = new File("plugins/originblacklist/config.yml"); File conf = new File("plugins/originblacklist/config.yml");
try { try {
if (!f.exists()) { if (!conf.exists()) {
f.getParentFile().mkdirs(); conf.getParentFile().mkdirs();
try (InputStream in = ConfigManager.class.getResourceAsStream("/config.yml")) { try (InputStream in = ConfigManager.class.getResourceAsStream("/config.yml")) {
if (in != null) Files.copy(in, f.toPath(), StandardCopyOption.REPLACE_EXISTING); if (in != null) {
Files.copy(in, conf.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
} }
} }
Yaml y = new Yaml(new Constructor(ConfigManager.class, new LoaderOptions())); LoaderOptions options = new LoaderOptions();
ConfigManager l; Constructor constructor = new Constructor(ConfigManager.class, options);
try (InputStream in = new FileInputStream(f)) { l = y.load(in); } Yaml yaml = new Yaml(constructor);
return yaml.load(new FileInputStream(conf));
if (l == null) l = new ConfigManager();
Yaml raw = new Yaml();
Map<String, Object> u = raw.load(new FileInputStream(f));
Map<String, Object> d = raw.load(ConfigManager.class.getResourceAsStream("/config.yml"));
if (mergeConfig(u, d)) saveConfig(u, f);
return l;
} catch (IOException e) { } catch (IOException e) {
return new ConfigManager(); return new ConfigManager();
} }
} }
@SuppressWarnings("unchecked")
private static boolean mergeConfig(Map<String, Object> u, Map<String, Object> d) {
boolean c = false;
for (String k : d.keySet()) {
if (!u.containsKey(k)) {
u.put(k, d.get(k));
c = true;
} else if (u.get(k) instanceof Map && d.get(k) instanceof Map)
c |= mergeConfig((Map<String, Object>) u.get(k), (Map<String, Object>) d.get(k));
}
return c;
}
private static void saveConfig(Map<String, Object> m, File f) throws IOException {
DumperOptions o = new DumperOptions();
o.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
o.setPrettyFlow(true);
new Yaml(o).dump(m, new FileWriter(f));
}
public static class Blacklist { public static class Blacklist {
public List<String> origins; public List<String> origins;
public List<String> brands; public List<String> brands;
public List<String> players; public List<String> players;
public boolean missing_origin; public boolean missing_origin;
public String blacklist_redirect;
} }
public static class Discord { public static class Discord {
@ -79,7 +53,6 @@ public class ConfigManager {
public static class Messages { public static class Messages {
public String kick; public String kick;
public MOTD motd; public MOTD motd;
public Help help;
} }
public static class MOTD { public static class MOTD {
@ -87,9 +60,4 @@ public class ConfigManager {
public String text; public String text;
public String icon; public String icon;
} }
public static class Help {
public String generic;
public String player;
}
} }

View File

@ -2,7 +2,7 @@ package dev.colbster937.originblacklist.bukkit;
import dev.colbster937.originblacklist.base.Base; import dev.colbster937.originblacklist.base.Base;
import net.lax1dude.eaglercraft.backend.server.api.bukkit.EaglerXServerAPI; import net.lax1dude.eaglercraft.backend.server.api.bukkit.EaglerXServerAPI;
import net.lax1dude.eaglercraft.backend.server.api.bukkit.event.EaglercraftLoginEvent; import net.lax1dude.eaglercraft.backend.server.api.bukkit.event.EaglercraftClientBrandEvent;
import net.lax1dude.eaglercraft.backend.server.api.bukkit.event.EaglercraftMOTDEvent; import net.lax1dude.eaglercraft.backend.server.api.bukkit.event.EaglercraftMOTDEvent;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -42,7 +42,7 @@ public class OriginBlacklistBukkit extends JavaPlugin implements Listener {
} }
@EventHandler @EventHandler
public void onLogin(EaglercraftLoginEvent event) { public void onLogin(EaglercraftClientBrandEvent event) {
Base.handleConnection(event); Base.handleConnection(event);
} }

View File

@ -2,7 +2,7 @@ package dev.colbster937.originblacklist.bungee;
import dev.colbster937.originblacklist.base.Base; import dev.colbster937.originblacklist.base.Base;
import net.lax1dude.eaglercraft.backend.server.api.bungee.EaglerXServerAPI; import net.lax1dude.eaglercraft.backend.server.api.bungee.EaglerXServerAPI;
import net.lax1dude.eaglercraft.backend.server.api.bungee.event.EaglercraftLoginEvent; import net.lax1dude.eaglercraft.backend.server.api.bungee.event.EaglercraftClientBrandEvent;
import net.lax1dude.eaglercraft.backend.server.api.bungee.event.EaglercraftMOTDEvent; import net.lax1dude.eaglercraft.backend.server.api.bungee.event.EaglercraftMOTDEvent;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Listener;
@ -41,7 +41,7 @@ public class OriginBlacklistBungee extends Plugin implements Listener {
} }
@EventHandler @EventHandler
public void onLogin(EaglercraftLoginEvent event) { public void onLogin(EaglercraftClientBrandEvent event) {
Base.handleConnection(event); Base.handleConnection(event);
} }

View File

@ -6,7 +6,7 @@ import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.ProxyServer;
import dev.colbster937.originblacklist.base.Base; import dev.colbster937.originblacklist.base.Base;
import net.lax1dude.eaglercraft.backend.server.api.velocity.EaglerXServerAPI; import net.lax1dude.eaglercraft.backend.server.api.velocity.EaglerXServerAPI;
import net.lax1dude.eaglercraft.backend.server.api.velocity.event.EaglercraftLoginEvent; import net.lax1dude.eaglercraft.backend.server.api.velocity.event.EaglercraftClientBrandEvent;
import net.lax1dude.eaglercraft.backend.server.api.velocity.event.EaglercraftMOTDEvent; import net.lax1dude.eaglercraft.backend.server.api.velocity.event.EaglercraftMOTDEvent;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -44,7 +44,7 @@ public class OriginBlacklistVelocity {
} }
@Subscribe @Subscribe
public void onLogin(EaglercraftLoginEvent event) { public void onLogin(EaglercraftClientBrandEvent event) {
Base.handleConnection(event); Base.handleConnection(event);
} }

View File

@ -4,21 +4,13 @@ messages:
# - %blocktype% - Shows what the player was blocked for # - %blocktype% - Shows what the player was blocked for
# - %easyblocktype% - Shows what the player was blocked for in an eagler-kid readable form # - %easyblocktype% - Shows what the player was blocked for in an eagler-kid readable form
# - %host% - The IP the player pinged # - %host% - The IP the player pinged
# - %help% - The configured help message for the block type
kick: | kick: |
<red>This %easyblocktype% is not allowed on the server!</red> <red>This %easyblocktype% is not allowed on the server!</red>
<dark_gray>»</dark_gray> <gray>%blocked%</gray> <dark_gray>«</dark_gray> <dark_gray>»</dark_gray> <gray>%blocked%</gray> <dark_gray>«</dark_gray>
%help%
<gray>Think this is a mistake? Join our discord:</gray> <gray>Think this is a mistake? Join our discord:</gray>
<blue>discord.gg/changethisintheconfig</blue> <blue>discord.gg/changethisintheconfig</blue>
# Please note that help is only supported in the kick message, not the MOTD
help:
generic: "<gray>Please switch to a different %easyblocktype%.</gray>"
player: "<gray>Please change your %easyblocktype%.</gray>"
motd: motd:
enabled: true enabled: true
@ -31,14 +23,11 @@ messages:
# Everything should be lowercase # Everything should be lowercase
blacklist: blacklist:
origins: origins:
- "*eagler-clients.vercel.app*" - "hack.example.com"
- "*eaglerhackedclients.vercel.app*"
- "*eaglerhacks.github.io*"
brands: brands:
- "*dragonx*" - "*dragonx*"
- "*piclient*" - "*piclient*"
players: missing_origin: false
- "Admin"
discord: discord:
webhook: "" webhook: ""
@ -66,4 +55,15 @@ discord:
# :>
# :>