commit 0d901c0daa665a411ccd2ec0e002a00ca16e04fb Author: lax1dude Date: Thu May 2 17:38:46 2024 -0700 bungee impl mostly completed diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/OriginBlacklist.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/OriginBlacklist.java new file mode 100644 index 0000000..aa1bfe8 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/OriginBlacklist.java @@ -0,0 +1,381 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * Copyright (c) 2022-2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class OriginBlacklist { + + private final OriginBlacklistLoggerAdapter logger; + private String kickMessage = null; + private boolean blockClientsWithNoOriginHeader = false; + public final Collection regexBlacklist = new ArrayList(); + public final Collection regexLocalBlacklist = new ArrayList(); + public final Collection regexBlacklistReplit = new ArrayList(); + public final Collection simpleWhitelist = new ArrayList(); + private File localBlacklist = null; + private String subscriptionDownloadUserAgent = null; + private Collection blacklistSubscriptions = null; + private boolean blockOfflineDownload = false; + private boolean blockAllReplits = false; + private boolean localWhitelistMode = false; + private boolean simpleWhitelistMode = false; + private final HashSet brokenURLs = new HashSet(); + private final HashSet brokenRegex = new HashSet(); + + public static final HashSet regexBlacklistReplitInternalStrings = new HashSet(); + public static final Collection regexBlacklistReplitInternal = new ArrayList(); + + static { + regexBlacklistReplitInternalStrings.add(".*repl(it)?\\..{1,5}$"); + for(String s : regexBlacklistReplitInternalStrings) { + regexBlacklistReplitInternal.add(Pattern.compile(s)); + } + } + + private int updateRate = 15 * 60 * 1000; + private long lastLocalUpdate = 0l; + private long lastUpdate = 0; + + public OriginBlacklist(OriginBlacklistLoggerAdapter log) { + logger = log; + } + + public String getKickMessage() { + return kickMessage; + } + + public boolean getBlockClientsWithNoOriginHeader() { + return blockClientsWithNoOriginHeader; + } + + public boolean test(String origin) { + synchronized(regexBlacklist) { + if(blockOfflineDownload && origin.equalsIgnoreCase("null")) { + return true; + } + if(simpleWhitelistMode) { + for(String st : simpleWhitelist) { + if(origin.equalsIgnoreCase(st)) { + return false; + } + } + } + if(localWhitelistMode || simpleWhitelistMode) { + if(!blockOfflineDownload && origin.equalsIgnoreCase("null")) { + return false; + } + for(Pattern m : regexLocalBlacklist) { + if(m.matcher(origin).matches()) { + return false; + } + } + return true; + }else { + if(blockAllReplits) { + for(Pattern m : regexBlacklistReplitInternal) { + if(m.matcher(origin).matches()) { + return true; + } + } + for(Pattern m : regexBlacklistReplit) { + if(m.matcher(origin).matches()) { + return true; + } + } + } + for(Pattern m : regexBlacklist) { + if(m.matcher(origin).matches()) { + return true; + } + } + for(Pattern m : regexLocalBlacklist) { + if(m.matcher(origin).matches()) { + return true; + } + } + return false; + } + } + } + + public void init(OriginBlacklistConfigAdapter cfg) { + synchronized(regexBlacklist) { + brokenURLs.clear(); + brokenRegex.clear(); + regexBlacklist.clear(); + regexLocalBlacklist.clear(); + regexBlacklistReplit.clear(); + simpleWhitelist.clear(); + localBlacklist = cfg.getLocalBlacklistFile(); + kickMessage = cfg.getKickMessage(); + blockClientsWithNoOriginHeader = cfg.getBlockClientsWithNoOriginHeader(); + subscriptionDownloadUserAgent = cfg.getSubscriptionDownloadUserAgent(); + blacklistSubscriptions = cfg.getBlacklistURLs(); + blockOfflineDownload = cfg.shouldBlacklistOfflineDownload(); + blockAllReplits = cfg.shouldBlacklistReplits(); + simpleWhitelistMode = cfg.isSimpleWhitelistEnabled(); + simpleWhitelist.addAll(cfg.getBlacklistSimpleWhitelist()); + lastLocalUpdate = 0l; + lastUpdate = System.currentTimeMillis() - updateRate - 1000l; + update(); + } + } + + public void update() { + long ct = System.currentTimeMillis(); + if((int)(ct - lastUpdate) > updateRate) { + lastUpdate = ct; + synchronized(regexBlacklist) { + if(blacklistSubscriptions != null) { + ArrayList newBlacklist = new ArrayList(); + ArrayList newReplitBlacklist = new ArrayList(); + HashSet newBlacklistSet = new HashSet(); + newBlacklistSet.addAll(regexBlacklistReplitInternalStrings); + for(String str : blacklistSubscriptions) { + try { + URL u; + try { + u = new URL(str); + }catch(MalformedURLException e) { + if(brokenURLs.add(str)) { + logger.error("The blacklist subscription URL '" + str + "' is invalid"); + } + continue; + } + URLConnection cc = u.openConnection(); + if(cc instanceof HttpURLConnection) { + HttpURLConnection ccc = (HttpURLConnection)cc; + ccc.setRequestProperty("Accept", "text/plain,text/html,application/xhtml+xml,application/xml"); + ccc.setRequestProperty("User-Agent", subscriptionDownloadUserAgent); + } + cc.connect(); + try(BufferedReader is = new BufferedReader(new InputStreamReader(cc.getInputStream()))) { + String firstLine = is.readLine(); + if(firstLine == null) { + is.close(); + throw new IOException("Could not read line"); + } + firstLine = firstLine.trim(); + if(!firstLine.startsWith("#") || !firstLine.substring(1).trim().toLowerCase().startsWith("eaglercraft domain blacklist")) { + throw new IOException("File does not contain a list of domains"); + } + String ss; + while((ss = is.readLine()) != null) { + if((ss = ss.trim()).length() > 0) { + if(ss.startsWith("#")) { + ss = ss.substring(1).trim(); + if(ss.startsWith("replit-wildcard:")) { + ss = ss.substring(16).trim(); + if(newBlacklistSet.add(ss)) { + try { + newReplitBlacklist.add(Pattern.compile(ss)); + }catch(PatternSyntaxException shit) { + if(brokenRegex.add(ss)) { + logger.error("the blacklist replit wildcard regex '" + ss + "' is invalid"); + continue; + } + } + brokenRegex.remove(ss); + } + } + continue; + } + if(newBlacklistSet.add(ss)) { + try { + newBlacklist.add(Pattern.compile(ss)); + }catch(PatternSyntaxException shit) { + if(brokenRegex.add(ss)) { + logger.error("the blacklist regex '" + ss + "' is invalid"); + continue; + } + } + brokenRegex.remove(ss); + } + } + } + } + brokenURLs.remove(str); + }catch(Throwable t) { + if(brokenURLs.add(str)) { + logger.error("the blacklist subscription URL '" + str + "' is invalid"); + } + t.printStackTrace(); + } + } + if(!newBlacklist.isEmpty()) { + regexBlacklist.clear(); + regexBlacklist.addAll(newBlacklist); + } + if(!newReplitBlacklist.isEmpty()) { + regexBlacklistReplit.clear(); + regexBlacklistReplit.addAll(newReplitBlacklist); + } + }else { + brokenURLs.clear(); + brokenRegex.clear(); + regexBlacklist.clear(); + lastLocalUpdate = 0l; + } + } + } + if(localBlacklist.exists()) { + long lastLocalEdit = localBlacklist.lastModified(); + if(lastLocalEdit != lastLocalUpdate) { + lastLocalUpdate = lastLocalEdit; + synchronized(regexBlacklist) { + try(BufferedReader is = new BufferedReader(new FileReader(localBlacklist))) { + regexLocalBlacklist.clear(); + localWhitelistMode = false; + boolean foundWhitelistStatement = false; + String ss; + while((ss = is.readLine()) != null) { + try { + if((ss = ss.trim()).length() > 0) { + if(!ss.startsWith("#")) { + regexLocalBlacklist.add(Pattern.compile(ss)); + }else { + String st = ss.substring(1).trim(); + if(st.startsWith("whitelistMode:")) { + foundWhitelistStatement = true; + String str = st.substring(14).trim().toLowerCase(); + localWhitelistMode = str.equals("true") || str.equals("on") || str.equals("1"); + } + } + } + }catch(PatternSyntaxException shit) { + logger.error("the local " + (localWhitelistMode ? "whitelist" : "blacklist") + " regex '" + ss + "' is invalid"); + } + } + is.close(); + if(!foundWhitelistStatement) { + List newLines = new ArrayList(); + newLines.add("#whitelistMode: false"); + newLines.add(""); + try(BufferedReader is2 = new BufferedReader(new FileReader(localBlacklist))) { + while((ss = is2.readLine()) != null) { + newLines.add(ss); + } + } + try(PrintWriter os = new PrintWriter(new FileWriter(localBlacklist))) { + for(String str : newLines) { + os.println(str); + } + } + lastLocalUpdate = localBlacklist.lastModified(); + } + logger.info("Reloaded '" + localBlacklist.getName() + "'."); + }catch(IOException ex) { + regexLocalBlacklist.clear(); + logger.error("failed to read local " + (localWhitelistMode ? "whitelist" : "blacklist") + " file '" + localBlacklist.getName() + "'"); + ex.printStackTrace(); + } + } + } + }else { + synchronized(regexBlacklist) { + if(!regexLocalBlacklist.isEmpty()) { + logger.warn("the blacklist file '" + localBlacklist.getName() + "' has been deleted"); + } + regexLocalBlacklist.clear(); + } + } + } + + public void addLocal(String o) { + String p = "^" + Pattern.quote(o.trim()) + "$"; + ArrayList lines = new ArrayList(); + if(localBlacklist.exists()) { + try(BufferedReader is = new BufferedReader(new FileReader(localBlacklist))) { + String ss; + while((ss = is.readLine()) != null) { + if((ss = ss.trim()).length() > 0) { + lines.add(ss); + } + } + }catch(IOException ex) { + // ? + } + } + if(lines.isEmpty()) { + lines.add("#whitelist false"); + lines.add(""); + } + if(!lines.contains(p)) { + lines.add(p); + try(PrintWriter os = new PrintWriter(new FileWriter(localBlacklist))) { + for(String s : lines) { + os.println(s); + } + lastLocalUpdate = 0l; + update(); + }catch(IOException ex) { + // ? + } + } + } + + public boolean removeLocal(String o) { + String p = "^" + Pattern.quote(o.trim()) + "$"; + ArrayList lines = new ArrayList(); + if(localBlacklist.exists()) { + try(BufferedReader is = new BufferedReader(new FileReader(localBlacklist))) { + String ss; + while((ss = is.readLine()) != null) { + if((ss = ss.trim()).length() > 0) { + lines.add(ss); + } + } + }catch(IOException ex) { + // ? + } + } + if(lines.contains(p)) { + lines.remove(p); + try { + try(PrintWriter os = new PrintWriter(new FileWriter(localBlacklist))) { + for(String s : lines) { + os.println(s); + } + } + lastLocalUpdate = 0l; + update(); + return true; + }catch(IOException ex) { + logger.error("Failed to save '" + localBlacklist.getName() + "'"); + ex.printStackTrace(); + } + } + return false; + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/OriginBlacklistConfigAdapter.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/OriginBlacklistConfigAdapter.java new file mode 100644 index 0000000..13b22bd --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/OriginBlacklistConfigAdapter.java @@ -0,0 +1,41 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist; + +import java.io.File; +import java.util.Collection; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public interface OriginBlacklistConfigAdapter { + + File getLocalBlacklistFile(); + + String getKickMessage(); + + boolean getBlockClientsWithNoOriginHeader(); + + String getSubscriptionDownloadUserAgent(); + + Collection getBlacklistURLs(); + + boolean shouldBlacklistOfflineDownload(); + + boolean shouldBlacklistReplits(); + + boolean isSimpleWhitelistEnabled(); + + Collection getBlacklistSimpleWhitelist(); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/OriginBlacklistLoggerAdapter.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/OriginBlacklistLoggerAdapter.java new file mode 100644 index 0000000..3e637b3 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/OriginBlacklistLoggerAdapter.java @@ -0,0 +1,26 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public interface OriginBlacklistLoggerAdapter { + + void info(String msg); + + void warn(String msg); + + void error(String msg); + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/OriginBlacklistConfigBungee.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/OriginBlacklistConfigBungee.java new file mode 100644 index 0000000..330b770 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/OriginBlacklistConfigBungee.java @@ -0,0 +1,111 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.bungee; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; + +import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.EaglerXBungee; +import net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.OriginBlacklistConfigAdapter; +import net.md_5.bungee.config.Configuration; +import net.md_5.bungee.config.ConfigurationProvider; +import net.md_5.bungee.config.YamlConfiguration; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class OriginBlacklistConfigBungee implements OriginBlacklistConfigAdapter { + + public static OriginBlacklistConfigBungee loadConfig(File dataDir) throws IOException { + if(!dataDir.isDirectory() && !dataDir.mkdirs()) { + throw new IOException("Could not create directory: " + dataDir.getAbsolutePath()); + } + File configFile = new File(dataDir, "config.yml"); + if(!configFile.exists()) { + try(InputStream defaultConf = OriginBlacklistConfigBungee.class.getResourceAsStream("../default_config.yml")) { + try(OutputStream os = new FileOutputStream(configFile)) { + byte[] copyBuffer = new byte[1024]; + int i; + while((i = defaultConf.read(copyBuffer)) != -1) { + os.write(copyBuffer, 0, i); + } + } + } + } + Configuration conf = ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); + return new OriginBlacklistConfigBungee(dataDir, conf); + } + + private final File dataDir; + private final Configuration conf; + + private OriginBlacklistConfigBungee(File dataDir, Configuration conf) { + this.dataDir = dataDir; + this.conf = conf; + } + + @Override + public File getLocalBlacklistFile() { + return new File(dataDir, "origin_blacklist.txt"); + } + + @Override + public String getKickMessage() { + return conf.getString("origin_blacklist_kick_message", "End of stream"); + } + + @Override + public boolean getBlockClientsWithNoOriginHeader() { + return conf.getBoolean("origin_blacklist_block_missing_origin_header", false); + } + + @Override + public String getSubscriptionDownloadUserAgent() { + return "Mozilla/5.0 EaglerXBungee/" + EaglerXBungee.getEagler().getDescription().getVersion(); + } + + @Override + public Collection getBlacklistURLs() { + boolean enableSubscribe = conf.getBoolean("enable_web_origin_blacklist", false); + if(!enableSubscribe) { + return null; + } + return (Collection)conf.getList("origin_blacklist_subscriptions", new ArrayList()); + } + + @Override + public boolean shouldBlacklistOfflineDownload() { + return conf.getBoolean("origin_blacklist_block_offline_download", false); + } + + @Override + public boolean shouldBlacklistReplits() { + return conf.getBoolean("origin_blacklist_block_replit_clients", false); + } + + @Override + public boolean isSimpleWhitelistEnabled() { + return conf.getBoolean("origin_blacklist_use_simple_whitelist", false); + } + + @Override + public Collection getBlacklistSimpleWhitelist() { + return (Collection)conf.getList("origin_blacklist_simple_whitelist", new ArrayList()); + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/OriginBlacklistListenerBungee.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/OriginBlacklistListenerBungee.java new file mode 100644 index 0000000..a598b98 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/OriginBlacklistListenerBungee.java @@ -0,0 +1,59 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.bungee; + +import java.util.logging.Level; + +import net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.server.EaglerInitialHandler; +import net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.OriginBlacklist; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.event.LoginEvent; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.event.EventHandler; +import net.md_5.bungee.event.EventPriority; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class OriginBlacklistListenerBungee implements Listener { + + private final OriginBlacklistPluginBungee plugin; + + public OriginBlacklistListenerBungee(OriginBlacklistPluginBungee plugin) { + this.plugin = plugin; + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void handleLoginEvent(LoginEvent evt) { + if(evt.getConnection() instanceof EaglerInitialHandler) { + EaglerInitialHandler eaglerCon = (EaglerInitialHandler)evt.getConnection(); + String origin = eaglerCon.getOrigin(); + OriginBlacklist blacklist = plugin.list; + boolean shouldKick = true; + try { + shouldKick = (origin == null && blacklist.getBlockClientsWithNoOriginHeader()) || blacklist.test(origin); + }catch(Throwable t) { + plugin.getLogger().log(Level.SEVERE, "Failed to check origin blacklist for: " + origin, t); + } + if(shouldKick) { + plugin.getLogger().info("Disconnecting a player who joined from blacklisted origin: " + origin); + evt.setCancelled(true); + String msg = blacklist.getKickMessage(); + if(msg != null) { + evt.setReason(new TextComponent()); + } + } + } + } + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/OriginBlacklistPluginBungee.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/OriginBlacklistPluginBungee.java new file mode 100644 index 0000000..75d9a1d --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/OriginBlacklistPluginBungee.java @@ -0,0 +1,106 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.bungee; + +import java.io.IOException; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.OriginBlacklist; +import net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.OriginBlacklistConfigAdapter; +import net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.OriginBlacklistLoggerAdapter; +import net.md_5.bungee.api.plugin.Plugin; + +/** + * Copyright (c) 2024 lax1dude. All Rights Reserved. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +public class OriginBlacklistPluginBungee extends Plugin { + + private static OriginBlacklistPluginBungee instance = null; + + public final OriginBlacklist list; + + private Timer updateOriginBlacklistTimer = null; + + public OriginBlacklistPluginBungee() { + instance = this; + list = new OriginBlacklist(new OriginBlacklistLoggerAdapter() { + @Override + public void warn(String msg) { + OriginBlacklistPluginBungee.this.getLogger().warning(msg); + } + + @Override + public void info(String msg) { + OriginBlacklistPluginBungee.this.getLogger().info(msg); + } + + @Override + public void error(String msg) { + OriginBlacklistPluginBungee.this.getLogger().severe(msg); + } + }); + } + + @Override + public void onLoad() { + reloadConfig(); + } + + private void reloadConfig() { + OriginBlacklistConfigAdapter cfg; + try { + cfg = OriginBlacklistConfigBungee.loadConfig(getDataFolder()); + }catch(IOException ex) { + throw new RuntimeException("Could not load origin blacklist config file!", ex); + } + list.init(cfg); + } + + @Override + public void onEnable() { + if(updateOriginBlacklistTimer == null) { + updateOriginBlacklistTimer = new Timer("EaglerXBungee: Origin Blacklist Updater"); + updateOriginBlacklistTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + try { + list.update(); + }catch(Throwable t) { + OriginBlacklistPluginBungee.this.getLogger().log(Level.SEVERE, "Could not update origin blacklist!", t); + } + } + }, 0, 6000l); + } + getProxy().getPluginManager().registerListener(this, new OriginBlacklistListenerBungee(this)); + } + + @Override + public void onDisable() { + if(updateOriginBlacklistTimer != null) { + updateOriginBlacklistTimer.cancel(); + updateOriginBlacklistTimer = null; + } + getProxy().getPluginManager().unregisterListeners(this); + } + + public static OriginBlacklistPluginBungee getPlugin() { + return instance; + } + + public static Logger logger() { + return instance.getLogger(); + } +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/command/CommandDomainBlock.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/command/CommandDomainBlock.java new file mode 100644 index 0000000..38653e5 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/command/CommandDomainBlock.java @@ -0,0 +1,5 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.bungee.command; + +public class CommandDomainBlock { + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/command/CommandDomainBlockDomain.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/command/CommandDomainBlockDomain.java new file mode 100644 index 0000000..2edd067 --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/command/CommandDomainBlockDomain.java @@ -0,0 +1,5 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.bungee.command; + +public class CommandDomainBlockDomain { + +} diff --git a/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/command/CommandDomainUnblock.java b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/command/CommandDomainUnblock.java new file mode 100644 index 0000000..db7355f --- /dev/null +++ b/src/main/java/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/bungee/command/CommandDomainUnblock.java @@ -0,0 +1,5 @@ +package net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.bungee.command; + +public class CommandDomainUnblock { + +} diff --git a/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/default_config.yml b/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/default_config.yml new file mode 100644 index 0000000..a899297 --- /dev/null +++ b/src/main/resources/net/lax1dude/eaglercraft/v1_8/plugin/origin_blacklist/default_config.yml @@ -0,0 +1,11 @@ +origin_blacklist_kick_message: 'End of stream' +origin_blacklist_block_missing_origin_header: false +origin_blacklist_block_offline_download: false +origin_blacklist_block_replit_clients: false +enable_web_origin_blacklist: false +origin_blacklist_subscriptions: +- 'add url here' +origin_blacklist_use_simple_whitelist: false +origin_blacklist_simple_whitelist: +- 'type the name of your client\'s domain here' +- '(if \'origin_blacklist_use_simple_whitelist\' is true)' \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..d70c367 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,5 @@ +name: OriginBlacklist +main: net.lax1dude.eaglercraft.v1_8.plugin.origin_blacklist.bungee.OriginBlacklistPluginBungee +version: 1.0.0 +description: Plugin for EaglercraftXBungee servers to add the "origin blacklist" feature from 1.5.2 +author: lax1dude \ No newline at end of file