Merge pull request #9 from ayunami2000/updated
Updated to latest eaglercraft stuff
This commit is contained in:
commit
9c61e50041
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -11,4 +11,6 @@ stable-download/java/spigot_command/world/*
|
|||
stable-download/java/spigot_command/world_nether/*
|
||||
stable-download/java/spigot_command/world_the_end/*
|
||||
stable-download/java/spigot_command/server.log
|
||||
stable-download/java/bungee_command/proxy*
|
||||
stable-download/java/bungee_command/proxy*
|
||||
stable-download/web_
|
||||
lwjgl-rundir/_eagstorage*
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
An [Eaglercraft](https://github.com/LAX1DUDE/eaglercraft) fork
|
||||
|
||||
if you want to use this code, be sure to link back to this repo!! (or else i WILL get on your ass)
|
||||
if you want to use this code, be sure to link back to this repo!! (or else i WILL get on your ass)
|
||||
|
|
|
@ -41,7 +41,7 @@ teavm {
|
|||
maxTopLevelNames = 10000;
|
||||
properties = null;
|
||||
debugInformationGenerated = false;
|
||||
sourceMapsGenerated = false;
|
||||
sourceMapsGenerated = true;
|
||||
sourceFilesCopied = false;
|
||||
incremental = false;
|
||||
transformers = null;
|
||||
|
@ -50,7 +50,7 @@ teavm {
|
|||
targetDirectory = file("javascript");
|
||||
|
||||
/** The directory to monitor to decide if compile is up-to-date or not */
|
||||
//sourceDirectory = [file("src/main/java"),file("../minecrafthtml5mcp/src")];
|
||||
sourceDirectory = file("src");
|
||||
|
||||
/** How to name the result file. */
|
||||
targetFileName = "classes.js";
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# Updated 9/27/20 12:38 AM by Minecraft 1.5.2
|
||||
# victim name | ban date | banned by | banned until | reason
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
# Updated 9/27/20 12:38 AM by Minecraft 1.5.2
|
||||
# victim name | ban date | banned by | banned until | reason
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
# This is the main configuration file for Bukkit.
|
||||
# As you can see, there's actually not that much to configure without any plugins.
|
||||
# For a reference for any variable inside this file, check out the bukkit wiki at
|
||||
# http://wiki.bukkit.org/Bukkit.yml
|
||||
settings:
|
||||
allow-end: true
|
||||
warn-on-overload: true
|
||||
permissions-file: permissions.yml
|
||||
update-folder: update
|
||||
ping-packet-limit: 100
|
||||
use-exact-login-location: false
|
||||
plugin-profiling: false
|
||||
connection-throttle: 4000
|
||||
query-plugins: true
|
||||
deprecated-verbose: default
|
||||
shutdown-message: Server closed
|
||||
spawn-limits:
|
||||
monsters: 70
|
||||
animals: 15
|
||||
water-animals: 5
|
||||
ambient: 15
|
||||
chunk-gc:
|
||||
period-in-ticks: 600
|
||||
load-threshold: 0
|
||||
ticks-per:
|
||||
animal-spawns: 400
|
||||
monster-spawns: 1
|
||||
autosave: 0
|
||||
auto-updater:
|
||||
enabled: true
|
||||
on-broken:
|
||||
- warn-console
|
||||
- warn-ops
|
||||
on-update:
|
||||
- warn-console
|
||||
- warn-ops
|
||||
preferred-channel: rb
|
||||
host: dl.bukkit.org
|
||||
suggest-channels: true
|
||||
database:
|
||||
username: bukkit
|
||||
isolation: SERIALIZABLE
|
||||
driver: org.sqlite.JDBC
|
||||
password: walrus
|
||||
url: jdbc:sqlite:{DIR}{NAME}.db
|
Binary file not shown.
|
@ -1,56 +0,0 @@
|
|||
# This is the help configuration file for Bukkit.
|
||||
#
|
||||
# By default you do not need to modify this file. Help topics for all plugin commands are automatically provided by
|
||||
# or extracted from your installed plugins. You only need to modify this file if you wish to add new help pages to
|
||||
# your server or override the help pages of existing plugin commands.
|
||||
#
|
||||
# This file is divided up into the following parts:
|
||||
# -- general-topics: lists admin defined help topics
|
||||
# -- index-topics: lists admin defined index topics
|
||||
# -- amend-topics: lists topic amendments to apply to existing help topics
|
||||
# -- ignore-plugins: lists any plugins that should be excluded from help
|
||||
#
|
||||
# Examples are given below. When amending command topic, the string <text> will be replaced with the existing value
|
||||
# in the help topic. Color codes can be used in topic text. The color code character is & followed by 0-F.
|
||||
# ================================================================
|
||||
#
|
||||
# Set this to true to list the individual command help topics in the master help.
|
||||
# command-topics-in-master-index: true
|
||||
#
|
||||
# Each general topic will show up as a separate topic in the help index along with all the plugin command topics.
|
||||
# general-topics:
|
||||
# Rules:
|
||||
# shortText: Rules of the server
|
||||
# fullText: |
|
||||
# &61. Be kind to your fellow players.
|
||||
# &B2. No griefing.
|
||||
# &D3. No swearing.
|
||||
# permission: topics.rules
|
||||
#
|
||||
# Each index topic will show up as a separate sub-index in the help index along with all the plugin command topics.
|
||||
# To override the default help index (displayed when the user executes /help), name the index topic "Default".
|
||||
# index-topics:
|
||||
# Ban Commands:
|
||||
# shortText: Player banning commands
|
||||
# preamble: Moderator - do not abuse these commands
|
||||
# permission: op
|
||||
# commands:
|
||||
# - /ban
|
||||
# - /ban-ip
|
||||
# - /banlist
|
||||
#
|
||||
# Topic amendments are used to change the content of automatically generated plugin command topics.
|
||||
# amended-topics:
|
||||
# /stop:
|
||||
# shortText: Stops the server cold....in its tracks!
|
||||
# fullText: <text> - This kills the server.
|
||||
# permission: you.dont.have
|
||||
#
|
||||
# Any plugin in the ignored plugins list will be excluded from help. The name must match the name displayed by
|
||||
# the /plugins command. Ignore "Bukkit" to remove the standard bukkit commands from the index. Ignore "All"
|
||||
# to completely disable automatic help topic generation.
|
||||
# ignore-plugins:
|
||||
# - PluginNameOne
|
||||
# - PluginNameTwo
|
||||
# - PluginNameThree
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
lax2dude
|
||||
lax1dude
|
|
@ -1,4 +0,0 @@
|
|||
# http://mcstats.org
|
||||
opt-out: false
|
||||
guid: c015ae6f-e6ca-48d6-b4af-6e1cb5825cb9
|
||||
debug: false
|
|
@ -1,3 +0,0 @@
|
|||
@echo off
|
||||
java -Xmx512M -Xms512M -jar craftbukkit-1.5.2-R1.0.jar
|
||||
pause
|
|
@ -1,30 +0,0 @@
|
|||
#Minecraft server properties
|
||||
#Sun Sep 27 00:38:00 PDT 2020
|
||||
generator-settings=
|
||||
allow-nether=true
|
||||
level-name=world
|
||||
enable-query=false
|
||||
allow-flight=false
|
||||
server-port=25501
|
||||
level-type=DEFAULT
|
||||
enable-rcon=false
|
||||
force-gamemode=true
|
||||
level-seed=
|
||||
server-ip=
|
||||
max-build-height=256
|
||||
spawn-npcs=true
|
||||
white-list=false
|
||||
spawn-animals=true
|
||||
hardcore=false
|
||||
snooper-enabled=true
|
||||
texture-pack=
|
||||
online-mode=false
|
||||
pvp=true
|
||||
difficulty=1
|
||||
gamemode=1
|
||||
max-players=20
|
||||
spawn-monsters=true
|
||||
generate-structures=true
|
||||
view-distance=10
|
||||
spawn-protection=16
|
||||
motd=A Minecraft Server
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
%ני<D7A0>g<EFBFBD>D´<44>Mם³<D79D>צ<>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
{_¸+PEc¹ <20>Í°|aã
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
ûÚå<EFBFBD>å<EFBFBD>D¶£OΊ§¿ïh
|
Binary file not shown.
|
@ -19,7 +19,6 @@ import net.md_5.bungee.api.connection.ProxiedPlayer;
|
|||
import java.util.MissingResourceException;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import io.netty.channel.ChannelException;
|
||||
import java.util.Iterator;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
import java.net.SocketAddress;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
|
@ -28,7 +27,6 @@ import io.netty.util.AttributeKey;
|
|||
import net.md_5.bungee.netty.PipelineUtils;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
|
@ -38,7 +36,7 @@ import net.md_5.bungee.api.ChatColor;
|
|||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.command.ConsoleCommandSender;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.Calendar;
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
import jline.UnsupportedTerminal;
|
||||
import java.io.OutputStream;
|
||||
|
@ -50,9 +48,18 @@ import jline.internal.Log;
|
|||
import java.io.PrintStream;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import net.md_5.bungee.command.CommandFind;
|
||||
import net.md_5.bungee.command.CommandGlobalBan;
|
||||
import net.md_5.bungee.command.CommandGlobalBanIP;
|
||||
import net.md_5.bungee.command.CommandGlobalBanRegex;
|
||||
import net.md_5.bungee.command.CommandGlobalBanReload;
|
||||
import net.md_5.bungee.command.CommandGlobalBanWildcard;
|
||||
import net.md_5.bungee.command.CommandGlobalCheckBan;
|
||||
import net.md_5.bungee.command.CommandGlobalListBan;
|
||||
import net.md_5.bungee.command.CommandGlobalUnban;
|
||||
import net.md_5.bungee.command.CommandSend;
|
||||
import net.md_5.bungee.command.CommandPerms;
|
||||
import net.md_5.bungee.command.CommandBungee;
|
||||
import net.md_5.bungee.command.CommandClearRatelimit;
|
||||
import net.md_5.bungee.command.CommandAlert;
|
||||
import net.md_5.bungee.command.CommandIP;
|
||||
import net.md_5.bungee.command.CommandServer;
|
||||
|
@ -61,10 +68,9 @@ import net.md_5.bungee.command.CommandEnd;
|
|||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.command.CommandReload;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import net.md_5.bungee.scheduler.BungeeScheduler;
|
||||
import net.md_5.bungee.config.YamlConfig;
|
||||
import net.md_5.bungee.eaglercraft.PluginEaglerAuth;
|
||||
import net.md_5.bungee.eaglercraft.BanList;
|
||||
import net.md_5.bungee.eaglercraft.PluginEaglerSkins;
|
||||
import net.md_5.bungee.eaglercraft.WebSocketListener;
|
||||
|
||||
|
@ -99,6 +105,8 @@ public class BungeeCord extends ProxyServer {
|
|||
public final ScheduledThreadPoolExecutor executors;
|
||||
public final MultithreadEventLoopGroup eventLoops;
|
||||
private final Timer saveThread;
|
||||
private final Timer reloadBanThread;
|
||||
private final Timer closeInactiveSockets;
|
||||
private Collection<Channel> listeners;
|
||||
private Collection<WebSocketListener> wsListeners;
|
||||
private final Map<String, UserConnection> connections;
|
||||
|
@ -111,6 +119,7 @@ public class BungeeCord extends ProxyServer {
|
|||
private final TaskScheduler scheduler;
|
||||
private ConsoleReader consoleReader;
|
||||
private final Logger logger;
|
||||
private Collection<Command> banCommands;
|
||||
|
||||
public static BungeeCord getInstance() {
|
||||
return (BungeeCord) ProxyServer.getInstance();
|
||||
|
@ -122,6 +131,8 @@ public class BungeeCord extends ProxyServer {
|
|||
this.executors = new BungeeThreadPool(new ThreadFactoryBuilder().setNameFormat("Bungee Pool Thread #%1$d").build());
|
||||
this.eventLoops = (MultithreadEventLoopGroup) new NioEventLoopGroup(Runtime.getRuntime().availableProcessors(), new ThreadFactoryBuilder().setNameFormat("Netty IO Thread #%1$d").build());
|
||||
this.saveThread = new Timer("Reconnect Saver");
|
||||
this.reloadBanThread = new Timer("Ban List Reload");
|
||||
this.closeInactiveSockets = new Timer("close Inactive WebSockets");
|
||||
this.listeners = new HashSet<Channel>();
|
||||
this.wsListeners = new HashSet<WebSocketListener>();
|
||||
this.connections = (Map<String, UserConnection>) new CaseInsensitiveMap();
|
||||
|
@ -131,6 +142,7 @@ public class BungeeCord extends ProxyServer {
|
|||
this.pluginChannels = new HashSet<String>();
|
||||
this.pluginsFolder = new File("plugins");
|
||||
this.scheduler = new BungeeScheduler();
|
||||
this.banCommands = new ArrayList();
|
||||
this.getPluginManager().registerCommand(null, new CommandReload());
|
||||
this.getPluginManager().registerCommand(null, new CommandEnd());
|
||||
this.getPluginManager().registerCommand(null, new CommandList());
|
||||
|
@ -141,6 +153,7 @@ public class BungeeCord extends ProxyServer {
|
|||
this.getPluginManager().registerCommand(null, new CommandPerms());
|
||||
this.getPluginManager().registerCommand(null, new CommandSend());
|
||||
this.getPluginManager().registerCommand(null, new CommandFind());
|
||||
this.getPluginManager().registerCommand(null, new CommandClearRatelimit());
|
||||
this.registerChannel("BungeeCord");
|
||||
Log.setOutput(new PrintStream(ByteStreams.nullOutputStream()));
|
||||
AnsiConsole.systemInstall();
|
||||
|
@ -153,6 +166,42 @@ public class BungeeCord extends ProxyServer {
|
|||
this.logger.info("NOTE: This error is non crucial, and BungeeCord will still function correctly! Do not bug the author about it unless you are still unable to get it working");
|
||||
}
|
||||
}
|
||||
|
||||
public void reconfigureBanCommands(boolean replaceBukkit) {
|
||||
if(banCommands.size() > 0) {
|
||||
for(Command c : banCommands) {
|
||||
this.getPluginManager().unregisterCommand(c);
|
||||
}
|
||||
banCommands.clear();
|
||||
}
|
||||
|
||||
Command cBan = new CommandGlobalBan(replaceBukkit);
|
||||
Command cUnban = new CommandGlobalUnban(replaceBukkit);
|
||||
Command cBanReload = new CommandGlobalBanReload(replaceBukkit);
|
||||
Command cBanIP = new CommandGlobalBanIP(replaceBukkit);
|
||||
Command cBanWildcard = new CommandGlobalBanWildcard(replaceBukkit);
|
||||
Command cBanRegex = new CommandGlobalBanRegex(replaceBukkit);
|
||||
Command cBanCheck = new CommandGlobalCheckBan(replaceBukkit);
|
||||
Command cBanList = new CommandGlobalListBan(replaceBukkit);
|
||||
|
||||
banCommands.add(cBan);
|
||||
banCommands.add(cUnban);
|
||||
banCommands.add(cBanReload);
|
||||
banCommands.add(cBanIP);
|
||||
banCommands.add(cBanWildcard);
|
||||
banCommands.add(cBanRegex);
|
||||
banCommands.add(cBanCheck);
|
||||
banCommands.add(cBanList);
|
||||
|
||||
this.getPluginManager().registerCommand(null, cBan);
|
||||
this.getPluginManager().registerCommand(null, cUnban);
|
||||
this.getPluginManager().registerCommand(null, cBanReload);
|
||||
this.getPluginManager().registerCommand(null, cBanIP);
|
||||
this.getPluginManager().registerCommand(null, cBanWildcard);
|
||||
this.getPluginManager().registerCommand(null, cBanRegex);
|
||||
this.getPluginManager().registerCommand(null, cBanCheck);
|
||||
this.getPluginManager().registerCommand(null, cBanList);
|
||||
}
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
final BungeeCord bungee = new BungeeCord();
|
||||
|
@ -186,6 +235,25 @@ public class BungeeCord extends ProxyServer {
|
|||
BungeeCord.this.getReconnectHandler().save();
|
||||
}
|
||||
}, 0L, TimeUnit.MINUTES.toMillis(5L));
|
||||
this.reloadBanThread.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
BanList.maybeReloadBans(null);
|
||||
}
|
||||
}, 0L, TimeUnit.SECONDS.toMillis(3L));
|
||||
this.closeInactiveSockets.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
for(WebSocketListener lst : BungeeCord.this.wsListeners) {
|
||||
lst.closeInactiveSockets();
|
||||
ListenerInfo info = lst.getInfo();
|
||||
if(info.getRateLimitIP() != null) info.getRateLimitIP().deleteClearLimiters();
|
||||
if(info.getRateLimitLogin() != null) info.getRateLimitLogin().deleteClearLimiters();
|
||||
if(info.getRateLimitMOTD() != null) info.getRateLimitMOTD().deleteClearLimiters();
|
||||
if(info.getRateLimitQuery() != null) info.getRateLimitQuery().deleteClearLimiters();
|
||||
}
|
||||
}
|
||||
}, 0L, TimeUnit.SECONDS.toMillis(10L));
|
||||
}
|
||||
|
||||
public void startListeners() {
|
||||
|
|
|
@ -4,13 +4,10 @@
|
|||
|
||||
package net.md_5.bungee;
|
||||
|
||||
import net.md_5.bungee.api.connection.Server;
|
||||
import net.md_5.bungee.api.connection.PendingConnection;
|
||||
import java.beans.ConstructorProperties;
|
||||
import net.md_5.bungee.util.CaseInsensitiveSet;
|
||||
import java.util.HashSet;
|
||||
import net.md_5.bungee.api.config.TexturePackInfo;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.event.PermissionCheckEvent;
|
||||
import java.util.Collections;
|
||||
import java.net.InetSocketAddress;
|
||||
|
@ -36,10 +33,14 @@ import io.netty.channel.Channel;
|
|||
import io.netty.channel.ChannelInitializer;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import java.util.Objects;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import net.md_5.bungee.api.event.ServerConnectEvent;
|
||||
import net.md_5.bungee.protocol.packet.DefinedPacket;
|
||||
import com.google.common.base.Preconditions;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import net.md_5.bungee.api.connection.Connection;
|
||||
import net.md_5.bungee.api.score.Scoreboard;
|
||||
import net.md_5.bungee.protocol.packet.PacketCCSettings;
|
||||
|
@ -71,6 +72,7 @@ public final class UserConnection implements ProxiedPlayer {
|
|||
private final Scoreboard serverSentScoreboard;
|
||||
private String displayName;
|
||||
private final Connection.Unsafe unsafe;
|
||||
private final Map<String, Object> attachment = new WeakHashMap();
|
||||
|
||||
public void init() {
|
||||
this.displayName = this.name;
|
||||
|
@ -383,4 +385,9 @@ public final class UserConnection implements ProxiedPlayer {
|
|||
public String getDisplayName() {
|
||||
return this.displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAttachment() {
|
||||
return attachment;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package net.md_5.bungee.api;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
public interface CommandSender {
|
||||
String getName();
|
||||
|
@ -22,4 +23,6 @@ public interface CommandSender {
|
|||
boolean hasPermission(final String p0);
|
||||
|
||||
void setPermission(final String p0, final boolean p1);
|
||||
|
||||
Map<String, Object> getAttachment();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package net.md_5.bungee.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MOTD extends QueryConnection {
|
||||
|
||||
public void sendToUser();
|
||||
|
||||
public String getLine1();
|
||||
public String getLine2();
|
||||
public List<String> getPlayerList();
|
||||
public int[] getBitmap();
|
||||
public int getOnlinePlayers();
|
||||
public int getMaxPlayers();
|
||||
public String getSubType();
|
||||
|
||||
public void setLine1(String p);
|
||||
public void setLine2(String p);
|
||||
public void setPlayerList(List<String> p);
|
||||
public void setPlayerList(String... p);
|
||||
public void setBitmap(int[] p);
|
||||
public void setOnlinePlayers(int i);
|
||||
public void setMaxPlayers(int i);
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package net.md_5.bungee.api;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.eaglercraft.EaglercraftBungee;
|
||||
|
||||
public interface QueryConnection {
|
||||
|
||||
public InetAddress getRemoteAddress();
|
||||
public ListenerInfo getListener();
|
||||
|
||||
public String getAccept();
|
||||
public void setReturnType(String type);
|
||||
public String getReturnType();
|
||||
|
||||
public int availableRequests();
|
||||
|
||||
public default JSONObject readRequestData() {
|
||||
String s = readRequestString();
|
||||
return s == null ? null : new JSONObject(s);
|
||||
}
|
||||
|
||||
public String readRequestString();
|
||||
public long getConnectionTimestamp();
|
||||
|
||||
public default long getConnectionAge() {
|
||||
return System.currentTimeMillis() - getConnectionTimestamp();
|
||||
}
|
||||
|
||||
public default void writeResponse(JSONObject msg) {
|
||||
JSONObject toSend = new JSONObject();
|
||||
toSend.put("type", getReturnType());
|
||||
toSend.put("name", BungeeCord.getInstance().config.getServerName());
|
||||
toSend.put("brand", EaglercraftBungee.brand);
|
||||
toSend.put("vers", EaglercraftBungee.version);
|
||||
toSend.put("cracked", EaglercraftBungee.cracked);
|
||||
toSend.put("time", System.currentTimeMillis());
|
||||
toSend.put("uuid", BungeeCord.getInstance().config.getUuid());
|
||||
toSend.put("data", msg);
|
||||
writeResponseRaw(toSend.toString());
|
||||
}
|
||||
|
||||
public default void writeResponse(String msg) {
|
||||
JSONObject toSend = new JSONObject();
|
||||
toSend.put("type", getReturnType());
|
||||
toSend.put("name", BungeeCord.getInstance().config.getServerName());
|
||||
toSend.put("brand", EaglercraftBungee.brand);
|
||||
toSend.put("vers", EaglercraftBungee.version);
|
||||
toSend.put("cracked", EaglercraftBungee.cracked);
|
||||
toSend.put("time", System.currentTimeMillis());
|
||||
toSend.put("uuid", BungeeCord.getInstance().config.getUuid());
|
||||
toSend.put("data", msg);
|
||||
writeResponseRaw(toSend.toString());
|
||||
}
|
||||
|
||||
public void writeResponseRaw(String msg);
|
||||
public void writeResponseBinary(byte[] blob);
|
||||
|
||||
public void keepAlive(boolean yes);
|
||||
public boolean shouldKeepAlive();
|
||||
public boolean isClosed();
|
||||
public void close();
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package net.md_5.bungee.api;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public class ServerIcon {
|
||||
|
||||
public static int[] createServerIcon(BufferedImage awtIcon) {
|
||||
BufferedImage icon = awtIcon;
|
||||
boolean gotScaled = false;
|
||||
if(icon.getWidth() != 64 || icon.getHeight() != 64) {
|
||||
icon = new BufferedImage(64, 64, awtIcon.getType());
|
||||
Graphics2D g = (Graphics2D) icon.getGraphics();
|
||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, (awtIcon.getWidth() < 64 || awtIcon.getHeight() < 64) ?
|
||||
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR : RenderingHints.VALUE_INTERPOLATION_BICUBIC);
|
||||
g.setBackground(Color.BLACK);
|
||||
g.clearRect(0, 0, 64, 64);
|
||||
int ow = awtIcon.getWidth();
|
||||
int oh = awtIcon.getHeight();
|
||||
int nw, nh;
|
||||
float aspectRatio = (float)oh / (float)ow;
|
||||
if(aspectRatio >= 1.0f) {
|
||||
nw = (int)(64 / aspectRatio);
|
||||
nh = 64;
|
||||
}else {
|
||||
nw = 64;
|
||||
nh = (int)(64 * aspectRatio);
|
||||
}
|
||||
g.drawImage(awtIcon, (64 - nw) / 2, (64 - nh) / 2, (64 - nw) / 2 + nw, (64 - nh) / 2 + nh, 0, 0, awtIcon.getWidth(), awtIcon.getHeight(), null);
|
||||
g.dispose();
|
||||
gotScaled = true;
|
||||
}
|
||||
int[] pxls = icon.getRGB(0, 0, 64, 64, new int[4096], 0, 64);
|
||||
if(gotScaled) {
|
||||
for(int i = 0; i < pxls.length; ++i) {
|
||||
if((pxls[i] & 0xFFFFFF) == 0) {
|
||||
pxls[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pxls;
|
||||
}
|
||||
|
||||
public static int[] createServerIcon(InputStream f) {
|
||||
try {
|
||||
return createServerIcon(ImageIO.read(f));
|
||||
}catch(Throwable t) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static int[] createServerIcon(File f) {
|
||||
try {
|
||||
return createServerIcon(ImageIO.read(f));
|
||||
}catch(Throwable t) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -25,4 +25,8 @@ public interface ConfigurationAdapter {
|
|||
Collection<String> getPermissions(final String p0);
|
||||
|
||||
AuthServiceInfo getAuthSettings();
|
||||
|
||||
Map<String, Object> getMap();
|
||||
|
||||
void forceSave();
|
||||
}
|
||||
|
|
|
@ -4,12 +4,17 @@
|
|||
|
||||
package net.md_5.bungee.api.config;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.io.File;
|
||||
|
||||
import net.md_5.bungee.api.ServerIcon;
|
||||
import net.md_5.bungee.api.tab.TabListHandler;
|
||||
import net.md_5.bungee.eaglercraft.WebSocketRateLimiter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class ListenerInfo {
|
||||
private final String hostString;
|
||||
private final InetSocketAddress host;
|
||||
private final String motd;
|
||||
private final int maxPlayers;
|
||||
|
@ -18,13 +23,27 @@ public class ListenerInfo {
|
|||
private final String fallbackServer;
|
||||
private final boolean forceDefault;
|
||||
private final boolean websocket;
|
||||
private final boolean forwardIp;
|
||||
private final Map<String, String> forcedHosts;
|
||||
private final TexturePackInfo texturePack;
|
||||
private final Class<? extends TabListHandler> tabList;
|
||||
private final String serverIcon;
|
||||
private final int[] serverIconCache;
|
||||
private boolean serverIconLoaded;
|
||||
private boolean serverIconSet;
|
||||
private final boolean allowMOTD;
|
||||
private final boolean allowQuery;
|
||||
private final MOTDCacheConfiguration cacheConfig;
|
||||
private final WebSocketRateLimiter rateLimitIP;
|
||||
private final WebSocketRateLimiter rateLimitLogin;
|
||||
private final WebSocketRateLimiter rateLimitMOTD;
|
||||
private final WebSocketRateLimiter rateLimitQuery;
|
||||
|
||||
|
||||
@ConstructorProperties({ "host", "motd", "maxPlayers", "tabListSize", "defaultServer", "fallbackServer", "forceDefault", "websocket", "forcedHosts", "texturePack", "tabList" })
|
||||
public ListenerInfo(final InetSocketAddress host, final String motd, final int maxPlayers, final int tabListSize, final String defaultServer, final String fallbackServer, final boolean forceDefault, final boolean websocket,
|
||||
final Map<String, String> forcedHosts, final TexturePackInfo texturePack, final Class<? extends TabListHandler> tabList) {
|
||||
public ListenerInfo(final String hostString, final InetSocketAddress host, final String motd, final int maxPlayers, final int tabListSize, final String defaultServer, final String fallbackServer, final boolean forceDefault, final boolean websocket,
|
||||
final boolean forwardIp, final Map<String, String> forcedHosts, final TexturePackInfo texturePack, final Class<? extends TabListHandler> tabList, final String serverIcon, final MOTDCacheConfiguration cacheConfig,
|
||||
final boolean allowMOTD, final boolean allowQuery, final WebSocketRateLimiter rateLimitIP, final WebSocketRateLimiter rateLimitLogin, final WebSocketRateLimiter rateLimitMOTD, final WebSocketRateLimiter rateLimitQuery) {
|
||||
this.hostString = hostString;
|
||||
this.host = host;
|
||||
this.motd = motd;
|
||||
this.maxPlayers = maxPlayers;
|
||||
|
@ -33,9 +52,25 @@ public class ListenerInfo {
|
|||
this.fallbackServer = fallbackServer;
|
||||
this.forceDefault = forceDefault;
|
||||
this.websocket = websocket;
|
||||
this.forwardIp = forwardIp;
|
||||
this.forcedHosts = forcedHosts;
|
||||
this.texturePack = texturePack;
|
||||
this.tabList = tabList;
|
||||
this.serverIcon = serverIcon;
|
||||
this.serverIconCache = new int[4096];
|
||||
this.serverIconLoaded = false;
|
||||
this.serverIconSet = false;
|
||||
this.allowMOTD = allowMOTD;
|
||||
this.allowQuery = allowQuery;
|
||||
this.cacheConfig = cacheConfig;
|
||||
this.rateLimitIP = rateLimitIP;
|
||||
this.rateLimitLogin = rateLimitLogin;
|
||||
this.rateLimitMOTD = rateLimitMOTD;
|
||||
this.rateLimitQuery = rateLimitQuery;
|
||||
}
|
||||
|
||||
public String getHostString() {
|
||||
return this.hostString;
|
||||
}
|
||||
|
||||
public InetSocketAddress getHost() {
|
||||
|
@ -120,6 +155,9 @@ public class ListenerInfo {
|
|||
if (this.getTabListSize() != other.getTabListSize()) {
|
||||
return false;
|
||||
}
|
||||
if (this.isWebsocket() != other.isWebsocket()) {
|
||||
return false;
|
||||
}
|
||||
final Object this$defaultServer = this.getDefaultServer();
|
||||
final Object other$defaultServer = other.getDefaultServer();
|
||||
Label_0165: {
|
||||
|
@ -180,6 +218,15 @@ public class ListenerInfo {
|
|||
} else if (this$tabList.equals(other$tabList)) {
|
||||
return true;
|
||||
}
|
||||
final Object this$getServerIcon = this.getServerIcon();
|
||||
final Object other$getServerIcon = other.getServerIcon();
|
||||
if (this$getServerIcon == null) {
|
||||
if (other$getServerIcon == null) {
|
||||
return true;
|
||||
}
|
||||
} else if (this$getServerIcon.equals(other$getServerIcon)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -208,6 +255,8 @@ public class ListenerInfo {
|
|||
result = result * 31 + (($texturePack == null) ? 0 : $texturePack.hashCode());
|
||||
final Object $tabList = this.getTabList();
|
||||
result = result * 31 + (($tabList == null) ? 0 : $tabList.hashCode());
|
||||
final Object $serverIconCache = this.getTabList();
|
||||
result = result * 31 + (($serverIconCache == null) ? 0 : $serverIconCache.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -220,4 +269,76 @@ public class ListenerInfo {
|
|||
public boolean isWebsocket() {
|
||||
return websocket;
|
||||
}
|
||||
|
||||
public boolean hasForwardedHeaders() {
|
||||
return forwardIp;
|
||||
}
|
||||
|
||||
public String getServerIcon() {
|
||||
return serverIcon;
|
||||
}
|
||||
|
||||
public int[] getServerIconCache() {
|
||||
if(!serverIconLoaded) {
|
||||
if(serverIcon != null) {
|
||||
int[] img = ServerIcon.createServerIcon(new File(serverIcon));
|
||||
if(img != null) {
|
||||
System.arraycopy(img, 0, serverIconCache, 0, img.length);
|
||||
serverIconSet = true;
|
||||
}else {
|
||||
serverIconSet = false;
|
||||
}
|
||||
}else {
|
||||
serverIconSet = false;
|
||||
}
|
||||
serverIconLoaded = true;
|
||||
}
|
||||
return serverIconCache;
|
||||
}
|
||||
|
||||
public boolean isIconSet() {
|
||||
getServerIconCache();
|
||||
return serverIconSet;
|
||||
}
|
||||
|
||||
public boolean isForwardIp() {
|
||||
return forwardIp;
|
||||
}
|
||||
|
||||
public boolean isServerIconLoaded() {
|
||||
return serverIconLoaded;
|
||||
}
|
||||
|
||||
public boolean isServerIconSet() {
|
||||
return serverIconSet;
|
||||
}
|
||||
|
||||
public boolean isAllowMOTD() {
|
||||
return allowMOTD;
|
||||
}
|
||||
|
||||
public boolean isAllowQuery() {
|
||||
return allowQuery;
|
||||
}
|
||||
|
||||
public MOTDCacheConfiguration getCacheConfig() {
|
||||
return cacheConfig;
|
||||
}
|
||||
|
||||
public WebSocketRateLimiter getRateLimitIP() {
|
||||
return rateLimitIP;
|
||||
}
|
||||
|
||||
public WebSocketRateLimiter getRateLimitLogin() {
|
||||
return rateLimitLogin;
|
||||
}
|
||||
|
||||
public WebSocketRateLimiter getRateLimitMOTD() {
|
||||
return rateLimitMOTD;
|
||||
}
|
||||
|
||||
public WebSocketRateLimiter getRateLimitQuery() {
|
||||
return rateLimitQuery;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package net.md_5.bungee.api.config;
|
||||
|
||||
public class MOTDCacheConfiguration {
|
||||
|
||||
public final int cacheTTL;
|
||||
public final boolean cacheServerListAnimation;
|
||||
public final boolean cacheServerListResults;
|
||||
public final boolean cacheServerListTrending;
|
||||
public final boolean cacheServerListPortfolios;
|
||||
|
||||
public MOTDCacheConfiguration(int cacheTTL, boolean cacheServerListAnimation, boolean cacheServerListResults,
|
||||
boolean cacheServerListTrending, boolean cacheServerListPortfolios) {
|
||||
this.cacheTTL = cacheTTL;
|
||||
this.cacheServerListAnimation = cacheServerListAnimation;
|
||||
this.cacheServerListResults = cacheServerListResults;
|
||||
this.cacheServerListTrending = cacheServerListTrending;
|
||||
this.cacheServerListPortfolios = cacheServerListPortfolios;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package net.md_5.bungee.api.event;
|
||||
|
||||
import net.md_5.bungee.api.MOTD;
|
||||
|
||||
public class WebsocketMOTDEvent extends WebsocketQueryEvent {
|
||||
|
||||
public WebsocketMOTDEvent(MOTD connection) {
|
||||
super(connection);
|
||||
}
|
||||
|
||||
public MOTD getMOTD() {
|
||||
return (MOTD)connection;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package net.md_5.bungee.api.event;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import net.md_5.bungee.api.QueryConnection;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.plugin.Event;
|
||||
|
||||
public class WebsocketQueryEvent extends Event {
|
||||
|
||||
protected final QueryConnection connection;
|
||||
|
||||
public WebsocketQueryEvent(QueryConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
public InetAddress getRemoteAddress() {
|
||||
return connection.getRemoteAddress();
|
||||
}
|
||||
|
||||
public ListenerInfo getListener() {
|
||||
return connection.getListener();
|
||||
}
|
||||
|
||||
public String getAccept() {
|
||||
return connection.getAccept();
|
||||
}
|
||||
|
||||
public QueryConnection getQuery() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
package net.md_5.bungee.command;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
||||
public class CommandClearRatelimit extends Command {
|
||||
|
||||
public CommandClearRatelimit() {
|
||||
super("eag-ratelimit", "bungeecord.command.eag.ratelimit", "e-ratelimit", "gratelimit");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender p0, String[] p1) {
|
||||
if(p1.length >= 1 && ("clear".equalsIgnoreCase(p1[0]) || "reset".equalsIgnoreCase(p1[0]))) {
|
||||
if(p1.length == 1 || (p1.length == 2 && "all".equalsIgnoreCase(p1[1]))) {
|
||||
for(ListenerInfo l : BungeeCord.getInstance().config.getListeners()) {
|
||||
if(l.getRateLimitIP() != null) l.getRateLimitIP().resetLimiters();
|
||||
if(l.getRateLimitLogin() != null) l.getRateLimitLogin().resetLimiters();
|
||||
if(l.getRateLimitMOTD() != null) l.getRateLimitMOTD().resetLimiters();
|
||||
if(l.getRateLimitQuery() != null) l.getRateLimitQuery().resetLimiters();
|
||||
}
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all ratelimits");
|
||||
return;
|
||||
}else if(p1.length == 2 || p1.length == 3) {
|
||||
ListenerInfo ll = null;
|
||||
if(p1.length == 3) {
|
||||
for(ListenerInfo l : BungeeCord.getInstance().config.getListeners()) {
|
||||
if(l.getHostString().equalsIgnoreCase(p1[2])) {
|
||||
ll = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(ll == null) {
|
||||
p0.sendMessage(ChatColor.RED + "Listener does not exist: " + ChatColor.WHITE + p1[2]);
|
||||
String accum = "";
|
||||
for(ListenerInfo l : BungeeCord.getInstance().config.getListeners()) {
|
||||
if(accum.length() > 0) {
|
||||
accum += ", ";
|
||||
}
|
||||
accum += l.getHostString();
|
||||
}
|
||||
p0.sendMessage(ChatColor.GREEN + "Listeners Available: " + ChatColor.WHITE + accum);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if("all".equalsIgnoreCase(p1[1])) {
|
||||
if(ll != null) {
|
||||
if(ll.getRateLimitIP() != null) ll.getRateLimitIP().resetLimiters();
|
||||
if(ll.getRateLimitLogin() != null) ll.getRateLimitLogin().resetLimiters();
|
||||
if(ll.getRateLimitMOTD() != null) ll.getRateLimitMOTD().resetLimiters();
|
||||
if(ll.getRateLimitQuery() != null) ll.getRateLimitQuery().resetLimiters();
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all ratelimits on listener: " + ChatColor.WHITE + ll.getHostString());
|
||||
}else {
|
||||
for(ListenerInfo l : BungeeCord.getInstance().config.getListeners()) {
|
||||
if(l.getRateLimitIP() != null) l.getRateLimitIP().resetLimiters();
|
||||
if(l.getRateLimitLogin() != null) l.getRateLimitLogin().resetLimiters();
|
||||
if(l.getRateLimitMOTD() != null) l.getRateLimitMOTD().resetLimiters();
|
||||
if(l.getRateLimitQuery() != null) l.getRateLimitQuery().resetLimiters();
|
||||
}
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all ratelimits");
|
||||
}
|
||||
return;
|
||||
}else if("ip".equalsIgnoreCase(p1[1])) {
|
||||
if(ll != null) {
|
||||
if(ll.getRateLimitIP() != null) ll.getRateLimitIP().resetLimiters();
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all IP ratelimits on listener: " + ChatColor.WHITE + ll.getHostString());
|
||||
}else {
|
||||
for(ListenerInfo l : BungeeCord.getInstance().config.getListeners()) {
|
||||
if(l.getRateLimitIP() != null) l.getRateLimitIP().resetLimiters();
|
||||
}
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all IP ratelimits.");
|
||||
}
|
||||
return;
|
||||
}else if("login".equalsIgnoreCase(p1[1])) {
|
||||
if(ll != null) {
|
||||
if(ll.getRateLimitLogin() != null) ll.getRateLimitLogin().resetLimiters();
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all login ratelimits on listener: " + ChatColor.WHITE + ll.getHostString());
|
||||
}else {
|
||||
for(ListenerInfo l : BungeeCord.getInstance().config.getListeners()) {
|
||||
if(l.getRateLimitLogin() != null) l.getRateLimitLogin().resetLimiters();
|
||||
}
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all login ratelimits.");
|
||||
}
|
||||
return;
|
||||
}else if("motd".equalsIgnoreCase(p1[1])) {
|
||||
if(ll != null) {
|
||||
if(ll.getRateLimitMOTD() != null) ll.getRateLimitMOTD().resetLimiters();
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all MOTD ratelimits on listener: " + ChatColor.WHITE + ll.getHostString());
|
||||
}else {
|
||||
for(ListenerInfo l : BungeeCord.getInstance().config.getListeners()) {
|
||||
if(l.getRateLimitMOTD() != null) l.getRateLimitMOTD().resetLimiters();
|
||||
}
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all MOTD ratelimits.");
|
||||
}
|
||||
return;
|
||||
}else if("query".equalsIgnoreCase(p1[1])) {
|
||||
if(ll != null) {
|
||||
if(ll.getRateLimitMOTD() != null) ll.getRateLimitMOTD().resetLimiters();
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all query ratelimits on listener: " + ChatColor.WHITE + ll.getHostString());
|
||||
}else {
|
||||
for(ListenerInfo l : BungeeCord.getInstance().config.getListeners()) {
|
||||
if(l.getRateLimitMOTD() != null) l.getRateLimitMOTD().resetLimiters();
|
||||
}
|
||||
p0.sendMessage(ChatColor.GREEN + "Reset all query ratelimits.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
p0.sendMessage(ChatColor.RED + "How to reset all rate limits: " + ChatColor.WHITE + "/eag-ratelimit reset");
|
||||
p0.sendMessage(ChatColor.RED + "How to reset a specific rate limit: " + ChatColor.WHITE + "/eag-ratelimit reset <ip|login|motd|query>");
|
||||
p0.sendMessage(ChatColor.RED + "How to reset a specific listener: " + ChatColor.WHITE + "/eag-ratelimit reset <all|ip|login|motd|query> <host>");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package net.md_5.bungee.command;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.eaglercraft.BanList;
|
||||
|
||||
public class CommandGlobalBan extends Command {
|
||||
|
||||
private final boolean replaceBukkit;
|
||||
|
||||
public CommandGlobalBan(boolean replaceBukkit) {
|
||||
super(replaceBukkit ? "ban" : "eag-ban", "bungeecord.command.eag.ban", replaceBukkit ? new String[] { "kickban", "eag-ban", "e-ban", "gban" } : new String[] { "e-ban", "gban" });
|
||||
this.replaceBukkit = replaceBukkit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender p0, String[] p1) {
|
||||
if(p1.length >= 1) {
|
||||
String p = p1[0].trim().toLowerCase();
|
||||
if(p0.getName().equalsIgnoreCase(p)) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "You cannot ban yourself");
|
||||
return;
|
||||
}
|
||||
String reason = "The ban hammer has spoken!";
|
||||
if(p1.length >= 2) {
|
||||
reason = "";
|
||||
for(int i = 1; i < p1.length; ++i) {
|
||||
if(reason.length() > 0) {
|
||||
reason += " ";
|
||||
}
|
||||
reason += p1[i];
|
||||
}
|
||||
}
|
||||
String wasTheKick = null;
|
||||
Collection<ProxiedPlayer> playerz = BungeeCord.getInstance().getPlayers();
|
||||
for(ProxiedPlayer pp : playerz) {
|
||||
if(pp.getName().equalsIgnoreCase(p)) {
|
||||
wasTheKick = pp.getName();
|
||||
pp.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: " + reason);
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.WHITE + "Kicked: " + pp.getName());
|
||||
}
|
||||
}
|
||||
if(BanList.ban(p, reason)) {
|
||||
if(wasTheKick == null) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Warning! '" + ChatColor.WHITE + p + ChatColor.YELLOW + "' is not currently on this server");
|
||||
}
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Username '" + ChatColor.WHITE + (wasTheKick == null ? p : wasTheKick) + ChatColor.GREEN + "' was added to the ban list");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Username '" + ChatColor.WHITE + p + ChatColor.RED + "' is already banned");
|
||||
}
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To ban a player, use: " + ChatColor.WHITE + "/" + (replaceBukkit?"":"eag-") + "ban <player> [reason]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
package net.md_5.bungee.command;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.eaglercraft.BanList;
|
||||
import net.md_5.bungee.eaglercraft.BanList.IPBan;
|
||||
|
||||
public class CommandGlobalBanIP extends Command {
|
||||
|
||||
private final boolean replaceBukkit;
|
||||
|
||||
public CommandGlobalBanIP(boolean replaceBukkit) {
|
||||
super(replaceBukkit ? "ban-ip" : "eag-ban-ip", "bungeecord.command.eag.banip", (replaceBukkit ? new String[] {"eag-ban-ip", "banip", "e-ban-ip", "gban-ip"} :
|
||||
new String[] {"gban-ip", "e-ban-ip", "gbanip", "e-banip"}) );
|
||||
this.replaceBukkit = replaceBukkit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender p0, String[] p1) {
|
||||
String w = (String) p0.getAttachment().get("banIPWaitingToAdd");
|
||||
if(w != null) {
|
||||
List<ProxiedPlayer> lst = (List<ProxiedPlayer>)p0.getAttachment().get("banIPWaitingToKick");
|
||||
if(p1.length != 1 || (!p1[0].equalsIgnoreCase("confirm") && !p1[0].equalsIgnoreCase("cancel"))) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-ip" : "/eag-ban-ip") + " confirm" + ChatColor.RED + " to add IP " + ChatColor.WHITE + w +
|
||||
ChatColor.RED + " and ban " + ChatColor.WHITE + lst.size() + ChatColor.RED + " players");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-ip" : "/eag-ban-ip") + " cancel" + ChatColor.RED + " to cancel this operation");
|
||||
}else {
|
||||
if(p1[0].equalsIgnoreCase("confirm")) {
|
||||
try {
|
||||
if(BanList.banIP(w)) {
|
||||
for(ProxiedPlayer pp : lst) {
|
||||
pp.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by IP");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + pp.getName());
|
||||
}
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added IP '" + ChatColor.WHITE + w + ChatColor.GREEN + "' to the ban list");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "IP '" + ChatColor.WHITE + w + ChatColor.RED + "' is already on the ban list");
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "ERROR: address '" + ChatColor.WHITE + w + ChatColor.RED + "' is suddenly invalid for some reason");
|
||||
}
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Canceled ban");
|
||||
}
|
||||
p0.getAttachment().remove("banIPWaitingToAdd");
|
||||
p0.getAttachment().remove("banIPWaitingToKick");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(p1.length != 1) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "How to use: " + ChatColor.WHITE + (replaceBukkit ? "/ban-ip" : "/eag-ban-ip") + " <addr|player>");
|
||||
return;
|
||||
}
|
||||
boolean isPlayer = false;
|
||||
IPBan p = null;
|
||||
try {
|
||||
p = BanList.constructIpBan(p1[0]);
|
||||
}catch(Throwable t) {
|
||||
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
|
||||
if(pp.getName().equalsIgnoreCase(p1[0])) {
|
||||
Object addr = pp.getAttachment().get("remoteAddr");
|
||||
if(addr != null) {
|
||||
String newAddr = ((InetAddress)addr).getHostAddress();
|
||||
isPlayer = true;
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Player '" + ChatColor.WHITE + p1[0] + ChatColor.GREEN + "' has IP " + ChatColor.WHITE + newAddr);
|
||||
p1[0] = newAddr;
|
||||
try {
|
||||
p = BanList.constructIpBan(p1[0]);
|
||||
}catch(UnknownHostException ex) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Address '" + ChatColor.WHITE + p1[0] + "' is suddenly invalid: " + ChatColor.WHITE + p1[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!isPlayer) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Player '" + ChatColor.WHITE + p1[0] + "' is not on this server");
|
||||
return;
|
||||
}
|
||||
}
|
||||
boolean blocked = false;
|
||||
for(IPBan b : BanList.blockedBans) {
|
||||
if(b.checkBan(p.getBaseAddress()) || p.checkBan(b.getBaseAddress())) {
|
||||
blocked = true;
|
||||
}
|
||||
}
|
||||
if(blocked) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Cannot ban '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "', it will ban local addresses that may break your game");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To force, add to the " + ChatColor.WHITE + "[IPs]" + ChatColor.RED + " section of " + ChatColor.WHITE + "bans.txt" + ChatColor.RED + " in your bungee directory");
|
||||
return;
|
||||
}
|
||||
boolean isSenderGonnaGetKicked = false;
|
||||
List<ProxiedPlayer> usersThatAreGonnaBeKicked = new ArrayList();
|
||||
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
|
||||
Object addr = pp.getAttachment().get("remoteAddr");
|
||||
if(addr != null) {
|
||||
InetAddress addrr = (InetAddress)addr;
|
||||
if(p.checkBan(addrr)) {
|
||||
usersThatAreGonnaBeKicked.add(pp);
|
||||
if(pp.getName().equalsIgnoreCase(p0.getName())) {
|
||||
isSenderGonnaGetKicked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isSenderGonnaGetKicked) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "banning address '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' will ban you off of your own server");
|
||||
return;
|
||||
}
|
||||
if(usersThatAreGonnaBeKicked.size() > 1) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "WARNING: banning address '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is gonna ban " +
|
||||
ChatColor.WHITE + usersThatAreGonnaBeKicked.size() + ChatColor.RED + " players off of your server");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-ip" : "/eag-ban-ip") + " confirm" + ChatColor.RED + " to continue, or type " +
|
||||
ChatColor.WHITE + (replaceBukkit ? "/ban-ip" : "/eag-ban-ip") + " cancel" + ChatColor.RED + " to cancel");
|
||||
p0.getAttachment().put("banIPWaitingToKick", usersThatAreGonnaBeKicked);
|
||||
p0.getAttachment().put("banIPWaitingToAdd", p1[0]);
|
||||
}else {
|
||||
try {
|
||||
if(BanList.banIP(p1[0])) {
|
||||
if(usersThatAreGonnaBeKicked.size() > 0) {
|
||||
usersThatAreGonnaBeKicked.get(0).disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by IP");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + usersThatAreGonnaBeKicked.get(0).getName());
|
||||
}
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added IP '" + ChatColor.WHITE + p1[0] + ChatColor.GREEN + "' to the ban list");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "IP '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is already on the ban list");
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
e.printStackTrace();
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "ERROR: address '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is suddenly invalid for some reason");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package net.md_5.bungee.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.eaglercraft.BanList;
|
||||
|
||||
public class CommandGlobalBanRegex extends Command {
|
||||
|
||||
private final boolean replaceBukkit;
|
||||
|
||||
public CommandGlobalBanRegex(boolean replaceBukkit) {
|
||||
super(replaceBukkit ? "ban-regex" : "eag-ban-regex", "bungeecord.command.eag.banregex", replaceBukkit ? new String[] { "eag-ban-regex", "e-ban-regex",
|
||||
"gban-regex", "eag-banregex", "e-banregex", "gbanregex", "banregex" } : new String[] { "e-ban-regex", "gban-regex",
|
||||
"eag-banregex", "e-banregex", "gbanregex" });
|
||||
this.replaceBukkit = replaceBukkit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender p0, String[] p1) {
|
||||
String w = (String) p0.getAttachment().get("banRegexWaitingToAdd");
|
||||
if(w != null) {
|
||||
List<ProxiedPlayer> lst = (List<ProxiedPlayer>)p0.getAttachment().get("banRegexWaitingToKick");
|
||||
if(p1.length != 1 || (!p1[0].equalsIgnoreCase("confirm") && !p1[0].equalsIgnoreCase("cancel"))) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-regex" : "/eag-ban-regex") + " confirm" + ChatColor.RED + " to add regex " + ChatColor.WHITE + w +
|
||||
ChatColor.RED + " and ban " + ChatColor.WHITE + lst.size() + ChatColor.RED + " players");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-regex" : "/eag-ban-regex") + " cancel" + ChatColor.RED + " to cancel this operation");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
|
||||
}else {
|
||||
if(p1[0].equalsIgnoreCase("confirm")) {
|
||||
if(BanList.banRegex(w)) {
|
||||
for(ProxiedPlayer pp : lst) {
|
||||
pp.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by regex");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + pp.getName());
|
||||
}
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added regex '" + ChatColor.WHITE + w + ChatColor.GREEN + "' to the ban list");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Regex '" + ChatColor.WHITE + w + ChatColor.RED + "' is already banned");
|
||||
}
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Canceled ban");
|
||||
}
|
||||
p0.getAttachment().remove("banRegexWaitingToAdd");
|
||||
p0.getAttachment().remove("banRegexWaitingToKick");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(p1.length != 1) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "How to use: " + ChatColor.WHITE + (replaceBukkit ? "/ban-regex" : "/eag-ban-regex") + " <pattern>");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
|
||||
return;
|
||||
}
|
||||
Pattern p;
|
||||
try {
|
||||
p = Pattern.compile(p1[0]);
|
||||
}catch(Throwable t) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Regex syntax error: " + t.getMessage());
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
|
||||
return;
|
||||
}
|
||||
boolean isSenderGonnaGetKicked = false;
|
||||
List<ProxiedPlayer> usersThatAreGonnaBeKicked = new ArrayList();
|
||||
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
|
||||
String n = pp.getName().toLowerCase();
|
||||
if(p.matcher(n).matches()) {
|
||||
usersThatAreGonnaBeKicked.add(pp);
|
||||
if(n.equalsIgnoreCase(p0.getName())) {
|
||||
isSenderGonnaGetKicked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isSenderGonnaGetKicked) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "banning regex '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is gonna ban your own username");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
|
||||
return;
|
||||
}
|
||||
if(usersThatAreGonnaBeKicked.size() > 1) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "WARNING: banning regex '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is gonna ban " +
|
||||
ChatColor.WHITE + usersThatAreGonnaBeKicked.size() + ChatColor.RED + " players off of your server");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-regex" : "/eag-ban-regex") + " confirm" + ChatColor.RED + " to continue, or type " +
|
||||
ChatColor.WHITE + "/eag-ban-regex cancel" + ChatColor.RED + " to cancel");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
|
||||
p0.getAttachment().put("banRegexWaitingToKick", usersThatAreGonnaBeKicked);
|
||||
p0.getAttachment().put("banRegexWaitingToAdd", p1[0]);
|
||||
}else {
|
||||
if(BanList.banRegex(p1[0])) {
|
||||
if(usersThatAreGonnaBeKicked.size() > 0) {
|
||||
usersThatAreGonnaBeKicked.get(0).disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by regex");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + usersThatAreGonnaBeKicked.get(0).getName());
|
||||
}
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added regex '" + ChatColor.WHITE + p1[0] + ChatColor.GREEN + "' to the ban list");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Note: all usernames are converted to lowercase before being matched");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Regex '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is already banned");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package net.md_5.bungee.command;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.eaglercraft.BanList;
|
||||
|
||||
public class CommandGlobalBanReload extends Command {
|
||||
|
||||
public CommandGlobalBanReload(boolean replaceBukkit) {
|
||||
super(replaceBukkit ? "reloadban" : "eag-reloadban", "bungeecord.command.eag.reloadban", replaceBukkit ? new String[] { "eag-reloadban", "banreload", "eag-banreload", "e-reloadban",
|
||||
"e-banreload", "gbanreload", "greloadban"} : new String[] { "eag-banreload", "e-reloadban", "e-banreload", "gbanreload", "greloadban"});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender p0, String[] p1) {
|
||||
BanList.maybeReloadBans(p0);
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.WHITE + "Ban list reloaded");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package net.md_5.bungee.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.eaglercraft.BanList;
|
||||
|
||||
public class CommandGlobalBanWildcard extends Command {
|
||||
|
||||
private final boolean replaceBukkit;
|
||||
|
||||
public CommandGlobalBanWildcard(boolean replaceBukkit) {
|
||||
super(replaceBukkit ? "ban-wildcard" : "eag-ban-wildcard", "bungeecord.command.eag.banwildcard", replaceBukkit ? new String[] { "eag-ban-wildcard", "e-ban-wildcard", "gban-wildcard",
|
||||
"banwildcard", "eag-banwildcard", "banwildcard"} : new String[] { "e-ban-wildcard", "gban-wildcard", "eag-banwildcard"});
|
||||
this.replaceBukkit = replaceBukkit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender p0, String[] p1) {
|
||||
String w = (String) p0.getAttachment().get("banWildcardWaitingToAdd");
|
||||
if(w != null) {
|
||||
List<ProxiedPlayer> lst = (List<ProxiedPlayer>)p0.getAttachment().get("banWildcardWaitingToKick");
|
||||
if(p1.length != 1 || (!p1[0].equalsIgnoreCase("confirm") && !p1[0].equalsIgnoreCase("cancel"))) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-wildcard" : "/eag-ban-wildcard") + " confirm" + ChatColor.RED + " to add wildcard " + ChatColor.WHITE + w +
|
||||
ChatColor.RED + " and ban " + ChatColor.WHITE + lst.size() + ChatColor.RED + " players");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-wildcard" : "/eag-ban-wildcard") + " cancel" + ChatColor.RED + " to cancel this operation");
|
||||
}else {
|
||||
if(p1[0].equalsIgnoreCase("confirm")) {
|
||||
if(BanList.banWildcard(w)) {
|
||||
for(ProxiedPlayer pp : lst) {
|
||||
pp.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by wildcard");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + pp.getName());
|
||||
}
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added wildcard '" + ChatColor.WHITE + w + ChatColor.GREEN + "' to the ban list");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Wildcard '" + ChatColor.WHITE + w + ChatColor.RED + "' is already banned");
|
||||
}
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Canceled ban");
|
||||
}
|
||||
p0.getAttachment().remove("banWildcardWaitingToAdd");
|
||||
p0.getAttachment().remove("banWildcardWaitingToKick");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(p1.length != 1) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "How to use: " + ChatColor.WHITE + (replaceBukkit ? "/ban-wildcard" : "/eag-ban-wildcard") + " <pattern>");
|
||||
return;
|
||||
}
|
||||
p1[0] = p1[0].toLowerCase();
|
||||
String s = p1[0];
|
||||
boolean startStar = s.startsWith("*");
|
||||
if(startStar) {
|
||||
s = s.substring(1);
|
||||
}
|
||||
boolean endStar = s.endsWith("*");
|
||||
if(endStar) {
|
||||
s = s.substring(0, s.length() - 1);
|
||||
}
|
||||
if(!startStar && !endStar) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "'" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is not a wildcard, try '"
|
||||
+ ChatColor.WHITE + "*" + p1[0] + ChatColor.RED + "' or '" + ChatColor.WHITE + p1[0] + "*" + ChatColor.RED + "' or '" + ChatColor.WHITE
|
||||
+ "*" + p1[0] + "*" + ChatColor.RED + "' instead");
|
||||
return;
|
||||
}
|
||||
boolean isSenderGonnaGetKicked = false;
|
||||
List<ProxiedPlayer> usersThatAreGonnaBeKicked = new ArrayList();
|
||||
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
|
||||
String n = pp.getName().toLowerCase();
|
||||
if(startStar && endStar) {
|
||||
if(n.contains(s)) {
|
||||
usersThatAreGonnaBeKicked.add(pp);
|
||||
if(pp.getName().equalsIgnoreCase(p0.getName())) {
|
||||
isSenderGonnaGetKicked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if(startStar) {
|
||||
if(n.endsWith(s)) {
|
||||
usersThatAreGonnaBeKicked.add(pp);
|
||||
if(pp.getName().equalsIgnoreCase(p0.getName())) {
|
||||
isSenderGonnaGetKicked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if(endStar) {
|
||||
if(n.startsWith(s)) {
|
||||
usersThatAreGonnaBeKicked.add(pp);
|
||||
if(pp.getName().equalsIgnoreCase(p0.getName())) {
|
||||
isSenderGonnaGetKicked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(isSenderGonnaGetKicked) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "banning wildcard '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is gonna ban your own username");
|
||||
return;
|
||||
}
|
||||
if(usersThatAreGonnaBeKicked.size() > 1) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "WARNING: banning wildcard '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is gonna ban " +
|
||||
ChatColor.WHITE + usersThatAreGonnaBeKicked.size() + ChatColor.RED + " players off of your server");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Type " + ChatColor.WHITE + (replaceBukkit ? "/ban-wildcard" : "/eag-ban-wildcard") + " confirm" + ChatColor.RED + " to continue, or type " +
|
||||
ChatColor.WHITE + (replaceBukkit ? "/ban-wildcard" : "/eag-ban-wildcard") + " cancel" + ChatColor.RED + " to cancel");
|
||||
p0.getAttachment().put("banWildcardWaitingToKick", usersThatAreGonnaBeKicked);
|
||||
p0.getAttachment().put("banWildcardWaitingToAdd", p1[0]);
|
||||
}else {
|
||||
if(BanList.banWildcard(p1[0])) {
|
||||
if(usersThatAreGonnaBeKicked.size() > 0) {
|
||||
usersThatAreGonnaBeKicked.get(0).disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: banned by wildcard");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Kicked: " + ChatColor.WHITE + usersThatAreGonnaBeKicked.get(0).getName());
|
||||
}
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Added wildcard '" + ChatColor.WHITE + p1[0] + ChatColor.GREEN + "' to the ban list");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Wildcard '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is already banned");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package net.md_5.bungee.command;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.eaglercraft.BanList;
|
||||
import net.md_5.bungee.eaglercraft.BanList.BanCheck;
|
||||
import net.md_5.bungee.eaglercraft.BanList.BanState;
|
||||
|
||||
public class CommandGlobalCheckBan extends Command {
|
||||
|
||||
private final boolean replaceBukkit;
|
||||
|
||||
public CommandGlobalCheckBan(boolean replaceBukkit) {
|
||||
super(replaceBukkit ? "banned" : "eag-bannned", "bungeecord.command.eag.banned", replaceBukkit ? new String[] { "eag-banned", "isbanned", "e-banned", "gbanned", "eag-isbanned", "e-isbanned", "gisbanned" } :
|
||||
new String[] { "e-banned", "gbanned", "eag-isbanned", "e-isbanned", "gisbanned" });
|
||||
this.replaceBukkit = replaceBukkit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender p0, String[] p1) {
|
||||
if(p1.length != 1) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To check if a player or IP is banned, use: " + ChatColor.WHITE + (replaceBukkit ? "/banned" : "/eag-banned") + " <username|ip>");
|
||||
}else {
|
||||
BanCheck bc = BanList.checkBanned(p1[0]);
|
||||
if(!bc.isBanned()) {
|
||||
try {
|
||||
InetAddress addr = InetAddress.getByName(p1[0]);
|
||||
bc = BanList.checkIpBanned(addr);
|
||||
if(bc.isBanned()) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "IP address '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is banned by: "
|
||||
+ "'" + ChatColor.WHITE + bc.match + ChatColor.RED + "' " + ChatColor.YELLOW + "(" + bc.string + ")");
|
||||
return;
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
// no
|
||||
}
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Player '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' has not been banned");
|
||||
}else {
|
||||
if(bc.reason == BanState.USER_BANNED) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Player '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is banned by username, reason: "
|
||||
+ ChatColor.YELLOW + "\"" + bc.string + "\"");
|
||||
}else if(bc.reason == BanState.WILDCARD_BANNED) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Player '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is banned by wildcard: "
|
||||
+ ChatColor.WHITE + "\"" + bc.match + "\"");
|
||||
}else if(bc.reason == BanState.REGEX_BANNED) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Player '" + ChatColor.WHITE + p1[0] + ChatColor.RED + "' is banned by regex: "
|
||||
+ ChatColor.WHITE + "\"" + bc.match + "\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package net.md_5.bungee.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.eaglercraft.BanList;
|
||||
|
||||
public class CommandGlobalListBan extends Command {
|
||||
|
||||
private final boolean replaceBukkit;
|
||||
|
||||
public CommandGlobalListBan(boolean replaceBukkit) {
|
||||
super(replaceBukkit ? "banlist" : "eag-banlist", "bungeecord.command.eag.banlist", replaceBukkit ? new String[] { "eag-banlist", "gbanlist", "e-banlist",
|
||||
"gbanlist" } : new String[] { "gbanlist", "e-banlist" });
|
||||
this.replaceBukkit = replaceBukkit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender p0, String[] p1) {
|
||||
if(p1.length == 0 || (p1.length == 1 && (p1[0].equalsIgnoreCase("user") || p1[0].equalsIgnoreCase("username")
|
||||
|| p1[0].equalsIgnoreCase("users") || p1[0].equalsIgnoreCase("usernames")))) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Players banned by username: " + ChatColor.WHITE + BanList.listAllBans());
|
||||
return;
|
||||
}else if(p1.length == 1) {
|
||||
if(p1[0].equalsIgnoreCase("regex") || p1[0].equalsIgnoreCase("regexes")) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Regex ban list: " + ChatColor.WHITE + BanList.listAllRegexBans());
|
||||
return;
|
||||
}else if(p1[0].equalsIgnoreCase("wildcard") || p1[0].equalsIgnoreCase("wildcards")) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Wildcard ban list: " + ChatColor.WHITE + BanList.listAllWildcardBans());
|
||||
return;
|
||||
}else if(p1[0].equalsIgnoreCase("ip") || p1[0].equalsIgnoreCase("ips")) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To list IP bans, use: " + ChatColor.WHITE + (replaceBukkit ? "/banlist" : "/eag-banlist") + " ip <addr|netmask> [v4|v6]");
|
||||
return;
|
||||
}
|
||||
}else if(p1.length > 1 && p1.length <= 3 && (p1[0].equalsIgnoreCase("ip") || p1[0].equalsIgnoreCase("ips"))) {
|
||||
int addrOrNetmask = 0;
|
||||
if(p1[1].equalsIgnoreCase("addr") || p1[1].equalsIgnoreCase("addrs")) {
|
||||
addrOrNetmask = 1;
|
||||
}else if(p1[1].equalsIgnoreCase("netmask") || p1[1].equalsIgnoreCase("netmasks")) {
|
||||
addrOrNetmask = 2;
|
||||
}
|
||||
if(addrOrNetmask > 0) {
|
||||
boolean yes = false;
|
||||
if(p1.length == 2 || (p1.length == 3 && (p1[2].equalsIgnoreCase("v4") || p1[2].equals("4")))) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "IPv4 " + (addrOrNetmask == 2 ? "netmask" : "address") + " ban list: " + ChatColor.WHITE + BanList.listAllIPBans(false, addrOrNetmask == 2));
|
||||
yes = true;
|
||||
}
|
||||
if(p1.length == 2 || (p1.length == 3 && (p1[2].equalsIgnoreCase("v6") || p1[2].equals("6")))) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "IPv6 " + (addrOrNetmask == 2 ? "netmask" : "address") + " ban list: " + ChatColor.WHITE + BanList.listAllIPBans(true, addrOrNetmask == 2));
|
||||
yes = true;
|
||||
}
|
||||
if(yes) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To list IP bans, use: " + ChatColor.WHITE + (replaceBukkit ? "/banlist" : "/eag-banlist") + " ip <addr|netmask> [v4|v6]");
|
||||
return;
|
||||
}
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To list all user bans, use: " + ChatColor.WHITE + (replaceBukkit ? "/banlist" : "/eag-banlist"));
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To list ips, regexes, and wildcards, use: " + ChatColor.WHITE + (replaceBukkit ? "/banlist" : "/eag-banlist") + " <ip|regex|wildcard>");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package net.md_5.bungee.command;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
import net.md_5.bungee.eaglercraft.BanList;
|
||||
|
||||
public class CommandGlobalUnban extends Command {
|
||||
|
||||
private final boolean replaceBukkit;
|
||||
|
||||
public CommandGlobalUnban(boolean replaceBukkit) {
|
||||
super(replaceBukkit ? "unban" : "eag-unban", "bungeecord.command.eag.unban", replaceBukkit ? new String[] {"eag-unban", "e-unban", "gunban"} :new String[] {"e-unban", "gunban"});
|
||||
this.replaceBukkit = replaceBukkit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender p0, String[] p1) {
|
||||
if(p1.length != 2 || (!p1[0].equalsIgnoreCase("user") && !p1[0].equalsIgnoreCase("username") && !p1[0].equalsIgnoreCase("player")
|
||||
&& !p1[0].equalsIgnoreCase("wildcard") && !p1[0].equalsIgnoreCase("regex") && !p1[0].equalsIgnoreCase("ip"))) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To unban a player, use: " + ChatColor.WHITE + "/" + (replaceBukkit?"":"eag-") + "unban user <player>");
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "To unban an ip/wildcard/regex, use: " + ChatColor.WHITE + "/" + (replaceBukkit?"":"eag-") + "unban <ip|wildcard|regex> <value>");
|
||||
return;
|
||||
}
|
||||
if(p1[0].equalsIgnoreCase("user") || p1[0].equalsIgnoreCase("username") || p1[0].equalsIgnoreCase("player")) {
|
||||
if(BanList.unban(p1[1])) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "User '" + ChatColor.WHITE + p1[1] + ChatColor.GREEN + "' was unbanned");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "User '" + ChatColor.WHITE + p1[1] + ChatColor.RED + "' is not banned");
|
||||
}
|
||||
}else if(p1[0].equalsIgnoreCase("ip")) {
|
||||
try {
|
||||
if(BanList.unbanIP(p1[1])) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "IP '" + ChatColor.WHITE + p1[1] + ChatColor.GREEN + "' was unbanned");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "IP '" + ChatColor.WHITE + p1[1] + ChatColor.RED + "' is not banned");
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "IP address '" + ChatColor.WHITE + p1[1] + ChatColor.RED + "' is invalid: " + t.getMessage());
|
||||
}
|
||||
}else if(p1[0].equalsIgnoreCase("wildcard")) {
|
||||
if(BanList.unbanWildcard(p1[1])) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Wildcard '" + ChatColor.WHITE + p1[1] + ChatColor.GREEN + "' was unbanned");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Wildcard '" + ChatColor.WHITE + p1[1] + ChatColor.RED + "' is not banned");
|
||||
}
|
||||
}else if(p1[0].equalsIgnoreCase("regex")) {
|
||||
if(BanList.unbanRegex(p1[1])) {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.GREEN + "Regex '" + ChatColor.WHITE + p1[1] + ChatColor.GREEN + "' was unbanned");
|
||||
}else {
|
||||
p0.sendMessage(BanList.banChatMessagePrefix + ChatColor.RED + "Regex '" + ChatColor.WHITE + p1[1] + ChatColor.RED + "' is not banned");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -6,6 +6,9 @@ package net.md_5.bungee.command;
|
|||
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.plugin.Command;
|
||||
|
@ -25,7 +28,12 @@ public class CommandIP extends Command {
|
|||
if (user == null) {
|
||||
sender.sendMessage(ChatColor.RED + "That user is not online");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.BLUE + "IP of " + args[0] + " is " + user.getAddress());
|
||||
Object o = user.getAttachment().get("remoteAddr");
|
||||
if(o != null) {
|
||||
sender.sendMessage(ChatColor.BLUE + "IP of " + args[0] + " is " + (InetAddress)o);
|
||||
}else {
|
||||
sender.sendMessage(ChatColor.BLUE + "IP of " + args[0] + " is " + user.getAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,16 @@
|
|||
|
||||
package net.md_5.bungee.command;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.Collection;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
|
||||
public class ConsoleCommandSender implements CommandSender {
|
||||
private static final ConsoleCommandSender instance;
|
||||
private static final Map<String, Object> attachment = new WeakHashMap();
|
||||
|
||||
private ConsoleCommandSender() {
|
||||
}
|
||||
|
@ -65,4 +67,9 @@ public class ConsoleCommandSender implements CommandSender {
|
|||
static {
|
||||
instance = new ConsoleCommandSender();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAttachment() {
|
||||
return attachment;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.google.common.base.Preconditions;
|
|||
import net.md_5.bungee.api.ProxyServer;
|
||||
import java.util.UUID;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.eaglercraft.EaglercraftBungee;
|
||||
import gnu.trove.map.TMap;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import java.util.Collection;
|
||||
|
@ -24,6 +25,7 @@ public class Configuration {
|
|||
private AuthServiceInfo authInfo;
|
||||
private boolean onlineMode;
|
||||
private int playerLimit;
|
||||
private String name;
|
||||
|
||||
public Configuration() {
|
||||
this.timeout = 30000;
|
||||
|
@ -38,9 +40,17 @@ public class Configuration {
|
|||
this.listeners = adapter.getListeners();
|
||||
this.timeout = adapter.getInt("timeout", this.timeout);
|
||||
this.uuid = adapter.getString("stats", this.uuid);
|
||||
if(this.uuid.equalsIgnoreCase("595698b3-9c36-4e86-b1ee-cb3027038f41")) {
|
||||
this.uuid = UUID.randomUUID().toString();
|
||||
System.err.println("Notice: this server has the stats UUID \"595698b3-9c36-4e86-b1ee-cb3027038f41\" which is a known duplicate");
|
||||
System.err.println("It has been updated to \"" + this.uuid + "\". This is not an error");
|
||||
adapter.getMap().put("stats", this.uuid);
|
||||
adapter.forceSave();
|
||||
}
|
||||
this.authInfo = adapter.getAuthSettings();
|
||||
this.onlineMode = false;
|
||||
this.playerLimit = adapter.getInt("player_limit", this.playerLimit);
|
||||
this.name = adapter.getString("server_name", EaglercraftBungee.name + " Server");
|
||||
Preconditions.checkArgument(this.listeners != null && !this.listeners.isEmpty(), (Object) "No listeners defined.");
|
||||
final Map<String, ServerInfo> newServers = adapter.getServers();
|
||||
Preconditions.checkArgument(newServers != null && !newServers.isEmpty(), (Object) "No servers defined");
|
||||
|
@ -88,4 +98,8 @@ public class Configuration {
|
|||
public AuthServiceInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,13 @@ import net.md_5.bungee.tab.ServerUnique;
|
|||
import net.md_5.bungee.tab.GlobalPing;
|
||||
import net.md_5.bungee.tab.Global;
|
||||
import net.md_5.bungee.api.tab.TabListHandler;
|
||||
import net.md_5.bungee.eaglercraft.WebSocketRateLimiter;
|
||||
import net.md_5.bungee.api.config.TexturePackInfo;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import java.util.HashSet;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.MOTDCacheConfiguration;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Iterator;
|
||||
|
@ -24,6 +27,7 @@ import java.io.FileWriter;
|
|||
import java.util.LinkedHashMap;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.io.IOException;
|
||||
|
@ -67,18 +71,11 @@ public class YamlConfig implements ConfigurationAdapter {
|
|||
final Map<String, Object> permissions = this.get("permissions", new HashMap<String, Object>());
|
||||
if (permissions.isEmpty()) {
|
||||
permissions.put("default", Arrays.asList("bungeecord.command.server", "bungeecord.command.list"));
|
||||
permissions.put("admin", Arrays.asList("bungeecord.command.alert", "bungeecord.command.end", "bungeecord.command.ip", "bungeecord.command.reload"));
|
||||
permissions.put("admin", Arrays.asList("bungeecord.command.alert", "bungeecord.command.end", "bungeecord.command.ip", "bungeecord.command.reload",
|
||||
"bungeecord.command.eag.ban", "bungeecord.command.eag.banwildcard", "bungeecord.command.eag.banip", "bungeecord.command.eag.banregex",
|
||||
"bungeecord.command.eag.reloadban", "bungeecord.command.eag.banned", "bungeecord.command.eag.banlist", "bungeecord.command.eag.unban", "bungeecord.command.eag.ratelimit"));
|
||||
}
|
||||
this.get("groups", new HashMap<String, Object>());
|
||||
/*
|
||||
final Map<String, Object> auth = this.get("authservice", new HashMap<String, Object>());
|
||||
if(auth.isEmpty()) {
|
||||
auth.put("enabled", false);
|
||||
auth.put("limbo", "lobby");
|
||||
auth.put("authfile", "passwords.yml");
|
||||
auth.put("timeout", 30);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private <T> T get(final String path, final T def) {
|
||||
|
@ -152,13 +149,25 @@ public class YamlConfig implements ConfigurationAdapter {
|
|||
//forcedDef.put("pvp.md-5.net", "pvp");
|
||||
final Collection<ListenerInfo> ret = new HashSet<ListenerInfo>();
|
||||
for (final Map<String, Object> val : base) {
|
||||
String motd = this.get("motd", "&6&lbungeecord eaglercraft server |>", val);
|
||||
String motd = this.get("motd", null, val);
|
||||
if(motd != null) {
|
||||
val.remove("motd");
|
||||
}
|
||||
motd = this.get("motd1", motd, val);
|
||||
if(motd == null) {
|
||||
motd = this.get("motd1", "&6An Eaglercraft server", val);
|
||||
}
|
||||
motd = ChatColor.translateAlternateColorCodes('&', motd);
|
||||
String motd2 = this.get("motd2", null, val);
|
||||
if(motd2 != null && motd2.length() > 0) {
|
||||
motd = motd + "\n" + ChatColor.translateAlternateColorCodes('&', motd2);
|
||||
}
|
||||
final int maxPlayers = this.get("max_players", 60, val);
|
||||
final String defaultServer = this.get("default_server", "lobby", val);
|
||||
final String fallbackServer = this.get("fallback_server", defaultServer, val);
|
||||
final boolean forceDefault = this.get("force_default_server", true, val);
|
||||
final boolean websocket = this.get("websocket", true, val);
|
||||
final boolean forwardIp = this.get("forward_ip", false, val);
|
||||
final String host = this.get("host", "0.0.0.0:25565", val);
|
||||
final int tabListSize = this.get("tab_size", 60, val);
|
||||
final InetSocketAddress address = Util.getAddr(host);
|
||||
|
@ -167,15 +176,77 @@ public class YamlConfig implements ConfigurationAdapter {
|
|||
final int textureSize = this.get("texture_size", 16, val);
|
||||
final TexturePackInfo texture = (textureURL == null) ? null : new TexturePackInfo(textureURL, textureSize);
|
||||
final String tabListName = this.get("tab_list", "GLOBAL_PING", val);
|
||||
final String serverIcon = this.get("server_icon", "server-icon.png", val);
|
||||
final boolean allowMOTD = this.get("allow_motd", true, val);
|
||||
final boolean allowQuery = this.get("allow_query", true, val);
|
||||
final MOTDCacheConfiguration cacheConfig = readCacheConfiguration(this.get("request_motd_cache", new HashMap<String, Object>(), val));
|
||||
|
||||
WebSocketRateLimiter ratelimitIP = null;
|
||||
WebSocketRateLimiter ratelimitLogin = null;
|
||||
WebSocketRateLimiter ratelimitMOTD = null;
|
||||
WebSocketRateLimiter ratelimitQuery = null;
|
||||
final Map<String, Object> rateLimits = this.get("ratelimit", new HashMap<String, Object>(), val);
|
||||
final Map<String, Object> ratelimitIPConfig = this.get("ip", new HashMap<String, Object>(), rateLimits);
|
||||
final Map<String, Object> ratelimitLoginConfig = this.get("login", new HashMap<String, Object>(), rateLimits);
|
||||
final Map<String, Object> ratelimitMOTDConfig = this.get("motd", new HashMap<String, Object>(), rateLimits);
|
||||
final Map<String, Object> ratelimitQueryConfig = this.get("query", new HashMap<String, Object>(), rateLimits);
|
||||
|
||||
if(this.get("enable", true, ratelimitIPConfig)) {
|
||||
ratelimitIP = new WebSocketRateLimiter(
|
||||
this.get("period", 90, ratelimitIPConfig),
|
||||
this.get("limit", 60, ratelimitIPConfig),
|
||||
this.get("limit_lockout", 80, ratelimitIPConfig),
|
||||
this.get("lockout_duration", 1200, ratelimitIPConfig),
|
||||
this.get("exceptions", new ArrayList<String>(), ratelimitIPConfig)
|
||||
);
|
||||
}
|
||||
if(this.get("enable", true, ratelimitLoginConfig)) {
|
||||
ratelimitLogin = new WebSocketRateLimiter(
|
||||
this.get("period", 50, ratelimitLoginConfig),
|
||||
this.get("limit", 5, ratelimitLoginConfig),
|
||||
this.get("limit_lockout", 10, ratelimitLoginConfig),
|
||||
this.get("lockout_duration", 300, ratelimitLoginConfig),
|
||||
this.get("exceptions", new ArrayList<String>(), ratelimitLoginConfig)
|
||||
);
|
||||
}
|
||||
if(this.get("enable", true, ratelimitMOTDConfig)) {
|
||||
ratelimitMOTD = new WebSocketRateLimiter(
|
||||
this.get("period", 30, ratelimitMOTDConfig),
|
||||
this.get("limit", 5, ratelimitMOTDConfig),
|
||||
this.get("limit_lockout", 15, ratelimitMOTDConfig),
|
||||
this.get("lockout_duration", 1200, ratelimitMOTDConfig),
|
||||
this.get("exceptions", new ArrayList<String>(), ratelimitMOTDConfig)
|
||||
);
|
||||
}
|
||||
if(this.get("enable", true, ratelimitQueryConfig)) {
|
||||
ratelimitQuery = new WebSocketRateLimiter(
|
||||
this.get("period", 90, ratelimitQueryConfig),
|
||||
this.get("limit", 60, ratelimitQueryConfig),
|
||||
this.get("limit_lockout", 80, ratelimitQueryConfig),
|
||||
this.get("lockout_duration", 1200, ratelimitQueryConfig),
|
||||
this.get("exceptions", new ArrayList<String>(), ratelimitQueryConfig)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
DefaultTabList value = DefaultTabList.valueOf(tabListName.toUpperCase());
|
||||
if (value == null) {
|
||||
value = DefaultTabList.GLOBAL_PING;
|
||||
}
|
||||
final ListenerInfo info = new ListenerInfo(address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, websocket, forced, texture, value.clazz);
|
||||
ret.add(info);
|
||||
ret.add(new ListenerInfo(host, address, motd, maxPlayers, tabListSize, defaultServer, fallbackServer, forceDefault, websocket, forwardIp,
|
||||
forced, texture, value.clazz, serverIcon, cacheConfig, allowMOTD, allowQuery, ratelimitIP, ratelimitLogin, ratelimitMOTD, ratelimitQuery));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private MOTDCacheConfiguration readCacheConfiguration(Map<String, Object> val) {
|
||||
final int ttl = this.get("cache_ttl", 7200, val);
|
||||
final boolean anim = this.get("online_server_list_animation", false, val);
|
||||
final boolean results = this.get("online_server_list_results", true, val);
|
||||
final boolean trending = this.get("online_server_list_trending", true, val);
|
||||
final boolean portfolios = this.get("online_server_list_portfolios", false, val);
|
||||
return new MOTDCacheConfiguration(ttl, anim, results, trending, portfolios);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getGroups(final String player) {
|
||||
|
@ -206,4 +277,15 @@ public class YamlConfig implements ConfigurationAdapter {
|
|||
//return new AuthServiceInfo(this.get("enabled", true, auth), this.get("limbo", "lobby", auth), new File(this.get("authfile", "passwords.yml", auth)), this.get("timeout", 30, auth));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getMap() {
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceSave() {
|
||||
this.save();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ package net.md_5.bungee.connection;
|
|||
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.util.ArrayList;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import net.md_5.bungee.protocol.packet.PacketFFKick;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
|
@ -37,6 +38,9 @@ import net.md_5.bungee.protocol.Forge;
|
|||
import net.md_5.bungee.netty.PacketDecoder;
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
import net.md_5.bungee.eaglercraft.BanList;
|
||||
import net.md_5.bungee.eaglercraft.WebSocketProxy;
|
||||
import net.md_5.bungee.eaglercraft.BanList.BanCheck;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.protocol.packet.PacketFEPing;
|
||||
import net.md_5.bungee.Util;
|
||||
|
@ -112,23 +116,63 @@ public class InitialHandler extends PacketHandler implements PendingConnection {
|
|||
if (handshake.getProcolVersion() == 69) {
|
||||
skipEncryption = true;
|
||||
this.handshake.swapProtocol((byte) 61);
|
||||
}else if(handshake.getProcolVersion() == 71) {
|
||||
this.disconnect("this server does not support microsoft accounts");
|
||||
return;
|
||||
}else if(handshake.getProcolVersion() != 61) {
|
||||
this.disconnect("minecraft 1.5.2 required for eaglercraft backdoor access");
|
||||
return;
|
||||
}
|
||||
if (handshake.getUsername().length() < 3) {
|
||||
String un = handshake.getUsername();
|
||||
if (un.length() < 3) {
|
||||
this.disconnect("Username must be at least 3 characters");
|
||||
return;
|
||||
}
|
||||
if (handshake.getUsername().length() > 16) {
|
||||
if (un.length() > 16) {
|
||||
this.disconnect("Cannot have username longer than 16 characters");
|
||||
return;
|
||||
}
|
||||
if(!un.equals(un.replaceAll("[^A-Za-z0-9\\-_]", "_").trim())) {
|
||||
this.disconnect("Go fuck yourself");
|
||||
return;
|
||||
}
|
||||
InetAddress sc = WebSocketProxy.localToRemote.get(this.ch.getHandle().remoteAddress());
|
||||
if(sc == null) {
|
||||
System.out.println("WARNING: player '" + un + "' doesn't have a websocket IP, remote address: " + this.ch.getHandle().remoteAddress().toString());
|
||||
}else {
|
||||
BanCheck bc = BanList.checkIpBanned(sc);
|
||||
if(bc.isBanned()) {
|
||||
System.err.println("Player '" + un + "' [" + sc.toString() + "] is banned by IP: " + bc.match + " (" + bc.string + ")");
|
||||
this.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: " + bc.string);
|
||||
return;
|
||||
}else {
|
||||
System.out.println("Player '" + un + "' [" + sc.toString() + "] has remote websocket IP: " + sc.getHostAddress());
|
||||
}
|
||||
}
|
||||
BanCheck bc = BanList.checkBanned(un);
|
||||
if(bc.isBanned()) {
|
||||
switch(bc.reason) {
|
||||
case USER_BANNED:
|
||||
System.err.println("Player '" + un + "' is banned by username, because '" + bc.string + "'");
|
||||
break;
|
||||
case WILDCARD_BANNED:
|
||||
System.err.println("Player '" + un + "' is banned by wildcard: " + bc.match);
|
||||
break;
|
||||
case REGEX_BANNED:
|
||||
System.err.println("Player '" + un + "' is banned by regex: " + bc.match);
|
||||
break;
|
||||
default:
|
||||
System.err.println("Player '" + un + "' is banned: " + bc.string);
|
||||
}
|
||||
this.disconnect("" + ChatColor.RED + "You are banned.\n" + ChatColor.DARK_GRAY + "Reason: " + bc.string);
|
||||
return;
|
||||
}
|
||||
final int limit = BungeeCord.getInstance().config.getPlayerLimit();
|
||||
if (limit > 0 && this.bungee.getOnlineCount() > limit) {
|
||||
this.disconnect(this.bungee.getTranslation("proxy_full"));
|
||||
return;
|
||||
}
|
||||
if (!BungeeCord.getInstance().config.isOnlineMode() && this.bungee.getPlayer(handshake.getUsername()) != null) {
|
||||
if (!BungeeCord.getInstance().config.isOnlineMode() && this.bungee.getPlayer(un) != null) {
|
||||
this.disconnect(this.bungee.getTranslation("already_connected"));
|
||||
return;
|
||||
}
|
||||
|
@ -189,6 +233,10 @@ public class InitialHandler extends PacketHandler implements PendingConnection {
|
|||
public void handle(final PacketCDClientStatus clientStatus) throws Exception {
|
||||
Preconditions.checkState(this.thisState == State.LOGIN, (Object) "Not expecting LOGIN");
|
||||
final UserConnection userCon = new UserConnection(this.bungee, this.ch, this.getName(), this);
|
||||
InetAddress ins = WebSocketProxy.localToRemote.get(this.ch.getHandle().remoteAddress());
|
||||
if(ins != null) {
|
||||
userCon.getAttachment().put("remoteAddr", ins);
|
||||
}
|
||||
userCon.init();
|
||||
this.bungee.getPluginManager().callEvent(new PostLoginEvent(userCon));
|
||||
((HandlerBoss) this.ch.getHandle().pipeline().get((Class) HandlerBoss.class)).setHandler(new UpstreamBridge(this.bungee, userCon));
|
||||
|
|
|
@ -0,0 +1,872 @@
|
|||
package net.md_5.bungee.eaglercraft;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.math.BigInteger;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.eaglercraft.sun.net.util.IPAddressUtil;
|
||||
|
||||
public class BanList {
|
||||
|
||||
private static final Object banListMutex = new Object();
|
||||
|
||||
public static enum BanState {
|
||||
NOT_BANNED, USER_BANNED, IP_BANNED, WILDCARD_BANNED, REGEX_BANNED;
|
||||
}
|
||||
|
||||
public static class BanCheck {
|
||||
public final BanState reason;
|
||||
public final String match;
|
||||
public final String string;
|
||||
private BanCheck(BanState reason, String match, String string) {
|
||||
this.reason = reason;
|
||||
this.match = match;
|
||||
this.string = string;
|
||||
}
|
||||
public boolean isBanned() {
|
||||
return reason != BanState.NOT_BANNED;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RegexBan {
|
||||
public final String string;
|
||||
public final Pattern compiled;
|
||||
private RegexBan(String string, Pattern compiled) {
|
||||
this.string = string;
|
||||
this.compiled = compiled;
|
||||
}
|
||||
public String toString() {
|
||||
return string;
|
||||
}
|
||||
public int hashCode() {
|
||||
return string.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public static interface IPBan {
|
||||
|
||||
boolean checkBan(InetAddress addr);
|
||||
InetAddress getBaseAddress();
|
||||
boolean hasNetMask();
|
||||
|
||||
}
|
||||
|
||||
private static class IPBan4 implements IPBan {
|
||||
|
||||
private final int addr;
|
||||
private final InetAddress addrI;
|
||||
private final int mask;
|
||||
private final String string;
|
||||
|
||||
protected IPBan4(Inet4Address addr, String s, int mask) {
|
||||
if(mask >= 32) {
|
||||
this.mask = 0xFFFFFFFF;
|
||||
}else {
|
||||
this.mask = ~((1 << (32 - mask)) - 1);
|
||||
}
|
||||
this.string = s;
|
||||
byte[] bits = addr.getAddress();
|
||||
this.addr = this.mask & ((bits[0] << 24) | (bits[1] << 16) | (bits[2] << 8) | (bits[3] & 0xFF));
|
||||
this.addrI = addr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkBan(InetAddress addr4) {
|
||||
if(addr4 instanceof Inet4Address) {
|
||||
Inet4Address a = (Inet4Address)addr4;
|
||||
byte[] bits = a.getAddress();
|
||||
int addrBits = ((bits[0] << 24) | (bits[1] << 16) | (bits[2] << 8) | (bits[3] & 0xFF));
|
||||
return (mask & addrBits) == addr;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getBaseAddress() {
|
||||
return addrI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return string.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o != null && o instanceof IPBan4 && ((IPBan4)o).addr == addr && ((IPBan4)o).mask == mask;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNetMask() {
|
||||
return mask != 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class IPBan6 implements IPBan {
|
||||
|
||||
private static final BigInteger mask128 = new BigInteger(1, new byte[] {
|
||||
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
|
||||
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
|
||||
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,
|
||||
(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF
|
||||
});
|
||||
|
||||
private final BigInteger addr;
|
||||
private final InetAddress addrI;
|
||||
private final BigInteger mask;
|
||||
private final String string;
|
||||
|
||||
protected IPBan6(Inet6Address addr, String s, int mask) {
|
||||
this.mask = BigInteger.valueOf(1l).shiftLeft(128 - mask).subtract(BigInteger.valueOf(1l)).xor(mask128);
|
||||
this.string = s.toLowerCase();
|
||||
this.addr = new BigInteger(1, addr.getAddress()).and(this.mask);
|
||||
this.addrI = addr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkBan(InetAddress addr6) {
|
||||
if(addr6 instanceof Inet6Address) {
|
||||
Inet6Address a = (Inet6Address)addr6;
|
||||
BigInteger addrBits = new BigInteger(1, a.getAddress()).and(this.mask);
|
||||
return addr.equals(addrBits);
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getBaseAddress() {
|
||||
return addrI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return string.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o != null && o instanceof IPBan6 && ((IPBan6)o).addr.equals(addr) && ((IPBan6)o).mask.equals(mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNetMask() {
|
||||
return !mask.equals(mask128);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final File bansFile = new File("bans.txt");
|
||||
|
||||
public static final String banChatMessagePrefix = ChatColor.GOLD + "[BanList] ";
|
||||
|
||||
public static final Map<String,String> userBans = new HashMap();
|
||||
public static final Set<IPBan> ipBans = new HashSet();
|
||||
public static final Set<String> wildcardBans = new HashSet();
|
||||
public static final Set<RegexBan> regexBans = new HashSet();
|
||||
private static List<String> currentBanList = null;
|
||||
|
||||
public static final List<IPBan> blockedBans = new ArrayList();
|
||||
|
||||
static {
|
||||
try {
|
||||
blockedBans.add(constructIpBan("127.0.0.0/8"));
|
||||
}catch(UnknownHostException e) {
|
||||
System.err.println("Error: could not whitelist '127.0.0.0/8'");
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
blockedBans.add(constructIpBan("10.0.0.0/8"));
|
||||
}catch(UnknownHostException e) {
|
||||
System.err.println("Error: could not whitelist '10.0.0.0/8'");
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
blockedBans.add(constructIpBan("172.24.0.0/14"));
|
||||
}catch(UnknownHostException e) {
|
||||
System.err.println("Error: could not whitelist '172.24.0.0/14'");
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
blockedBans.add(constructIpBan("192.168.0.0/16"));
|
||||
}catch(UnknownHostException e) {
|
||||
System.err.println("Error: could not whitelist '192.168.0.0/16'");
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
blockedBans.add(constructIpBan("::1/128"));
|
||||
}catch(UnknownHostException e) {
|
||||
System.err.println("Error: could not whitelist '::1/128'");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isBlockedBan(InetAddress addr) {
|
||||
for(IPBan b : BanList.blockedBans) {
|
||||
if(b.checkBan(addr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static long lastListTest = 0l;
|
||||
private static long lastListLoad = 0l;
|
||||
private static boolean fileIsBroken = false;
|
||||
|
||||
public static BanCheck checkIpBanned(InetAddress addr) {
|
||||
synchronized(banListMutex) {
|
||||
for(IPBan b : ipBans) {
|
||||
if(b.checkBan(addr)) {
|
||||
return new BanCheck(BanState.IP_BANNED, b.toString(), b.hasNetMask() ? "Banned by Netmask" : "Banned by IP");
|
||||
}
|
||||
}
|
||||
}
|
||||
return new BanCheck(BanState.NOT_BANNED, "none", "not banned");
|
||||
}
|
||||
|
||||
public static BanCheck checkBanned(String player) {
|
||||
synchronized(banListMutex) {
|
||||
player = player.trim().toLowerCase();
|
||||
String r = userBans.get(player);
|
||||
if(r != null) {
|
||||
if(r.length() <= 0) {
|
||||
r = "The ban hammer has spoken";
|
||||
}
|
||||
return new BanCheck(BanState.USER_BANNED, player, r);
|
||||
}
|
||||
for(String ss : wildcardBans) {
|
||||
String s = ss;
|
||||
boolean startStar = s.startsWith("*");
|
||||
if(startStar) {
|
||||
s = s.substring(1);
|
||||
}
|
||||
boolean endStar = s.endsWith("*");
|
||||
if(endStar) {
|
||||
s = s.substring(0, s.length() - 1);
|
||||
}
|
||||
if(startStar && endStar) {
|
||||
if(player.contains(s)) {
|
||||
return new BanCheck(BanState.WILDCARD_BANNED, ss, "You've been banned via wildcard");
|
||||
}
|
||||
}else if(endStar) {
|
||||
if(player.startsWith(s)) {
|
||||
return new BanCheck(BanState.WILDCARD_BANNED, ss, "You've been banned via wildcard");
|
||||
}
|
||||
}else if(startStar) {
|
||||
if(player.endsWith(s)) {
|
||||
return new BanCheck(BanState.WILDCARD_BANNED, ss, "You've been banned via wildcard");
|
||||
}
|
||||
}else {
|
||||
if(player.equals(s)) {
|
||||
return new BanCheck(BanState.WILDCARD_BANNED, ss, "You've been banned via wildcard");
|
||||
}
|
||||
}
|
||||
}
|
||||
for(RegexBan p : regexBans) {
|
||||
if(p.compiled.matcher(player).matches()) {
|
||||
return new BanCheck(BanState.REGEX_BANNED, p.string, "You've been banned via regex");
|
||||
}
|
||||
}
|
||||
}
|
||||
return new BanCheck(BanState.NOT_BANNED, "none", "not banned");
|
||||
}
|
||||
|
||||
private static void saveCurrentBanListLines() {
|
||||
try {
|
||||
PrintWriter pf = new PrintWriter(new FileWriter(bansFile));
|
||||
for(String s : currentBanList) {
|
||||
pf.println(s);
|
||||
}
|
||||
pf.close();
|
||||
lastListLoad = lastListTest = System.currentTimeMillis();
|
||||
}catch(Throwable t) {
|
||||
System.err.println("ERROR: the ban list could not be saved to file '" + bansFile.getName() + "', please fix this or you will lose all your bans next time this server restarts");
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean addEntryToFile(BanState b, String s) {
|
||||
if(b == null || b == BanState.NOT_BANNED) {
|
||||
return false;
|
||||
}
|
||||
String wantedHeader = b == BanState.USER_BANNED ? "[Usernames]" : (b == BanState.WILDCARD_BANNED ? "[Wildcards]" : (b == BanState.REGEX_BANNED ? "[Regex]" : (b == BanState.IP_BANNED ? "[IPs]" : "shit")));
|
||||
int lastFullPart = -1;
|
||||
boolean isFilePart = false;
|
||||
boolean isPartStart = false;
|
||||
for(int i = 0, l = currentBanList.size(); i < l; ++i) {
|
||||
String ss = currentBanList.get(i).trim();
|
||||
if(ss.length() <= 0) {
|
||||
continue;
|
||||
}
|
||||
if(ss.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
if(ss.equalsIgnoreCase(wantedHeader)) {
|
||||
isFilePart = true;
|
||||
isPartStart = true;
|
||||
lastFullPart = i;
|
||||
}else if(ss.indexOf('[') != -1) {
|
||||
if(isFilePart) {
|
||||
break;
|
||||
}
|
||||
}else {
|
||||
if(isFilePart) {
|
||||
lastFullPart = i;
|
||||
isPartStart = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(lastFullPart != -1) {
|
||||
if(isPartStart) {
|
||||
lastFullPart += 1;
|
||||
currentBanList.add(lastFullPart, "");
|
||||
}
|
||||
lastFullPart += 1;
|
||||
currentBanList.add(lastFullPart, s);
|
||||
lastFullPart += 1;
|
||||
if(currentBanList.size() > lastFullPart && currentBanList.get(lastFullPart).trim().length() > 0) {
|
||||
currentBanList.add(lastFullPart, "");
|
||||
}
|
||||
}else {
|
||||
if(currentBanList.size() > 0 && currentBanList.get(currentBanList.size() - 1).trim().length() > 0) {
|
||||
currentBanList.add("");
|
||||
}
|
||||
currentBanList.add(wantedHeader);
|
||||
currentBanList.add("");
|
||||
currentBanList.add(s);
|
||||
currentBanList.add("");
|
||||
}
|
||||
saveCurrentBanListLines();
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean removeEntryFromFile(BanState b, String s, boolean ignoreCase) {
|
||||
if(b == null || b == BanState.NOT_BANNED) {
|
||||
return false;
|
||||
}
|
||||
String wantedHeader = b == BanState.USER_BANNED ? "[Usernames]" : (b == BanState.WILDCARD_BANNED ? "[Wildcards]" : (b == BanState.REGEX_BANNED ? "[Regex]" : (b == BanState.IP_BANNED ? "[IPs]" : "shit")));
|
||||
Iterator<String> lns = currentBanList.iterator();
|
||||
boolean isFilePart = false;
|
||||
boolean wasRemoved = false;
|
||||
while(lns.hasNext()) {
|
||||
String ss = lns.next().trim();
|
||||
if(ss.length() <= 0) {
|
||||
continue;
|
||||
}
|
||||
if(ss.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
if(ss.equalsIgnoreCase(wantedHeader)) {
|
||||
isFilePart = true;
|
||||
}else if(ss.indexOf('[') != -1) {
|
||||
isFilePart = false;
|
||||
}else {
|
||||
if(b == BanState.USER_BANNED && ss.contains(":")) {
|
||||
ss = ss.substring(0, ss.indexOf(':')).trim();
|
||||
}
|
||||
if(isFilePart && (ignoreCase ? ss.equalsIgnoreCase(s) : ss.equals(s))) {
|
||||
lns.remove();
|
||||
wasRemoved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(wasRemoved) {
|
||||
saveCurrentBanListLines();
|
||||
}
|
||||
return wasRemoved;
|
||||
}
|
||||
|
||||
public static boolean unban(String player) {
|
||||
synchronized(banListMutex) {
|
||||
String s = player.trim().toLowerCase();
|
||||
if(userBans.remove(s) != null) {
|
||||
removeEntryFromFile(BanState.USER_BANNED, player, true);
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean ban(String player, String reason) {
|
||||
synchronized(banListMutex) {
|
||||
player = player.trim().toLowerCase();
|
||||
if(userBans.put(player, reason) == null) {
|
||||
addEntryToFile(BanState.USER_BANNED, player + (reason == null || reason.length() <= 0 ? "" : ": " + reason));
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean banWildcard(String wc) throws PatternSyntaxException {
|
||||
synchronized(banListMutex) {
|
||||
wc = wc.trim().toLowerCase();
|
||||
boolean b = wc.contains("*");
|
||||
if(!b || (b && !wc.startsWith("*") && !wc.endsWith("*"))) {
|
||||
throw new PatternSyntaxException("Wildcard can only begin and/or end with *", wc, 0);
|
||||
}
|
||||
if(wildcardBans.add(wc)) {
|
||||
addEntryToFile(BanState.WILDCARD_BANNED, wc);
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean unbanWildcard(String wc) {
|
||||
synchronized(banListMutex) {
|
||||
wc = wc.trim().toLowerCase();
|
||||
if(wildcardBans.remove(wc)) {
|
||||
removeEntryFromFile(BanState.WILDCARD_BANNED, wc, true);
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean banRegex(String regex) throws PatternSyntaxException {
|
||||
synchronized(banListMutex) {
|
||||
regex = regex.trim();
|
||||
Pattern p = Pattern.compile(regex);
|
||||
if(regexBans.add(new RegexBan(regex, p))) {
|
||||
addEntryToFile(BanState.REGEX_BANNED, regex);
|
||||
return true;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean unbanRegex(String regex) {
|
||||
synchronized(banListMutex) {
|
||||
regex = regex.trim();
|
||||
Iterator<RegexBan> banz = regexBans.iterator();
|
||||
while(banz.hasNext()) {
|
||||
if(banz.next().string.equals(regex)) {
|
||||
banz.remove();
|
||||
removeEntryFromFile(BanState.REGEX_BANNED, regex, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static IPBan constructIpBan(String ip) throws UnknownHostException {
|
||||
synchronized(banListMutex) {
|
||||
ip = ip.trim();
|
||||
String s = ip;
|
||||
int subnet = -1;
|
||||
int i = s.indexOf('/');
|
||||
if(i != -1) {
|
||||
String s2 = s.substring(i + 1);
|
||||
s = s.substring(0, i);
|
||||
try {
|
||||
subnet = Integer.parseInt(s2);
|
||||
}catch(Throwable t) {
|
||||
throw new UnknownHostException("Invalid netmask: '" + s + "'");
|
||||
}
|
||||
}
|
||||
|
||||
if(!IPAddressUtil.isIPv4LiteralAddress(s) && !IPAddressUtil.isIPv6LiteralAddress(s)) {
|
||||
throw new UnknownHostException("Invalid address: '" + s + "'");
|
||||
}
|
||||
|
||||
InetAddress aa = InetAddress.getByName(s);
|
||||
if(aa instanceof Inet4Address) {
|
||||
if(subnet > 32 || subnet < -1) {
|
||||
throw new UnknownHostException("IPv4 netmask '" + subnet + "' is invalid");
|
||||
}
|
||||
if(subnet == -1) {
|
||||
subnet = 32;
|
||||
}
|
||||
return new IPBan4((Inet4Address)aa, ip, subnet);
|
||||
}else if(aa instanceof Inet6Address) {
|
||||
if(subnet > 128 || subnet < -1) {
|
||||
throw new UnknownHostException("IPv6 netmask '" + subnet + "' is invalid");
|
||||
}
|
||||
if(subnet == -1) {
|
||||
subnet = 128;
|
||||
}
|
||||
return new IPBan6((Inet6Address)aa, ip, subnet);
|
||||
}else {
|
||||
throw new UnknownHostException("Only ipv4 and ipv6 addresses allowed in Eaglercraft");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean banIP(String ip) throws UnknownHostException {
|
||||
synchronized(banListMutex) {
|
||||
ip = ip.trim();
|
||||
IPBan b = constructIpBan(ip);
|
||||
if(b != null) {
|
||||
if(ipBans.add(b)) {
|
||||
addEntryToFile(BanState.IP_BANNED, ip);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean unbanIP(String ip) throws UnknownHostException {
|
||||
synchronized(banListMutex) {
|
||||
ip = ip.trim();
|
||||
IPBan b = constructIpBan(ip);
|
||||
if(b != null) {
|
||||
Iterator<IPBan> banz = ipBans.iterator();
|
||||
while(banz.hasNext()) {
|
||||
IPBan bb = banz.next();
|
||||
if(bb.equals(b)) {
|
||||
banz.remove();
|
||||
removeEntryFromFile(BanState.IP_BANNED, bb.toString(), true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MAX_CHAT_LENGTH = 118;
|
||||
|
||||
public static String listAllBans() {
|
||||
synchronized(banListMutex) {
|
||||
String ret = "";
|
||||
for(String s : userBans.keySet()) {
|
||||
if(ret.length() > 0) {
|
||||
ret += ", ";
|
||||
}
|
||||
ret += s;
|
||||
}
|
||||
return ret.length() > 0 ? ret : "(none)";
|
||||
}
|
||||
}
|
||||
|
||||
public static String listAllWildcardBans() {
|
||||
synchronized(banListMutex) {
|
||||
String ret = "";
|
||||
for(String s : wildcardBans) {
|
||||
if(ret.length() > 0) {
|
||||
ret += ", ";
|
||||
}
|
||||
ret += s;
|
||||
}
|
||||
return ret.length() > 0 ? ret : "(none)";
|
||||
}
|
||||
}
|
||||
|
||||
public static String listAllRegexBans() {
|
||||
synchronized(banListMutex) {
|
||||
String ret = "";
|
||||
for(RegexBan s : regexBans) {
|
||||
if(ret.length() > 0) {
|
||||
ret += " | ";
|
||||
}
|
||||
ret += s.string;
|
||||
}
|
||||
return ret.length() > 0 ? ret : "(none)";
|
||||
}
|
||||
}
|
||||
|
||||
public static String listAllIPBans(boolean v6, boolean netmask) {
|
||||
synchronized(banListMutex) {
|
||||
String ret = "";
|
||||
for(IPBan b : ipBans) {
|
||||
if(v6) {
|
||||
if(b instanceof IPBan6) {
|
||||
IPBan6 b2 = (IPBan6)b;
|
||||
if(netmask == b2.hasNetMask()) {
|
||||
if(ret.length() > 0) {
|
||||
ret += ", ";
|
||||
}
|
||||
ret += b2.string;
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if(b instanceof IPBan4) {
|
||||
IPBan4 b2 = (IPBan4)b;
|
||||
if(netmask == b2.hasNetMask()) {
|
||||
if(ret.length() > 0) {
|
||||
ret += ", ";
|
||||
}
|
||||
ret += b2.string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(ret.length() <= 0) {
|
||||
ret = "(none)";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public static void maybeReloadBans(CommandSender cs) {
|
||||
synchronized(banListMutex) {
|
||||
long st = System.currentTimeMillis();
|
||||
if(cs == null && st - lastListTest < 1000l) {
|
||||
return;
|
||||
}
|
||||
lastListTest = st;
|
||||
boolean ex = bansFile.exists();
|
||||
if(!fileIsBroken && !ex) {
|
||||
try {
|
||||
PrintWriter p = new PrintWriter(new FileWriter(bansFile));
|
||||
p.println();
|
||||
p.println("#");
|
||||
p.println("# This file allows you to configure bans for eaglercraftbungee");
|
||||
p.println("# When it is saved, eaglercraft should reload it automatically");
|
||||
p.println("# (check the console though to be safe)");
|
||||
p.println("#");
|
||||
p.println("# For a [Usernames] ban, just add the player's name. Use a colon ':' to put in a ban reason");
|
||||
p.println("# For a [IPs] ban, just add the player's IP, or a subnet like 69.69.0.0/16 to ban all IPs beginning with 69.69.*");
|
||||
p.println("# For a [Wildcards] ban, type a string and prefix and/or suffix it with * to define the wildcard");
|
||||
p.println("# For a [Regex] ban, type a valid regular expression in the java.util.regex format");
|
||||
p.println("#");
|
||||
p.println("# All bans are case-insensitive, USERNAMES ARE CONVERTED TO LOWERCASE BEFORE BEING MATCHED VIA REGEX");
|
||||
p.println("# Java regex syntax: https://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html");
|
||||
p.println("#");
|
||||
p.println();
|
||||
p.println("# set this to to true to use \"/ban\" to ban on bungee instead of \"/eag-ban\"");
|
||||
p.println("# (most likely needs a restart to take effect)");
|
||||
p.println("replace-bukkit=false");
|
||||
p.println();
|
||||
p.println();
|
||||
p.println("[Usernames]");
|
||||
p.println();
|
||||
p.println("# ban_test1: The ban hammer has spoken!");
|
||||
p.println("# ban_test2: custom ban message here");
|
||||
p.println("# ban_test3");
|
||||
p.println();
|
||||
p.println("# (remove the '#' before each line to enable)");
|
||||
p.println();
|
||||
p.println("[IPs]");
|
||||
p.println();
|
||||
p.println("# WARNING: if you're using nginx, banning any player's IP is gonna ban ALL PLAYERS on your server");
|
||||
p.println("# For this reason, the ban IP command doesn't ban 127.0.0.1 or any other 'private' range IPs");
|
||||
p.println();
|
||||
p.println("# 101.202.69.11");
|
||||
p.println("# 123.21.43.0/24");
|
||||
p.println("# 2601:1062:69:418:BEEF::10");
|
||||
p.println("# 2601:6090:420::/48");
|
||||
p.println();
|
||||
p.println();
|
||||
p.println("[Wildcards]");
|
||||
p.println();
|
||||
p.println("# *fuck*");
|
||||
p.println("# shi*");
|
||||
p.println();
|
||||
p.println();
|
||||
p.println("[Regex]");
|
||||
p.println();
|
||||
p.println("# you.+are.(a|the).+bitch");
|
||||
p.println();
|
||||
p.println();
|
||||
p.println("# end of file");
|
||||
p.println();
|
||||
p.close();
|
||||
System.out.println("Wrote a new bans.txt to: " + bansFile.getAbsolutePath());
|
||||
lastListLoad = 0l;
|
||||
}catch(Throwable t) {
|
||||
fileIsBroken = true;
|
||||
if(cs != null) {
|
||||
cs.sendMessage(banChatMessagePrefix + ChatColor.RED + "Could not create blank 'bans.txt' list file");
|
||||
cs.sendMessage(banChatMessagePrefix + ChatColor.RED + "(Reason: " + t.toString() + ")");
|
||||
}
|
||||
System.err.println("Could not create blank 'bans.txt' list file");
|
||||
System.err.println("(Reason: " + t.toString() + ")");
|
||||
t.printStackTrace();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(fileIsBroken && ex) {
|
||||
fileIsBroken = false;
|
||||
lastListLoad = 0l;
|
||||
}
|
||||
if(fileIsBroken) {
|
||||
return;
|
||||
}
|
||||
long lastEdit = bansFile.lastModified();
|
||||
if(cs != null || lastEdit - lastListLoad > 400l) {
|
||||
try {
|
||||
BufferedReader r = new BufferedReader(new FileReader(bansFile));
|
||||
currentBanList = new LinkedList();
|
||||
String s;
|
||||
while((s = r.readLine()) != null) {
|
||||
currentBanList.add(s);
|
||||
}
|
||||
r.close();
|
||||
lastListLoad = lastEdit;
|
||||
System.out.println("Server bans.txt changed, it will be reloaded automatically");
|
||||
if(cs == null) {
|
||||
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
|
||||
if(pp.hasPermission("bungeecord.command.eag.reloadban")) {
|
||||
pp.sendMessage(BanList.banChatMessagePrefix + ChatColor.WHITE + "Your Eaglercraftbungee bans.txt just got modified, it will be reloaded asap");
|
||||
pp.sendMessage(BanList.banChatMessagePrefix + ChatColor.YELLOW + "Stop your server and check your config immediately if you don't know how this happened!!");
|
||||
}
|
||||
}
|
||||
}
|
||||
parseListFrom();
|
||||
System.out.println("Reload complete");
|
||||
}catch(Throwable t) {
|
||||
if(cs != null) {
|
||||
cs.sendMessage(banChatMessagePrefix + ChatColor.RED + "Could not reload 'bans.txt' list file");
|
||||
cs.sendMessage(banChatMessagePrefix + ChatColor.RED + "(Reason: " + t.toString() + ")");
|
||||
}
|
||||
System.err.println("Could not reload 'bans.txt' list file");
|
||||
System.err.println("(Reason: " + t.toString() + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseListFrom() {
|
||||
userBans.clear();
|
||||
ipBans.clear();
|
||||
wildcardBans.clear();
|
||||
regexBans.clear();
|
||||
|
||||
int filePart = 0;
|
||||
boolean replaceBukkit = false;
|
||||
|
||||
for(String s : currentBanList) {
|
||||
s = s.trim();
|
||||
if(s.length() <= 0) {
|
||||
continue;
|
||||
}
|
||||
if(s.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
if(s.equals("[Usernames]")) {
|
||||
filePart = 1;
|
||||
}else if(s.equals("[Wildcards]")) {
|
||||
filePart = 2;
|
||||
}else if(s.equals("[Regex]")) {
|
||||
filePart = 3;
|
||||
}else if(s.equals("[IPs]")) {
|
||||
filePart = 4;
|
||||
}else if(s.equals("replace-bukkit=true")) {
|
||||
replaceBukkit = true;
|
||||
}else if(s.equals("replace-bukkit=false")) {
|
||||
continue;
|
||||
}else {
|
||||
if(filePart == 1) {
|
||||
int i = s.indexOf(':');
|
||||
if(i == -1) {
|
||||
userBans.put(s.toLowerCase(), "");
|
||||
}else {
|
||||
userBans.put(s.substring(0, i).trim().toLowerCase(), s.substring(i + 1).trim());
|
||||
}
|
||||
}else if(filePart == 2) {
|
||||
boolean ws = s.startsWith("*");
|
||||
boolean we = s.endsWith("*");
|
||||
if(!ws && !we) {
|
||||
if(s.contains("*")) {
|
||||
System.err.println("Error: wildcard '" + s + "' contains a '*' not at the start/end of the string");
|
||||
}else {
|
||||
System.err.println("Error: wildcard '" + s + "' does not contain a '*' wildcard character");
|
||||
}
|
||||
}else {
|
||||
int total = (ws ? 1 : 0) + (we ? 1 : 0);
|
||||
int t2 = 0;
|
||||
for(char c : s.toCharArray()) {
|
||||
if(c == '*') ++t2;
|
||||
}
|
||||
if(total != t2) {
|
||||
System.err.println("Error: wildcard '" + s + "' contains a '*' not at the start/end of the string");
|
||||
}
|
||||
}
|
||||
wildcardBans.add(s.toLowerCase());
|
||||
}else if(filePart == 3) {
|
||||
Pattern p = null;
|
||||
try {
|
||||
p = Pattern.compile(s);
|
||||
}catch(Throwable t) {
|
||||
System.err.println("Error: the regex " + s.toLowerCase() + " is invalid");
|
||||
System.err.println("Reason: " + t.getClass().getSimpleName() + ": " + t.getLocalizedMessage());
|
||||
}
|
||||
if(p != null) {
|
||||
regexBans.add(new RegexBan(s, p));
|
||||
}
|
||||
}else if(filePart == 4) {
|
||||
String ss = s;
|
||||
int subnet = -1;
|
||||
int i = s.indexOf('/');
|
||||
if(i != -1) {
|
||||
String s2 = s.substring(i + 1);
|
||||
s = s.substring(0, i);
|
||||
try {
|
||||
subnet = Integer.parseInt(s2);
|
||||
}catch(Throwable t) {
|
||||
System.err.println("Error: the subnet '"+ s2 +"' for IP ban address " + s + " was invalid");
|
||||
subnet = -2;
|
||||
}
|
||||
}
|
||||
if(subnet >= -1) {
|
||||
try {
|
||||
InetAddress aa = InetAddress.getByName(s);
|
||||
if(aa instanceof Inet4Address) {
|
||||
if(subnet == -1) {
|
||||
subnet = 32;
|
||||
}
|
||||
ipBans.add(new IPBan4((Inet4Address)aa, ss, subnet));
|
||||
}else if(aa instanceof Inet6Address) {
|
||||
if(subnet == -1) {
|
||||
subnet = 128;
|
||||
}
|
||||
ipBans.add(new IPBan6((Inet6Address)aa, ss, subnet));
|
||||
}else {
|
||||
throw new UnknownHostException("Only ipv4 and ipv6 addresses allowed in Eaglercraft");
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
System.err.println("Error: the IP ban address " + s + " could not be parsed");
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BungeeCord.getInstance().reconfigureBanCommands(replaceBukkit);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package net.md_5.bungee.eaglercraft;
|
||||
|
||||
public class EaglercraftBungee {
|
||||
|
||||
public static final String brand = "Eagtek";
|
||||
public static final String name = "EaglercraftBungee";
|
||||
public static final String version = "0.2.0";
|
||||
public static final boolean cracked = true;
|
||||
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
package net.md_5.bungee.eaglercraft;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.MOTD;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.MOTDCacheConfiguration;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
public class MOTDConnectionImpl extends QueryConnectionImpl implements MOTD {
|
||||
|
||||
private String line1;
|
||||
private String line2;
|
||||
private List<String> players;
|
||||
private int[] bitmap;
|
||||
private int onlinePlayers;
|
||||
private int maxPlayers;
|
||||
private boolean hasIcon;
|
||||
private boolean iconDirty;
|
||||
private String subType;
|
||||
|
||||
public MOTDConnectionImpl(ListenerInfo listener, InetAddress addr, WebSocket socket, String arg1) {
|
||||
super(listener, addr, socket, "motd");
|
||||
String[] lns = listener.getMotd().split("\n");
|
||||
if(lns.length >= 1) {
|
||||
line1 = lns[0];
|
||||
}
|
||||
if(lns.length >= 2) {
|
||||
line2 = lns[1];
|
||||
}
|
||||
maxPlayers = listener.getMaxPlayers();
|
||||
onlinePlayers = BungeeCord.getInstance().getOnlineCount();
|
||||
players = new ArrayList();
|
||||
for(ProxiedPlayer pp : BungeeCord.getInstance().getPlayers()) {
|
||||
players.add(pp.getDisplayName());
|
||||
if(players.size() >= 9) {
|
||||
players.add("" + ChatColor.GRAY + ChatColor.ITALIC + "(" + (onlinePlayers - players.size()) + " more)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
bitmap = new int[4096];
|
||||
setReturnType("motd");
|
||||
int i = arg1.indexOf('.');
|
||||
if(i > 0) {
|
||||
subType = arg1.substring(i + 1);
|
||||
if(subType.length() == 0) {
|
||||
subType = "motd";
|
||||
}
|
||||
}else {
|
||||
subType = "motd";
|
||||
}
|
||||
if(!subType.startsWith("noicon") && !subType.startsWith("cache.noicon")) {
|
||||
iconDirty = hasIcon = listener.isIconSet();
|
||||
if(hasIcon) {
|
||||
System.arraycopy(listener.getServerIconCache(), 0, bitmap, 0, 4096);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLine1() {
|
||||
return line1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLine2() {
|
||||
return line2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPlayerList() {
|
||||
return players;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getBitmap() {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOnlinePlayers() {
|
||||
return onlinePlayers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPlayers() {
|
||||
return maxPlayers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubType() {
|
||||
return subType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLine1(String p) {
|
||||
line1 = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLine2(String p) {
|
||||
line2 = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerList(List<String> p) {
|
||||
players = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerList(String... p) {
|
||||
players = Arrays.asList(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBitmap(int[] p) {
|
||||
iconDirty = hasIcon = true;
|
||||
bitmap = p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnlinePlayers(int i) {
|
||||
onlinePlayers = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxPlayers(int i) {
|
||||
maxPlayers = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToUser() {
|
||||
if(!isClosed()) {
|
||||
JSONObject obj = new JSONObject();
|
||||
if(subType.startsWith("cache.anim")) {
|
||||
obj.put("unsupported", true);
|
||||
writeResponse(obj);
|
||||
close();
|
||||
return;
|
||||
}else if(subType.startsWith("cache")) {
|
||||
JSONArray cacheControl = new JSONArray();
|
||||
MOTDCacheConfiguration cc = listener.getCacheConfig();
|
||||
if(cc.cacheServerListAnimation) {
|
||||
cacheControl.put("animation");
|
||||
}
|
||||
if(cc.cacheServerListResults) {
|
||||
cacheControl.put("results");
|
||||
}
|
||||
if(cc.cacheServerListTrending) {
|
||||
cacheControl.put("trending");
|
||||
}
|
||||
if(cc.cacheServerListPortfolios) {
|
||||
cacheControl.put("portfolio");
|
||||
}
|
||||
obj.put("cache", cacheControl);
|
||||
obj.put("ttl", cc.cacheTTL);
|
||||
}else {
|
||||
MOTDCacheConfiguration cc = listener.getCacheConfig();
|
||||
obj.put("cache", cc.cacheServerListAnimation || cc.cacheServerListResults ||
|
||||
cc.cacheServerListTrending || cc.cacheServerListPortfolios);
|
||||
}
|
||||
boolean noIcon = subType.startsWith("noicon") || subType.startsWith("cache.noicon");
|
||||
JSONArray motd = new JSONArray();
|
||||
if(line1 != null && line1.length() > 0) motd.put(line1);
|
||||
if(line2 != null && line2.length() > 0) motd.put(line2);
|
||||
obj.put("motd", motd);
|
||||
obj.put("icon", hasIcon && !noIcon);
|
||||
obj.put("online", onlinePlayers);
|
||||
obj.put("max", maxPlayers);
|
||||
JSONArray playerz = new JSONArray();
|
||||
for(String s : players) {
|
||||
playerz.put(s);
|
||||
}
|
||||
obj.put("players", playerz);
|
||||
writeResponse(obj);
|
||||
if(hasIcon && !noIcon && iconDirty && bitmap != null) {
|
||||
byte[] iconPixels = new byte[16384];
|
||||
for(int i = 0; i < 4096; ++i) {
|
||||
iconPixels[i * 4] = (byte)((bitmap[i] >> 16) & 0xFF);
|
||||
iconPixels[i * 4 + 1] = (byte)((bitmap[i] >> 8) & 0xFF);
|
||||
iconPixels[i * 4 + 2] = (byte)(bitmap[i] & 0xFF);
|
||||
iconPixels[i * 4 + 3] = (byte)((bitmap[i] >> 24) & 0xFF);
|
||||
}
|
||||
writeResponseBinary(iconPixels);
|
||||
iconDirty = false;
|
||||
}
|
||||
if(subType.startsWith("cache")) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -16,7 +16,7 @@ public class PluginEaglerSkins extends Plugin implements Listener {
|
|||
|
||||
private final HashMap<String,byte[]> skinCollection = new HashMap();
|
||||
|
||||
private static final int[] SKIN_DATA_SIZE = new int[] { 64*32*4, 64*64*4, 128*64*4, 128*128*4, 1 };
|
||||
private static final int[] SKIN_DATA_SIZE = new int[] { 64*32*4, 64*64*4, 128*64*4, 128*128*4, 1, 64*64*4, 128*128*4 };
|
||||
|
||||
private static final int VALID_DEFAULT_SKINS = 33;
|
||||
|
||||
|
@ -41,27 +41,31 @@ public class PluginEaglerSkins extends Plugin implements Listener {
|
|||
if(event.getSender() instanceof UserConnection && event.getData().length > 0) {
|
||||
String user = ((UserConnection)event.getSender()).getName();
|
||||
byte[] msg = event.getData();
|
||||
if("EAG|MySkin".equals(event.getTag())) {
|
||||
int t = (int)msg[0] & 0xFF;
|
||||
if(t >= 0 && t < SKIN_DATA_SIZE.length && msg.length == (SKIN_DATA_SIZE[t] + 1)) {
|
||||
if(msg.length == 2) {
|
||||
if(((int)msg[1] & 0xFF) >= VALID_DEFAULT_SKINS) {
|
||||
msg[1] = 0;
|
||||
try {
|
||||
if("EAG|MySkin".equals(event.getTag())) {
|
||||
int t = (int)msg[0] & 0xFF;
|
||||
if(t >= 0 && t < SKIN_DATA_SIZE.length && msg.length == (SKIN_DATA_SIZE[t] + 1)) {
|
||||
if(msg.length == 2) {
|
||||
if(((int)msg[1] & 0xFF) >= VALID_DEFAULT_SKINS) {
|
||||
msg[1] = 0;
|
||||
}
|
||||
}
|
||||
skinCollection.put(user, msg);
|
||||
}
|
||||
}else if("EAG|FetchSkin".equals(event.getTag())) {
|
||||
if(msg.length > 2) {
|
||||
String fetch = new String(msg, 2, msg.length - 2, StandardCharsets.UTF_8);
|
||||
byte[] data;
|
||||
if((data = skinCollection.get(fetch)) != null) {
|
||||
byte[] conc = new byte[data.length + 2];
|
||||
conc[0] = msg[0]; conc[1] = msg[1]; //synchronization cookie
|
||||
System.arraycopy(data, 0, conc, 2, data.length);
|
||||
((UserConnection)event.getSender()).sendData("EAG|UserSkin", conc);
|
||||
}
|
||||
}
|
||||
skinCollection.put(user, msg);
|
||||
}
|
||||
}else if("EAG|FetchSkin".equals(event.getTag())) {
|
||||
if(msg.length > 2) {
|
||||
String fetch = new String(msg, 2, msg.length - 2, StandardCharsets.UTF_8);
|
||||
byte[] data;
|
||||
if((data = skinCollection.get(fetch)) != null) {
|
||||
byte[] conc = new byte[data.length + 2];
|
||||
conc[0] = msg[0]; conc[1] = msg[1]; //synchronization cookie
|
||||
System.arraycopy(data, 0, conc, 2, data.length);
|
||||
((UserConnection)event.getSender()).sendData("EAG|UserSkin", conc);
|
||||
}
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
// hacker
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
package net.md_5.bungee.eaglercraft;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
|
||||
import net.md_5.bungee.api.QueryConnection;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
|
||||
public class QueryConnectionImpl implements QueryConnection {
|
||||
|
||||
protected ListenerInfo listener;
|
||||
protected InetAddress addr;
|
||||
protected WebSocket socket;
|
||||
protected String accept;
|
||||
protected String responseType;
|
||||
protected List<String> packetBuffer = new LinkedList();
|
||||
protected long creationTime;
|
||||
protected boolean keepAlive = false;
|
||||
|
||||
public QueryConnectionImpl(ListenerInfo listener, InetAddress addr, WebSocket socket, String accept) {
|
||||
this.listener = listener;
|
||||
this.addr = addr;
|
||||
this.socket = socket;
|
||||
this.accept = accept.toLowerCase();
|
||||
this.responseType = "unknown";
|
||||
this.creationTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public void postMessage(String m) {
|
||||
synchronized(packetBuffer) {
|
||||
packetBuffer.add(m);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetAddress getRemoteAddress() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenerInfo getListener() {
|
||||
return listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAccept() {
|
||||
return accept;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int availableRequests() {
|
||||
synchronized(packetBuffer) {
|
||||
return packetBuffer.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readRequestString() {
|
||||
synchronized(packetBuffer) {
|
||||
if(packetBuffer.size() > 0) {
|
||||
return packetBuffer.remove(0);
|
||||
}else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getConnectionTimestamp() {
|
||||
return creationTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeResponseRaw(String msg) {
|
||||
socket.send(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeResponseBinary(byte[] blob) {
|
||||
socket.send(blob);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keepAlive(boolean yes) {
|
||||
keepAlive = yes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldKeepAlive() {
|
||||
return keepAlive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return socket.isClosing() || socket.isClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
socket.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReturnType(String type) {
|
||||
if(!"unknown".equals(responseType) && !type.equalsIgnoreCase(responseType)) {
|
||||
throw new IllegalStateException("Tried to change query return type to '" + type + "' when it was already set to '" + responseType + "'");
|
||||
}
|
||||
responseType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReturnType() {
|
||||
return responseType;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +1,86 @@
|
|||
package net.md_5.bungee.eaglercraft;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
import org.java_websocket.handshake.ClientHandshake;
|
||||
import org.java_websocket.server.WebSocketServer;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.MOTD;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.event.WebsocketMOTDEvent;
|
||||
import net.md_5.bungee.api.event.WebsocketQueryEvent;
|
||||
import net.md_5.bungee.eaglercraft.WebSocketRateLimiter.RateLimit;
|
||||
|
||||
public class WebSocketListener extends WebSocketServer {
|
||||
|
||||
public static final String queryResponseBlocked = "{\"type\":\"blocked\"}";
|
||||
public static final String queryResponseLockout = "{\"type\":\"locked\"}";
|
||||
|
||||
public static final String ipBlockedString = "BLOCKED";
|
||||
public static final String ipLockedString = "LOCKED";
|
||||
|
||||
public static class PendingSocket {
|
||||
public long openTime;
|
||||
public InetAddress realAddress;
|
||||
public boolean bypassBan;
|
||||
protected PendingSocket(long openTime, InetAddress realAddress, boolean bypassBan) {
|
||||
this.openTime = openTime;
|
||||
this.realAddress = realAddress;
|
||||
this.bypassBan = bypassBan;
|
||||
}
|
||||
}
|
||||
|
||||
private InetSocketAddress bungeeProxy;
|
||||
private ProxyServer bungeeCord;
|
||||
private ListenerInfo info;
|
||||
private final WebSocketRateLimiter ratelimitIP;
|
||||
private final WebSocketRateLimiter ratelimitLogin;
|
||||
private final WebSocketRateLimiter ratelimitMOTD;
|
||||
private final WebSocketRateLimiter ratelimitQuery;
|
||||
|
||||
public WebSocketListener(ListenerInfo info, InetSocketAddress sock, ProxyServer bungeeCord) {
|
||||
super(info.getHost());
|
||||
this.setTcpNoDelay(true);
|
||||
this.setConnectionLostTimeout(5);
|
||||
this.setConnectionLostTimeout(20);
|
||||
this.start();
|
||||
this.info = info;
|
||||
this.bungeeProxy = sock;
|
||||
this.bungeeCord = bungeeCord;
|
||||
this.ratelimitIP = info.getRateLimitIP();
|
||||
this.ratelimitLogin = info.getRateLimitLogin();
|
||||
this.ratelimitMOTD = info.getRateLimitMOTD();
|
||||
this.ratelimitQuery = info.getRateLimitQuery();
|
||||
if(this.ratelimitIP != null) {
|
||||
this.ratelimitIP.resetLimiters();
|
||||
}
|
||||
if(this.ratelimitLogin != null) {
|
||||
this.ratelimitLogin.resetLimiters();
|
||||
}
|
||||
if(this.ratelimitMOTD != null) {
|
||||
this.ratelimitMOTD.resetLimiters();
|
||||
}
|
||||
if(this.ratelimitQuery != null) {
|
||||
this.ratelimitQuery.resetLimiters();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(WebSocket arg0, int arg1, String arg2, boolean arg3) {
|
||||
if(arg0.getAttachment() != null) {
|
||||
((WebSocketProxy)arg0.getAttachment()).killConnection();
|
||||
Object o = arg0.getAttachment();
|
||||
if(o != null) {
|
||||
if(o instanceof WebSocketProxy) {
|
||||
((WebSocketProxy)arg0.getAttachment()).killConnection();
|
||||
}
|
||||
}
|
||||
System.out.println("websocket closed - " + arg0.getRemoteSocketAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,28 +90,199 @@ public class WebSocketListener extends WebSocketServer {
|
|||
|
||||
@Override
|
||||
public void onMessage(WebSocket arg0, String arg1) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket arg0, ByteBuffer arg1) {
|
||||
if(arg0.getAttachment() != null) {
|
||||
((WebSocketProxy)arg0.getAttachment()).sendPacket(arg1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(WebSocket arg0, ClientHandshake arg1) {
|
||||
System.out.println("websocket opened - " + arg0.getRemoteSocketAddress());
|
||||
WebSocketProxy proxyObj = new WebSocketProxy(arg0, bungeeProxy);
|
||||
arg0.setAttachment(proxyObj);
|
||||
if(!proxyObj.connect()) {
|
||||
Object o = arg0.getAttachment();
|
||||
if(o != null) {
|
||||
if(o instanceof PendingSocket) {
|
||||
InetAddress realAddr = ((PendingSocket)o).realAddress;
|
||||
arg1 = arg1.trim().toLowerCase();
|
||||
if(arg1.startsWith("accept:")) {
|
||||
arg1 = arg1.substring(7).trim();
|
||||
QueryConnectionImpl con;
|
||||
WebsocketQueryEvent evt;
|
||||
if(arg1.startsWith("motd")) {
|
||||
if(info.isAllowMOTD()) {
|
||||
if(ratelimitMOTD != null && !BanList.isBlockedBan(realAddr)) {
|
||||
RateLimit l = ratelimitMOTD.rateLimit(realAddr);
|
||||
if(l.blocked()) {
|
||||
if(l == RateLimit.LIMIT) {
|
||||
arg0.send(queryResponseBlocked);
|
||||
}else if(l == RateLimit.NOW_LOCKED_OUT) {
|
||||
arg0.send(queryResponseLockout);
|
||||
}
|
||||
arg0.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
con = new MOTDConnectionImpl(info, realAddr, arg0, arg1);
|
||||
evt = new WebsocketMOTDEvent((MOTD)con);
|
||||
}else {
|
||||
arg0.send(queryResponseBlocked);
|
||||
arg0.close();
|
||||
return;
|
||||
}
|
||||
}else {
|
||||
if(info.isAllowQuery()) {
|
||||
if(ratelimitQuery != null && !BanList.isBlockedBan(realAddr)) {
|
||||
RateLimit l = ratelimitQuery.rateLimit(realAddr);
|
||||
if(l.blocked()) {
|
||||
if(l == RateLimit.LIMIT) {
|
||||
arg0.send(queryResponseBlocked);
|
||||
}else if(l == RateLimit.NOW_LOCKED_OUT) {
|
||||
arg0.send(queryResponseLockout);
|
||||
}
|
||||
arg0.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
con = new QueryConnectionImpl(info, realAddr, arg0, arg1);
|
||||
evt = new WebsocketQueryEvent(con);
|
||||
}else {
|
||||
arg0.send(queryResponseBlocked);
|
||||
arg0.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
BungeeCord.getInstance().getPluginManager().callEvent(evt);
|
||||
if(!con.isClosed() && (con instanceof MOTDConnectionImpl)) {
|
||||
((MOTDConnectionImpl)con).sendToUser();
|
||||
}
|
||||
if(!con.shouldKeepAlive() && !con.isClosed()) {
|
||||
con.close();
|
||||
}else {
|
||||
if(!arg0.isClosed()) {
|
||||
arg0.setAttachment(con);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
arg0.close();
|
||||
}
|
||||
return;
|
||||
}else if(o instanceof QueryConnectionImpl) {
|
||||
((QueryConnectionImpl)o).postMessage(arg1);
|
||||
}
|
||||
}else {
|
||||
arg0.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket arg0, ByteBuffer arg1) {
|
||||
Object o = arg0.getAttachment();
|
||||
if(o == null || (o instanceof PendingSocket)) {
|
||||
InetAddress realAddr;
|
||||
if(o == null) {
|
||||
realAddr = arg0.getRemoteSocketAddress().getAddress();
|
||||
}else {
|
||||
realAddr = ((PendingSocket)o).realAddress;
|
||||
}
|
||||
if(ratelimitLogin != null && !BanList.isBlockedBan(realAddr)) {
|
||||
RateLimit l = ratelimitLogin.rateLimit(realAddr);
|
||||
if(l.blocked()) {
|
||||
if(l == RateLimit.LIMIT) {
|
||||
arg0.send(createRawKickPacket("BLOCKED"));
|
||||
}else if(l == RateLimit.NOW_LOCKED_OUT) {
|
||||
arg0.send(createRawKickPacket("LOCKED"));
|
||||
}
|
||||
arg0.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
WebSocketProxy proxyObj = new WebSocketProxy(arg0, realAddr, bungeeProxy);
|
||||
arg0.setAttachment(proxyObj);
|
||||
if(!proxyObj.connect()) {
|
||||
System.err.println("loopback to '" + bungeeProxy.toString() + "' failed - " + realAddr);
|
||||
arg0.close();
|
||||
return;
|
||||
}
|
||||
o = proxyObj;
|
||||
}
|
||||
if(o != null) {
|
||||
if(o instanceof WebSocketProxy) {
|
||||
((WebSocketProxy)o).sendPacket(arg1);
|
||||
}else {
|
||||
arg0.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(WebSocket arg0, ClientHandshake arg1) {
|
||||
InetAddress addr;
|
||||
if(info.hasForwardedHeaders()) {
|
||||
String s = arg1.getFieldValue("X-Real-IP");
|
||||
if(s != null) {
|
||||
try {
|
||||
addr = InetAddress.getByName(s);
|
||||
}catch(UnknownHostException e) {
|
||||
System.out.println("invalid 'X-Real-IP' header - " + e.toString());
|
||||
arg0.close();
|
||||
return;
|
||||
}
|
||||
}else {
|
||||
addr = arg0.getRemoteSocketAddress().getAddress();
|
||||
}
|
||||
}else {
|
||||
addr = arg0.getRemoteSocketAddress().getAddress();
|
||||
}
|
||||
boolean bypassBan = BanList.isBlockedBan(addr);
|
||||
if(!bypassBan && ratelimitIP != null) {
|
||||
RateLimit l = ratelimitIP.rateLimit(addr);
|
||||
if(l.blocked()) {
|
||||
if(l == RateLimit.LIMIT) {
|
||||
arg0.send(ipBlockedString);
|
||||
}else if(l == RateLimit.NOW_LOCKED_OUT) {
|
||||
arg0.send(ipLockedString);
|
||||
}
|
||||
arg0.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
arg0.setAttachment(new PendingSocket(System.currentTimeMillis(), addr, bypassBan));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
|
||||
}
|
||||
|
||||
public void closeInactiveSockets() {
|
||||
for(WebSocket w : this.getConnections()) {
|
||||
Object o = w.getAttachment();
|
||||
if(o == null) {
|
||||
w.close();
|
||||
}else if(o instanceof PendingSocket) {
|
||||
if(System.currentTimeMillis() - ((PendingSocket)o).openTime > 1500l) {
|
||||
w.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws IOException, InterruptedException {
|
||||
for(WebSocket w : this.getConnections()) {
|
||||
Object o = w.getAttachment();
|
||||
if(o != null && o instanceof WebSocketProxy) {
|
||||
((WebSocketProxy)o).killConnection();
|
||||
}
|
||||
}
|
||||
super.stop();
|
||||
}
|
||||
|
||||
private byte[] createRawKickPacket(String str) {
|
||||
ByteArrayOutputStream bao = new ByteArrayOutputStream();
|
||||
DataOutputStream dout = new DataOutputStream(bao);
|
||||
try {
|
||||
dout.write(255);
|
||||
dout.writeShort(str.length());
|
||||
dout.writeChars(str);
|
||||
return bao.toByteArray();
|
||||
}catch(IOException e) {
|
||||
return new byte[] { (byte)255, 0, 0 };
|
||||
}
|
||||
}
|
||||
|
||||
public ListenerInfo getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package net.md_5.bungee.eaglercraft;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.java_websocket.WebSocket;
|
||||
|
||||
|
@ -16,6 +18,8 @@ import io.netty.channel.SimpleChannelInboundHandler;
|
|||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
|
||||
/**
|
||||
* Not the ideal solution but what are we supposed to do
|
||||
|
@ -25,20 +29,22 @@ public class WebSocketProxy extends SimpleChannelInboundHandler<ByteBuf> {
|
|||
|
||||
private WebSocket client;
|
||||
private InetSocketAddress tcpListener;
|
||||
private InetSocketAddress localAddress;
|
||||
private InetAddress realRemoteAddr;
|
||||
private NioSocketChannel tcpChannel;
|
||||
|
||||
private static final EventLoopGroup group = new NioEventLoopGroup(4);
|
||||
public static final HashMap<InetSocketAddress,InetAddress> localToRemote = new HashMap();
|
||||
|
||||
public WebSocketProxy(WebSocket w, InetSocketAddress addr) {
|
||||
public WebSocketProxy(WebSocket w, InetAddress remoteAddr, InetSocketAddress addr) {
|
||||
client = w;
|
||||
realRemoteAddr = remoteAddr;
|
||||
tcpListener = addr;
|
||||
tcpChannel = null;
|
||||
}
|
||||
|
||||
public void killConnection() {
|
||||
if(client.isOpen()) {
|
||||
client.close();
|
||||
}
|
||||
localToRemote.remove(localAddress);
|
||||
if(tcpChannel != null && tcpChannel.isOpen()) {
|
||||
try {
|
||||
tcpChannel.disconnect().sync();
|
||||
|
@ -59,9 +65,16 @@ public class WebSocketProxy extends SimpleChannelInboundHandler<ByteBuf> {
|
|||
clientBootstrap.handler(new ChannelInitializer<SocketChannel>() {
|
||||
protected void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
socketChannel.pipeline().addLast(WebSocketProxy.this);
|
||||
socketChannel.closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
|
||||
@Override
|
||||
public void operationComplete(Future<? super Void> paramF) throws Exception {
|
||||
localToRemote.remove(localAddress);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
tcpChannel = (NioSocketChannel) clientBootstrap.connect().sync().channel();
|
||||
localToRemote.put(localAddress = tcpChannel.localAddress(), realRemoteAddr);
|
||||
return true;
|
||||
}
|
||||
}catch(Throwable t) {
|
||||
|
@ -89,4 +102,8 @@ public class WebSocketProxy extends SimpleChannelInboundHandler<ByteBuf> {
|
|||
}
|
||||
}
|
||||
|
||||
public void finalize() {
|
||||
localToRemote.remove(localAddress);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
package net.md_5.bungee.eaglercraft;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
public class WebSocketRateLimiter {
|
||||
|
||||
public static enum RateLimit {
|
||||
NONE, LIMIT, LOCKED_OUT, NOW_LOCKED_OUT;
|
||||
public boolean blocked() {
|
||||
return this != NONE;
|
||||
}
|
||||
}
|
||||
|
||||
public final int period;
|
||||
public final int limit;
|
||||
public final int lockoutLimit;
|
||||
public final int lockoutTime;
|
||||
public final Collection<String> exceptions;
|
||||
|
||||
protected final Map<String, RateLimiter> ratelimiters = new HashMap();
|
||||
|
||||
public WebSocketRateLimiter(int period, int limit, int lockoutLimit, int lockoutTime, Collection<String> exceptions) {
|
||||
this.period = period;
|
||||
this.limit = limit;
|
||||
this.lockoutLimit = lockoutLimit;
|
||||
this.lockoutTime = lockoutTime;
|
||||
this.exceptions = exceptions;
|
||||
}
|
||||
|
||||
protected static class RateLimiter {
|
||||
|
||||
protected final WebSocketRateLimiter limiterConfig;
|
||||
|
||||
protected RateLimiter(WebSocketRateLimiter limiterConfig) {
|
||||
this.limiterConfig = limiterConfig;
|
||||
this.cooldownTimestamp = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
protected int requestCounter = 0;
|
||||
protected long lockoutTimestamp = 0l;
|
||||
protected long cooldownTimestamp;
|
||||
|
||||
private boolean checkLockout(long currentTimeMillis) {
|
||||
if(lockoutTimestamp > 0l) {
|
||||
if(currentTimeMillis - lockoutTimestamp < (long)(limiterConfig.lockoutTime * 1000l)) {
|
||||
return true;
|
||||
}else {
|
||||
lockoutTimestamp = 0l;
|
||||
requestCounter = 0;
|
||||
cooldownTimestamp = currentTimeMillis;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkCooldown(long currentTimeMillis) {
|
||||
long cooldownIncrement = limiterConfig.period * 1000 / limiterConfig.limit;
|
||||
while(currentTimeMillis - cooldownTimestamp > cooldownIncrement && requestCounter > 0) {
|
||||
--requestCounter;
|
||||
cooldownTimestamp += cooldownIncrement;
|
||||
}
|
||||
if(requestCounter == 0) {
|
||||
cooldownTimestamp = currentTimeMillis;
|
||||
return false;
|
||||
}else {
|
||||
return requestCounter >= limiterConfig.limit;
|
||||
}
|
||||
}
|
||||
|
||||
protected RateLimit increment() {
|
||||
long t = System.currentTimeMillis();
|
||||
if(checkLockout(t)) {
|
||||
return RateLimit.LOCKED_OUT;
|
||||
}
|
||||
++requestCounter;
|
||||
boolean blockByCooldown = checkCooldown(t);
|
||||
if(requestCounter >= limiterConfig.lockoutLimit) {
|
||||
requestCounter = 0;
|
||||
cooldownTimestamp = t;
|
||||
lockoutTimestamp = t;
|
||||
return RateLimit.NOW_LOCKED_OUT;
|
||||
}
|
||||
if(blockByCooldown) {
|
||||
return RateLimit.LIMIT;
|
||||
}else {
|
||||
return RateLimit.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
protected RateLimit checkLimited() {
|
||||
long t = System.currentTimeMillis();
|
||||
if(checkLockout(t)) {
|
||||
return RateLimit.LOCKED_OUT;
|
||||
}else if(checkCooldown(t)) {
|
||||
return RateLimit.LIMIT;
|
||||
}else {
|
||||
return RateLimit.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean checkClear() {
|
||||
long t = System.currentTimeMillis();
|
||||
if(checkLockout(t) || checkCooldown(t)) {
|
||||
return false;
|
||||
}else if(requestCounter > 0) {
|
||||
return false;
|
||||
}else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void resetLimiters() {
|
||||
synchronized(ratelimiters) {
|
||||
ratelimiters.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteClearLimiters() {
|
||||
synchronized(ratelimiters) {
|
||||
Iterator<RateLimiter> itr = ratelimiters.values().iterator();
|
||||
while(itr.hasNext()) {
|
||||
if(itr.next().checkClear()) {
|
||||
itr.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RateLimit checkLimit(InetAddress identifier) {
|
||||
return checkLimit(identifier.getHostAddress());
|
||||
}
|
||||
|
||||
public RateLimit rateLimit(InetAddress identifier) {
|
||||
return rateLimit(identifier.getHostAddress());
|
||||
}
|
||||
|
||||
public RateLimit checkLimit(String identifier) {
|
||||
if(exceptions.contains(identifier)) {
|
||||
return RateLimit.NONE;
|
||||
}
|
||||
synchronized(ratelimiters) {
|
||||
RateLimiter l = ratelimiters.get(identifier);
|
||||
if(l == null) {
|
||||
return RateLimit.NONE;
|
||||
}else {
|
||||
return l.checkLimited();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RateLimit rateLimit(String identifier) {
|
||||
if(exceptions.contains(identifier)) {
|
||||
return RateLimit.NONE;
|
||||
}
|
||||
synchronized(ratelimiters) {
|
||||
RateLimiter l = ratelimiters.get(identifier);
|
||||
if(l == null) {
|
||||
l = new RateLimiter(this);
|
||||
ratelimiters.put(identifier, l);
|
||||
}
|
||||
return l.increment();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,321 @@
|
|||
package net.md_5.bungee.eaglercraft.sun.net.util;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class IPAddressUtil {
|
||||
private static final int INADDR4SZ = 4;
|
||||
|
||||
private static final int INADDR16SZ = 16;
|
||||
|
||||
private static final int INT16SZ = 2;
|
||||
|
||||
private static final long L_IPV6_DELIMS = 0L;
|
||||
|
||||
private static final long H_IPV6_DELIMS = 671088640L;
|
||||
|
||||
private static final long L_GEN_DELIMS = -8935000888854970368L;
|
||||
|
||||
private static final long H_GEN_DELIMS = 671088641L;
|
||||
|
||||
private static final long L_AUTH_DELIMS = 288230376151711744L;
|
||||
|
||||
private static final long H_AUTH_DELIMS = 671088641L;
|
||||
|
||||
private static final long L_COLON = 288230376151711744L;
|
||||
|
||||
private static final long H_COLON = 0L;
|
||||
|
||||
private static final long L_SLASH = 140737488355328L;
|
||||
|
||||
private static final long H_SLASH = 0L;
|
||||
|
||||
private static final long L_BACKSLASH = 0L;
|
||||
|
||||
private static final long H_BACKSLASH = 268435456L;
|
||||
|
||||
private static final long L_NON_PRINTABLE = 4294967295L;
|
||||
|
||||
private static final long H_NON_PRINTABLE = -9223372036854775808L;
|
||||
|
||||
private static final long L_EXCLUDE = -8935000884560003073L;
|
||||
|
||||
private static final long H_EXCLUDE = -9223372035915251711L;
|
||||
|
||||
public static byte[] textToNumericFormatV4(String paramString) {
|
||||
byte[] arrayOfByte = new byte[4];
|
||||
long l = 0L;
|
||||
byte b1 = 0;
|
||||
boolean bool = true;
|
||||
int i = paramString.length();
|
||||
if (i == 0 || i > 15)
|
||||
return null;
|
||||
for (byte b2 = 0; b2 < i; b2++) {
|
||||
char c = paramString.charAt(b2);
|
||||
if (c == '.') {
|
||||
if (bool || l < 0L || l > 255L || b1 == 3)
|
||||
return null;
|
||||
arrayOfByte[b1++] = (byte) (int) (l & 0xFFL);
|
||||
l = 0L;
|
||||
bool = true;
|
||||
} else {
|
||||
int j = Character.digit(c, 10);
|
||||
if (j < 0)
|
||||
return null;
|
||||
l *= 10L;
|
||||
l += j;
|
||||
bool = false;
|
||||
}
|
||||
}
|
||||
if (bool || l < 0L || l >= 1L << (4 - b1) * 8)
|
||||
return null;
|
||||
switch (b1) {
|
||||
case 0 :
|
||||
arrayOfByte[0] = (byte) (int) (l >> 24L & 0xFFL);
|
||||
case 1 :
|
||||
arrayOfByte[1] = (byte) (int) (l >> 16L & 0xFFL);
|
||||
case 2 :
|
||||
arrayOfByte[2] = (byte) (int) (l >> 8L & 0xFFL);
|
||||
case 3 :
|
||||
arrayOfByte[3] = (byte) (int) (l >> 0L & 0xFFL);
|
||||
break;
|
||||
}
|
||||
return arrayOfByte;
|
||||
}
|
||||
|
||||
public static byte[] textToNumericFormatV6(String paramString) {
|
||||
if (paramString.length() < 2)
|
||||
return null;
|
||||
char[] arrayOfChar = paramString.toCharArray();
|
||||
byte[] arrayOfByte1 = new byte[16];
|
||||
int j = arrayOfChar.length;
|
||||
int k = paramString.indexOf("%");
|
||||
if (k == j - 1)
|
||||
return null;
|
||||
if (k != -1)
|
||||
j = k;
|
||||
byte b = -1;
|
||||
byte b1 = 0, b2 = 0;
|
||||
if (arrayOfChar[b1] == ':' && arrayOfChar[++b1] != ':')
|
||||
return null;
|
||||
byte b3 = b1;
|
||||
boolean bool = false;
|
||||
int i = 0;
|
||||
while (b1 < j) {
|
||||
char c = arrayOfChar[b1++];
|
||||
int m = Character.digit(c, 16);
|
||||
if (m != -1) {
|
||||
i <<= 4;
|
||||
i |= m;
|
||||
if (i > 65535)
|
||||
return null;
|
||||
bool = true;
|
||||
continue;
|
||||
}
|
||||
if (c == ':') {
|
||||
b3 = b1;
|
||||
if (!bool) {
|
||||
if (b != -1)
|
||||
return null;
|
||||
b = b2;
|
||||
continue;
|
||||
}
|
||||
if (b1 == j)
|
||||
return null;
|
||||
if (b2 + 2 > 16)
|
||||
return null;
|
||||
arrayOfByte1[b2++] = (byte) (i >> 8 & 0xFF);
|
||||
arrayOfByte1[b2++] = (byte) (i & 0xFF);
|
||||
bool = false;
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
if (c == '.' && b2 + 4 <= 16) {
|
||||
String str = paramString.substring(b3, j);
|
||||
byte b4 = 0;
|
||||
int n = 0;
|
||||
while ((n = str.indexOf('.', n)) != -1) {
|
||||
b4++;
|
||||
n++;
|
||||
}
|
||||
if (b4 != 3)
|
||||
return null;
|
||||
byte[] arrayOfByte = textToNumericFormatV4(str);
|
||||
if (arrayOfByte == null)
|
||||
return null;
|
||||
for (byte b5 = 0; b5 < 4; b5++)
|
||||
arrayOfByte1[b2++] = arrayOfByte[b5];
|
||||
bool = false;
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (bool) {
|
||||
if (b2 + 2 > 16)
|
||||
return null;
|
||||
arrayOfByte1[b2++] = (byte) (i >> 8 & 0xFF);
|
||||
arrayOfByte1[b2++] = (byte) (i & 0xFF);
|
||||
}
|
||||
if (b != -1) {
|
||||
int m = b2 - b;
|
||||
if (b2 == 16)
|
||||
return null;
|
||||
for (b1 = 1; b1 <= m; b1++) {
|
||||
arrayOfByte1[16 - b1] = arrayOfByte1[b + m - b1];
|
||||
arrayOfByte1[b + m - b1] = 0;
|
||||
}
|
||||
b2 = 16;
|
||||
}
|
||||
if (b2 != 16)
|
||||
return null;
|
||||
byte[] arrayOfByte2 = convertFromIPv4MappedAddress(arrayOfByte1);
|
||||
if (arrayOfByte2 != null)
|
||||
return arrayOfByte2;
|
||||
return arrayOfByte1;
|
||||
}
|
||||
|
||||
public static boolean isIPv4LiteralAddress(String paramString) {
|
||||
return (textToNumericFormatV4(paramString) != null);
|
||||
}
|
||||
|
||||
public static boolean isIPv6LiteralAddress(String paramString) {
|
||||
return (textToNumericFormatV6(paramString) != null);
|
||||
}
|
||||
|
||||
public static byte[] convertFromIPv4MappedAddress(byte[] paramArrayOfbyte) {
|
||||
if (isIPv4MappedAddress(paramArrayOfbyte)) {
|
||||
byte[] arrayOfByte = new byte[4];
|
||||
System.arraycopy(paramArrayOfbyte, 12, arrayOfByte, 0, 4);
|
||||
return arrayOfByte;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isIPv4MappedAddress(byte[] paramArrayOfbyte) {
|
||||
if (paramArrayOfbyte.length < 16)
|
||||
return false;
|
||||
if (paramArrayOfbyte[0] == 0 && paramArrayOfbyte[1] == 0 && paramArrayOfbyte[2] == 0 && paramArrayOfbyte[3] == 0
|
||||
&& paramArrayOfbyte[4] == 0 && paramArrayOfbyte[5] == 0 && paramArrayOfbyte[6] == 0
|
||||
&& paramArrayOfbyte[7] == 0 && paramArrayOfbyte[8] == 0 && paramArrayOfbyte[9] == 0
|
||||
&& paramArrayOfbyte[10] == -1 && paramArrayOfbyte[11] == -1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean match(char paramChar, long paramLong1, long paramLong2) {
|
||||
if (paramChar < '@')
|
||||
return ((1L << paramChar & paramLong1) != 0L);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int scan(String paramString, long paramLong1, long paramLong2) {
|
||||
byte b = -1;
|
||||
int i;
|
||||
if (paramString == null || (i = paramString.length()) == 0)
|
||||
return -1;
|
||||
boolean bool = false;
|
||||
while (++b < i && !(bool = match(paramString.charAt(b), paramLong1, paramLong2)));
|
||||
if (bool)
|
||||
return b;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static int scan(String paramString, long paramLong1, long paramLong2, char[] paramArrayOfchar) {
|
||||
byte b = -1;
|
||||
int i;
|
||||
if (paramString == null || (i = paramString.length()) == 0)
|
||||
return -1;
|
||||
boolean bool = false;
|
||||
char c2 = paramArrayOfchar[0];
|
||||
char c1;
|
||||
while (++b < i && !(bool = match(c1 = paramString.charAt(b), paramLong1, paramLong2))) {
|
||||
if (c1 >= c2 && Arrays.binarySearch(paramArrayOfchar, c1) > -1) {
|
||||
bool = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bool)
|
||||
return b;
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static String describeChar(char paramChar) {
|
||||
if (paramChar < ' ' || paramChar == '') {
|
||||
if (paramChar == '\n')
|
||||
return "LF";
|
||||
if (paramChar == '\r')
|
||||
return "CR";
|
||||
return "control char (code=" + paramChar + ")";
|
||||
}
|
||||
if (paramChar == '\\')
|
||||
return "'\\'";
|
||||
return "'" + paramChar + "'";
|
||||
}
|
||||
|
||||
private static String checkUserInfo(String paramString) {
|
||||
int i = scan(paramString, -9223231260711714817L, -9223372035915251711L);
|
||||
if (i >= 0)
|
||||
return "Illegal character found in user-info: " + describeChar(paramString.charAt(i));
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String checkHost(String paramString) {
|
||||
if (paramString.startsWith("[") && paramString.endsWith("]")) {
|
||||
paramString = paramString.substring(1, paramString.length() - 1);
|
||||
if (isIPv6LiteralAddress(paramString)) {
|
||||
int j = paramString.indexOf('%');
|
||||
if (j >= 0) {
|
||||
j = scan(paramString = paramString.substring(j), 4294967295L, -9223372036183687168L);
|
||||
if (j >= 0)
|
||||
return "Illegal character found in IPv6 scoped address: " + describeChar(paramString.charAt(j));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return "Unrecognized IPv6 address format";
|
||||
}
|
||||
int i = scan(paramString, -8935000884560003073L, -9223372035915251711L);
|
||||
if (i >= 0)
|
||||
return "Illegal character found in host: " + describeChar(paramString.charAt(i));
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String checkAuth(String paramString) {
|
||||
int i = scan(paramString, -9223231260711714817L, -9223372036586340352L);
|
||||
if (i >= 0)
|
||||
return "Illegal character found in authority: " + describeChar(paramString.charAt(i));
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String checkAuthority(URL paramURL) {
|
||||
if (paramURL == null)
|
||||
return null;
|
||||
String str1;
|
||||
String str2;
|
||||
if ((str1 = checkUserInfo(str2 = paramURL.getUserInfo())) != null)
|
||||
return str1;
|
||||
String str3;
|
||||
if ((str1 = checkHost(str3 = paramURL.getHost())) != null)
|
||||
return str1;
|
||||
if (str3 == null && str2 == null)
|
||||
return checkAuth(paramURL.getAuthority());
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String checkExternalForm(URL paramURL) {
|
||||
if (paramURL == null)
|
||||
return null;
|
||||
String str;
|
||||
int i = scan(str = paramURL.getUserInfo(), 140741783322623L, Long.MIN_VALUE);
|
||||
if (i >= 0)
|
||||
return "Illegal character found in authority: " + describeChar(str.charAt(i));
|
||||
if ((str = checkHostString(paramURL.getHost())) != null)
|
||||
return str;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String checkHostString(String paramString) {
|
||||
if (paramString == null)
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/jdk1.8.0_231"/>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
|
@ -1,17 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>PackageCompiler</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<output url="file://$MODULE_DIR$/bin" />
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,7 +1,12 @@
|
|||
Use this tool like this:
|
||||
TO QUICKLY MAKE RESOURCE PACK:
|
||||
1. make your changes to the files in '/lwjgl-rundir/resources'
|
||||
2. double click 'run.bat' on windows, or run './run_unix.sh' in terminal on mac
|
||||
3. copy 'assets.epk from '/javascript' to your web directory
|
||||
|
||||
To manually use the CompilePackage.jar on a custom directory, run the jar file like this:
|
||||
|
||||
java -jar CompilePackage.jar <source directory> <output file>
|
||||
|
||||
To recompile the assets.epk file found in /javascript, make your changes to the game's resources in /lwjgl-rundir/resources and then run this command within this /epkcompiler directory:
|
||||
To recompile the assets.epk file found in /javascript, run:
|
||||
|
||||
java -jar CompilePackage.jar "../lwjgl-rundir/resources" "../javascript/assets.epk"
|
2
epkcompiler/run.bat
Normal file
2
epkcompiler/run.bat
Normal file
|
@ -0,0 +1,2 @@
|
|||
@echo off
|
||||
java -jar CompilePackage.jar "../lwjgl-rundir/resources" "../javascript/assets.epk"
|
2
epkcompiler/run_unix.sh
Normal file
2
epkcompiler/run_unix.sh
Normal file
|
@ -0,0 +1,2 @@
|
|||
#!/bin/sh
|
||||
java -jar CompilePackage.jar "../lwjgl-rundir/resources" "../javascript/assets.epk"
|
Binary file not shown.
215384
javascript/classes.js
215384
javascript/classes.js
File diff suppressed because it is too large
Load Diff
1
javascript/classes.js.map
Normal file
1
javascript/classes.js.map
Normal file
File diff suppressed because one or more lines are too long
|
@ -15,7 +15,7 @@
|
|||
|
||||
<script type="text/javascript" src="music.js"></script>
|
||||
|
||||
<script type="text/javascript" src="classes.js?t=updateme9"></script>
|
||||
<script type="text/javascript" src="classes.js?t=updateme10"></script>
|
||||
<script type="text/javascript">
|
||||
//window.eag_self_proxy=true;//set to true to set the default proxy to the current url
|
||||
//window.eag_proxy_list="";//set to a string of comma-separated proxy ip:port combinations for a custom proxy list
|
||||
|
@ -27,43 +27,8 @@ window.minecraftOpts = [
|
|||
"game_frame","assets.epk",
|
||||
btoa(atob("CgAACQAHc2VydmVycwoAAAABCAAKZm9yY2VkTU9URABtb3RkaGVyZQEAC2hpZGVBZGRyZXNzAQgAAmlwAGlwaGVyZQgABG5hbWUAbmFtZWhlcmUAAA==").replace("motdhere",String.fromCharCode(motd.length)+motd).replace("namehere",String.fromCharCode(name.length)+name).replace("iphere",String.fromCharCode(ip.length)+ip))
|
||||
]; main(); });
|
||||
//modified from https://gist.github.com/GlauberF/d8278ce3aa592389e6e3d4e758e6a0c2
|
||||
function simulateKey (key, type) {
|
||||
var keyCode = key.charCodeAt(0);
|
||||
var evtName = (typeof(type) === "string") ? "key" + type : "keydown";
|
||||
|
||||
var event = document.createEvent("HTMLEvents");
|
||||
event.initEvent(evtName, true, false);
|
||||
event.keyCode = event.which = keyCode;
|
||||
event.key = key;
|
||||
event.shiftKey = false;
|
||||
event.ctrlKey = false;
|
||||
event.metaKey = false;
|
||||
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
if(window.navigator.clipboard&&window.isSecureContext&&navigator.userAgent.toLowerCase().indexOf('firefox')==-1){
|
||||
window.addEventListener("keydown",function(e){
|
||||
if((e.ctrlKey||e.metaKey)&&e.keyCode==86&&!e.altKey){
|
||||
window.navigator.clipboard.readText().then(clipdata=>{
|
||||
if(clipdata==null||clipdata=="")return;
|
||||
simulateKey("\u0011","up");
|
||||
simulateKey("\u0011","press");
|
||||
simulateKey("\b","down");
|
||||
simulateKey("\b","up");
|
||||
simulateKey("\b","press");
|
||||
var clipchars=clipdata.split("");
|
||||
for(var clipchar of clipchars){
|
||||
simulateKey(clipchar,"down");
|
||||
simulateKey(clipchar,"up");
|
||||
simulateKey(clipchar,"press");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body style="margin:0px;width:100vw;height:100vh;" id="game_frame">
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
33
javascript/queryTest.html
Normal file
33
javascript/queryTest.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>query test</title>
|
||||
<script type="text/javascript">
|
||||
window.addEventListener("load", () => {
|
||||
const output = document.getElementById("out");
|
||||
document.getElementById("testButton").addEventListener("click", () => {
|
||||
const ws = new WebSocket(document.getElementById("uriField").value);
|
||||
ws.onopen = (e) => {
|
||||
output.innerText = "please wait";
|
||||
ws.send(document.getElementById("acceptField").value);
|
||||
};
|
||||
ws.onmessage = (e) => {
|
||||
try {
|
||||
output.innerText += JSON.stringify(JSON.parse(e.data), null, 4);
|
||||
}catch(ee) {
|
||||
output.innerText += e.data;
|
||||
}
|
||||
};
|
||||
ws.onclose = (e) => {
|
||||
output.innerText = output.innerText + "\n\nSocket Closed.";
|
||||
};
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body style="font-family:sans-serif;">
|
||||
<input type="text" id="uriField" value="ws://127.0.0.1:25565/" /><br />
|
||||
<input type="text" id="acceptField" value="accept: motd" /><br />
|
||||
<button id="testButton">send</button>
|
||||
<pre id="out" style="font-family:sans-serif;"></pre>
|
||||
</body>
|
||||
</html>
|
|
@ -13,7 +13,7 @@ eaglercraft makes use of baislsl's java PNG decoder, which is available at §nht
|
|||
|
||||
all graphical assets in this project were ripped from mojang's official minecraft.jar for minecraft version 1.5.2 and they are mojang's intellectual property. assets ommitted include the minecraft soundtrack and music disks and all software references to the mojang/minecraft api.
|
||||
|
||||
eaglercraft servers are powered by md_5's BungeeCord and the CraftBukkit project available at §nhttp://www.spigotmc.org/§r. BungeeCord has been modified to accept eaglercraft's strange login packets and to host a websocket server to translate browser connections to raw TCP that vanilla minecraft servers can understand. All java plugins designed for CraftBukkit 1.5.2 are compatible with this configuration.
|
||||
eaglercraft servers are powered by md_5's BungeeCord and the CraftBukkit project available at §nhttps://bukkit.org/§r. BungeeCord has been modified to accept eaglercraft's strange login packets and to host a websocket server to translate browser connections to raw TCP that vanilla minecraft servers can understand. All java plugins designed for CraftBukkit 1.5.2 are compatible with this configuration.
|
||||
|
||||
scroll down for the detailed license statements
|
||||
|
||||
|
|
|
@ -202,10 +202,40 @@ disconnect.closed=Connection closed
|
|||
disconnect.loginFailed=Failed to login
|
||||
disconnect.loginFailedInfo=Failed to login: %s
|
||||
disconnect.quitting=Quitting
|
||||
disconnect.endOfStream=End of stream
|
||||
disconnect.endOfStream=End of stream (RIP)
|
||||
disconnect.overflow=Buffer overflow
|
||||
disconnect.spam=Kicked for spamming
|
||||
|
||||
disconnect.ratelimit.ipNowLocked.title=Connection Closed
|
||||
disconnect.ratelimit.ipNowLocked.description0=Suspected Denial of Service
|
||||
disconnect.ratelimit.ipNowLocked.description1=Your IP is now blocked
|
||||
disconnect.ratelimit.ipNowLocked.tryAgain=please try again in an hour
|
||||
|
||||
disconnect.ratelimit.ipLocked.title=Connection Refused
|
||||
disconnect.ratelimit.ipLocked.description0=Suspected Denial of Service
|
||||
disconnect.ratelimit.ipLocked.description1=Your IP is still blocked
|
||||
disconnect.ratelimit.ipLocked.tryAgain=please try again in an hour
|
||||
|
||||
disconnect.ratelimit.ipFailedPossiblyLocked.title=Connection Failed
|
||||
disconnect.ratelimit.ipFailedPossiblyLocked.description0=You've been kicked by this server before for suspected
|
||||
disconnect.ratelimit.ipFailedPossiblyLocked.description1=$Denial of Service (DoS), your IP is probably blocked
|
||||
disconnect.ratelimit.ipFailedPossiblyLocked.tryAgain=please try again in an hour
|
||||
|
||||
disconnect.ratelimit.ipBlocked.title=Connection Closed
|
||||
disconnect.ratelimit.ipBlocked.description0=Too many connections from your IP
|
||||
disconnect.ratelimit.ipBlocked.description1=Please try again in a few minutes
|
||||
disconnect.ratelimit.ipBlocked.tryAgain=(Suspected Denial of Service)
|
||||
|
||||
disconnect.ratelimit.kickBlocked.title=Connection Closed
|
||||
disconnect.ratelimit.kickBlocked.description0=You're reconnecting too quickly!
|
||||
disconnect.ratelimit.kickBlocked.description1=Please try again in a minute
|
||||
disconnect.ratelimit.kickBlocked.tryAgain=(too many logins from your IP)
|
||||
|
||||
disconnect.ratelimit.kickLocked.title=Connection Closed
|
||||
disconnect.ratelimit.kickLocked.description0=Suspected Denial of Service
|
||||
disconnect.ratelimit.kickLocked.description1=Logins from you IP are now blocked
|
||||
disconnect.ratelimit.kickLocked.tryAgain=please try again in an hour
|
||||
|
||||
options.off=OFF
|
||||
options.on=ON
|
||||
options.visible=Shown
|
||||
|
|
Binary file not shown.
11
src/lwjgl/java/me/ayunami2000/ayuncraft/KeyHolder.java
Normal file
11
src/lwjgl/java/me/ayunami2000/ayuncraft/KeyHolder.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package me.ayunami2000.ayuncraft;
|
||||
|
||||
import java.security.Key;
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public class KeyHolder {
|
||||
public SecretKey sharedKeyForEncryption;
|
||||
public Key toKey(){
|
||||
return (Key) sharedKeyForEncryption;
|
||||
}
|
||||
}
|
|
@ -1,13 +1,7 @@
|
|||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import net.lax1dude.eaglercraft.EaglerAdapter;
|
||||
import net.lax1dude.eaglercraft.LocalStorageManager;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.src.ServerList;
|
||||
|
||||
|
@ -19,7 +13,14 @@ public class MinecraftMain {
|
|||
|
||||
EaglerAdapter.initializeContext();
|
||||
LocalStorageManager.loadStorage();
|
||||
ServerList.loadDefaultServers(Base64.encodeBase64String(EaglerAdapter.loadLocalStorage("forced")));
|
||||
|
||||
byte[] b = EaglerAdapter.loadLocalStorage("forced");
|
||||
if(b != null) {
|
||||
ServerList.loadDefaultServers(Base64.encodeBase64String(b));
|
||||
}
|
||||
if(par0ArrayOfStr.length > 0) {
|
||||
EaglerAdapter.setServerToJoinOnLaunch(par0ArrayOfStr[0]);
|
||||
}
|
||||
|
||||
Minecraft mc = new Minecraft();
|
||||
mc.run();
|
||||
|
|
|
@ -1,314 +0,0 @@
|
|||
package net.lax1dude.eaglercraft;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import java.security.Key;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.src.*;
|
||||
import me.ayunami2000.ayuncraft.CryptManager;
|
||||
import org.bouncycastle.crypto.BufferedBlockCipher;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
|
||||
public class WebsocketNetworkManager implements INetworkManager {
|
||||
private boolean isInputBeingDecrypted;
|
||||
private boolean isOutputEncrypted;
|
||||
private SecretKey sharedKeyForEncryption;
|
||||
|
||||
private final boolean logpackets=false;
|
||||
|
||||
private BufferedBlockCipher inputBufferedBlockCipher=null;
|
||||
private BufferedBlockCipher outputBufferedBlockCipher=null;
|
||||
|
||||
private NetHandler netHandler;
|
||||
|
||||
Pattern ipPattern = Pattern.compile("^"
|
||||
+ "(((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}" // Domain name
|
||||
+ "|"
|
||||
+ "localhost" // localhost
|
||||
+ "|"
|
||||
+ "(([0-9]{1,3}\\.){3})[0-9]{1,3})" // Ip
|
||||
+ "(:"
|
||||
+ "[0-9]{1,5})?$"); // Port
|
||||
|
||||
public WebsocketNetworkManager(String uri, String eagler, NetHandler netHandler) throws IOException {
|
||||
this.netHandler = netHandler;
|
||||
this.sharedKeyForEncryption = null;
|
||||
this.isInputBeingDecrypted = false;
|
||||
this.isOutputEncrypted = false;
|
||||
String proxyUrl=Minecraft.getMinecraft().gameSettings.proxy;
|
||||
boolean stillConnect=true;
|
||||
if(!proxyUrl.equals("")&&!uri.contains("/")){
|
||||
stillConnect=false;
|
||||
if (ipPattern.matcher(proxyUrl).matches()&&ipPattern.matcher(uri).matches()) {
|
||||
String ip = uri;
|
||||
String port = "25565";
|
||||
if (uri.contains(":")) {
|
||||
String[] ipPort = uri.split(":", 2);
|
||||
ip = ipPort[0];
|
||||
port = ipPort[1];
|
||||
}
|
||||
//send initial request (lag client)
|
||||
URL url = new URL("http"+(EaglerAdapter.isSSLPage()?"s":"")+"://"+proxyUrl+"/api/vm/net/connect");
|
||||
URLConnection con = url.openConnection();
|
||||
HttpURLConnection http = (HttpURLConnection)con;
|
||||
http.setRequestMethod("POST");
|
||||
http.setDoOutput(true);
|
||||
byte[] out = ("{\"port\":\""+port+"\",\"host\":\""+ip+"\"}").getBytes(StandardCharsets.UTF_8);
|
||||
http.setFixedLengthStreamingMode(out.length);
|
||||
http.setRequestProperty("Content-Type","application/json; charset=UTF-8");
|
||||
http.setConnectTimeout(5000);
|
||||
http.setReadTimeout(5000);
|
||||
http.connect();
|
||||
http.getOutputStream().write(out);
|
||||
Reader in = new BufferedReader(new InputStreamReader(http.getInputStream(), "UTF-8"));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int c; (c = in.read()) >= 0;)
|
||||
sb.append((char)c);
|
||||
String response = sb.toString();
|
||||
response=response.substring(10);
|
||||
response=response.split("\"",2)[0];
|
||||
uri="ws"+(EaglerAdapter.isSSLPage()?"s":"")+"://"+proxyUrl+"/api/vm/net/socket?token="+response;
|
||||
stillConnect=true;
|
||||
}
|
||||
}
|
||||
if(!stillConnect||!EaglerAdapter.startConnection(uri)) {
|
||||
throw new IOException("websocket to "+uri+" failed");
|
||||
}
|
||||
EaglerAdapter.setDebugVar("minecraftServer", uri);
|
||||
}
|
||||
|
||||
public void setNetHandler(NetHandler netHandler) {
|
||||
this.netHandler = netHandler;
|
||||
}
|
||||
|
||||
private ByteArrayOutputStream sendBuffer = new ByteArrayOutputStream();
|
||||
|
||||
public void addToSendQueue(Packet var1) {
|
||||
try {
|
||||
sendBuffer.reset();
|
||||
|
||||
DataOutputStream yee;
|
||||
if(this.isOutputEncrypted&&!(var1 instanceof Packet252SharedKey)){
|
||||
yee = this.encryptOuputStream();
|
||||
}else{
|
||||
yee = new DataOutputStream(sendBuffer);
|
||||
}
|
||||
|
||||
if (Minecraft.getMinecraft().gameSettings.useDefaultProtocol && var1 instanceof Packet252SharedKey && !this.isOutputEncrypted)
|
||||
{
|
||||
this.sharedKeyForEncryption = ((Packet252SharedKey)var1).getSharedKey();
|
||||
this.isOutputEncrypted=true;
|
||||
//yee=this.encryptOuputStream(yee);
|
||||
}
|
||||
Packet.writePacket(var1, yee);
|
||||
if(logpackets)System.out.println("SENDING: "+var1);
|
||||
yee.flush();
|
||||
EaglerAdapter.writePacket(sendBuffer.toByteArray());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void wakeThreads() {
|
||||
}
|
||||
|
||||
private static class ByteBufferDirectInputStream extends InputStream {
|
||||
private ByteBuffer buf;
|
||||
private ByteBufferDirectInputStream(ByteBuffer b) {
|
||||
this.buf = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return buf.remaining() > 0 ? ((int)buf.get() & 0xFF) : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() {
|
||||
return buf.remaining();
|
||||
}
|
||||
}
|
||||
|
||||
private ByteBuffer oldChunkBuffer = null;
|
||||
private LinkedList<ByteBuffer> readChunks = new LinkedList();
|
||||
|
||||
private ByteBuffer oldDecryptedChunkBuffer = null;
|
||||
private LinkedList<ByteBuffer> decryptedReadChunks = new LinkedList();
|
||||
|
||||
public void processReadPackets() {
|
||||
readChunks.clear();
|
||||
|
||||
if(oldChunkBuffer != null) {
|
||||
readChunks.add(oldChunkBuffer);
|
||||
}
|
||||
|
||||
byte[] packet;
|
||||
while((packet = EaglerAdapter.readPacket()) != null) {
|
||||
readChunks.add(ByteBuffer.wrap(packet));
|
||||
}
|
||||
if(!readChunks.isEmpty()) {
|
||||
|
||||
int cap = 0;
|
||||
for(ByteBuffer b : readChunks) {
|
||||
cap += b.limit();
|
||||
}
|
||||
|
||||
ByteBuffer stream = ByteBuffer.allocate(cap);
|
||||
for(ByteBuffer b : readChunks) {
|
||||
stream.put(b);
|
||||
}
|
||||
stream.flip();
|
||||
|
||||
if(this.isInputBeingDecrypted){
|
||||
decryptedReadChunks.clear();
|
||||
|
||||
if (oldDecryptedChunkBuffer != null) {
|
||||
decryptedReadChunks.add(oldDecryptedChunkBuffer);
|
||||
oldDecryptedChunkBuffer = null;
|
||||
}
|
||||
|
||||
byte[] block = new byte[/*2048*/32];
|
||||
byte[] decryp = new byte[this.inputBufferedBlockCipher.getOutputSize(/*2048*/32)];
|
||||
while (stream.remaining() >= /*2048*/32) {
|
||||
stream.get(block);
|
||||
int i = this.inputBufferedBlockCipher.processByte(block, 0, /*2048*/32, decryp, 0);
|
||||
ByteBuffer chunk = ByteBuffer.allocate(i);
|
||||
chunk.put(decryp, 0, i);
|
||||
chunk.flip();
|
||||
decryptedReadChunks.add(chunk);
|
||||
}
|
||||
|
||||
oldChunkBuffer = stream.remaining() > 0 ? stream.slice() : null;
|
||||
|
||||
int cap2 = 0;
|
||||
for (ByteBuffer b : decryptedReadChunks) {
|
||||
cap2 += b.limit();
|
||||
}
|
||||
|
||||
ByteBuffer decStream = ByteBuffer.allocate(cap2);
|
||||
for (ByteBuffer b : decryptedReadChunks) {
|
||||
decStream.put(b);
|
||||
}
|
||||
decStream.flip();
|
||||
|
||||
DataInputStream packetStream = new DataInputStream(new ByteBufferDirectInputStream(decStream));
|
||||
while (decStream.hasRemaining()) {
|
||||
decStream.mark();
|
||||
try {
|
||||
Packet pkt = Packet.readPacket(packetStream, false);
|
||||
if(logpackets)System.out.println("RECEIVING: " + pkt);
|
||||
pkt.processPacket(this.netHandler);
|
||||
} catch (EOFException e) {
|
||||
decStream.reset();
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
continue;
|
||||
} catch (Throwable e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (decStream.hasRemaining()) {
|
||||
oldDecryptedChunkBuffer = decStream.slice();
|
||||
} else {
|
||||
oldDecryptedChunkBuffer = null;
|
||||
}
|
||||
}else {
|
||||
DataInputStream packetStream = new DataInputStream(new ByteBufferDirectInputStream(stream));
|
||||
while (stream.hasRemaining()) {
|
||||
stream.mark();
|
||||
try {
|
||||
Packet pkt = Packet.readPacket(packetStream, false);
|
||||
boolean change=false;
|
||||
if (pkt != null) {
|
||||
if (Minecraft.getMinecraft().gameSettings.useDefaultProtocol && pkt instanceof Packet252SharedKey && !this.isInputBeingDecrypted) {
|
||||
packetStream = this.decryptInputStream(new ByteBufferDirectInputStream(stream));
|
||||
change=true;
|
||||
}
|
||||
if(logpackets)System.out.println("RECEIVING: " + pkt);
|
||||
pkt.processPacket(this.netHandler);
|
||||
if(change){
|
||||
processReadPackets();
|
||||
return;
|
||||
//break;
|
||||
}
|
||||
}
|
||||
} catch (EOFException e) {
|
||||
stream.reset();
|
||||
break;
|
||||
} catch (IOException e) {
|
||||
continue;
|
||||
} catch (Throwable e2) {
|
||||
e2.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (stream.hasRemaining()) {
|
||||
oldChunkBuffer = stream.slice();
|
||||
} else {
|
||||
oldChunkBuffer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void serverShutdown() {
|
||||
if(EaglerAdapter.connectionOpen()) {
|
||||
EaglerAdapter.endConnection();
|
||||
EaglerAdapter.setDebugVar("minecraftServer", "null");
|
||||
}
|
||||
}
|
||||
|
||||
private DataInputStream decryptInputStream(ByteBufferDirectInputStream var1) throws IOException
|
||||
{
|
||||
this.isInputBeingDecrypted = true;
|
||||
if(this.inputBufferedBlockCipher==null){
|
||||
this.inputBufferedBlockCipher = CryptManager.createBufferedBlockCipher(false, (Key) this.sharedKeyForEncryption);
|
||||
}
|
||||
return new DataInputStream(CryptManager.decryptInputStream(this.inputBufferedBlockCipher, var1));
|
||||
}
|
||||
|
||||
/**
|
||||
* flushes the stream and replaces it with an encryptedOutputStream
|
||||
*/
|
||||
private DataOutputStream encryptOuputStream(DataOutputStream var0) throws IOException
|
||||
{
|
||||
var0.flush();
|
||||
this.isOutputEncrypted = true;
|
||||
BufferedOutputStream var1 = new BufferedOutputStream(CryptManager.encryptOuputStream(this.sharedKeyForEncryption, var0), 5120);
|
||||
return new DataOutputStream(var1);
|
||||
}
|
||||
private DataOutputStream encryptOuputStream() throws IOException
|
||||
{
|
||||
if(this.outputBufferedBlockCipher==null){
|
||||
this.outputBufferedBlockCipher = CryptManager.createBufferedBlockCipher(true, (Key) this.sharedKeyForEncryption);
|
||||
}
|
||||
BufferedOutputStream var1 = new BufferedOutputStream(CryptManager.encryptOuputStream(this.outputBufferedBlockCipher, sendBuffer), 5120);
|
||||
return new DataOutputStream(var1);
|
||||
}
|
||||
|
||||
public int packetSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void networkShutdown(String var1, Object... var2) {
|
||||
serverShutdown();
|
||||
}
|
||||
|
||||
public void closeConnections() {
|
||||
if(EaglerAdapter.connectionOpen()) {
|
||||
EaglerAdapter.endConnection();
|
||||
EaglerAdapter.setDebugVar("minecraftServer", "null");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -7,6 +7,12 @@ import java.awt.Component;
|
|||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Frame;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
import java.awt.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -23,7 +29,9 @@ import java.nio.ByteOrder;
|
|||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.swing.JFileChooser;
|
||||
|
@ -33,10 +41,12 @@ import javax.swing.filechooser.FileFilter;
|
|||
|
||||
import org.java_websocket.client.WebSocketClient;
|
||||
import org.java_websocket.handshake.ServerHandshake;
|
||||
import org.json.JSONObject;
|
||||
import org.lwjgl.LWJGLException;
|
||||
import org.lwjgl.Sys;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import org.lwjgl.input.Mouse;
|
||||
import org.lwjgl.openal.AL;
|
||||
import org.lwjgl.opengl.ARBDebugOutput;
|
||||
import org.lwjgl.opengl.ARBDebugOutputCallback;
|
||||
import org.lwjgl.opengl.ARBOcclusionQuery2;
|
||||
|
@ -50,13 +60,15 @@ import org.lwjgl.opengl.GL13;
|
|||
import org.lwjgl.opengl.GL15;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
import org.lwjgl.opengl.GL30;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
import org.lwjgl.opengl.PixelFormat;
|
||||
import org.lwjgl.util.glu.GLU;
|
||||
|
||||
import de.cuina.fireandfuel.CodecJLayerMP3;
|
||||
import net.lax1dude.eaglercraft.AssetRepository;
|
||||
import net.lax1dude.eaglercraft.EarlyLoadScreen;
|
||||
import net.lax1dude.eaglercraft.ServerQuery;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.ProgramGL;
|
||||
import net.lax1dude.eaglercraft.adapter.EaglerAdapterImpl2.RateLimit;
|
||||
import net.lax1dude.eaglercraft.adapter.lwjgl.GameWindowListener;
|
||||
import net.minecraft.src.MathHelper;
|
||||
import paulscode.sound.SoundSystem;
|
||||
|
@ -257,6 +269,7 @@ public class EaglerAdapterImpl2 {
|
|||
public static final int _wGL_DRAW_FRAMEBUFFER = GL30.GL_DRAW_FRAMEBUFFER;
|
||||
public static final int _wGL_READ_FRAMEBUFFER = GL30.GL_READ_FRAMEBUFFER;
|
||||
public static final int _wGL_FRAMEBUFFER = GL30.GL_FRAMEBUFFER;
|
||||
public static final int _wGL_POLYGON_OFFSET_FILL = GL11.GL_POLYGON_OFFSET_FILL;
|
||||
|
||||
public static final class TextureGL {
|
||||
protected final int obj;
|
||||
|
@ -618,6 +631,9 @@ public class EaglerAdapterImpl2 {
|
|||
public static final float _wglGetTexParameterf(int p1) {
|
||||
return GL11.glGetTexParameterf(GL11.GL_TEXTURE_2D, p1);
|
||||
}
|
||||
public static final int _wglGetAttribLocation(ProgramGL p1, String p2) {
|
||||
return GL20.glGetAttribLocation(p1.obj, p2);
|
||||
}
|
||||
|
||||
|
||||
// =======================================================================================
|
||||
|
@ -752,10 +768,16 @@ public class EaglerAdapterImpl2 {
|
|||
Display.destroy();
|
||||
Keyboard.destroy();
|
||||
Mouse.destroy();
|
||||
eagler.dispose();
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
eagler.dispose();
|
||||
}
|
||||
});
|
||||
if(ss != null) {
|
||||
ss.cleanup();
|
||||
}
|
||||
AL.destroy();
|
||||
}
|
||||
public static final boolean isWindows() {
|
||||
return System.getProperty("os.name").toLowerCase().contains("windows");
|
||||
|
@ -862,6 +884,9 @@ public class EaglerAdapterImpl2 {
|
|||
Display.sync(performanceToFps);
|
||||
}
|
||||
|
||||
private static final Set<String> rateLimitedAddresses = new HashSet();
|
||||
private static final Set<String> blockedAddresses = new HashSet();
|
||||
|
||||
private static WebSocketClient clientSocket = null;
|
||||
private static final Object socketSync = new Object();
|
||||
|
||||
|
@ -870,15 +895,31 @@ public class EaglerAdapterImpl2 {
|
|||
private static class EaglerSocketClient extends WebSocketClient {
|
||||
|
||||
private Exception currentException = null;
|
||||
private boolean wasAbleToConnect = false;
|
||||
private String serverUriString;
|
||||
private boolean socketIsAlive = false;
|
||||
|
||||
public EaglerSocketClient(URI serverUri) throws IOException, InterruptedException {
|
||||
public EaglerSocketClient(URI serverUri, String str) throws IOException, InterruptedException {
|
||||
super(serverUri);
|
||||
this.setTcpNoDelay(true);
|
||||
this.setConnectionLostTimeout(5);
|
||||
System.out.println("[ws] connecting to "+serverUri.toString());
|
||||
rateLimitStatus = null;
|
||||
if(!this.connectBlocking(5, TimeUnit.SECONDS)) {
|
||||
synchronized(socketSync) {
|
||||
if(rateLimitStatus == null) {
|
||||
if(blockedAddresses.contains(str)) {
|
||||
rateLimitStatus = RateLimit.BLOCKED;
|
||||
}else if(rateLimitedAddresses.contains(str)) {
|
||||
rateLimitStatus = RateLimit.FAILED_POSSIBLY_LOCKED;
|
||||
}else {
|
||||
rateLimitStatus = RateLimit.FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IOException("could not connect socket", currentException);
|
||||
}
|
||||
serverUriString = str;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -887,6 +928,17 @@ public class EaglerAdapterImpl2 {
|
|||
readPackets.clear();
|
||||
System.out.println("[ws] disconnecting - " + currentException);
|
||||
currentException = null;
|
||||
if(!wasAbleToConnect && rateLimitStatus == null) {
|
||||
if(blockedAddresses.contains(serverUriString)) {
|
||||
rateLimitStatus = RateLimit.LOCKED;
|
||||
}else if(rateLimitedAddresses.contains(serverUriString)) {
|
||||
rateLimitStatus = RateLimit.FAILED_POSSIBLY_LOCKED;
|
||||
}else {
|
||||
rateLimitStatus = RateLimit.FAILED;
|
||||
}
|
||||
}else if(!socketIsAlive) {
|
||||
rateLimitStatus = RateLimit.LOCKED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -897,12 +949,28 @@ public class EaglerAdapterImpl2 {
|
|||
|
||||
@Override
|
||||
public void onMessage(String arg0) {
|
||||
System.out.println("[ws] " + arg0);
|
||||
wasAbleToConnect = true;
|
||||
synchronized(socketSync) {
|
||||
if(arg0.equalsIgnoreCase("BLOCKED")) {
|
||||
rateLimitedAddresses.add(serverUriString);
|
||||
if(rateLimitStatus == null) {
|
||||
rateLimitStatus = RateLimit.BLOCKED;
|
||||
}
|
||||
}else if(arg0.equalsIgnoreCase("LOCKED")) {
|
||||
blockedAddresses.add(serverUriString);
|
||||
rateLimitedAddresses.add(serverUriString);
|
||||
if(rateLimitStatus == null) {
|
||||
rateLimitStatus = RateLimit.NOW_LOCKED;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.close();
|
||||
currentException = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer arg0) {
|
||||
wasAbleToConnect = true;
|
||||
synchronized(socketSync) {
|
||||
readPackets.add(arg0.array());
|
||||
}
|
||||
|
@ -917,17 +985,19 @@ public class EaglerAdapterImpl2 {
|
|||
}
|
||||
|
||||
public static final boolean startConnection(String uri) {
|
||||
if(clientSocket == null) {
|
||||
try {
|
||||
clientSocket = new EaglerSocketClient(new URI(uri));
|
||||
return true;
|
||||
}catch(InterruptedException e) {
|
||||
clientSocket = null;
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if(clientSocket != null) {
|
||||
clientSocket.close();
|
||||
}
|
||||
rateLimitStatus = null;
|
||||
try {
|
||||
clientSocket = new EaglerSocketClient(new URI(uri), uri);
|
||||
return true;
|
||||
}catch(InterruptedException e) {
|
||||
clientSocket = null;
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -956,6 +1026,35 @@ public class EaglerAdapterImpl2 {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
private static RateLimit rateLimitStatus = null;
|
||||
public static enum RateLimit {
|
||||
NONE, FAILED, BLOCKED, FAILED_POSSIBLY_LOCKED, LOCKED, NOW_LOCKED;
|
||||
}
|
||||
public static final RateLimit getRateLimitStatus() {
|
||||
RateLimit l = rateLimitStatus;
|
||||
rateLimitStatus = null;
|
||||
return l;
|
||||
}
|
||||
public static final void logRateLimit(String addr, RateLimit l) {
|
||||
synchronized(socketSync) {
|
||||
if(l == RateLimit.LOCKED) {
|
||||
blockedAddresses.add(addr);
|
||||
}else {
|
||||
rateLimitedAddresses.add(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static final RateLimit checkRateLimitHistory(String addr) {
|
||||
synchronized(socketSync) {
|
||||
if(blockedAddresses.contains(addr)) {
|
||||
return RateLimit.LOCKED;
|
||||
}else if(rateLimitedAddresses.contains(addr)) {
|
||||
return RateLimit.BLOCKED;
|
||||
}else {
|
||||
return RateLimit.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static final byte[] loadLocalStorage(String key) {
|
||||
try {
|
||||
File f = new File("_eagstorage."+key+".dat");
|
||||
|
@ -1060,6 +1159,9 @@ public class EaglerAdapterImpl2 {
|
|||
ss.setListenerOrientation(var13, var14, var15, var16, var17, var18);
|
||||
ss.setListenerVelocity(vx, vy, vz);
|
||||
}
|
||||
public static final void setPlaybackOffsetDelay(float f) {
|
||||
// nah
|
||||
}
|
||||
private static int playbackId = 0;
|
||||
public static final int beginPlayback(String fileName, float x, float y, float z, float volume, float pitch) {
|
||||
int id = ++playbackId;
|
||||
|
@ -1179,7 +1281,7 @@ public class EaglerAdapterImpl2 {
|
|||
return Runtime.getRuntime().freeMemory();
|
||||
}
|
||||
public static final void exit() {
|
||||
System.exit(0);
|
||||
Runtime.getRuntime().halt(0);
|
||||
}
|
||||
public static final int _wArrayByteLength(Object obj) {
|
||||
return ((IntBuffer)obj).remaining() * 4;
|
||||
|
@ -1202,5 +1304,176 @@ public class EaglerAdapterImpl2 {
|
|||
appendbuffer.flip();
|
||||
return appendbuffer;
|
||||
}
|
||||
|
||||
public static final String getUserAgent() {
|
||||
return System.getProperty("os.name");
|
||||
}
|
||||
|
||||
public static final String getClipboard() {
|
||||
try {
|
||||
return (String)Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor);
|
||||
} catch (HeadlessException | UnsupportedFlavorException | IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final void setClipboard(String str) {
|
||||
StringSelection selection = new StringSelection(str);
|
||||
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
|
||||
clipboard.setContents(selection, selection);
|
||||
}
|
||||
|
||||
public static final void saveScreenshot() {
|
||||
|
||||
}
|
||||
|
||||
private static class ServerQueryImpl extends WebSocketClient implements ServerQuery {
|
||||
|
||||
private final LinkedList<QueryResponse> queryResponses = new LinkedList();
|
||||
private final LinkedList<byte[]> queryResponsesBytes = new LinkedList();
|
||||
private final String type;
|
||||
private boolean open;
|
||||
private boolean alive;
|
||||
private String serverUri;
|
||||
|
||||
private ServerQueryImpl(String type, URI serverUri, String serverUriString) throws IOException {
|
||||
super(serverUri);
|
||||
this.serverUri = serverUriString;
|
||||
this.type = type;
|
||||
this.open = true;
|
||||
this.alive = false;
|
||||
this.setConnectionLostTimeout(5);
|
||||
this.setTcpNoDelay(true);
|
||||
this.connect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int responseAvailable() {
|
||||
synchronized(queryResponses) {
|
||||
return queryResponses.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int responseBinaryAvailable() {
|
||||
synchronized(queryResponsesBytes) {
|
||||
return queryResponsesBytes.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryResponse getResponse() {
|
||||
synchronized(queryResponses) {
|
||||
return queryResponses.size() > 0 ? queryResponses.remove(0) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBinaryResponse() {
|
||||
synchronized(queryResponsesBytes) {
|
||||
return queryResponsesBytes.size() > 0 ? queryResponsesBytes.remove(0) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(int arg0, String arg1, boolean arg2) {
|
||||
open = false;
|
||||
if(!alive) {
|
||||
synchronized(socketSync) {
|
||||
if(EaglerAdapterImpl2.blockedAddresses.contains(serverUri)) {
|
||||
queryResponses.add(new QueryResponse(true));
|
||||
}else if(EaglerAdapterImpl2.rateLimitedAddresses.contains(serverUri)) {
|
||||
queryResponses.add(new QueryResponse(false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception arg0) {
|
||||
System.err.println("WebSocket query error: " + arg0.toString());
|
||||
open = false;
|
||||
this.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(String arg0) {
|
||||
this.alive = true;
|
||||
synchronized(queryResponses) {
|
||||
if(arg0.equalsIgnoreCase("BLOCKED")) {
|
||||
synchronized(socketSync) {
|
||||
EaglerAdapterImpl2.rateLimitedAddresses.add(serverUri);
|
||||
queryResponses.add(new QueryResponse(false));
|
||||
}
|
||||
this.close();
|
||||
return;
|
||||
}else if(arg0.equalsIgnoreCase("LOCKED")) {
|
||||
synchronized(socketSync) {
|
||||
EaglerAdapterImpl2.blockedAddresses.add(serverUri);
|
||||
queryResponses.add(new QueryResponse(true));
|
||||
}
|
||||
this.close();
|
||||
return;
|
||||
}else {
|
||||
try {
|
||||
QueryResponse q = new QueryResponse(new JSONObject(arg0));
|
||||
if(q.rateLimitStatus != null) {
|
||||
synchronized(socketSync) {
|
||||
if(q.rateLimitStatus == RateLimit.BLOCKED) {
|
||||
EaglerAdapterImpl2.rateLimitedAddresses.add(serverUri);
|
||||
}else if(q.rateLimitStatus == RateLimit.LOCKED) {
|
||||
EaglerAdapterImpl2.blockedAddresses.add(serverUri);
|
||||
}
|
||||
}
|
||||
this.close();
|
||||
}
|
||||
queryResponses.add(q);
|
||||
}catch(Throwable t) {
|
||||
System.err.println("Query response parse error: " + t.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(ByteBuffer arg0) {
|
||||
this.alive = true;
|
||||
synchronized(queryResponsesBytes) {
|
||||
byte[] pkt = new byte[arg0.limit()];
|
||||
arg0.get(pkt);
|
||||
queryResponsesBytes.add(pkt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(ServerHandshake arg0) {
|
||||
send("Accept: " + type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQueryOpen() {
|
||||
return open;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static final ServerQuery openQuery(String type, String uri) {
|
||||
try {
|
||||
return new ServerQueryImpl(type, new URI(uri), uri);
|
||||
}catch(Throwable t) {
|
||||
System.err.println("WebSocket query error: " + t.toString());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String serverToJoinOnLaunch = null;
|
||||
|
||||
public static final void setServerToJoinOnLaunch(String s) {
|
||||
serverToJoinOnLaunch = s;
|
||||
}
|
||||
|
||||
public static final String getServerToJoinOnLaunch() {
|
||||
return serverToJoinOnLaunch;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,58 +6,57 @@ import com.baislsl.png.util.ByteHandler;
|
|||
* Created by baislsl on 17-7-9.
|
||||
*/
|
||||
public class Chunk {
|
||||
protected long length;
|
||||
protected ChunkType type;
|
||||
protected byte[] data;
|
||||
protected byte[] crc = new byte[4];
|
||||
protected long length;
|
||||
protected ChunkType type;
|
||||
protected byte[] data;
|
||||
protected byte[] crc = new byte[4];
|
||||
|
||||
public byte[] dump() {
|
||||
byte[] output = new byte[4 + 4 + data.length + 4];
|
||||
Byte[] lengthBytes = new Byte[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
output[3 - i] = (byte) (length & 0xff);
|
||||
}
|
||||
String typeName = type.name().toUpperCase();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
output[4 + i] = (byte) typeName.charAt(i);
|
||||
}
|
||||
System.arraycopy(data, 0, output, 8, data.length);
|
||||
System.arraycopy(crc, 0, output, output.length - crc.length, crc.length);
|
||||
return output;
|
||||
}
|
||||
public byte[] dump() {
|
||||
byte[] output = new byte[4 + 4 + data.length + 4];
|
||||
Byte[] lengthBytes = new Byte[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
output[3 - i] = (byte) (length & 0xff);
|
||||
}
|
||||
String typeName = type.name().toUpperCase();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
output[4 + i] = (byte) typeName.charAt(i);
|
||||
}
|
||||
System.arraycopy(data, 0, output, 8, data.length);
|
||||
System.arraycopy(crc, 0, output, output.length - crc.length, crc.length);
|
||||
return output;
|
||||
}
|
||||
|
||||
protected Chunk(byte[] length, byte[] type, byte[] data, byte[] crc) {
|
||||
this.length = ByteHandler.byteToLong(length);
|
||||
this.data = data;
|
||||
this.crc = crc;
|
||||
|
||||
protected Chunk(byte[] length, byte[] type, byte[] data, byte[] crc) {
|
||||
this.length = ByteHandler.byteToLong(length);
|
||||
this.data = data;
|
||||
this.crc = crc;
|
||||
for (ChunkType chunkType : ChunkType.values()) {
|
||||
if (chunkType.name().equals(ByteHandler.byteToString(type))) {
|
||||
this.type = chunkType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (ChunkType chunkType : ChunkType.values()) {
|
||||
if (chunkType.name().equals(ByteHandler.byteToString(type))) {
|
||||
this.type = chunkType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public long dataLength() {
|
||||
return data.length;
|
||||
}
|
||||
|
||||
public long dataLength() {
|
||||
return data.length;
|
||||
}
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
public ChunkType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public ChunkType getType() {
|
||||
return type;
|
||||
}
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public byte[] getCrc() {
|
||||
return crc;
|
||||
}
|
||||
public byte[] getCrc() {
|
||||
return crc;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,31 +8,37 @@ import com.baislsl.png.decode.PNG;
|
|||
*/
|
||||
public enum ChunkType {
|
||||
|
||||
IHDR {
|
||||
@Override
|
||||
public void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
png.setIhdr(new IHDR(length, type, data, crc));
|
||||
}
|
||||
},
|
||||
PLTE {
|
||||
@Override
|
||||
public void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
png.setPlte(new PLTE(length, type, data, crc));
|
||||
}
|
||||
},
|
||||
IDAT {
|
||||
@Override
|
||||
public void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
png.add(new IDAT(length, type, data, crc));
|
||||
}
|
||||
},
|
||||
IEND {
|
||||
@Override
|
||||
public void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
png.setIend(new IEND(length, type, data, crc));
|
||||
}
|
||||
};
|
||||
IHDR {
|
||||
@Override
|
||||
public void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
png.setIhdr(new IHDR(length, type, data, crc));
|
||||
}
|
||||
},
|
||||
tRNS {
|
||||
@Override
|
||||
public void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
png.setTrns(new tRNS(length, type, data, crc));
|
||||
}
|
||||
},
|
||||
PLTE {
|
||||
@Override
|
||||
public void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
png.setPlte(new PLTE(length, type, data, crc));
|
||||
}
|
||||
},
|
||||
IDAT {
|
||||
@Override
|
||||
public void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
png.add(new IDAT(length, type, data, crc));
|
||||
}
|
||||
},
|
||||
IEND {
|
||||
@Override
|
||||
public void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
png.setIend(new IEND(length, type, data, crc));
|
||||
}
|
||||
};
|
||||
|
||||
public abstract void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException;
|
||||
public abstract void apply(PNG png, byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException;
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ package com.baislsl.png.chunk;
|
|||
*/
|
||||
public class IDAT extends Chunk {
|
||||
|
||||
public IDAT(byte[] length, byte[] type, byte[] data, byte[] crc) {
|
||||
super(length, type, data, crc);
|
||||
}
|
||||
public IDAT(byte[] length, byte[] type, byte[] data, byte[] crc) {
|
||||
super(length, type, data, crc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ package com.baislsl.png.chunk;
|
|||
* Created by baislsl on 17-7-9.
|
||||
*/
|
||||
public class IEND extends Chunk {
|
||||
public IEND(byte[] length, byte[] type, byte[] data, byte[] crc) {
|
||||
super(length, type, data, crc);
|
||||
}
|
||||
public IEND(byte[] length, byte[] type, byte[] data, byte[] crc) {
|
||||
super(length, type, data, crc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,112 +7,113 @@ import com.baislsl.png.util.ByteHandler;
|
|||
* Created by baislsl on 17-7-9.
|
||||
*/
|
||||
public class IHDR extends Chunk {
|
||||
private long width, height;
|
||||
private int bitDepth, colorType, compressionMethod, filterMethod, interlaceMethod;
|
||||
private long width, height;
|
||||
private int bitDepth, colorType, compressionMethod, filterMethod, interlaceMethod;
|
||||
|
||||
final private static int[] colorTypeValid = {0, 2, 3, 4, 6};
|
||||
final private static int[][] mapColorBitDepth = {
|
||||
{1, 2, 4, 8, 16}, // color type = 0
|
||||
{},
|
||||
{8, 16}, // color type = 2
|
||||
{1, 2, 4, 8}, // color type = 3
|
||||
{8, 16}, // color type = 4
|
||||
{},
|
||||
{8, 16} // color type = 6
|
||||
};
|
||||
final private static int[] colorTypeValid = { 0, 2, 3, 4, 6 };
|
||||
final private static int[][] mapColorBitDepth = { { 1, 2, 4, 8, 16 }, // color type = 0
|
||||
{}, { 8, 16 }, // color type = 2
|
||||
{ 1, 2, 4, 8 }, // color type = 3
|
||||
{ 8, 16 }, // color type = 4
|
||||
{}, { 8, 16 } // color type = 6
|
||||
};
|
||||
|
||||
// the number of bytes per complete pixel, rounding up to one
|
||||
public int getBpp() {
|
||||
if (colorType == 2) { // Each pixel is an R,G,B triple.
|
||||
return 3;
|
||||
} else if (colorType == 6) { // Each pixel is an R,G,B triple, followed by an alpha sample.
|
||||
return 4;
|
||||
} else if (colorType == 3) { // palette index, roll up to 1
|
||||
return 1;
|
||||
} else {
|
||||
//LOG.error("Error when find bpp");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
// the number of bytes per complete pixel, rounding up to one
|
||||
public int getBpp() {
|
||||
if (colorType == 2) { // Each pixel is an R,G,B triple.
|
||||
return 3;
|
||||
} else if (colorType == 6) { // Each pixel is an R,G,B triple, followed by an alpha sample.
|
||||
return 4;
|
||||
} else if (colorType == 3) { // palette index, roll up to 1
|
||||
return 1;
|
||||
} else {
|
||||
// LOG.error("Error when find bpp");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public IHDR(byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
super(length, type, data, crc);
|
||||
build();
|
||||
checkLegal();
|
||||
}
|
||||
public IHDR(byte[] length, byte[] type, byte[] data, byte[] crc) throws DecodeException {
|
||||
super(length, type, data, crc);
|
||||
build();
|
||||
checkLegal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("width=");sb.append(width);
|
||||
sb.append("height=");sb.append(height);
|
||||
sb.append("bitDepth=");sb.append(bitDepth);
|
||||
sb.append("colorType=");sb.append(colorType);
|
||||
sb.append("compressionMethod=");sb.append(compressionMethod);
|
||||
sb.append("filterMethod=");sb.append(filterMethod);
|
||||
sb.append("interlaceMethod=");sb.append(interlaceMethod);
|
||||
return sb.toString();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("width=");
|
||||
sb.append(width);
|
||||
sb.append("height=");
|
||||
sb.append(height);
|
||||
sb.append("bitDepth=");
|
||||
sb.append(bitDepth);
|
||||
sb.append("colorType=");
|
||||
sb.append(colorType);
|
||||
sb.append("compressionMethod=");
|
||||
sb.append(compressionMethod);
|
||||
sb.append("filterMethod=");
|
||||
sb.append(filterMethod);
|
||||
sb.append("interlaceMethod=");
|
||||
sb.append(interlaceMethod);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void build() {
|
||||
this.width = ByteHandler.byteToLong(data);
|
||||
this.height = ByteHandler.byteToLong(data, 4);
|
||||
this.bitDepth = ((int) data[8]) & 0xFF;
|
||||
this.colorType = ((int) data[9]) & 0xFF;
|
||||
this.compressionMethod = ((int) data[10]) & 0xFF;
|
||||
this.filterMethod = ((int) data[11]) & 0xFF;
|
||||
this.interlaceMethod = ((int) data[12]) & 0xFF;
|
||||
}
|
||||
|
||||
private void build() {
|
||||
this.width = ByteHandler.byteToLong(data);
|
||||
this.height = ByteHandler.byteToLong(data, 4);
|
||||
this.bitDepth = ((int)data[8]) & 0xFF;
|
||||
this.colorType = ((int)data[9]) & 0xFF;
|
||||
this.compressionMethod = ((int)data[10]) & 0xFF;
|
||||
this.filterMethod = ((int)data[11]) & 0xFF;
|
||||
this.interlaceMethod = ((int)data[12]) & 0xFF;
|
||||
}
|
||||
private void checkLegal() throws DecodeException {
|
||||
boolean legal = false;
|
||||
for (int c : colorTypeValid) {
|
||||
if (c == colorType) {
|
||||
legal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!legal) {
|
||||
throw new DecodeException("Initialize IHDR : color type not legal to be " + colorType);
|
||||
}
|
||||
for (int b : mapColorBitDepth[colorType]) {
|
||||
if (b == bitDepth) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new DecodeException(
|
||||
"Initialzie IHDR : bit depth " + bitDepth + " not valid matching color type " + colorType);
|
||||
}
|
||||
|
||||
public long getWidth() {
|
||||
return this.width;
|
||||
}
|
||||
|
||||
private void checkLegal() throws DecodeException {
|
||||
boolean legal = false;
|
||||
for (int c : colorTypeValid) {
|
||||
if (c == colorType) {
|
||||
legal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!legal) {
|
||||
throw new DecodeException("Initialize IHDR : color type not legal to be " + colorType);
|
||||
}
|
||||
for (int b : mapColorBitDepth[colorType]) {
|
||||
if (b == bitDepth) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new DecodeException("Initialzie IHDR : bit depth " + bitDepth + " not valid matching color type " + colorType);
|
||||
}
|
||||
public long getHeight() {
|
||||
return this.height;
|
||||
}
|
||||
|
||||
public int getBitDepth() {
|
||||
return bitDepth;
|
||||
}
|
||||
|
||||
public long getWidth() {
|
||||
return this.width;
|
||||
}
|
||||
public int getColorType() {
|
||||
return colorType;
|
||||
}
|
||||
|
||||
public long getHeight() {
|
||||
return this.height;
|
||||
}
|
||||
public int getCompressionMethod() {
|
||||
return compressionMethod;
|
||||
}
|
||||
|
||||
public int getBitDepth() {
|
||||
return bitDepth;
|
||||
}
|
||||
|
||||
public int getColorType() {
|
||||
return colorType;
|
||||
}
|
||||
|
||||
public int getCompressionMethod() {
|
||||
return compressionMethod;
|
||||
}
|
||||
|
||||
public int getFilterMethod() {
|
||||
return filterMethod;
|
||||
}
|
||||
|
||||
public int getInterlaceMethod() {
|
||||
return interlaceMethod;
|
||||
}
|
||||
public int getFilterMethod() {
|
||||
return filterMethod;
|
||||
}
|
||||
|
||||
public int getInterlaceMethod() {
|
||||
return interlaceMethod;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user