Compare commits

...

8 Commits

Author SHA1 Message Date
Colbster937
89311ee6de eagler 2026-01-16 18:06:31 -06:00
Colbster937
14ffd4eb08 relocate deps 2026-01-16 16:09:04 -06:00
Colbster937
50fdbb0c28 add http blacklist sharing 2026-01-14 16:44:44 -06:00
Colbster937
bb71befe78 update readme 2026-01-14 14:55:22 -06:00
Colbster937
49f4e249e5 bump version 2026-01-14 14:54:56 -06:00
Colbster937
5491efa79a management cmds 2026-01-14 14:54:30 -06:00
Colbster937
5e29f7f74a add manual update command 2026-01-13 20:32:08 -06:00
Colbster937
ffdbcfa3b4 fix version sorting 2026-01-12 16:27:50 -06:00
25 changed files with 924 additions and 347 deletions

4
.gitignore vendored
View File

@@ -1,8 +1,10 @@
/.gradle/
/.vscode/
/gradle/
/gradle/**
/build/
/bin/
/run/
/gradlew
/gradlew.bat
!/gradle/wrapper/
!/gradle/wrapper/*.properties

View File

@@ -9,16 +9,19 @@
- [x] Client brand based blacklisting
- [x] Username based blacklisting
- [x] IP based blacklisting
- [x] Modular multi-platform support
- [x] JSON5 based configuration
- [x] Kick message customization
- [x] Blacklist MOTD customization
- [x] MiniMessage and legacy formattings supported
- [x] Plugin update checker
- [x] Send blacklist logs to a webhook
- [ ] Ingame blacklist management command
- [x] Ingame blacklist management commands
- [x] Reverse blacklist (whitelist)
- [ ] Subscribe to an auto-updating blacklist
- [ ] Reverse blacklist (whitelist)
<h2>Changes from v1</h2>
- [x] Modular multi-platform support
- [x] JSON5 based configuration
<h2>Download</h2>
The latest release can be found at <b><a href="https://github.com/WebMCDevelopment/originblacklist/releases/latest/">https://github.com/WebMCDevelopment/originblacklist/releases/latest/</a></b>

View File

@@ -1,4 +1,5 @@
import groovy.lang.Closure
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import com.palantir.gradle.gitversion.VersionDetails
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.language.jvm.tasks.ProcessResources
@@ -11,9 +12,9 @@ import xyz.jpenilla.runvelocity.task.RunVelocity
val PLUGIN_NAME = "OriginBlacklist"
val PLUGIN_IDEN = "originblacklist"
val PLUGIN_DOMN = "xyz.webmc"
val PLUGIN_DOMN = "xyz.webmc.$PLUGIN_IDEN"
val PLUGIN_DESC = "An eaglercraft client blacklist plugin."
val PLUGIN_VERS = "2.0.3"
val PLUGIN_VERS = "2.0.6"
val PLUGIN_SITE = "https://github.com/WebMCDevelopment/$PLUGIN_IDEN"
val PLUGIN_DEPA = listOf("EaglercraftXServer")
val PLUGIN_DEPB = listOf("EaglercraftXServer")
@@ -37,9 +38,11 @@ val PLUGIN_PROV_J = getBukkitBungeeDeps(PLUGIN_PROV)
val PLUGIN_ATHR_J = getBukkitBungeeDeps(PLUGIN_ATHR)
val PLUGIN_CTBR_J = getBukkitBungeeDeps(PLUGIN_CTBR)
val EAGXS_VER = "1.0.8"
plugins {
id("java")
id("com.gradleup.shadow") version "9.3.0"
id("com.gradleup.shadow") version "9.3.1"
id("com.palantir.git-version") version "4.2.0"
id("xyz.jpenilla.run-paper") version "3.0.2"
id("xyz.jpenilla.run-waterfall") version "3.0.2"
@@ -113,7 +116,7 @@ tasks.withType<JavaCompile>().configureEach {
options.release.set(17)
}
tasks.withType<ProcessResources>() {
tasks.withType<ProcessResources>().configureEach {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
outputs.upToDateWhen { false }
@@ -126,7 +129,6 @@ tasks.withType<ProcessResources>() {
doLast {
val file = destinationDir.resolve("build.properties")
file.parentFile.mkdirs()
file.writeText(
BUILD_PROPS.entries.joinToString("\n") { (k, v) ->
"$k = $v"
@@ -137,42 +139,25 @@ tasks.withType<ProcessResources>() {
inputs.files(tasks.named<JavaCompile>("compileJava").map { it.outputs.files })
}
tasks.withType<RunServer>() {
minecraftVersion("1.12.2")
runDirectory.set(layout.projectDirectory.dir("run/paper"))
downloadPlugins {
github("lax1dude", "eaglerxserver", "v1.0.8", "EaglerXServer.jar")
modrinth("placeholderapi", "2.11.7")
}
tasks.withType<Jar>().configureEach {
if (this !is ShadowJar) enabled = false
}
tasks.withType<RunWaterfall>() {
waterfallVersion("1.21")
runDirectory.set(layout.projectDirectory.dir("run/waterfall"))
downloadPlugins {
github("lax1dude", "eaglerxserver", "v1.0.8", "EaglerXServer.jar")
tasks.withType<ShadowJar>().configureEach {
doFirst {
delete(layout.buildDirectory.dir("libs"))
mkdir(layout.buildDirectory.dir("libs"))
}
}
tasks.withType<RunVelocity>() {
velocityVersion("3.4.0-SNAPSHOT")
runDirectory.set(layout.projectDirectory.dir("run/velocity"))
downloadPlugins {
github("lax1dude", "eaglerxserver", "v1.0.8", "EaglerXServer.jar")
modrinth("miniplaceholders", "3.1.0")
}
}
tasks.jar {
relocate("inet.ipaddr", "$PLUGIN_DOMN.shaded.ipaddress")
relocate("de.marhali.json5", "$PLUGIN_DOMN.shaded.json5")
relocate("org.bstats", "$PLUGIN_DOMN.shaded.bstats")
relocate("org.semver4j.semver4j", "$PLUGIN_DOMN.shaded.semver4j")
// relocate("net.kyori.adventure", "$PLUGIN_DOMN.shaded.adventure")
archiveFileName.set("$PLUGIN_NAME-$PLUGIN_VERS.jar")
}
tasks.shadowJar {
relocate("org.bstats", "$PLUGIN_DOMN.$PLUGIN_IDEN.shaded.bstats")
relocate("de.marhali.json5", "$PLUGIN_DOMN.$PLUGIN_IDEN.shaded.json5")
relocate("org.semver4j.semver4j", "$PLUGIN_DOMN.$PLUGIN_IDEN.shaded.semver4j")
// relocate("net.kyori.adventure", "$PLUGIN_DOMN.$PLUGIN_IDEN.shaded.adventure")
archiveFileName.set("$PLUGIN_NAME-$PLUGIN_VERS.jar")
tasks.named("build") {
dependsOn(tasks.named("shadowJar"))
}
tasks.register("printVars") {
@@ -183,6 +168,32 @@ tasks.register("printVars") {
}
}
tasks.withType<RunServer>().configureEach {
minecraftVersion("1.12.2")
runDirectory.set(layout.projectDirectory.dir("run/paper"))
downloadPlugins {
github("lax1dude", "eaglerxserver", "v" + EAGXS_VER, "EaglerXServer.jar")
modrinth("placeholderapi", "2.11.7")
}
}
tasks.withType<RunWaterfall>().configureEach {
waterfallVersion("1.21")
runDirectory.set(layout.projectDirectory.dir("run/waterfall"))
downloadPlugins {
github("lax1dude", "eaglerxserver", "v" + EAGXS_VER, "EaglerXServer.jar")
}
}
tasks.withType<RunVelocity>().configureEach {
velocityVersion("3.4.0-SNAPSHOT")
runDirectory.set(layout.projectDirectory.dir("run/velocity"))
downloadPlugins {
github("lax1dude", "eaglerxserver", "v" + EAGXS_VER, "EaglerXServer.jar")
modrinth("miniplaceholders", "3.1.0")
}
}
fun getBukkitBungeeDeps(list: List<String>): String {
return list.joinToString(
prefix = "[",

View File

@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -6,6 +6,7 @@ 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;
import xyz.webmc.originblacklist.base.http.OriginBlacklistHTTPServer;
import xyz.webmc.originblacklist.base.util.BuildInfo;
import xyz.webmc.originblacklist.base.util.IOriginBlacklistPlugin;
import xyz.webmc.originblacklist.base.util.OPlayer;
@@ -21,46 +22,72 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import de.marhali.json5.Json5;
import de.marhali.json5.Json5Array;
import de.marhali.json5.Json5Element;
import de.marhali.json5.Json5Object;
import inet.ipaddr.AddressStringException;
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;
import org.semver4j.Semver;
public final class OriginBlacklist {
private static final String COMMIT_L = BuildInfo.get("git_cm_hash");
private static final String COMMIT_S = COMMIT_L.substring(0, 8);
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 CENSORED_STR = "CENSORED";
public static final String PLUGIN_REPO = "WebMCDevelopment/originblacklist";
public static final int BSTATS_ID = 28776;
private final IOriginBlacklistPlugin plugin;
private final OriginBlacklistConfig config;
private final OriginBlacklistHTTPServer http;
private final Json5 json5;
private String updateURL;
public OriginBlacklist(final IOriginBlacklistPlugin plugin) {
this.plugin = plugin;
this.config = new OriginBlacklistConfig(plugin);
this.config = new OriginBlacklistConfig(this);
this.http = new OriginBlacklistHTTPServer(this);
this.json5 = Json5.builder(builder -> builder.prettyPrinting().indentFactor(0).build());
plugin.scheduleRepeat(() -> {
this.checkForUpdate();
}, 60, TimeUnit.MINUTES);
this.checkForUpdates();
}, this.config.getInteger("update_checker.check_timer"), TimeUnit.SECONDS);
}
public final void init() {
this.plugin.log(EnumLogLevel.INFO, "Initialized Plugin");
this.plugin.log(EnumLogLevel.DEBUG, "Commit " + BuildInfo.get("git_cm_hash"));
this.plugin.log(EnumLogLevel.DEBUG, "Commit " + COMMIT_L);
if (this.isHTTPServerEnabled()) {
this.http.start();
}
}
public final void shutdown() {
this.plugin.log(EnumLogLevel.INFO, "Shutting down...");
this.http.stop();
this.plugin.shutdown();
}
public final void handleReload() {
if (this.isHTTPServerEnabled()) {
this.http.start();
} else {
this.http.stop();
}
}
public final void handleLogin(final OriginBlacklistLoginEvent event) {
@@ -86,6 +113,7 @@ public final class OriginBlacklist {
final String name = player.getName();
if (isNonNull(name)) {
this.plugin.log(EnumLogLevel.INFO, "Prevented blacklisted player " + name + " from joining.");
this.updateLogFile(event, blacklisted);
}
}
}
@@ -109,11 +137,19 @@ public final class OriginBlacklist {
}
public final boolean isDebugEnabled() {
return this.config.get("debug").getAsBoolean();
return this.config.getBoolean("debug");
}
public final boolean isMetricsEnabled() {
return this.config.get("bStats").getAsBoolean();
return this.config.getBoolean("bStats");
}
public final boolean isLogFileEnabled() {
return this.config.getBoolean("logFile");
}
public final boolean isHTTPServerEnabled() {
return this.config.getBoolean("blacklist_http_share.enabled");
}
public final OriginBlacklistConfig getConfig() {
@@ -135,57 +171,170 @@ public final class OriginBlacklist {
conn.disconnect();
}
private final EnumBlacklistType testBlacklist(final OPlayer player) {
public final void checkForUpdates(final Runnable action1, final Runnable action2) {
if (this.config.getBoolean("update_checker.enabled")) {
this.plugin.runAsync(() -> {
this.updateURL = UpdateChecker.checkForUpdates(PLUGIN_REPO, this.plugin.getPluginVersion(),
this.config.getBoolean("update_checker.allow_snapshots"));
if (isNonNull((this.updateURL))) {
action1.run();
return;
}
action2.run();
});
} else {
action2.run();
}
}
public final void updatePlugin(final Runnable action1, final Runnable action2) {
try {
final URL url = new URL(this.updateURL);
final Path jar = this.plugin.getPluginJarPath();
final Path bak = jar.resolveSibling(jar.getFileName().toString() + ".bak");
final Path upd = jar
.resolveSibling(Paths.get(URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8)).getFileName());
try {
Files.copy(jar, bak, StandardCopyOption.REPLACE_EXISTING);
} catch (final Throwable t) {
t.printStackTrace();
}
try {
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(15000);
conn.setReadTimeout(15000);
conn.setRequestProperty("User-Agent", OriginBlacklist.getUserAgent());
conn.connect();
try (final InputStream in = conn.getInputStream()) {
Files.copy(in, upd, StandardCopyOption.REPLACE_EXISTING);
} finally {
conn.disconnect();
}
Files.delete(jar);
Files.delete(bak);
action1.run();
return;
} catch (final Throwable t) {
t.printStackTrace();
Files.move(bak, jar, StandardCopyOption.REPLACE_EXISTING);
}
} catch (final Throwable t) {
t.printStackTrace();
}
action2.run();
}
public final void updatePlugin() {
this.updatePlugin(() -> {
}, () -> {
});
}
public final EnumBlacklistType testBlacklist(final OPlayer player) {
final String name = player.getName();
final String addr = player.getAddr();
final String origin = player.getOrigin();
final String brand = player.getBrand();
final boolean whitelist = this.config.getBoolean("blacklist_to_whitelist");
EnumBlacklistType type = EnumBlacklistType.NONE;
if (isNonNull(origin)) {
for (final Json5Element element : this.config.get("blacklist.origins").getAsJson5Array()) {
if (whitelist && !type.isBlacklisted())
type = EnumBlacklistType.ORIGIN;
for (final Json5Element element : this.config.getArray("blacklist.origins").getAsJson5Array()) {
if (origin.matches(element.getAsString())) {
return EnumBlacklistType.ORIGIN;
if (whitelist)
type = EnumBlacklistType.NONE;
else if (!type.isBlacklisted())
type = EnumBlacklistType.ORIGIN;
break;
}
}
} else if (this.config.getBoolean("block_undefined_origin")) {
return whitelist ? EnumBlacklistType.NONE : EnumBlacklistType.ORIGIN;
}
if (isNonNull(brand)) {
for (final Json5Element element : this.config.get("blacklist.brands").getAsJson5Array()) {
if (whitelist && !type.isBlacklisted())
type = EnumBlacklistType.BRAND;
for (final Json5Element element : this.config.getArray("blacklist.brands")) {
if (brand.matches(element.getAsString())) {
return EnumBlacklistType.BRAND;
if (whitelist)
type = EnumBlacklistType.NONE;
else if (!type.isBlacklisted())
type = EnumBlacklistType.BRAND;
break;
}
}
}
if (isNonNull(name)) {
for (final Json5Element element : this.config.get("blacklist.player_names").getAsJson5Array()) {
this.plugin.log(EnumLogLevel.DEBUG, element.getAsString());
if (whitelist && !type.isBlacklisted())
type = EnumBlacklistType.NAME;
for (final Json5Element element : this.config.getArray("blacklist.player_names")) {
if (name.matches(element.getAsString())) {
return EnumBlacklistType.NAME;
if (whitelist)
type = EnumBlacklistType.NONE;
else if (!type.isBlacklisted())
type = EnumBlacklistType.NAME;
break;
}
}
}
if (isNonNull(addr)) {
for (final Json5Element element : this.config.get("blacklist.ip_addresses").getAsJson5Array()) {
if (whitelist && !type.isBlacklisted())
type = EnumBlacklistType.ADDR;
for (final Json5Element element : this.config.getArray("blacklist.ip_addresses")) {
try {
if ((new IPAddressString(element.getAsString()).toAddress())
.contains((new IPAddressString(addr)).toAddress())) {
return EnumBlacklistType.ADDR;
if (whitelist)
type = EnumBlacklistType.NONE;
else if (!type.isBlacklisted())
type = EnumBlacklistType.ADDR;
break;
}
} catch (final AddressStringException exception) {
// exception.printStackTrace();
if (this.isDebugEnabled())
exception.printStackTrace();
}
}
}
return EnumBlacklistType.NONE;
return type;
}
public final String getBlacklistShare() {
try {
final Json5Object obj = new Json5Object();
obj.addProperty("plugin_version", this.plugin.getPluginVersion().getVersion());
obj.addProperty("blacklist_to_whitelist", this.config.getBoolean("blacklist_to_whitelist"));
obj.addProperty("block_undefined_origin", this.config.getBoolean("block_undefined_origin"));
final Json5Object bObj = new Json5Object();
final String[] types = new String[] { "origins", "brands", "player_names", "ip_addresses" };
for (final String type : types) {
bObj.add(type, this.config.getArray("blacklist." + type));
}
obj.add("blacklist", bObj);
return this.json5.serialize(obj);
} catch (final Throwable t) {
return null;
}
}
public final String getDataDir() {
return "plugins/" + plugin.getPluginId();
}
private final Component getBlacklistedComponent(final String type, final String id, final String blockType,
final String blockTypeAlt, final String notAllowed, final String notAllowedAlt, final String blockValue,
final String action) {
final Json5Array arr = this.config.get("messages." + type).getAsJson5Array();
final Json5Array arr = this.config.getArray("messages." + type);
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < arr.size(); i++) {
if (i > 0)
@@ -193,7 +342,7 @@ public final class OriginBlacklist {
sb.append(arr.get(i).getAsString());
}
final String str = sb.toString()
.replaceAll("%action%", this.config.get("messages.actions." + action).getAsString())
.replaceAll("%action%", this.config.getString("messages.actions." + action))
.replaceAll("%block_type%", blockType)
.replaceAll("%block_type%", blockType)
.replaceAll("%not_allowed%", notAllowed)
@@ -203,17 +352,16 @@ public final class OriginBlacklist {
}
private final void sendWebhooks(final OriginBlacklistLoginEvent event, final EnumBlacklistType type) {
Json5Element element = this.config.get("discord.enabled");
if (element.getAsBoolean()) {
if (this.config.getBoolean("discord.enabled")) {
final OPlayer player = event.getPlayer();
final EnumConnectionType connType = event.getConnectionType();
final String userAgent;
/* 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(
"""
{
@@ -221,11 +369,11 @@ public final class OriginBlacklist {
"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",
"description": "**→ Name:** %s\\n**→ Origin:** %s\\n**→ Brand:** %s\\n**→ IP Address:** %s\\n**→ Protocol Version:** %s\\n**→ Host:** %s\\n**→ Rewind:** %s\\n**→ Player Type:** %s",
"color": 15801922,
"fields": [],
"footer": {
"text": "OriginBlacklist v%s",
"text": "%s v%s",
"icon_url": "https://raw.githubusercontent.com/%s/refs/heads/main/img/icon.png"
}
}
@@ -252,21 +400,21 @@ public final class OriginBlacklist {
player.getName().replaceAll("_", "\\_"),
player.getOrigin(),
player.getBrand(),
this.config.get("discord.send_ips").getAsBoolean() ? player.getAddr() : "*\\*CENSORED\\**",
this.config.getBoolean("discord.send_ips") ? player.getAddr() : CENSORED_STR,
player.getPVN(),
userAgent,
player.getVHost(),
// userAgent,
player.isRewind() ? "YES" : "NO",
connType.toString(),
this.plugin.getPluginVersion(),
BuildInfo.get("plugin_name"),
this.plugin.getPluginVersion() + "" + COMMIT_S,
PLUGIN_REPO,
PLUGIN_REPO
).getBytes();
element = this.config.get("discord.webhook_urls");
if (element instanceof Json5Array) {
for (final Json5Element _element : element.getAsJson5Array()) {
CompletableFuture.runAsync(() -> {
PLUGIN_REPO).getBytes();
final Json5Array arr = this.config.get("discord.webhook_urls").getAsJson5Array();
for (final Json5Element element : arr) {
this.plugin.runAsync(() -> {
try {
final URL url = new URL(_element.getAsString());
final URL url = new URL(element.getAsString());
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
@@ -291,57 +439,35 @@ public final class OriginBlacklist {
}
}
}
}
private final void checkForUpdate() {
if (this.config.get("update_checker.enabled").getAsBoolean()) {
CompletableFuture.runAsync(() -> {
this.updateURL = UpdateChecker.checkForUpdate(PLUGIN_REPO, this.plugin.getPluginVersion(),
this.config.get("update_checker.allow_snapshots").getAsBoolean());
if (isNonNull((this.updateURL))) {
if (!this.config.get("update_checker.auto_update").getAsBoolean()) {
private final void checkForUpdates() {
this.checkForUpdates(() -> {
if (!this.config.getBoolean("update_checker.auto_update")) {
this.plugin.log(EnumLogLevel.INFO, "An update is available! Download it at " + this.updateURL);
} else {
this.updatePlugin();
}
}
}, () -> {
});
}
}
private final void updatePlugin() {
private final void updateLogFile(final OriginBlacklistLoginEvent event, final EnumBlacklistType type) {
if (this.isLogFileEnabled()) {
final OPlayer player = event.getPlayer();
final String txt = Instant.now() + " - [player=" + player.getName() + "," + "blacklist_reason=" + type.toString() + "]";
final Path dir = Paths.get(this.getDataDir());
try {
final URL url = new URL(this.updateURL);
final Path jar = this.plugin.getPluginJarPath();
final Path bak = jar.resolveSibling(jar.getFileName().toString() + ".bak");
final Path upd = jar.resolveSibling(Paths.get(URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8)).getFileName());
try {
Files.copy(jar, bak, StandardCopyOption.REPLACE_EXISTING);
Files.createDirectories(dir);
Files.writeString(
dir.resolve("blacklist.log"),
txt + "\n",
StandardOpenOption.CREATE,
StandardOpenOption.WRITE,
StandardOpenOption.APPEND
);
} catch (final Throwable t) {
t.printStackTrace();
}
try {
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(15000);
conn.setReadTimeout(15000);
conn.setRequestProperty("User-Agent", OriginBlacklist.getUserAgent());
conn.connect();
try (final InputStream in = conn.getInputStream()) {
Files.copy(in, upd, StandardCopyOption.REPLACE_EXISTING);
} finally {
conn.disconnect();
}
Files.delete(jar);
Files.delete(bak);
} catch (final Throwable t) {
t.printStackTrace();
Files.move(bak, jar, StandardCopyOption.REPLACE_EXISTING);
}
} catch (final Throwable t) {
t.printStackTrace();
}
}

View File

@@ -1,8 +1,15 @@
package xyz.webmc.originblacklist.base.command;
import xyz.webmc.originblacklist.base.OriginBlacklist;
public interface CommandContext {
public OriginBlacklist getPlugin();
public String getPlayerName();
public void reply(final String message);
public boolean hasPermission(final String permission);
public String[] getArgs();
}

View File

@@ -4,7 +4,10 @@ import java.util.List;
public interface ICommand {
public static final String NO_PERMISSION = "<red>You don't have permission to use this command.</red>";
public boolean execute(final CommandContext ctx);
public List<String> suggest(final CommandContext ctx);
public void usage(final CommandContext ctx);
}

View File

@@ -1,10 +1,15 @@
package xyz.webmc.originblacklist.base.command;
import xyz.webmc.originblacklist.base.OriginBlacklist;
import xyz.webmc.originblacklist.base.config.OriginBlacklistConfig;
import xyz.webmc.originblacklist.base.enums.EnumBlacklistType;
import xyz.webmc.originblacklist.base.util.OPlayer;
import java.util.List;
import de.marhali.json5.Json5Array;
import de.marhali.json5.Json5Element;
import de.marhali.json5.Json5Primitive;
public class OriginBlacklistCommand implements ICommand {
private final OriginBlacklist plugin;
@@ -18,31 +23,105 @@ public class OriginBlacklistCommand implements ICommand {
final String[] args = ctx.getArgs();
if (ctx.hasPermission("originblacklist.command")) {
if (args.length > 0) {
final String command = args[0].toLowerCase();
if ("reload".equals(command)) {
final OriginBlacklistConfig config = this.plugin.getConfig();
final String command = args[0];
final String argA = args.length > 1 ? args[1] : null;
;
final String argB = args.length > 2 ? args[2] : null;
final boolean add = "add".equalsIgnoreCase(command);
final boolean remove = "remove".equalsIgnoreCase(command);
if ("reload".equalsIgnoreCase(command)) {
if (ctx.hasPermission("originblacklist.command.reload")) {
this.plugin.getConfig().reloadConfig();
config.reloadConfig();
this.plugin.handleReload();
ctx.reply("<green>Configuration Reloaded</green>");
} else {
ctx.reply(NO_PERMISSION);
}
} else if ("list".equals(command)) {
if (ctx.hasPermission("originblacklist.command.reload")) {
} else if ("update".equalsIgnoreCase(command)) {
if (ctx.hasPermission("originblacklist.command.update")) {
ctx.reply("<aqua>Checking for updates...</aqua>");
this.plugin.checkForUpdates(() -> {
ctx.reply("<yellow>Updating plugin...</yellow>");
this.plugin.updatePlugin(() -> {
ctx.reply("<green>Successfully updated plugin.</green>");
}, () -> {
ctx.reply("<red>Failed to update plugin.</red>");
});
}, () -> {
ctx.reply("<green>Plugin is up to date.</green>");
});
} else {
ctx.reply(NO_PERMISSION);
}
} else if ((add || remove) && OriginBlacklist.isNonNull(argB)) {
if ((add && ctx.hasPermission("originblacklist.command.add"))
|| (remove && ctx.hasPermission("originblacklist.command.add"))) {
final String arrName;
if ("origin".equalsIgnoreCase(argA)) {
arrName = "origins";
} else if ("brand".equalsIgnoreCase(argA)) {
arrName = "brands";
} else if ("name".equalsIgnoreCase(argA)) {
arrName = "player_names";
} else if ("ip".equalsIgnoreCase(argA)) {
arrName = "ip_addresses";
} else {
arrName = null;
}
if (OriginBlacklist.isNonNull(arrName)) {
final String arrPath = "blacklist." + arrName;
final Json5Array arr = config.getArray(arrPath);
if (add) {
if (!arr.contains(Json5Primitive.fromString(argB))) {
arr.add(argB);
config.set(arrPath, arr);
ctx.reply("<green>Added " + argB + " to the " + argA + " blacklist</green>");
} else {
ctx.reply("<red>" + argB + " is already on the " + argA + " blacklist</red>");
}
} else if (remove) {
if (arr.contains(Json5Primitive.fromString(argB))) {
arr.remove(Json5Primitive.fromString(argB));
config.set(arrPath, arr);
ctx.reply("<green>Removed " + argB + " from the " + argA + " blacklist</green>");
} else {
ctx.reply("<red>" + argB + " not on the " + argA + " blacklist</red>");
}
}
} else {
this.usage(ctx);
}
} else {
ctx.reply(NO_PERMISSION);
}
} else if ("test".equalsIgnoreCase(command) && OriginBlacklist.isNonNull(argA)) {
if (ctx.hasPermission("originblacklist.command.test")) {
if (this.isBlacklisted(argA)) {
ctx.reply("<green>" + argA + " is on the blacklist.</green>");
} else {
ctx.reply("<red>" + argA + " is not on the blacklist.</red>");
}
} else {
ctx.reply(NO_PERMISSION);
}
} else if ("list".equalsIgnoreCase(command)) {
if (ctx.hasPermission("originblacklist.command.list")) {
ctx.reply("<aqua>Blacklist:</aqua>");
ctx.reply("<gold> - Origins:</gold>");
for (final Json5Element element : this.plugin.getConfig().get("blacklist.origins").getAsJson5Array()) {
for (final Json5Element element : config.getArray("blacklist.origins")) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
ctx.reply("<gold> - Brands:</gold>");
for (final Json5Element element : this.plugin.getConfig().get("blacklist.brands").getAsJson5Array()) {
for (final Json5Element element : config.getArray("blacklist.brands")) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
ctx.reply("<gold> - Players:</gold>");
for (final Json5Element element : this.plugin.getConfig().get("blacklist.player_names").getAsJson5Array()) {
for (final Json5Element element : config.getArray("blacklist.player_names")) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
ctx.reply("<gold> - IPs:</gold>");
for (final Json5Element element : this.plugin.getConfig().get("blacklist.ip_addresses").getAsJson5Array()) {
for (final Json5Element element : config.getArray("blacklist.ip_addresses")) {
ctx.reply("<gray> - " + element.getAsString() + "</gray>");
}
} else {
@@ -61,16 +140,23 @@ public class OriginBlacklistCommand implements ICommand {
}
@Override
public List<String> suggest(final CommandContext ctx) {
public final List<String> suggest(final CommandContext ctx) {
return List.of();
}
@Override
public void usage(CommandContext ctx) {
public final void usage(CommandContext ctx) {
ctx.reply("<aqua>Commands:</aqua>");
ctx.reply("<gray> - /originblacklist reload</gray>");
// ctx.reply("<gray> - /originblacklist add <brand/origin/name/ip> <value></gray>");
// ctx.reply("<gray> - /originblacklist remove <brand/origin/name/ip> <value></gray>");
ctx.reply("<gray> - /originblacklist update</gray>");
ctx.reply("<gray> - /originblacklist add <origin/brand/name/ip> <arg></gray>");
ctx.reply("<gray> - /originblacklist remove <origin/brand/name/ip> <arg></gray>");
ctx.reply("<gray> - /originblacklist test <arg></gray>");
ctx.reply("<gray> - /originblacklist list</gray>");
}
private final boolean isBlacklisted(final String str) {
final OPlayer player = new OPlayer(null, str, null, str, str, null, -1);
return this.plugin.testBlacklist(player) != EnumBlacklistType.NONE;
}
}

View File

@@ -31,7 +31,7 @@ public final class OriginBlacklistConfig {
private byte[] icon;
private String icon64;
public OriginBlacklistConfig(IOriginBlacklistPlugin plugin) {
public OriginBlacklistConfig(final OriginBlacklist plugin) {
this.json5 = Json5.builder(builder -> builder
.quoteless()
.quoteSingle()
@@ -39,10 +39,10 @@ public final class OriginBlacklistConfig {
.writeComments()
.prettyPrinting()
.build());
final String dir = "plugins/" + plugin.getPluginId();
this.file = new File(dir + "/config.json5");
this.file = new File(plugin.getDataDir() + "/config.json5");
this.filePath = file.toPath();
this.iconFile = new File(dir + "/blacklisted.png");
this.iconFile = new File(plugin.getDataDir() + "/blacklisted.png");
this.iconPath = iconFile.toPath();
this.loadConfig();
}
@@ -50,19 +50,19 @@ public final class OriginBlacklistConfig {
private final void loadConfig() {
try {
this.reloadConfigUnsafe();
this.reloadIconImage();
} catch (final IOException exception) {
throw new RuntimeException("Failed to load config.", exception);
}
this.reloadIconImage();
}
public final void reloadConfig() {
try {
this.reloadConfigUnsafe();
this.reloadIconImage();
} catch (final IOException exception) {
exception.printStackTrace();
}
this.reloadIconImage();
}
private final void reloadConfigUnsafe() throws IOException {
@@ -95,10 +95,10 @@ public final class OriginBlacklistConfig {
final BufferedImage img = ImageIO.read(iconFile);
if (img.getWidth() == 64 && img.getHeight() == 64) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(img, "png", baos);
this.icon64 = OriginBlacklist.getPNGBase64FromBytes(baos.toByteArray());
byte[] bytes = new byte[64 * 64 * 4];
final byte[] bytes = new byte[64 * 64 * 4];
for (int y = 0; y < 64; y++) {
for (int x = 0; x < 64; x++) {
int pixel = img.getRGB(x, y);
@@ -132,7 +132,7 @@ public final class OriginBlacklistConfig {
if (this.config != null && OriginBlacklist.isNonNull(key)) {
element = this.config;
final String[] parts = key.split("\\.");
final String[] parts = splitPath(key);
for (final String part : parts) {
if (element instanceof Json5Object) {
@@ -155,6 +155,95 @@ public final class OriginBlacklistConfig {
return element;
}
public final boolean set(final String key, final Json5Element value) {
boolean ret = false;
if (this.config != null && value != null) {
final String[] parts = splitPath(key);
if (parts.length > 0) {
Json5Object obj = this.config;
for (int i = 0; i < parts.length - 1; i++) {
final String part = parts[i];
final Json5Element cur = obj.has(part) ? obj.get(part) : null;
if (cur instanceof Json5Object next) {
obj = next;
} else {
final Json5Object next = new Json5Object();
obj.add(part, next);
obj = next;
}
}
obj.add(parts[parts.length - 1], value.deepCopy());
this.saveConfig();
ret = true;
}
}
return ret;
}
public final boolean remove(final String key) {
boolean ret = false;
if (this.config != null) {
final String[] parts = splitPath(key);
if (parts.length > 0) {
Json5Object obj = this.config;
Json5Element element = obj;
for (int i = 0; i < parts.length - 1; i++) {
if (element instanceof Json5Object cur && cur.has(parts[i])) {
element = cur.get(parts[i]);
if (element instanceof Json5Object) {
obj = (Json5Object) element;
} else {
element = null;
}
} else {
element = null;
}
if (element == null) {
break;
}
}
if (element != null && obj.has(parts[parts.length - 1])) {
obj.remove(parts[parts.length - 1]);
this.saveConfig();
ret = true;
}
}
}
return ret;
}
public final String getString(final String key) {
return this.get(key).getAsString();
}
public final boolean getBoolean(final String key) {
return this.get(key).getAsBoolean();
}
public final int getInteger(final String key) {
return this.get(key).getAsInt();
}
public final Json5Array getArray(final String key) {
return this.get(key).getAsJson5Array();
}
public final Json5Object getObject(final String key) {
return this.get(key).getAsJson5Object();
}
public final byte[] getIconBytes() {
return this.icon;
}
@@ -166,7 +255,7 @@ public final class OriginBlacklistConfig {
private static final Json5Object getDefaultConfig() {
final Json5Object obj = new Json5Object();
addJSONObj(obj, "debug", Json5Primitive.fromBoolean(false), null);
final Json5Object mobj = new Json5Object();
final Json5Object mObj = new Json5Object();
final Json5Array kick = new Json5Array();
kick.add("<red>This %block_type% is %not_allowed_alt%!</red>");
kick.add("<dark_gray>»</dark_gray> <gray>%blocked_value%</gray> <dark_gray>«</dark_gray>");
@@ -175,18 +264,18 @@ public final class OriginBlacklistConfig {
kick.add("");
kick.add("<aqua>Think this is a mistake? Join our discord:</aqua>");
kick.add("<blue>discord.gg/changethisintheconfig</blue>");
addJSONObj(mobj, "kick", kick, null);
addJSONObj(mObj, "kick", kick, null);
final Json5Array motd = new Json5Array();
motd.add("<red>This %block_type% is %not_allowed%!</red>");
motd.add("<dark_gray>»</dark_gray> <gray>%blocked_value%</gray>");
addJSONObj(mobj, "motd", motd, null);
addJSONObj(mObj, "motd", motd, null);
final Json5Object actions = new Json5Object();
actions.add("generic", Json5Primitive.fromString("<gold>Please switch to a different %block_type%.</gold>"));
actions.add("player_name", Json5Primitive.fromString("<gold>Please change your %block_type%.</gold>"));
actions.add("ip_address", Json5Primitive.fromString("<gold>Please contact staff for assistance.</gold>"));
addJSONObj(mobj, "actions", actions, null);
addJSONObj(obj, "messages", mobj, null);
final Json5Object bobj = new Json5Object();
addJSONObj(mObj, "actions", actions, null);
addJSONObj(obj, "messages", mObj, null);
final Json5Object bObj = new Json5Object();
final Json5Array origins = new Json5Array();
origins.add(".*eaglerhackedclients\\.vercel\\.app.*");
origins.add(".*eaglerhacks\\.github\\.io.*");
@@ -198,32 +287,42 @@ public final class OriginBlacklistConfig {
origins.add(".*uec\\.vercel\\.app.*");
origins.add(".*valux-game\\.github\\.io.*");
origins.add(".*project516\\.dev.*");
addJSONObj(bobj, "origins", origins, null);
addJSONObj(bObj, "origins", origins, null);
final Json5Array brands = new Json5Array();
brands.add(".*dragonx.*");
brands.add(".*piclient.*");
brands.add(".*justin.*");
brands.add(".*wurstx.*");
brands.add(".*moonlight.*");
addJSONObj(bobj, "brands", brands, null);
addJSONObj(bObj, "brands", brands, null);
final Json5Array players = new Json5Array();
players.add("Admin");
addJSONObj(bobj, "player_names", players, null);
addJSONObj(bObj, "player_names", players, null);
final Json5Array ips = new Json5Array();
ips.add("192.0.2.0/24");
addJSONObj(bobj, "ip_addresses", ips, null);
addJSONObj(obj, "blacklist", bobj, null);
final Json5Object dobj = new Json5Object();
addJSONObj(dobj, "enabled", Json5Primitive.fromBoolean(false), null);
addJSONObj(dobj, "webhook_urls", new Json5Array(), null);
addJSONObj(dobj, "send_ips", Json5Primitive.fromBoolean(true), null);
addJSONObj(obj, "discord", dobj, null);
final Json5Object uobj = new Json5Object();
addJSONObj(uobj, "enabled", Json5Primitive.fromBoolean(true), null);
addJSONObj(uobj, "allow_snapshots", Json5Primitive.fromBoolean(false), null);
addJSONObj(uobj, "auto_update", Json5Primitive.fromBoolean(true), null);
addJSONObj(obj, "update_checker", uobj, null);
addJSONObj(bObj, "ip_addresses", ips, null);
addJSONObj(obj, "blacklist", bObj, null);
final Json5Object dObj = new Json5Object();
addJSONObj(dObj, "enabled", Json5Primitive.fromBoolean(false), null);
addJSONObj(dObj, "webhook_urls", new Json5Array(), null);
addJSONObj(dObj, "send_ips", Json5Primitive.fromBoolean(true), null);
addJSONObj(obj, "discord", dObj, null);
final Json5Object uObj = new Json5Object();
addJSONObj(uObj, "enabled", Json5Primitive.fromBoolean(true), null);
addJSONObj(uObj, "allow_snapshots", Json5Primitive.fromBoolean(false), null);
addJSONObj(uObj, "check_timer", Json5Primitive.fromNumber(3600), null);
addJSONObj(uObj, "auto_update", Json5Primitive.fromBoolean(true), null);
addJSONObj(obj, "update_checker", uObj, null);
final Json5Object hObj = new Json5Object();
addJSONObj(hObj, "enabled", Json5Primitive.fromBoolean(false), null);
addJSONObj(hObj, "http_port", Json5Primitive.fromNumber(8080), null);
addJSONObj(hObj, "listen_addr", Json5Primitive.fromString("0.0.0.0"), null);
addJSONObj(obj, "blacklist_http_share", hObj, null);
addJSONObj(obj, "blacklist_to_whitelist", Json5Primitive.fromBoolean(false), null);
addJSONObj(obj, "block_undefined_origin", Json5Primitive.fromBoolean(false), null);
addJSONObj(obj, "bStats", Json5Primitive.fromBoolean(true), null);
addJSONObj(obj, "logFile", Json5Primitive.fromBoolean(true), null);
addJSONObj(obj, "config_version", Json5Primitive.fromNumber(1), "DO NOT CHANGE");
return obj;
}
@@ -255,4 +354,16 @@ public final class OriginBlacklistConfig {
}
obj.add(key, value);
}
private static final String[] splitPath(final String key) {
final String[] ret;
if (OriginBlacklist.isNonNull(key)) {
ret = key.split("\\.");
} else {
ret = new String[0];
}
return ret;
}
}

View File

@@ -36,4 +36,8 @@ public enum EnumBlacklistType {
public final String getActionString() {
return this.act;
}
public final boolean isBlacklisted() {
return this != NONE;
}
}

View File

@@ -0,0 +1,39 @@
package xyz.webmc.originblacklist.base.http;
import xyz.webmc.originblacklist.base.OriginBlacklist;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
public class OriginBlacklistHTTPHandler implements HttpHandler {
private final OriginBlacklist plugin;
public OriginBlacklistHTTPHandler(final OriginBlacklist plugin) {
this.plugin = plugin;
}
@Override
public final void handle(final HttpExchange exchange) throws IOException {
try {
final String path = exchange.getRequestURI().getPath();
if ("/".equals(path)) {
final byte[] bytes = this.plugin.getBlacklistShare().getBytes(StandardCharsets.UTF_8);
exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
exchange.sendResponseHeaders(200, bytes.length);
try (final OutputStream os = exchange.getResponseBody()) {
os.write(bytes);
}
} else {
exchange.sendResponseHeaders(404, -1);
}
} finally {
exchange.close();
}
}
}

View File

@@ -0,0 +1,56 @@
package xyz.webmc.originblacklist.base.http;
import xyz.webmc.originblacklist.base.OriginBlacklist;
import xyz.webmc.originblacklist.base.config.OriginBlacklistConfig;
import java.net.InetSocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.sun.net.httpserver.HttpServer;
public class OriginBlacklistHTTPServer {
private final OriginBlacklist plugin;
private final ExecutorService executor;
private HttpServer server;
private boolean running;
public OriginBlacklistHTTPServer(final OriginBlacklist plugin) {
this.plugin = plugin;
this.executor = Executors.newFixedThreadPool(4);
this.running = false;
}
public final void start() {
if (!this.running) {
try {
this.server = this.createServer();
this.server.start();
this.running = true;
} catch (final Throwable t) {
}
}
}
public final void stop() {
if (this.running && this.server != null) {
this.server.stop(0);
this.running = false;
}
}
public final void shutdown() {
this.stop();
this.executor.shutdownNow();
}
private final HttpServer createServer() throws Throwable {
final OriginBlacklistConfig config = this.plugin.getConfig();
final HttpServer server = HttpServer
.create(new InetSocketAddress(config.getString("blacklist_http_share.listen_addr"),
config.getInteger("blacklist_http_share.http_port")), 0);
server.createContext("/", new OriginBlacklistHTTPHandler(this.plugin));
server.setExecutor(executor);
return server;
}
}

View File

@@ -3,7 +3,7 @@ package xyz.webmc.originblacklist.base.util;
import java.io.InputStream;
import java.util.Properties;
public class BuildInfo {
public final class BuildInfo {
private static final Properties properties;
public static final String get(final String key) {
@@ -14,6 +14,7 @@ public class BuildInfo {
properties = new Properties();
try (final InputStream in = BuildInfo.class.getClassLoader().getResourceAsStream("build.properties")) {
properties.load(in);
} catch (final Throwable t) {}
} catch (final Throwable t) {
}
}
}

View File

@@ -12,12 +12,22 @@ import org.semver4j.Semver;
public interface IOriginBlacklistPlugin {
public String getPluginId();
public Semver getPluginVersion();
public Path getPluginJarPath();
public void log(final EnumLogLevel level, final String txt);
public void kickPlayer(final Component txt, final OriginBlacklistLoginEvent event);
public void setMOTD(final Component txt, final OriginBlacklistMOTDEvent event);
public String parsePlaceholders(final OPlayer player, final String str);
public void scheduleRepeat(final Runnable task, final int period, final TimeUnit unit);
public void runAsync(final Runnable task);
public void shutdown();
}

View File

@@ -16,16 +16,18 @@ public final class OPlayer {
private final String name;
private final UUID uuid;
private final String brand;
private final String vhost;
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 int pvn) {
final String brand, final String vhost, final int pvn) {
this.name = name;
this.uuid = uuid;
if (conn != null) {
this.origin = conn.getWebSocketHeader(EnumWebSocketHeader.HEADER_ORIGIN);
this.addr = formatSocketAddress(conn.getSocketAddress());
this.vhost = conn.isWebSocketSecure() ? "wss://" : "ws://" + conn.getWebSocketHost();
if (conn instanceof IEaglerLoginConnection) {
final IEaglerLoginConnection loginConn = (IEaglerLoginConnection) conn;
this.brand = loginConn.getEaglerBrandString();
@@ -40,13 +42,14 @@ public final class OPlayer {
this.origin = OriginBlacklist.UNKNOWN_STR;
this.addr = formatIPAddress(addr);
this.brand = brand;
this.vhost = vhost;
this.rewind = false;
this.pvn = pvn;
}
}
public OPlayer(final IEaglerConnection conn, final String name, final UUID uuid) {
this(conn, name, uuid, null, null, -1);
this(conn, name, uuid, null, null, null, -1);
}
public final String getOrigin() {
@@ -69,6 +72,10 @@ public final class OPlayer {
return this.brand;
}
public final String getVHost() {
return this.vhost;
}
public final boolean isRewind() {
return this.rewind;
}
@@ -78,9 +85,7 @@ public final class OPlayer {
}
private static final String formatIPAddress(String addr) {
if (addr == null) {
addr = OriginBlacklist.UNKNOWN_STR;
} else {
if (OriginBlacklist.isNonNull(addr)) {
if (addr.startsWith("/")) {
addr = addr.substring(1);
}
@@ -132,6 +137,8 @@ public final class OPlayer {
if (hex && c == 6 && addr.indexOf("::") == -1) {
addr = addr + "::";
}
} else {
addr = OriginBlacklist.UNKNOWN_STR;
}
return addr;

View File

@@ -14,10 +14,11 @@ import de.marhali.json5.Json5Object;
import org.semver4j.Semver;
import org.semver4j.Semver.VersionDiff;
public class UpdateChecker {
public final class UpdateChecker {
private static final Json5 json5 = Json5.builder(builder -> builder.build());
public static final String checkForUpdate(final String repo, final Semver currentVersion, final boolean allowSnapshots) {
public static final String checkForUpdates(final String repo, final Semver currentVersion,
final boolean allowSnapshots) {
try {
final URL url = new URL("https://api.github.com/repos/" + repo + "/releases");
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
@@ -31,31 +32,57 @@ public class UpdateChecker {
String ret = null;
Json5Element element = json5.parse(reader);
reader.close();
Json5Object rel = null;
Json5Object snap = null;
if (element instanceof Json5Array) {
final Json5Array arr = element.getAsJson5Array();
if (arr.size() > 0) {
for (int i = 0; i < Math.min(2, arr.size()); i++) {
for (int i = 0; i < arr.size(); i++) {
element = arr.get(i);
if (element instanceof Json5Object) {
final Json5Object obj = element.getAsJson5Object();
if (allowSnapshots || !obj.get("prerelease").getAsBoolean()) {
if (!obj.has("published_at")) {
continue;
}
final boolean pre = obj.get("prerelease").getAsBoolean();
if (!pre) {
if (rel == null
|| obj.get("published_at").getAsString().compareTo(rel.get("published_at").getAsString()) > 0) {
rel = obj;
}
} else {
if (snap == null
|| obj.get("published_at").getAsString().compareTo(snap.get("published_at").getAsString()) > 0) {
snap = obj;
}
}
}
continue;
}
for (int i = 0; i < 2; i++) {
final Json5Object obj = i == 0 ? rel : snap;
if (obj == null || (i == 1 && !allowSnapshots)) {
continue;
}
final String tag = obj.get("tag_name").getAsString();
final Semver ver = new Semver(tag.startsWith("v") ? tag.substring(1) : tag);
String comm;
try {
comm = ver.getBuild().get(0).trim();
} catch (Throwable t) {
} catch (final Throwable t) {
comm = "";
}
if (ver.isGreaterThan(currentVersion) || (allowSnapshots && currentVersion.diff(ver) == VersionDiff.BUILD && OriginBlacklist.isNonNull(comm) && !BuildInfo.get("git_cm_hash").startsWith(comm))) {
if (ver.isGreaterThan(currentVersion) || (allowSnapshots && currentVersion.diff(ver) == VersionDiff.BUILD
&& OriginBlacklist.isNonNull(comm) && !BuildInfo.get("git_cm_hash").startsWith(comm))) {
element = obj.get("assets");
if (element instanceof Json5Array) {
final Json5Array aArr = element.getAsJson5Array();
if (aArr.size() > 0) {
element = aArr.get(0);
if (element instanceof Json5Object) {
final Json5Object vObj = element.getAsJson5Object();
ret = vObj.get("browser_download_url").getAsString();
ret = element.getAsJson5Object().get("browser_download_url").getAsString();
break;
}
}
@@ -63,10 +90,7 @@ public class UpdateChecker {
}
}
}
continue;
}
}
}
conn.disconnect();
return ret;
} catch (final Throwable t) {

View File

@@ -93,6 +93,11 @@ public final class OriginBlacklistBukkit extends JavaPlugin implements Listener,
}
}
@Override
public void onDisable() {
this.blacklist.shutdown();
}
@EventHandler(priority = EventPriority.NORMAL)
public final void onEaglerLogin(final EaglercraftLoginEvent event) {
final OPlayer player = new OPlayer(event.getLoginConnection(), event.getProfileUsername(), event.getProfileUUID());
@@ -107,15 +112,13 @@ 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, OriginBlacklist.UNKNOWN_STR, -1);
final OPlayer player = new OPlayer(null, event.getName(), event.getUniqueId(), event.getAddress().toString(), OriginBlacklist.UNKNOWN_STR, 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, -1);
final OPlayer player = new OPlayer(null, null, null, event.getAddress().toString(), null, null, -1);
this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player));
}
@@ -234,6 +237,11 @@ public final class OriginBlacklistBukkit extends JavaPlugin implements Listener,
Bukkit.getScheduler().runTaskTimer(this, task, 0, ticks);
}
@Override
public final void runAsync(final Runnable task) {
Bukkit.getScheduler().runTaskAsynchronously(this, task);
}
@Override
public final void shutdown() {
this.metrics.shutdown();

View File

@@ -5,32 +5,39 @@ import xyz.webmc.originblacklist.base.command.CommandContext;
import org.bukkit.command.CommandSender;
public class BKTCommandContext implements CommandContext {
public final class BKTCommandContext implements CommandContext {
private final OriginBlacklist plugin;
private final CommandSender sender;
private final String[] args;
public BKTCommandContext(final CommandSender sender, final String[] args) {
public BKTCommandContext(final OriginBlacklist plugin, final CommandSender sender, final String[] args) {
this.plugin = plugin;
this.sender = sender;
this.args = args;
}
@Override
public String getPlayerName() {
public final OriginBlacklist getPlugin() {
return this.plugin;
}
@Override
public final String getPlayerName() {
return this.sender.getName();
}
@Override
public void reply(final String message) {
public final void reply(final String message) {
this.sender.sendMessage(OriginBlacklist.getLegacyFromMiniMessage(message));
}
@Override
public boolean hasPermission(final String permission) {
public final boolean hasPermission(final String permission) {
return this.sender.hasPermission(permission);
}
@Override
public String[] getArgs() {
public final String[] getArgs() {
return this.args;
}
}

View File

@@ -9,18 +9,22 @@ import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
public class OriginBlacklistCommandBukkit extends OriginBlacklistCommand implements TabExecutor {
public final class OriginBlacklistCommandBukkit extends OriginBlacklistCommand implements TabExecutor {
private final OriginBlacklist plugin;
public OriginBlacklistCommandBukkit(OriginBlacklist plugin) {
super(plugin);
this.plugin = plugin;
}
@Override
public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) {
return super.execute(new BKTCommandContext(sender, args));
return super.execute(new BKTCommandContext(this.plugin, sender, args));
}
@Override
public List<String> onTabComplete(final CommandSender sender, final Command command, final String label, final String[] args) {
return super.suggest(new BKTCommandContext(sender, args));
public List<String> onTabComplete(final CommandSender sender, final Command command, final String label,
final String[] args) {
return super.suggest(new BKTCommandContext(this.plugin, sender, args));
}
}

View File

@@ -10,6 +10,7 @@ import xyz.webmc.originblacklist.base.util.IncompatibleDependencyException;
import xyz.webmc.originblacklist.base.util.OPlayer;
import xyz.webmc.originblacklist.bungee.command.OriginBlacklistCommandBungee;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
@@ -23,6 +24,7 @@ import net.lax1dude.eaglercraft.backend.server.api.bungee.event.EaglercraftLogin
import net.lax1dude.eaglercraft.backend.server.api.bungee.event.EaglercraftMOTDEvent;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.event.PreLoginEvent;
@@ -89,6 +91,11 @@ public final class OriginBlacklistBungee extends Plugin implements Listener, IOr
}
}
@Override
public void onDisable() {
this.blacklist.shutdown();
}
@EventHandler(priority = EventPriority.HIGHEST)
public final void onEaglerLogin(final EaglercraftLoginEvent event) {
final OPlayer player = new OPlayer(event.getLoginConnection(), event.getProfileUsername(), event.getProfileUUID());
@@ -103,21 +110,27 @@ public final class OriginBlacklistBungee extends Plugin implements Listener, IOr
@EventHandler(priority = EventPriority.HIGHEST)
public final void onJavaLogin(final PostLoginEvent event) {
final PendingConnection conn = event.getPlayer().getPendingConnection();
final InetSocketAddress vhost = conn.getVirtualHost();
final ProxiedPlayer aPlayer = event.getPlayer();
final OPlayer bPlayer = new OPlayer(null, aPlayer.getName(), aPlayer.getUniqueId(),
aPlayer.getAddress().toString(), aPlayer.getClientBrand(), event.getPlayer().getPendingConnection().getVersion());
aPlayer.getAddress().toString(), aPlayer.getClientBrand(), vhost.getHostString() + vhost.getPort(), conn.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(), OriginBlacklist.UNKNOWN_STR, event.getConnection().getVersion());
final PendingConnection conn = event.getConnection();
final InetSocketAddress vhost = conn.getVirtualHost();
final OPlayer player = new OPlayer(null, null, null, conn.getAddress().toString(), OriginBlacklist.UNKNOWN_STR, vhost.getHostString() + vhost.getPort(), conn.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, -1);
final PendingConnection conn = event.getConnection();
final InetSocketAddress vhost = conn.getVirtualHost();
final OPlayer player = new OPlayer(null, null, null, conn.getAddress().toString(), null, vhost.getHostString() + vhost.getPort(), -1);
this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player));
}
@@ -198,6 +211,11 @@ public final class OriginBlacklistBungee extends Plugin implements Listener, IOr
this.proxy.getScheduler().schedule(this, task, 0, period, unit);
}
@Override
public final void runAsync(final Runnable task) {
this.proxy.getScheduler().runAsync(this, task);
}
@Override
public final void shutdown() {
this.metrics.shutdown();

View File

@@ -6,32 +6,39 @@ import xyz.webmc.originblacklist.base.command.CommandContext;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.TextComponent;
public class BNGCommandContext implements CommandContext {
public final class BNGCommandContext implements CommandContext {
private final OriginBlacklist plugin;
private final CommandSender sender;
private final String[] args;
public BNGCommandContext(final CommandSender sender, final String[] args) {
public BNGCommandContext(final OriginBlacklist plugin, final CommandSender sender, final String[] args) {
this.plugin = plugin;
this.sender = sender;
this.args = args;
}
@Override
public String getPlayerName() {
public final OriginBlacklist getPlugin() {
return this.plugin;
}
@Override
public final String getPlayerName() {
return this.sender.getName();
}
@Override
public void reply(final String message) {
public final void reply(final String message) {
this.sender.sendMessage(TextComponent.fromLegacy(OriginBlacklist.getLegacyFromMiniMessage(message)));
}
@Override
public boolean hasPermission(final String permission) {
public final boolean hasPermission(final String permission) {
return this.sender.hasPermission(permission);
}
@Override
public String[] getArgs() {
public final String[] getArgs() {
return this.args;
}
}

View File

@@ -10,21 +10,24 @@ import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
public class OriginBlacklistCommandBungee extends Command implements TabExecutor {
public final class OriginBlacklistCommandBungee extends Command implements TabExecutor {
private final OriginBlacklistCommand cmd;
private final OriginBlacklist blacklist;
public OriginBlacklistCommandBungee(final OriginBlacklistBungee plugin, final OriginBlacklist blacklist, final String command) {
public OriginBlacklistCommandBungee(final OriginBlacklistBungee plugin, final OriginBlacklist blacklist,
final String command) {
super(command);
this.cmd = new OriginBlacklistCommand(blacklist);
this.blacklist = blacklist;
}
@Override
public void execute(final CommandSender sender, final String[] args) {
this.cmd.execute(new BNGCommandContext(sender, args));
public final void execute(final CommandSender sender, final String[] args) {
this.cmd.execute(new BNGCommandContext(this.blacklist, sender, args));
}
@Override
public List<String> onTabComplete(final CommandSender sender, final String[] args) {
return this.cmd.suggest(new BNGCommandContext(sender, args));
public final List<String> onTabComplete(final CommandSender sender, final String[] args) {
return this.cmd.suggest(new BNGCommandContext(this.blacklist, sender, args));
}
}

View File

@@ -10,6 +10,7 @@ import xyz.webmc.originblacklist.base.util.IncompatibleDependencyException;
import xyz.webmc.originblacklist.base.util.OPlayer;
import xyz.webmc.originblacklist.velocity.command.OriginBlacklistCommandVelocity;
import java.net.InetSocketAddress;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
@@ -24,7 +25,9 @@ import com.velocitypowered.api.event.connection.PreLoginEvent;
import com.velocitypowered.api.event.player.PlayerClientBrandEvent;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
import com.velocitypowered.api.plugin.PluginContainer;
import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ProxyServer;
import com.velocitypowered.api.proxy.server.ServerPing;
@@ -64,7 +67,7 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin {
}
@Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) {
public final void onProxyInitialization(ProxyInitializeEvent event) {
this.proxy.getPluginManager().getPlugin("eaglerxserver").ifPresentOrElse(plugin -> {
final Semver version = new Semver(plugin.getDescription().getVersion().orElse("1.0.0"));
if (version.isLowerThan(OriginBlacklist.REQUIRED_API_VER)) {
@@ -105,6 +108,11 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin {
}
}
@Subscribe
public final void onProxyShutdown(final ProxyShutdownEvent e) {
this.blacklist.shutdown();
}
@Subscribe(order = PostOrder.FIRST)
public final void onEaglerLogin(final EaglercraftLoginEvent event) {
final OPlayer player = new OPlayer(event.getLoginConnection(), event.getProfileUsername(), event.getProfileUUID());
@@ -119,22 +127,29 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin {
@Subscribe(order = PostOrder.FIRST)
public final void onJavaLogin(final PreLoginEvent event) {
final InboundConnection conn = event.getConnection();
final InetSocketAddress vhost = conn.getVirtualHost().orElseThrow();
final OPlayer player = new OPlayer(null, event.getUsername(), event.getUniqueId(),
event.getConnection().getRemoteAddress().toString(), OriginBlacklist.UNKNOWN_STR, event.getConnection().getProtocolVersion().getProtocol());
conn.getRemoteAddress().toString(), OriginBlacklist.UNKNOWN_STR, vhost.getHostString() + vhost.getPort(),
conn.getProtocolVersion().getProtocol());
this.blacklist.handleLogin(new OriginBlacklistLoginEvent(null, event, EnumConnectionType.JAVA, player));
}
@Subscribe(order = PostOrder.FIRST)
public final void onJavaHandshake(final PlayerClientBrandEvent event) {
final Player aPlayer = (Player) event.getPlayer();
final InetSocketAddress vhost = event.getPlayer().getVirtualHost().orElseThrow();
final Player aPlayer = event.getPlayer();
final OPlayer bPlayer = new OPlayer(null, aPlayer.getUsername(), aPlayer.getUniqueId(),
aPlayer.getRemoteAddress().getAddress().toString(), event.getBrand(), event.getPlayer().getProtocolVersion().getProtocol());
aPlayer.getRemoteAddress().getAddress().toString(), event.getBrand(), vhost.getHostString() + vhost.getPort(),
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(),
final InboundConnection conn = event.getConnection();
final InetSocketAddress vhost = conn.getVirtualHost().orElseThrow();
final OPlayer player = new OPlayer(null, null, null, conn.getRemoteAddress().getHostString(), vhost.getHostString() + vhost.getPort(),
null, -1);
this.blacklist.handleMOTD(new OriginBlacklistMOTDEvent(null, event, EnumConnectionType.JAVA, player));
}
@@ -225,6 +240,13 @@ public final class OriginBlacklistVelocity implements IOriginBlacklistPlugin {
.schedule();
}
@Override
public final void runAsync(final Runnable task) {
this.proxy.getScheduler()
.buildTask(this, task)
.schedule();
}
@Override
public final void shutdown() {
this.metrics.shutdown();

View File

@@ -7,18 +7,21 @@ import java.util.List;
import com.velocitypowered.api.command.SimpleCommand;
public class OriginBlacklistCommandVelocity extends OriginBlacklistCommand implements SimpleCommand {
public final class OriginBlacklistCommandVelocity extends OriginBlacklistCommand implements SimpleCommand {
private final OriginBlacklist plugin;
public OriginBlacklistCommandVelocity(OriginBlacklist plugin) {
super(plugin);
this.plugin = plugin;
}
@Override
public void execute(final Invocation invocation) {
super.execute(new VCommandContext(invocation));
public final void execute(final Invocation invocation) {
super.execute(new VCommandContext(this.plugin, invocation));
}
@Override
public List<String> suggest(final Invocation invocation) {
return super.suggest(new VCommandContext(invocation));
public final List<String> suggest(final Invocation invocation) {
return super.suggest(new VCommandContext(this.plugin, invocation));
}
}

View File

@@ -1,34 +1,42 @@
package xyz.webmc.originblacklist.velocity.command;
import xyz.webmc.originblacklist.base.OriginBlacklist;
import xyz.webmc.originblacklist.base.command.CommandContext;
import com.velocitypowered.api.command.SimpleCommand.Invocation;
import net.kyori.adventure.text.minimessage.MiniMessage;
public class VCommandContext implements CommandContext {
public final class VCommandContext implements CommandContext {
private final OriginBlacklist plugin;
private final Invocation invocation;
public VCommandContext(final Invocation invocation) {
public VCommandContext(final OriginBlacklist plugin, final Invocation invocation) {
this.plugin = plugin;
this.invocation = invocation;
}
@Override
public String getPlayerName() {
public final OriginBlacklist getPlugin() {
return this.plugin;
}
@Override
public final String getPlayerName() {
return this.invocation.source().toString();
}
@Override
public void reply(final String message) {
public final void reply(final String message) {
this.invocation.source().sendMessage(MiniMessage.miniMessage().deserialize(message));
}
@Override
public boolean hasPermission(final String permission) {
public final boolean hasPermission(final String permission) {
return this.invocation.source().hasPermission(permission);
}
@Override
public String[] getArgs() {
public final String[] getArgs() {
return this.invocation.arguments();
}
}