Merge pull request 'Mod detection refactoring' (#509) from modDetectionRework into master
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful
Reviewed-on: #509 Reviewed-by: YoyoNow <jwsteam@nidido.de>
Dieser Commit ist enthalten in:
Commit
c74178abe1
21
build.gradle
21
build.gradle
@ -59,8 +59,26 @@ repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url 'https://m2.dv8tion.net/releases'
|
||||
content {
|
||||
includeGroup 'net.dv8tion'
|
||||
}
|
||||
}
|
||||
maven {
|
||||
url 'https://repo.lunarclient.dev'
|
||||
content {
|
||||
includeGroup 'com.lunarclient'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
exclude 'META-INF/*'
|
||||
//https://imperceptiblethoughts.com/shadow/configuration/minimizing/
|
||||
minimize {
|
||||
exclude project(':')
|
||||
}
|
||||
duplicatesStrategy DuplicatesStrategy.INCLUDE
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly 'org.projectlombok:lombok:1.18.22'
|
||||
@ -75,4 +93,7 @@ dependencies {
|
||||
}
|
||||
|
||||
implementation project(":CommonCore")
|
||||
|
||||
implementation 'com.lunarclient:apollo-api:1.1.0'
|
||||
implementation 'com.lunarclient:apollo-common:1.1.0'
|
||||
}
|
@ -23,11 +23,9 @@ import de.steamwar.bungeecore.bot.SteamwarDiscordBot;
|
||||
import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig;
|
||||
import de.steamwar.bungeecore.commands.*;
|
||||
import de.steamwar.bungeecore.listeners.*;
|
||||
import de.steamwar.bungeecore.listeners.mods.*;
|
||||
import de.steamwar.bungeecore.listeners.ping.PingListener;
|
||||
import de.steamwar.bungeecore.mods.ServerListPing;
|
||||
import de.steamwar.bungeecore.mods.*;
|
||||
import de.steamwar.bungeecore.network.BungeeNetworkHandler;
|
||||
import de.steamwar.bungeecore.network.NetworkReceiver;
|
||||
import de.steamwar.bungeecore.network.SWScriptSyntaxForwarder;
|
||||
import de.steamwar.bungeecore.tablist.TablistManager;
|
||||
import de.steamwar.command.SWCommandUtils;
|
||||
import de.steamwar.command.SWTypeMapperCreator;
|
||||
@ -38,7 +36,6 @@ import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.Team;
|
||||
import de.steamwar.sql.UserElo;
|
||||
import de.steamwar.sql.internal.Statement;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
@ -76,11 +73,6 @@ public class BungeeCore extends Plugin {
|
||||
|
||||
@Override
|
||||
public void onEnable(){
|
||||
getProxy().registerChannel("sw:bridge");
|
||||
getProxy().registerChannel("fabricmodsender:mods");
|
||||
getProxy().registerChannel("nochatreports:sync");
|
||||
getProxy().registerChannel("sw:script_syntax");
|
||||
|
||||
setInstance(this);
|
||||
MAIN_SERVER = ProxyServer.getInstance().getConfig().getListeners().stream().anyMatch(info -> ((InetSocketAddress) info.getSocketAddress()).getPort() == 25565);
|
||||
loadConfig();
|
||||
@ -98,25 +90,22 @@ public class BungeeCore extends Plugin {
|
||||
return tabCompleter.apply(sender, s);
|
||||
}
|
||||
});
|
||||
BungeeCord.getInstance().getScheduler().schedule(this, TabCompletionCache::invalidateOldEntries, 1, 1, TimeUnit.SECONDS);
|
||||
ProxyServer.getInstance().getScheduler().schedule(this, TabCompletionCache::invalidateOldEntries, 1, 1, TimeUnit.SECONDS);
|
||||
|
||||
new NonFabricFabricCheck();
|
||||
|
||||
new SWScriptSyntaxForwarder();
|
||||
new ConnectionListener();
|
||||
new Forge();
|
||||
new Forge12();
|
||||
new LabyMod();
|
||||
new Hostname();
|
||||
new ServerListPing();
|
||||
new PluginMessage();
|
||||
new Schematica();
|
||||
new Badlion();
|
||||
new FabricModSender();
|
||||
new ReplayMod();
|
||||
new FML2();
|
||||
|
||||
new ConnectionListener();
|
||||
new ChatListener();
|
||||
new BanListener();
|
||||
new CheckListener();
|
||||
new ModLoaderBlocker();
|
||||
new WorldDownloader();
|
||||
new BrandListener();
|
||||
new Fabric();
|
||||
new SubserverProtocolFixer();
|
||||
new PingListener();
|
||||
new IPSanitizer();
|
||||
|
||||
local = new Node.LocalNode();
|
||||
if(MAIN_SERVER) {
|
||||
@ -186,7 +175,6 @@ public class BungeeCore extends Plugin {
|
||||
|
||||
new EventStarter();
|
||||
new SessionManager();
|
||||
new NetworkReceiver();
|
||||
BungeeNetworkHandler.register();
|
||||
tablistManager = new TablistManager();
|
||||
new SettingsChangedListener();
|
||||
@ -321,9 +309,6 @@ public class BungeeCore extends Plugin {
|
||||
serverName,
|
||||
cmds.toArray(new String[0])
|
||||
);
|
||||
if(server.getBoolean("modchecked", false)) {
|
||||
ModLoaderBlocker.addServer(serverName);
|
||||
}
|
||||
}
|
||||
|
||||
File discordFile = new File(System.getProperty("user.home"), "discord.yml");
|
||||
|
@ -31,6 +31,7 @@ import java.util.logging.Level;
|
||||
|
||||
public abstract class Node {
|
||||
|
||||
//-Xquickstart Langzeitperformance testen!
|
||||
private static final List<String> OPENJ9_ARGS = Arrays.asList(
|
||||
"-XX:+EnableCRIUSupport", "-XX:-CRIURestoreNonPortableMode",
|
||||
"-Xgc:excessiveGCratio=80", "-Xdisableexplicitgc", "-Xnoclassgc", "-Xmos128M", "-Xmns48M", "-XX:+ExitOnOutOfMemoryError", // initial heap half values of memory observed by 1.19 spectate server
|
||||
|
@ -23,6 +23,7 @@ import com.google.gson.JsonParser;
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.Message;
|
||||
import de.steamwar.bungeecore.listeners.ConnectionListener;
|
||||
import de.steamwar.bungeecore.listeners.IPSanitizer;
|
||||
import de.steamwar.command.PreviousArguments;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
@ -96,14 +97,15 @@ public class PunishmentCommand {
|
||||
|
||||
ProxiedPlayer player = ProxyServer.getInstance().getPlayer(user.getUUID());
|
||||
if (player != null) {
|
||||
String ip = IPSanitizer.getTrueAddress(player.getPendingConnection()).getHostAddress();
|
||||
ChatSender.disconnect(player).system(punishmentMessage(user, Punishment.PunishmentType.Ban));
|
||||
for (BannedUserIPs banned : BannedUserIPs.get(player.getAddress().getAddress().getHostAddress())) {
|
||||
for (BannedUserIPs banned : BannedUserIPs.get(ip)) {
|
||||
SteamwarUser bannedUser = SteamwarUser.get(banned.getUserID());
|
||||
if (bannedUser.isPunished(Punishment.PunishmentType.Ban) && bannedUser.getPunishment(Punishment.PunishmentType.Ban).getEndTime().before(time)) {
|
||||
bannedUser.punish(Punishment.PunishmentType.Ban, time, banReason, punisher.getId(), perma);
|
||||
}
|
||||
}
|
||||
BannedUserIPs.banIP(user.getId(), player.getAddress().getAddress().getHostAddress());
|
||||
BannedUserIPs.banIP(user.getId(), ip);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
package de.steamwar.bungeecore.commands;
|
||||
|
||||
import de.steamwar.bungeecore.ArenaMode;
|
||||
import de.steamwar.bungeecore.listeners.mods.ModLoaderBlocker;
|
||||
import de.steamwar.command.SWCommandUtils;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
import de.steamwar.command.TypeValidator;
|
||||
@ -49,10 +48,6 @@ public class TypeMappers {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ModLoaderBlocker.isFabric(value)) {
|
||||
messageSender.send("MODLOADER_DENIED");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ package de.steamwar.bungeecore.commands;
|
||||
|
||||
import de.steamwar.bungeecore.Message;
|
||||
import de.steamwar.bungeecore.Storage;
|
||||
import de.steamwar.bungeecore.listeners.mods.Utils;
|
||||
import de.steamwar.bungeecore.mods.ModUtils;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import de.steamwar.command.SWCommandUtils;
|
||||
import de.steamwar.command.TypeMapper;
|
||||
@ -118,7 +118,7 @@ public class WhoisCommand extends SWCommand {
|
||||
sender.system("WHOIS_CURRENT_SERVER", target.getServer().getInfo().getName());
|
||||
sender.system("WHOIS_CURRENT_PROTOCOL", target.getPendingConnection().getVersion());
|
||||
|
||||
List<Mod> mods = Utils.playerModMap.get(user.getUUID());
|
||||
List<Mod> mods = ModUtils.getPlayerModMap().get(user.getUUID());
|
||||
if(mods == null)
|
||||
mods = Collections.emptyList();
|
||||
|
||||
|
@ -23,7 +23,6 @@ import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.Message;
|
||||
import de.steamwar.bungeecore.commands.PunishmentCommand;
|
||||
import de.steamwar.bungeecore.commands.WebpasswordCommand;
|
||||
import de.steamwar.bungeecore.listeners.mods.Forge;
|
||||
import de.steamwar.messages.ChatSender;
|
||||
import de.steamwar.sql.BannedUserIPs;
|
||||
import de.steamwar.sql.Punishment;
|
||||
@ -47,17 +46,17 @@ public class BanListener extends BasicListener {
|
||||
ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> {
|
||||
PendingConnection connection = event.getConnection();
|
||||
SteamwarUser user = SteamwarUser.getOrCreate(connection.getUniqueId(), connection.getName(), ConnectionListener::newPlayer, WebpasswordCommand::changeUsername);
|
||||
String ip = IPSanitizer.getTrueAddress(connection).getHostAddress();
|
||||
if (user.isPunished(Punishment.PunishmentType.Ban)) {
|
||||
event.setCancelled(true);
|
||||
BannedUserIPs.banIP(user.getId(), connection.getAddress().getAddress().getHostAddress());
|
||||
BannedUserIPs.banIP(user.getId(), ip);
|
||||
ChatSender.of(event).system(PunishmentCommand.punishmentMessage(user, Punishment.PunishmentType.Ban));
|
||||
event.completeIntent(BungeeCore.get());
|
||||
return;
|
||||
}
|
||||
|
||||
List<BannedUserIPs> ips = BannedUserIPs.get(connection.getAddress().getAddress().getHostAddress());
|
||||
List<BannedUserIPs> ips = BannedUserIPs.get(ip);
|
||||
if(!ips.isEmpty()){
|
||||
|
||||
Timestamp highestBan = ips.get(0).getTimestamp();
|
||||
boolean perma = false;
|
||||
for(BannedUserIPs banned : ips) {
|
||||
@ -74,7 +73,7 @@ public class BanListener extends BasicListener {
|
||||
}
|
||||
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/ban " + user.getUserName() + " "
|
||||
+ (perma?"perma":highestBan.toLocalDateTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy_HH:mm")))
|
||||
+ " Bannumgehung");
|
||||
+ " Ban Evasion - Bannumgehung");
|
||||
|
||||
ChatSender.serverteamReceivers().forEach(sender -> sender.system(
|
||||
"BAN_AVOIDING_ALERT",
|
||||
@ -89,7 +88,7 @@ public class BanListener extends BasicListener {
|
||||
));
|
||||
}
|
||||
|
||||
Forge.onServerConnected(event);
|
||||
event.completeIntent(BungeeCore.get());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners;
|
||||
|
||||
import de.steamwar.messages.ChatSender;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
|
||||
public class BrandListener extends BasicListener {
|
||||
|
||||
private static boolean isLocalHost(InetAddress addr) {
|
||||
if (addr.isAnyLocalAddress() || addr.isLoopbackAddress()) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
return NetworkInterface.getByInetAddress(addr) != null;
|
||||
} catch (SocketException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerSwitch(PluginMessageEvent event) {
|
||||
if(!event.getTag().equals("minecraft:brand") && !event.getTag().equals("MC|Brand")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getReceiver() == null || isLocalHost(event.getReceiver().getAddress().getAddress())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(event.getReceiver() instanceof ProxiedPlayer)) {
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
|
||||
ProxiedPlayer player = (ProxiedPlayer) event.getReceiver();
|
||||
String brandString = ChatSender.of(player).parseToLegacy("STEAMWAR_BRAND", ProxyServer.getInstance().getName(), player.getServer().getInfo().getName(), new String(event.getData(), 1, event.getData().length - 1));
|
||||
|
||||
ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer();
|
||||
DefinedPacket.writeString(brandString, brand);
|
||||
player.sendData(event.getTag(), DefinedPacket.toArray(brand));
|
||||
brand.release();
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ import de.steamwar.bungeecore.commands.ChallengeCommand;
|
||||
import de.steamwar.bungeecore.commands.CheckCommand;
|
||||
import de.steamwar.bungeecore.commands.ModCommand;
|
||||
import de.steamwar.bungeecore.commands.MsgCommand;
|
||||
import de.steamwar.bungeecore.listeners.mods.Utils;
|
||||
import de.steamwar.bungeecore.mods.ModUtils;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import net.md_5.bungee.api.AbstractReconnectHandler;
|
||||
@ -156,7 +156,7 @@ public class ConnectionListener extends BasicListener {
|
||||
public void onDisconnect(PlayerDisconnectEvent e){
|
||||
ChallengeCommand.remove(e.getPlayer());
|
||||
MsgCommand.remove(e.getPlayer());
|
||||
Utils.playerModMap.remove(e.getPlayer().getUniqueId());
|
||||
ModUtils.getPlayerModMap().remove(e.getPlayer().getUniqueId());
|
||||
ModCommand.playerFilterType.remove(e.getPlayer());
|
||||
}
|
||||
}
|
||||
|
66
src/de/steamwar/bungeecore/listeners/IPSanitizer.java
Normale Datei
66
src/de/steamwar/bungeecore/listeners/IPSanitizer.java
Normale Datei
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import net.md_5.bungee.api.connection.PendingConnection;
|
||||
import net.md_5.bungee.api.event.LoginEvent;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class IPSanitizer extends BasicListener {
|
||||
|
||||
private static final Field initialHandlerCh;
|
||||
static {
|
||||
try {
|
||||
initialHandlerCh = InitialHandler.class.getDeclaredField("ch");
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new SecurityException("Could not initialize Reflection", e);
|
||||
}
|
||||
initialHandlerCh.setAccessible(true);
|
||||
}
|
||||
|
||||
public static ChannelWrapper getChannelWrapper(PendingConnection connection) {
|
||||
try {
|
||||
return (ChannelWrapper) initialHandlerCh.get(connection);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new SecurityException("Could not get channel wrapper", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static InetAddress getTrueAddress(PendingConnection connection) {
|
||||
return ((InetSocketAddress) getChannelWrapper(connection).getHandle().remoteAddress()).getAddress();
|
||||
}
|
||||
|
||||
|
||||
private final InetSocketAddress sanitized = new InetSocketAddress("127.127.127.127", 25565);
|
||||
|
||||
@EventHandler
|
||||
public void loginEvent(LoginEvent e) {
|
||||
BungeeCore.get().getLogger().log(Level.INFO, e.getConnection().getSocketAddress() + " has logged in with user name " + e.getConnection().getName());
|
||||
getChannelWrapper(e.getConnection()).setRemoteAddress(sanitized);
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.Message;
|
||||
import de.steamwar.bungeecore.Storage;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.connection.Connection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.LoginEvent;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class NonFabricFabricCheck extends BasicListener {
|
||||
|
||||
private final Set<UUID> usingFabric = new HashSet<>();
|
||||
|
||||
private final Set<ProxiedPlayer> checking = new HashSet<>();
|
||||
private final Set<ProxiedPlayer> vanilla = new HashSet<>();
|
||||
|
||||
{
|
||||
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), usingFabric::clear, 0, 15, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void pluginMessageEvent(PluginMessageEvent e) {
|
||||
Connection sender = e.getSender();
|
||||
if(!(sender instanceof ProxiedPlayer))
|
||||
return;
|
||||
|
||||
ProxiedPlayer p = (ProxiedPlayer) sender;
|
||||
if (e.getTag().equals("minecraft:register") && new String(e.getData()).contains("fabric-screen-handler-api-v1:open_screen")) {
|
||||
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
|
||||
if (!sender.isConnected()) return;
|
||||
if (!vanilla.remove(p)) return;
|
||||
if (Storage.fabricCheckedPlayers.containsKey(p)) return;
|
||||
p.disconnect(Message.parse("MOD_USE_MODSENDER", p));
|
||||
}, 25, TimeUnit.SECONDS);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!e.getTag().equals("minecraft:brand"))
|
||||
return;
|
||||
|
||||
if(!new String(e.getData()).equals("vanilla"))
|
||||
return;
|
||||
vanilla.add(p);
|
||||
|
||||
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
|
||||
if (!p.isConnected()) return;
|
||||
if (Storage.fabricCheckedPlayers.containsKey(p)) return;
|
||||
checking.add(p);
|
||||
p.sendData("fabric-screen-handler-api-v1:open_screen", new byte[] {0});
|
||||
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> checking.remove(p), 1, TimeUnit.SECONDS);
|
||||
}, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerPreLogin(LoginEvent e) {
|
||||
if (usingFabric.remove(e.getConnection().getUniqueId())) {
|
||||
e.getConnection().disconnect(Message.parse("MOD_USE_MODSENDER", Locale.getDefault()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerDisconnect(PlayerDisconnectEvent e) {
|
||||
if (checking.remove(e.getPlayer())) {
|
||||
usingFabric.add(e.getPlayer().getUniqueId());
|
||||
}
|
||||
vanilla.remove(e.getPlayer());
|
||||
}
|
||||
}
|
216
src/de/steamwar/bungeecore/listeners/PluginMessage.java
Normale Datei
216
src/de/steamwar/bungeecore/listeners/PluginMessage.java
Normale Datei
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners;
|
||||
|
||||
import com.lunarclient.apollo.ApolloManager;
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.commands.TeamCommand;
|
||||
import de.steamwar.bungeecore.mods.*;
|
||||
import de.steamwar.bungeecore.network.ServerMetaInfo;
|
||||
import de.steamwar.messages.ChatSender;
|
||||
import de.steamwar.network.packets.NetworkPacket;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.Connection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.connection.Server;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class PluginMessage extends BasicListener {
|
||||
|
||||
public static void send(ProxiedPlayer player, String legacyChannel, String channel, byte[] data) {
|
||||
// 1.12 format change
|
||||
send(player, player.getPendingConnection().getVersion() > 340 ? channel : legacyChannel, data);
|
||||
}
|
||||
|
||||
public static void send(ProxiedPlayer player, String channel, byte[] data) {
|
||||
if(((InitialHandler)player.getPendingConnection()).getRegisteredChannels().contains(channel))
|
||||
player.sendData(channel, data);
|
||||
}
|
||||
|
||||
private static final Parser UNKNOWN = event -> BungeeCore.get().getLogger().log(Level.WARNING, () -> "Undefined PluginMessage on channel " + event.getTag() + " from " + event.getSender() + " received.\n" + Arrays.toString(event.getData()));
|
||||
private static final Parser PASS_THROUGH = event -> event.setCancelled(false);
|
||||
private static final Parser DROP = event -> {};
|
||||
|
||||
private final Lunar lunar = new Lunar();
|
||||
|
||||
private final Set<String> knownBrands = new HashSet<>();
|
||||
private final Set<String> knownChannels = new HashSet<>();
|
||||
private final Map<String, Parser> handlers = new HashMap<>();
|
||||
|
||||
public PluginMessage() {
|
||||
LabyMod labyMod = new LabyMod();
|
||||
FML fml = new FML();
|
||||
FabricModSender fabricModSender = new FabricModSender();
|
||||
WorldDownloader wdl = new WorldDownloader();
|
||||
|
||||
knownBrands.add("vanilla");
|
||||
knownBrands.add("fabric");
|
||||
knownBrands.add("forge"); //Forge registers all channels the server registers
|
||||
|
||||
knownChannels.add("fabric:container/open");
|
||||
knownChannels.add("fabric:registry/sync/direct");
|
||||
knownChannels.add("fabric-screen-handler-api-v1:open_screen");
|
||||
|
||||
knownChannels.add(FML.CHANNEL);
|
||||
knownChannels.add("fml:loginwrapper");
|
||||
knownChannels.add("fml:handshake");
|
||||
knownChannels.add("fml:play");
|
||||
knownChannels.add("forge:tier_sorting");
|
||||
knownChannels.add("forge:split");
|
||||
knownChannels.add("forge:login");
|
||||
knownChannels.add("forge:handshake");
|
||||
|
||||
knownChannels.add(ApolloManager.PLUGIN_MESSAGE_CHANNEL);
|
||||
|
||||
knownChannels.add("Replay|Restrict");
|
||||
knownChannels.add("replaymod:restrict");
|
||||
knownChannels.add("WDL|CONTROL");
|
||||
knownChannels.add("wdl:control");
|
||||
knownChannels.add("worldedit:cui");
|
||||
|
||||
register("REGISTER", false, directional(this::serverRegistersChannel, this::clientRegistersChannel));
|
||||
register("minecraft:register", false, directional(this::serverRegistersChannel, this::clientRegistersChannel));
|
||||
|
||||
register("BungeeCord", false, onlySWSource(PASS_THROUGH));
|
||||
register("bungeecord:main", false, onlySWSource(PASS_THROUGH));
|
||||
register("MC|Brand", false, directional(this::steamWarBrand, this::userBrand));
|
||||
register("minecraft:brand", false, directional(this::steamWarBrand, this::userBrand));
|
||||
|
||||
register("sw:bridge", false, directional(onlySWSource(async(event -> NetworkPacket.handle(new ServerMetaInfo(((Server) event.getSender()).getInfo()), event.getData()))), UNKNOWN));
|
||||
register("worldedit:cui", false, PASS_THROUGH);
|
||||
register("fabricmodsender:mods", true, directional(UNKNOWN, fabricModSender::handlePluginMessage));
|
||||
|
||||
register("WDL|REQUEST", false, DROP);
|
||||
register("wdl:request", false, DROP);
|
||||
register("WDL|INIT", true, directional(UNKNOWN, wdl::handlePluginMessage));
|
||||
register("wdl:init", true, directional(UNKNOWN, wdl::handlePluginMessage));
|
||||
|
||||
register(ApolloManager.PLUGIN_MESSAGE_CHANNEL, true, async(lunar::handlePluginMessage));
|
||||
register("LMC", true, directional(UNKNOWN, async(labyMod::handlePluginMessage)));
|
||||
register("labymod3:main", true, directional(UNKNOWN, async(labyMod::handlePluginMessage)));
|
||||
register(FML.CHANNEL, true, directional(UNKNOWN, async(fml::handlePluginMessage)));
|
||||
|
||||
//vanilla does not register any channels (sends only one minecraft:brand vanilla, nothing else (potential spoofed client detection))
|
||||
//meteor https://github.com/MeteorDevelopment/meteor-client/blob/master/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/ServerSpoof.java https://github.com/MeteorDevelopment/meteor-client/blob/master/src/main/java/meteordevelopment/meteorclient/systems/modules/misc/DiscordPresence.java
|
||||
//feather:client https://github.com/Koupah/Feather-Client-API/blob/main/src/club/koupah/feather/handler/FeatherHandler.java
|
||||
//litematica/malilib https://github.com/maruohon/litematica/issues/75 https://github.com/maruohon/malilib/blob/liteloader_1.12.2/src/main/java/malilib/network/message/ConfigLockPacketHandler.java#L65
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginMessage(PluginMessageEvent event) {
|
||||
event.setCancelled(true);
|
||||
|
||||
try {
|
||||
handlers.getOrDefault(event.getTag(), UNKNOWN).handle(event);
|
||||
} catch (Exception e) {
|
||||
throw new SecurityException("PluginMessage handling exception: " + event + "\n" + Arrays.toString(event.getData()), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void register(String channel, boolean clientSideRegister, Parser handler) {
|
||||
handlers.put(channel, handler);
|
||||
if(clientSideRegister)
|
||||
ProxyServer.getInstance().registerChannel(channel);
|
||||
}
|
||||
|
||||
private void clientRegistersChannel(PluginMessageEvent event) {
|
||||
ProxiedPlayer player = (ProxiedPlayer) event.getSender();
|
||||
|
||||
for(String channel : new String(event.getData()).split("\0")) {
|
||||
if(channel.equals(ApolloManager.PLUGIN_MESSAGE_CHANNEL))
|
||||
lunar.sendRestrictions(player);
|
||||
|
||||
if(!knownChannels.contains(channel))
|
||||
BungeeCore.get().getLogger().log(Level.WARNING, () -> player.getName() + " registered unknown channel " + channel);
|
||||
}
|
||||
|
||||
PASS_THROUGH.handle(event);
|
||||
}
|
||||
|
||||
private void serverRegistersChannel(PluginMessageEvent event) {
|
||||
ProxiedPlayer player = (ProxiedPlayer)event.getReceiver();
|
||||
|
||||
List<String> channels = new ArrayList<>(Arrays.asList(new String(event.getData()).split("\0")));
|
||||
channels.removeIf(channel -> channel.equals("sw:bridge"));
|
||||
player.sendData((player).getPendingConnection().getVersion() > 340 ? "minecraft:register" : "REGISTER", String.join("\0", channels).getBytes());
|
||||
}
|
||||
|
||||
private void userBrand(PluginMessageEvent event) {
|
||||
ProxiedPlayer player = (ProxiedPlayer) event.getSender();
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(event.getData());
|
||||
String brand = DefinedPacket.readString(buf);
|
||||
|
||||
if(brand.startsWith("lunarclient:")) {
|
||||
lunar.sendRestrictions(player);
|
||||
} else if(!knownBrands.contains(brand)) {
|
||||
BungeeCore.get().getLogger().log(Level.WARNING, () -> player.getName() + " joined with unknown brand " + brand);
|
||||
}
|
||||
|
||||
PASS_THROUGH.handle(event);
|
||||
}
|
||||
|
||||
private void steamWarBrand(PluginMessageEvent event) {
|
||||
ProxiedPlayer player = (ProxiedPlayer) event.getReceiver();
|
||||
String brandString = ChatSender.of(player).parseToLegacy("STEAMWAR_BRAND", ProxyServer.getInstance().getName(), player.getServer().getInfo().getName(), new String(event.getData(), 1, event.getData().length - 1));
|
||||
|
||||
ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer();
|
||||
DefinedPacket.writeString(brandString, brand);
|
||||
player.sendData(event.getTag(), DefinedPacket.toArray(brand));
|
||||
brand.release();
|
||||
}
|
||||
|
||||
|
||||
private Parser directional(Parser fromServer, Parser fromPlayer) {
|
||||
return event -> {
|
||||
if(event.getSender() instanceof ProxiedPlayer)
|
||||
fromPlayer.handle(event);
|
||||
else
|
||||
fromServer.handle(event);
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private Parser onlySWSource(Parser parser) {
|
||||
return event -> {
|
||||
Connection sender = event.getSender();
|
||||
if(TeamCommand.isLocalhost(sender instanceof ProxiedPlayer ? IPSanitizer.getTrueAddress(((ProxiedPlayer) sender).getPendingConnection()) : sender.getAddress().getAddress()))
|
||||
parser.handle(event);
|
||||
else
|
||||
UNKNOWN.handle(event);
|
||||
};
|
||||
}
|
||||
|
||||
private Parser async(Parser parser) {
|
||||
return event -> ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> parser.handle(event));
|
||||
}
|
||||
|
||||
private interface Parser {
|
||||
void handle(PluginMessageEvent event);
|
||||
}
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners;
|
||||
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.event.LoginEvent;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.connection.LoginResult;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.protocol.Property;
|
||||
import net.md_5.bungee.util.AddressUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class SubserverProtocolFixer extends BasicListener {
|
||||
|
||||
private final InetSocketAddress inetSocketAddress = new InetSocketAddress("127.127.127.127", 25565);
|
||||
|
||||
private Field field;
|
||||
|
||||
{
|
||||
try {
|
||||
field = InitialHandler.class.getDeclaredField("extraDataInHandshake");
|
||||
field.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
BungeeCord.getInstance().getLogger().log(Level.SEVERE, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void loginEvent(LoginEvent e) {
|
||||
InitialHandler initialHandler = ((InitialHandler) e.getConnection());
|
||||
|
||||
String undashedUUID = initialHandler.getUniqueId().toString().replace("-", "");
|
||||
String extraData = "\00" + AddressUtil.sanitizeAddress(inetSocketAddress) + "\00" + undashedUUID;
|
||||
|
||||
LoginResult result = initialHandler.getLoginProfile();
|
||||
if (result != null) {
|
||||
Property[] properties = result.getProperties();
|
||||
if (properties.length > 0) {
|
||||
extraData += "\00" + BungeeCord.getInstance().gson.toJson(properties);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
field.set(initialHandler, extraData);
|
||||
} catch (IllegalAccessException ex) {
|
||||
BungeeCord.getInstance().getLogger().log(Level.SEVERE, ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package de.steamwar.bungeecore.listeners.mods;
|
||||
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
public class Badlion extends BasicListener {
|
||||
|
||||
@EventHandler
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
/*
|
||||
{
|
||||
"modsDisallowed": {
|
||||
"Clear Glass":{"disabled":true},
|
||||
"ClearWater":{"disabled":true},
|
||||
"FOV Changer":{"disabled":true},
|
||||
"Hitboxes":{"disabled":true},
|
||||
"MiniMap":{"disabled":true},
|
||||
"MLG Cobweb":{"disabled":true},
|
||||
"Replay":{"disabled":true},
|
||||
"Schematica":{"disabled":true},
|
||||
"ToggleSneak":{"disabled":true},
|
||||
"ToggleSprint":{"disabled":true},
|
||||
"TNT Time":{"disabled":true}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
event.getPlayer().sendData("badlion:mods", ("{\"Clear Glass\":{\"disabled\":true},\"ClearWater\":{\"disabled\":true},\"FOV Changer\":{\"disabled\":true},\"Hitboxes\":{\"disabled\":true},\"LevelHead\":{\"disabled\":true},\"MiniMap\":{\"disabled\":true},\"MLG Cobweb\":{\"disabled\":true},\"Replay\":{\"disabled\":true},\"Schematica\":{\"disabled\":true},\"ToggleSneak\":{\"disabled\":true},\"ToggleSprint\":{\"disabled\":true},\"TNT Time\":{\"disabled\":true}}").getBytes());
|
||||
}
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners.mods;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.Storage;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import de.steamwar.sql.Mod;
|
||||
import de.steamwar.sql.SWException;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.charset.UnsupportedCharsetException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Fabric extends BasicListener {
|
||||
|
||||
public static void remove(ProxiedPlayer player) {
|
||||
Storage.fabricCheckedPlayers.remove(player);
|
||||
synchronized (Storage.fabricExpectPluginMessage) {
|
||||
Storage.fabricExpectPluginMessage.remove(player);
|
||||
}
|
||||
}
|
||||
|
||||
private static final HashSet<String> ppCircumventerList = new HashSet<>();
|
||||
static {
|
||||
ppCircumventerList.add("java");
|
||||
ppCircumventerList.add("minecraft");
|
||||
ppCircumventerList.add("org_joml_joml");
|
||||
ppCircumventerList.add("steamwarmodsender");
|
||||
}
|
||||
|
||||
private static final Set<String> neededMods = new HashSet<>();
|
||||
static {
|
||||
neededMods.add("java");
|
||||
neededMods.add("minecraft");
|
||||
neededMods.add("fabricloader");
|
||||
neededMods.add("steamwarmodsender");
|
||||
}
|
||||
|
||||
{
|
||||
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
|
||||
synchronized (Storage.fabricExpectPluginMessage) {
|
||||
for (Map.Entry<ProxiedPlayer, Long> entry : Storage.fabricExpectPluginMessage.entrySet()) {
|
||||
if (!Storage.fabricCheckedPlayers.containsKey(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
if (System.currentTimeMillis() - entry.getValue() > TimeUnit.SECONDS.toMillis(20)) {
|
||||
logMessage(SteamwarUser.get(entry.getKey().getUniqueId()), "Expected message not received", String.valueOf(entry.getValue()));
|
||||
Storage.fabricExpectPluginMessage.remove(entry.getKey());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginMessageEvent(PluginMessageEvent e){
|
||||
if(!e.getTag().equals("fabricmodsender:mods"))
|
||||
return;
|
||||
|
||||
if (!(e.getSender() instanceof ProxiedPlayer)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProxiedPlayer player = (ProxiedPlayer) e.getSender();
|
||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||
byte[] data = e.getData();
|
||||
|
||||
if (!Storage.fabricCheckedPlayers.containsKey(player)) {
|
||||
synchronized (Storage.fabricExpectPluginMessage) {
|
||||
if (Storage.fabricExpectPluginMessage.containsKey(player)) {
|
||||
logMessage(user, "Was not fabric checked but send message nonetheless", Arrays.toString(data));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Storage.fabricExpectPluginMessage.remove(player);
|
||||
|
||||
List<Mod> mods = new ArrayList<>();
|
||||
|
||||
Utils.VarInt varInt = Utils.readVarInt(data,0);
|
||||
|
||||
if(data.length != varInt.length + varInt.value) {
|
||||
logMessage(user, "Invalid message length", Arrays.toString(data));
|
||||
return;
|
||||
}
|
||||
|
||||
data = Arrays.copyOfRange(data,varInt.length, data.length);
|
||||
|
||||
String dataString;
|
||||
|
||||
try{
|
||||
dataString = new String(data, StandardCharsets.UTF_8);
|
||||
}catch (UnsupportedCharsetException exception) {
|
||||
logMessage(user, "Unsupported charset", Arrays.toString(data));
|
||||
return;
|
||||
}
|
||||
|
||||
JsonArray array;
|
||||
|
||||
try {
|
||||
array = JsonParser.parseString(dataString).getAsJsonArray();
|
||||
}catch (JsonSyntaxException exception) {
|
||||
logMessage(user, "Invalid json", dataString);
|
||||
return;
|
||||
}
|
||||
|
||||
for(JsonElement mod : array) {
|
||||
mods.add(Mod.getOrCreate(mod.getAsString(), Mod.Platform.FABRIC));
|
||||
}
|
||||
|
||||
boolean neededMods = neededModsContained(mods);
|
||||
if(!neededMods) {
|
||||
logMessage(user, "Needed mods are not contained", dataString);
|
||||
return;
|
||||
}
|
||||
|
||||
if(ppCircumventerCheck(mods))
|
||||
logMessage(user, "PP circumventer suspicion", dataString);
|
||||
|
||||
if(!Utils.handleMods(player,mods))
|
||||
return;
|
||||
|
||||
if (Storage.fabricCheckedPlayers.containsKey(player)) {
|
||||
long current = Storage.fabricCheckedPlayers.get(player);
|
||||
if (current != dataString.hashCode()) {
|
||||
logMessage(user, "Mods changed during runtime", dataString);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
Storage.fabricCheckedPlayers.put(player, dataString.hashCode());
|
||||
}
|
||||
Storage.fabricPlayers.remove(player);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerSwitchEvent(ServerSwitchEvent e) {
|
||||
if (e.getFrom() == null) return;
|
||||
synchronized (Storage.fabricExpectPluginMessage) {
|
||||
Storage.fabricExpectPluginMessage.put(e.getPlayer(), System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean neededModsContained(List<Mod> mods) {
|
||||
return mods.stream()
|
||||
.map(Mod::getModName)
|
||||
.filter(neededMods::contains)
|
||||
.count() == neededMods.size();
|
||||
}
|
||||
|
||||
private void logMessage(SteamwarUser user, String reason, String data) {
|
||||
SWException.log("FabricModSender " + user.getUserName() + ": " + reason, data);
|
||||
}
|
||||
|
||||
private boolean ppCircumventerCheck(List<Mod> mods) {
|
||||
for(Mod mod : mods) {
|
||||
String name = mod.getModName();
|
||||
if(!name.startsWith("fabric") && !ppCircumventerList.contains(name))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,147 +0,0 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners.mods;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import de.steamwar.sql.Mod;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.PendingConnection;
|
||||
import net.md_5.bungee.api.event.LoginEvent;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.netty.HandlerBoss;
|
||||
import net.md_5.bungee.netty.PacketHandler;
|
||||
import net.md_5.bungee.protocol.packet.LoginPayloadRequest;
|
||||
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class Forge extends BasicListener {
|
||||
|
||||
private static final String WRAPPER = "fml:loginwrapper";
|
||||
|
||||
private static final Field initialHandlerCh;
|
||||
static{
|
||||
try {
|
||||
initialHandlerCh = InitialHandler.class.getDeclaredField("ch");
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new SecurityException("Could not initialize Reflection", e);
|
||||
}
|
||||
initialHandlerCh.setAccessible(true);
|
||||
}
|
||||
|
||||
public static void onServerConnected(LoginEvent event) {
|
||||
if(event.getConnection().getVersion() < 341 || event.getConnection().getVersion() > 763) { //1.13 - 1.20.1
|
||||
event.completeIntent(BungeeCore.get());
|
||||
return;
|
||||
}
|
||||
|
||||
//fml:handshake without mods, channels and registries
|
||||
//for more information see https://wiki.vg/Minecraft_Forge_Handshake#FML2_protocol_.281.13_-_Current.29
|
||||
event.getConnection().unsafe().sendPacket(new LoginPayloadRequest(1, WRAPPER, new byte[]{13,102,109,108,58,104,97,110,100,115,104,97,107,101,4,1,0,0,0}));
|
||||
|
||||
InitialHandler handler = (InitialHandler) event.getConnection();
|
||||
|
||||
ChannelWrapper wrapper;
|
||||
try{
|
||||
wrapper = (ChannelWrapper) initialHandlerCh.get(handler);
|
||||
} catch (IllegalAccessException e) {
|
||||
BungeeCore.get().getLogger().log(Level.SEVERE, "Could not get Channel", e);
|
||||
event.completeIntent(BungeeCore.get());
|
||||
return;
|
||||
}
|
||||
|
||||
ChannelPipeline pipeline = wrapper.getHandle().pipeline();
|
||||
if(pipeline != null) {
|
||||
HandlerBoss handlerBoss = pipeline.get(HandlerBoss.class);
|
||||
if(handlerBoss != null)
|
||||
handlerBoss.setHandler(new CustomPacketHandler(event));
|
||||
}
|
||||
}
|
||||
|
||||
private static class CustomPacketHandler extends PacketHandler {
|
||||
private final LoginEvent event;
|
||||
|
||||
public CustomPacketHandler(LoginEvent event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SteamWar Forge Handler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(LoginPayloadResponse response){
|
||||
byte[] data = response.getData();
|
||||
if(data == null) {
|
||||
event.completeIntent(BungeeCore.get());
|
||||
return;
|
||||
}
|
||||
|
||||
//for more information see https://wiki.vg/Minecraft_Forge_Handshake#FML2_protocol_.281.13_-_Current.29
|
||||
Utils.VarInt channelLength = Utils.readVarInt(data, 0);
|
||||
int pos = channelLength.length;
|
||||
if(!new String(data, pos, channelLength.value).equals("fml:handshake")) {
|
||||
event.getConnection().disconnect(TextComponent.fromLegacyText("Invalid forge registry response (0x00)"));
|
||||
return;
|
||||
}
|
||||
pos += channelLength.value;
|
||||
|
||||
Utils.VarInt length = Utils.readVarInt(data, pos);
|
||||
pos += length.length;
|
||||
if(channelLength.length + channelLength.value + length.length + length.value != data.length) {
|
||||
event.getConnection().disconnect(TextComponent.fromLegacyText("Invalid forge registry response (0x01)"));
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.VarInt packetId = Utils.readVarInt(data, pos);
|
||||
pos += packetId.length;
|
||||
if(packetId.value != 2) {
|
||||
event.getConnection().disconnect(TextComponent.fromLegacyText("Invalid forge registry response (0x02)"));
|
||||
return;
|
||||
}
|
||||
|
||||
Utils.VarInt modCount = Utils.readVarInt(data, pos);
|
||||
pos += modCount.length;
|
||||
|
||||
List<Mod> mods = new ArrayList<>();
|
||||
for(int i = 0; i < modCount.value; i++) {
|
||||
Utils.VarInt nameLength = Utils.readVarInt(data, pos);
|
||||
pos += nameLength.length;
|
||||
|
||||
mods.add(Mod.getOrCreate(new String(data, pos, nameLength.value), Mod.Platform.FORGE));
|
||||
pos += nameLength.value;
|
||||
}
|
||||
|
||||
PendingConnection connection = event.getConnection();
|
||||
if(!Utils.handleMods(connection.getUniqueId(), Locale.getDefault(), event::setCancelReason, mods)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
event.completeIntent(BungeeCore.get());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners.mods;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import de.steamwar.sql.Mod;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.Connection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Forge12 extends BasicListener {
|
||||
private static final String FMLHS = "FML|HS";
|
||||
private static final byte[] REGISTER;
|
||||
private static final byte[] HELLO = new byte[]{0, 2, 0, 0, 0, 0};
|
||||
|
||||
private static final Set<UUID> unlocked = new HashSet<>();
|
||||
|
||||
static {
|
||||
ByteBuf buf = UnpooledByteBufAllocator.DEFAULT.directBuffer(7);
|
||||
buf.writeByte(6);
|
||||
buf.writeCharSequence(FMLHS, StandardCharsets.UTF_8);
|
||||
REGISTER = new byte[buf.readableBytes()];
|
||||
buf.readBytes(REGISTER);
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
|
||||
synchronized (unlocked) {
|
||||
if(unlocked.contains(player.getUniqueId())){
|
||||
unlocked.remove(player.getUniqueId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(player.getPendingConnection().getVersion() <= 340) {
|
||||
player.sendData("REGISTER", REGISTER); //1.12-
|
||||
player.sendData(FMLHS, HELLO);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPluginMessageEvent(PluginMessageEvent e){
|
||||
if(!e.getTag().equals(FMLHS))
|
||||
return;
|
||||
|
||||
e.setCancelled(true);
|
||||
byte[] data = e.getData();
|
||||
|
||||
Connection sender = e.getSender();
|
||||
if(!(sender instanceof ProxiedPlayer))
|
||||
return;
|
||||
ProxiedPlayer p = (ProxiedPlayer) sender;
|
||||
|
||||
if (data[0] == 2) {
|
||||
Utils.VarInt numMods = Utils.readVarInt(data, 1);
|
||||
List<Mod> mods = new LinkedList<>();
|
||||
|
||||
int bytePos = 1 + numMods.length;
|
||||
for (int i = 0; i < numMods.value; i++) {
|
||||
byte[] name = Arrays.copyOfRange(data, bytePos + 1, bytePos + data[bytePos] + 1);
|
||||
bytePos += 1 + data[bytePos];
|
||||
//Version information is unused
|
||||
bytePos += 1 + data[bytePos];
|
||||
|
||||
mods.add(Mod.getOrCreate(new String(name), Mod.Platform.FORGE));
|
||||
}
|
||||
|
||||
if (Utils.handleMods(p, mods)) {
|
||||
synchronized (unlocked) {
|
||||
unlocked.add(p.getUniqueId());
|
||||
}
|
||||
ProxyServer.getInstance().getScheduler().schedule(BungeeCore.get(),
|
||||
() -> p.disconnect(BungeeCore.stringToText("§7Deine installierten Mods wurden überprüft\n§aDu kannst nun §eSteam§8War §abetreten")),
|
||||
2, TimeUnit.SECONDS);
|
||||
ProxyServer.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
|
||||
synchronized (unlocked) {
|
||||
unlocked.remove(p.getUniqueId());
|
||||
}
|
||||
}, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,184 +0,0 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners.mods;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import de.steamwar.sql.Mod;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.Connection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class LabyMod extends BasicListener {
|
||||
|
||||
@EventHandler
|
||||
public void onPluginMessageEvent(PluginMessageEvent event){
|
||||
if(!event.getTag().equals("LMC"))
|
||||
return;
|
||||
|
||||
Connection sender = event.getSender();
|
||||
if(!(sender instanceof ProxiedPlayer))
|
||||
return;
|
||||
|
||||
event.setCancelled(true);
|
||||
updateGameInfo((ProxiedPlayer) sender);
|
||||
byte[] data = event.getData();
|
||||
|
||||
ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> runAsync(data, (ProxiedPlayer) sender));
|
||||
}
|
||||
|
||||
private void runAsync(byte[] data, ProxiedPlayer player) {
|
||||
VarString purpose = readString(data, 0);
|
||||
if(!"INFO".equals(purpose.value))
|
||||
return;
|
||||
|
||||
VarString value = readString(data, purpose.length);
|
||||
List<Mod> mods = new LinkedList<>();
|
||||
|
||||
try{
|
||||
InfoPacket info = new InfoPacket(value.value);
|
||||
for(InfoPacket.Addon addon : info.addons) {
|
||||
mods.add(Mod.getOrCreate(addon.name, Mod.Platform.LABYMOD));
|
||||
}
|
||||
}catch(IOException e){
|
||||
BungeeCore.log("Could not read JSON", e);
|
||||
}
|
||||
|
||||
Utils.handleMods(player, mods);
|
||||
}
|
||||
|
||||
private VarString readString(byte[] array, int startPos){
|
||||
Utils.VarInt varInt = Utils.readVarInt(array, startPos);
|
||||
startPos += varInt.length;
|
||||
return new VarString(varInt.value+varInt.length, new String(Arrays.copyOfRange(array, startPos, startPos + varInt.value), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private void updateGameInfo(ProxiedPlayer proxiedPlayer) {
|
||||
JsonObject obj = new JsonObject();
|
||||
obj.addProperty("hasGame", true);
|
||||
obj.addProperty("game_mode", "steamwar.de");
|
||||
obj.addProperty("game_startTime", 0);
|
||||
obj.addProperty("game_endTime", 0);
|
||||
String output = "{ \"hasGame\" : \"true\", \"game_mode\" : \"steamwar.de\", \"game_startTime\" : \"0\", \"game_endTime\" : \"0\" }";
|
||||
|
||||
proxiedPlayer.sendData("LMC", output.getBytes());
|
||||
}
|
||||
|
||||
private static class VarString{
|
||||
private final int length;
|
||||
private final String value;
|
||||
|
||||
private VarString(int length, String value) {
|
||||
this.length = length;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static class InfoPacket{
|
||||
String version = null;
|
||||
Feature ccp = null;
|
||||
Feature shadow = null;
|
||||
List<Addon> addons = new LinkedList<>();
|
||||
|
||||
InfoPacket(String input) throws IOException {
|
||||
JsonReader reader = new JsonReader(new StringReader(input));
|
||||
reader.beginObject();
|
||||
while(reader.hasNext()){
|
||||
String name = reader.nextName();
|
||||
switch(name){
|
||||
case "version":
|
||||
version = reader.nextString();
|
||||
break;
|
||||
case "ccp":
|
||||
ccp = new Feature(reader);
|
||||
break;
|
||||
case "shadow":
|
||||
shadow = new Feature(reader);
|
||||
break;
|
||||
case "addons":
|
||||
reader.beginArray();
|
||||
while(reader.hasNext()){
|
||||
addons.add(new Addon(reader));
|
||||
}
|
||||
reader.endArray();
|
||||
break;
|
||||
default:
|
||||
reader.skipValue();
|
||||
}
|
||||
}
|
||||
reader.endObject();
|
||||
reader.close();
|
||||
}
|
||||
|
||||
static class Addon{
|
||||
UUID uuid = null;
|
||||
String name = null;
|
||||
|
||||
Addon(JsonReader reader) throws IOException {
|
||||
reader.beginObject();
|
||||
while(reader.hasNext()){
|
||||
String n = reader.nextName();
|
||||
if(n.equals("uuid"))
|
||||
try{
|
||||
uuid = UUID.fromString(reader.nextString());
|
||||
}catch(IllegalArgumentException ignored){
|
||||
//ignored
|
||||
}
|
||||
else if(n.equals("name"))
|
||||
name = reader.nextString();
|
||||
else
|
||||
reader.skipValue();
|
||||
}
|
||||
reader.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
static class Feature{
|
||||
boolean enabled;
|
||||
int version;
|
||||
|
||||
Feature(JsonReader reader) throws IOException {
|
||||
reader.beginObject();
|
||||
while(reader.hasNext()){
|
||||
String name = reader.nextName();
|
||||
if(name.equals("version"))
|
||||
version = reader.nextInt();
|
||||
else if(name.equals("enabled"))
|
||||
enabled = reader.nextBoolean();
|
||||
else
|
||||
reader.skipValue();
|
||||
}
|
||||
reader.endObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners.mods;
|
||||
|
||||
import de.steamwar.bungeecore.*;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import net.md_5.bungee.api.connection.Connection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ModLoaderBlocker extends BasicListener {
|
||||
|
||||
private static final Set<String> BLOCKED_SERVER = new HashSet<>();
|
||||
|
||||
@EventHandler
|
||||
public void onPluginMessageEvent(PluginMessageEvent e){
|
||||
Connection sender = e.getSender();
|
||||
if(!(sender instanceof ProxiedPlayer))
|
||||
return;
|
||||
|
||||
ProxiedPlayer p = (ProxiedPlayer) sender;
|
||||
if (e.getTag().equals("lunarclient:pm")) {
|
||||
p.disconnect(Message.parseToComponent("MOD_LOADER_LUNAR_CLIENT", false, p));
|
||||
return;
|
||||
}
|
||||
|
||||
if(!e.getTag().equals("minecraft:brand"))
|
||||
return;
|
||||
|
||||
String brand = new String(e.getData());
|
||||
if(brand.contains("fabric") || brand.contains("quilt") || brand.contains("LiteLoader")){
|
||||
if (!Storage.fabricCheckedPlayers.containsKey(p)) {
|
||||
Storage.fabricPlayers.add(p);
|
||||
}
|
||||
} else if (brand.contains("lunar")) {
|
||||
p.disconnect(Message.parseToComponent("MOD_LOADER_LUNAR_CLIENT", false, p));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDisconnect(PlayerDisconnectEvent e){
|
||||
Fabric.remove(e.getPlayer());
|
||||
Storage.fabricPlayers.remove(e.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerSwitch(ServerSwitchEvent event) {
|
||||
if(((Subserver.getSubserver(event.getPlayer()) != null
|
||||
&& Subserver.getSubserver(event.getPlayer()).getType() == Servertype.ARENA)
|
||||
|| BLOCKED_SERVER.contains(event.getPlayer().getServer().getInfo().getName()))
|
||||
&& isFabric(event.getPlayer())) {
|
||||
event.getPlayer().connect(BungeeCore.get().getProxy().getServerInfo(BungeeCore.LOBBY_SERVER));
|
||||
Message.send("MODLOADER_DENIED", event.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFabric(ProxiedPlayer player) {
|
||||
return Storage.fabricPlayers.contains(player);
|
||||
}
|
||||
|
||||
public static void addServer(String server) {
|
||||
BLOCKED_SERVER.add(server);
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
package de.steamwar.bungeecore.listeners.mods;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import de.steamwar.sql.Mod;
|
||||
import net.md_5.bungee.api.connection.Connection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
public class WorldDownloader extends BasicListener {
|
||||
|
||||
private static final Set<String> wdlTags = Collections.unmodifiableSet(
|
||||
Sets.newHashSet("WDL|INIT", "wdl:init", "WDL|REQUEST", "wdl:request")
|
||||
);
|
||||
|
||||
@EventHandler
|
||||
public void onPluginMessageEvent(PluginMessageEvent event){
|
||||
if(!wdlTags.contains(event.getTag()))
|
||||
return;
|
||||
|
||||
Connection sender = event.getSender();
|
||||
if(!(sender instanceof ProxiedPlayer))
|
||||
return;
|
||||
|
||||
event.setCancelled(true);
|
||||
Utils.handleMods((ProxiedPlayer) sender, Lists.newArrayList(Mod.getOrCreate("wdl", Mod.Platform.FORGE)));
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners.ping;
|
||||
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
public class PingListener extends BasicListener {
|
||||
|
||||
@EventHandler
|
||||
public void onPing(ProxyPingEvent event) {
|
||||
event.setResponse(new SteamWarServerPing(event.getResponse(), event.getConnection().getVersion()));
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners.ping;
|
||||
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class SteamWarServerPing extends ServerPing {
|
||||
|
||||
private final boolean preventsChatReports = true;
|
||||
private final ForgeData forgeData;
|
||||
|
||||
public SteamWarServerPing(ServerPing existing, int version) {
|
||||
super(existing.getVersion(), existing.getPlayers(), existing.getDescriptionComponent(), existing.getFaviconObject());
|
||||
forgeData = new ForgeData(version);
|
||||
}
|
||||
|
||||
private static class ForgeData {
|
||||
private final List<ForgeChannel> channels = new ArrayList<>();
|
||||
private final List<ForgeMod> mods = new ArrayList<>();
|
||||
private final int fmlNetworkVersion = 2;
|
||||
|
||||
public ForgeData(int versionNumber) {
|
||||
channels.add(new ForgeChannel("minecraft:unregister"));
|
||||
channels.add(new ForgeChannel("minecraft:register"));
|
||||
channels.add(new ForgeChannel("fml:handshake"));
|
||||
mods.add(new ForgeMod("minecraft", ProtocolVersion.getVersion(versionNumber)));
|
||||
mods.add(new ForgeMod("forge", "ANY"));
|
||||
}
|
||||
|
||||
public final static class ProtocolVersion {
|
||||
|
||||
private static final HashMap<Integer, String> versions;
|
||||
|
||||
static {
|
||||
versions = new HashMap();
|
||||
versions.put(757, "1.18");
|
||||
versions.put(756, "1.17.1");
|
||||
versions.put(754, "1.16.5");
|
||||
versions.put(578, "1.15.2");
|
||||
versions.put(498, "1.14.1");
|
||||
versions.put(393, "1.13");
|
||||
}
|
||||
|
||||
public static String getVersion(int version) {
|
||||
return versions.get(version);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ForgeChannel {
|
||||
private final String res;
|
||||
private final String version = "FML2";
|
||||
private final boolean required = true;
|
||||
|
||||
private ForgeChannel(String res) {
|
||||
this.res = res;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ForgeMod {
|
||||
private final String modId;
|
||||
private final String modmarker;
|
||||
|
||||
private ForgeMod(String modId, String modmarker) {
|
||||
this.modId = modId;
|
||||
this.modmarker = modmarker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
57
src/de/steamwar/bungeecore/mods/Badlion.java
Normale Datei
57
src/de/steamwar/bungeecore/mods/Badlion.java
Normale Datei
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
public class Badlion extends BasicListener {
|
||||
// https://github.com/BadlionClient/BadlionClientModAPI
|
||||
|
||||
private final byte[] packet;
|
||||
|
||||
public Badlion() { //TODO check if working or (json) modsDisallowed wrapper necessary
|
||||
JsonObject disabled = new JsonObject();
|
||||
disabled.addProperty("disabled", true);
|
||||
|
||||
JsonObject json = new JsonObject();
|
||||
json.add("Clear Glass", disabled);
|
||||
json.add("ClearWater", disabled);
|
||||
json.add("FOV Changer", disabled);
|
||||
json.add("Hitboxes", disabled);
|
||||
json.add("LevelHead", disabled);
|
||||
json.add("MiniMap", disabled);
|
||||
json.add("MLG Cobweb", disabled);
|
||||
json.add("Replay", disabled); //TODO check if ReplayMod restrictions work
|
||||
json.add("Schematica", disabled);
|
||||
json.add("ToggleSneak", disabled);
|
||||
json.add("ToggleSprint", disabled);
|
||||
json.add("TNT Time", disabled);
|
||||
|
||||
packet = json.toString().getBytes();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
event.getPlayer().sendData("badlion:mods", packet);
|
||||
}
|
||||
}
|
98
src/de/steamwar/bungeecore/mods/FML.java
Normale Datei
98
src/de/steamwar/bungeecore/mods/FML.java
Normale Datei
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import de.steamwar.sql.Mod;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.PendingConnection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FML extends BasicListener {
|
||||
// https://wiki.vg/Minecraft_Forge_Handshake#FML_protocol_.281.7_-_1.12.29
|
||||
|
||||
public static boolean isFML(PendingConnection connection, String type) {
|
||||
return ((InitialHandler)connection).getExtraDataInHandshake().equals("\0" + type);
|
||||
}
|
||||
|
||||
public static final String CHANNEL = "FML|HS";
|
||||
private final byte[] helloPacket = new byte[]{
|
||||
/* Packet type: ServerHello */ 0,
|
||||
/* FML protocol version */ 2,
|
||||
/* Override dimension (int) */ 0, 0, 0, 0
|
||||
};
|
||||
|
||||
private static final Set<UUID> unlocked = new HashSet<>();
|
||||
|
||||
@EventHandler
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
|
||||
synchronized (unlocked) {
|
||||
if(unlocked.contains(player.getUniqueId())){
|
||||
unlocked.remove(player.getUniqueId());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(isFML(player.getPendingConnection(), "FML\0"))
|
||||
player.sendData(CHANNEL, helloPacket);
|
||||
}
|
||||
|
||||
public void handlePluginMessage(PluginMessageEvent event) {
|
||||
ProxiedPlayer p = (ProxiedPlayer) event.getSender();
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(event.getData());
|
||||
|
||||
if (buf.readByte() == /* ModList */ 2) {
|
||||
int numMods = DefinedPacket.readVarInt(buf);
|
||||
|
||||
List<Mod> mods = new ArrayList<>();
|
||||
for(int i = 0; i < numMods; i++) {
|
||||
String name = DefinedPacket.readString(buf);
|
||||
DefinedPacket.readString(buf); // version
|
||||
|
||||
mods.add(Mod.getOrCreate(name, Mod.Platform.FORGE));
|
||||
}
|
||||
|
||||
if (ModUtils.handleMods(p, mods)) {
|
||||
synchronized (unlocked) {
|
||||
unlocked.add(p.getUniqueId());
|
||||
}
|
||||
p.disconnect(BungeeCore.stringToText("§7Deine installierten Mods wurden überprüft\n§aDu kannst nun §eSteam§8War §abetreten"));
|
||||
ProxyServer.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
|
||||
synchronized (unlocked) {
|
||||
unlocked.remove(p.getUniqueId());
|
||||
}
|
||||
}, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
186
src/de/steamwar/bungeecore/mods/FML2.java
Normale Datei
186
src/de/steamwar/bungeecore/mods/FML2.java
Normale Datei
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import de.steamwar.bungeecore.listeners.IPSanitizer;
|
||||
import de.steamwar.sql.Mod;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.PendingConnection;
|
||||
import net.md_5.bungee.api.event.LoginEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.netty.HandlerBoss;
|
||||
import net.md_5.bungee.netty.PacketHandler;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.LoginPayloadRequest;
|
||||
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class FML2 extends BasicListener {
|
||||
// FML2: https://wiki.vg/Minecraft_Forge_Handshake#FML2_protocol_.281.13_-_Current.29
|
||||
// FML3: https://github.com/adde0109/Ambassador/tree/non-api/src/main/java/org/adde0109/ambassador/forge
|
||||
|
||||
// FORGE: https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/NetworkInitialization.java
|
||||
// FORGE: https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/ForgePacketHandler.java
|
||||
// FORGE: https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/packets/ModVersions.java
|
||||
|
||||
private final byte[] fml2ModListPacket;
|
||||
private final byte[] fml3ModListPacket;
|
||||
private final byte[] forgeModListPacket;
|
||||
|
||||
public FML2() {
|
||||
fml2ModListPacket = generateModListPacket(false);
|
||||
fml3ModListPacket = generateModListPacket(true);
|
||||
|
||||
ByteBuf packet = Unpooled.buffer();
|
||||
packet.writeByte(1); // Mod list packet
|
||||
DefinedPacket.writeVarInt(0, packet); // Mod amount
|
||||
|
||||
ByteBuf wrapper = Unpooled.buffer();
|
||||
wrapper.writeByte(0); // Login wrapper packet
|
||||
DefinedPacket.writeString("forge:handshake", wrapper);
|
||||
DefinedPacket.writeVarInt(packet.readableBytes(), wrapper);
|
||||
wrapper.writeBytes(packet);
|
||||
|
||||
forgeModListPacket = new byte[wrapper.readableBytes()];
|
||||
wrapper.readBytes(forgeModListPacket);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onLogin(LoginEvent event) {
|
||||
PendingConnection connection = event.getConnection();
|
||||
|
||||
boolean fml2 = FML.isFML(connection, "FML2\0");
|
||||
boolean fml3 = FML.isFML(connection, "FML3\0");
|
||||
boolean forge = FML.isFML(connection, "FORGE");
|
||||
if(!fml2 && !fml3 && !forge)
|
||||
return;
|
||||
|
||||
IPSanitizer.getChannelWrapper(connection).getHandle().pipeline().get(HandlerBoss.class).setHandler(new FML2LoginHandler(event));
|
||||
|
||||
event.registerIntent(BungeeCore.get());
|
||||
if(forge)
|
||||
connection.unsafe().sendPacket(new LoginPayloadRequest(1, "forge:login", forgeModListPacket));
|
||||
else
|
||||
connection.unsafe().sendPacket(new LoginPayloadRequest(1, "fml:loginwrapper", fml3 ? fml3ModListPacket : fml2ModListPacket));
|
||||
}
|
||||
|
||||
private byte[] generateModListPacket(boolean fml3) {
|
||||
ByteBuf packet = Unpooled.buffer();
|
||||
packet.writeByte(1); // Mod list packet
|
||||
DefinedPacket.writeVarInt(0, packet); // Mod amount
|
||||
|
||||
if(fml3) {
|
||||
DefinedPacket.writeVarInt(1, packet); // Channel amount
|
||||
DefinedPacket.writeString("forge:tier_sorting", packet);
|
||||
DefinedPacket.writeString("1.0", packet);
|
||||
} else {
|
||||
DefinedPacket.writeVarInt(0, packet); // Channel amount
|
||||
}
|
||||
|
||||
DefinedPacket.writeVarInt(0, packet); // Registries amount
|
||||
if(fml3)
|
||||
DefinedPacket.writeVarInt(0, packet); // DataPacks amount
|
||||
|
||||
ByteBuf wrapper = Unpooled.buffer();
|
||||
DefinedPacket.writeString("fml:handshake", wrapper);
|
||||
DefinedPacket.writeVarInt(packet.readableBytes(), wrapper);
|
||||
wrapper.writeBytes(packet);
|
||||
|
||||
byte[] data = new byte[wrapper.readableBytes()];
|
||||
wrapper.readBytes(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private static class FML2LoginHandler extends PacketHandler {
|
||||
private final LoginEvent event;
|
||||
|
||||
public FML2LoginHandler(LoginEvent event) {
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SteamWar Forge Handler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(LoginPayloadResponse response) {
|
||||
boolean forge = FML.isFML(event.getConnection(), "FORGE");
|
||||
byte[] data = response.getData();
|
||||
if(data == null) {
|
||||
abort(response, "Not FML2/3 client");
|
||||
return;
|
||||
}
|
||||
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(data);
|
||||
if(forge && buf.readByte() != 0) {
|
||||
abort(response, "Not FORGE login wrapper");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!DefinedPacket.readString(buf).equals(forge ? "forge:handshake" : "fml:handshake")) {
|
||||
abort(response, "Not FML2/3/FORGE handshake response");
|
||||
return;
|
||||
}
|
||||
|
||||
if(DefinedPacket.readVarInt(buf) != buf.readableBytes()) {
|
||||
abort(response, "FML2/3/FORGE packet size mismatch");
|
||||
return;
|
||||
}
|
||||
|
||||
if(DefinedPacket.readVarInt(buf) != (forge ? /* Mod Versions */ 1 : /* Mod List Reply */ 2)) {
|
||||
abort(response, "Not FML2/3/FORGE mod list reply");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Mod> mods = new ArrayList<>();
|
||||
|
||||
int modCount = DefinedPacket.readVarInt(buf);
|
||||
for(int i = 0; i < modCount; i++) {
|
||||
mods.add(Mod.getOrCreate(DefinedPacket.readString(buf), Mod.Platform.FORGE));
|
||||
|
||||
if(forge) {
|
||||
DefinedPacket.readString(buf); // Human readable name
|
||||
DefinedPacket.readString(buf); // Version
|
||||
}
|
||||
}
|
||||
|
||||
if(!ModUtils.handleMods(event.getConnection().getUniqueId(), Locale.getDefault(), event::setReason, mods))
|
||||
event.setCancelled(true);
|
||||
|
||||
event.completeIntent(BungeeCore.get());
|
||||
}
|
||||
|
||||
private void abort(LoginPayloadResponse response, String error) {
|
||||
event.setReason(TextComponent.fromLegacy(error));
|
||||
event.setCancelled(true);
|
||||
event.completeIntent(BungeeCore.get());
|
||||
BungeeCore.get().getLogger().log(Level.SEVERE, () -> error + "\n" + response);
|
||||
}
|
||||
}
|
||||
}
|
141
src/de/steamwar/bungeecore/mods/FabricModSender.java
Normale Datei
141
src/de/steamwar/bungeecore/mods/FabricModSender.java
Normale Datei
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.Storage;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import de.steamwar.sql.Mod;
|
||||
import de.steamwar.sql.SWException;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FabricModSender extends BasicListener {
|
||||
|
||||
private final Set<String> neededMods = new HashSet<>();
|
||||
|
||||
public FabricModSender() {
|
||||
neededMods.add("java");
|
||||
neededMods.add("minecraft");
|
||||
neededMods.add("fabricloader");
|
||||
neededMods.add("steamwarmodsender");
|
||||
|
||||
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
|
||||
synchronized (Storage.fabricExpectPluginMessage) {
|
||||
for (Map.Entry<ProxiedPlayer, Long> entry : Storage.fabricExpectPluginMessage.entrySet()) {
|
||||
if (!Storage.fabricCheckedPlayers.containsKey(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
if (System.currentTimeMillis() - entry.getValue() > TimeUnit.SECONDS.toMillis(20)) {
|
||||
Storage.fabricExpectPluginMessage.remove(entry.getKey());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public void handlePluginMessage(PluginMessageEvent e){
|
||||
ProxiedPlayer player = (ProxiedPlayer) e.getSender();
|
||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||
|
||||
if (!Storage.fabricCheckedPlayers.containsKey(player)) {
|
||||
synchronized (Storage.fabricExpectPluginMessage) {
|
||||
if (Storage.fabricExpectPluginMessage.containsKey(player)) {
|
||||
logMessage(user, "Was not fabric checked but send message nonetheless", Arrays.toString(e.getData()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Storage.fabricExpectPluginMessage.remove(player);
|
||||
|
||||
List<Mod> mods = new ArrayList<>();
|
||||
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(e.getData());
|
||||
String data = DefinedPacket.readString(buf, 1024*1024);
|
||||
if(buf.readableBytes() > 0) {
|
||||
logMessage(user, "Invalid message length", Arrays.toString(e.getData()));
|
||||
return;
|
||||
}
|
||||
|
||||
JsonArray array = JsonParser.parseString(data).getAsJsonArray();
|
||||
|
||||
for(JsonElement mod : array) {
|
||||
mods.add(Mod.getOrCreate(mod.getAsString(), Mod.Platform.FABRIC));
|
||||
}
|
||||
|
||||
if(!neededModsContained(mods)) {
|
||||
logMessage(user, "Needed mods are not contained", data);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!ModUtils.handleMods(player,mods))
|
||||
return;
|
||||
|
||||
if (!Storage.fabricCheckedPlayers.containsKey(player)) {
|
||||
Storage.fabricCheckedPlayers.put(player, data.hashCode());
|
||||
} else if (Storage.fabricCheckedPlayers.get(player) != data.hashCode()) {
|
||||
logMessage(user, "Mods changed during runtime", data);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onServerSwitchEvent(ServerSwitchEvent e) {
|
||||
if (e.getFrom() == null) return;
|
||||
synchronized (Storage.fabricExpectPluginMessage) {
|
||||
Storage.fabricExpectPluginMessage.put(e.getPlayer(), System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onDisconnect(PlayerDisconnectEvent e) {
|
||||
ProxiedPlayer player = e.getPlayer();
|
||||
|
||||
Storage.fabricCheckedPlayers.remove(player);
|
||||
synchronized (Storage.fabricExpectPluginMessage) {
|
||||
Storage.fabricExpectPluginMessage.remove(player);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean neededModsContained(List<Mod> mods) {
|
||||
return mods.stream()
|
||||
.map(Mod::getModName)
|
||||
.filter(neededMods::contains)
|
||||
.count() == neededMods.size();
|
||||
}
|
||||
|
||||
private void logMessage(SteamwarUser user, String reason, String data) {
|
||||
SWException.log("FabricModSender " + user.getUserName() + ": " + reason, data);
|
||||
}
|
||||
}
|
58
src/de/steamwar/bungeecore/mods/Hostname.java
Normale Datei
58
src/de/steamwar/bungeecore/mods/Hostname.java
Normale Datei
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import net.md_5.bungee.api.event.PlayerHandshakeEvent;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class Hostname extends BasicListener {
|
||||
|
||||
private final Set<String> knownHostnames = new HashSet<>();
|
||||
private final Set<String> knownExtraData = new HashSet<>();
|
||||
|
||||
public Hostname() {
|
||||
knownHostnames.add("steamwar.de");
|
||||
knownHostnames.add("78.31.71.136");
|
||||
|
||||
knownExtraData.add("");
|
||||
knownExtraData.add("\0FML\0");
|
||||
knownExtraData.add("\0FML2\0");
|
||||
knownExtraData.add("\0FML3\0");
|
||||
knownExtraData.add("\0FORGE");
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onHandshake(PlayerHandshakeEvent event) {
|
||||
String extraDataInHandshake = ((InitialHandler) event.getConnection()).getExtraDataInHandshake();
|
||||
if (!knownHostnames.contains(event.getHandshake().getHost().toLowerCase())) {
|
||||
BungeeCore.get().getLogger().log(Level.WARNING, () -> event.getConnection().getSocketAddress() + " connected with unknown hostname " + event.getHandshake() + " " + extraDataInHandshake);
|
||||
} else if (!knownExtraData.contains(extraDataInHandshake)) {
|
||||
BungeeCore.get().getLogger().log(Level.WARNING, () -> event.getConnection().getSocketAddress() + " connected with unknown extra data " + event.getHandshake() + " " + extraDataInHandshake);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
86
src/de/steamwar/bungeecore/mods/LabyMod.java
Normale Datei
86
src/de/steamwar/bungeecore/mods/LabyMod.java
Normale Datei
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.sql.Mod;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class LabyMod {
|
||||
// https://docs.labymod.net/pages/server/introduction/
|
||||
// https://github.com/LabyMod/labymod-server-api
|
||||
// https://dl.labymod.net/addons.json
|
||||
|
||||
private final byte[] gameInfoPacket;
|
||||
public LabyMod() {
|
||||
ByteBuf buf = Unpooled.buffer();
|
||||
DefinedPacket.writeString("discord_rpc", buf);
|
||||
|
||||
JsonObject json = new JsonObject();
|
||||
json.addProperty("hasGame", true);
|
||||
json.addProperty("game_mode", "steamwar.de");
|
||||
json.addProperty("game_startTime", 0);
|
||||
json.addProperty("game_endTime", 0);
|
||||
DefinedPacket.writeString(json.toString(), buf);
|
||||
|
||||
gameInfoPacket = new byte[buf.readableBytes()];
|
||||
buf.readBytes(gameInfoPacket);
|
||||
}
|
||||
|
||||
public void handlePluginMessage(PluginMessageEvent event) {
|
||||
ProxiedPlayer player = (ProxiedPlayer) event.getSender();
|
||||
player.sendData(event.getTag(), gameInfoPacket);
|
||||
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(event.getData());
|
||||
String purpose = DefinedPacket.readString(buf);
|
||||
if(!"INFO".equals(purpose))
|
||||
return;
|
||||
|
||||
JsonObject message = JsonParser.parseString(DefinedPacket.readString(buf)).getAsJsonObject();
|
||||
List<Mod> mods = new LinkedList<>();
|
||||
|
||||
for(JsonElement element : message.getAsJsonArray("addons")) {
|
||||
JsonObject addon = element.getAsJsonObject();
|
||||
mods.add(Mod.getOrCreate(addon.get("name").getAsString(), Mod.Platform.LABYMOD));
|
||||
}
|
||||
|
||||
if(message.has("mods")) {
|
||||
BungeeCore.get().getLogger().log(Level.WARNING, () -> "LabyMod External Mods for debugging: " + message.getAsJsonArray("mods"));
|
||||
for(JsonElement element : message.getAsJsonArray("mods")) {
|
||||
JsonObject addon = element.getAsJsonObject();
|
||||
//TODO observe: FORGE and FABRIC mods available, do they always and with .jar? (would equal new mod platform)
|
||||
//mods.add(Mod.getOrCreate(addon.get("name").getAsString().replace(".jar", ""), Mod.Platform.FORGE));
|
||||
}
|
||||
}
|
||||
|
||||
ModUtils.handleMods(player, mods);
|
||||
}
|
||||
}
|
132
src/de/steamwar/bungeecore/mods/Lunar.java
Normale Datei
132
src/de/steamwar/bungeecore/mods/Lunar.java
Normale Datei
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import com.lunarclient.apollo.ApolloManager;
|
||||
import com.lunarclient.apollo.libs.protobuf.Any;
|
||||
import com.lunarclient.apollo.libs.protobuf.InvalidProtocolBufferException;
|
||||
import com.lunarclient.apollo.libs.protobuf.Message;
|
||||
import com.lunarclient.apollo.mods.impl.*;
|
||||
import com.lunarclient.apollo.module.ApolloModuleManager;
|
||||
import com.lunarclient.apollo.module.ApolloModuleManagerImpl;
|
||||
import com.lunarclient.apollo.module.modsetting.ModSettingModule;
|
||||
import com.lunarclient.apollo.network.NetworkOptions;
|
||||
import com.lunarclient.apollo.option.Options;
|
||||
import com.lunarclient.apollo.player.AbstractApolloPlayer;
|
||||
import com.lunarclient.apollo.player.v1.ModMessage;
|
||||
import com.lunarclient.apollo.player.v1.PlayerHandshakeMessage;
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.sql.Mod;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class Lunar {
|
||||
// https://lunarclient.dev/apollo/introduction
|
||||
// https://github.com/LunarClient/Apollo
|
||||
|
||||
private final ApolloModuleManager manager = new ApolloModuleManagerImpl().addModule(ModSettingModule.class);
|
||||
|
||||
public Lunar() {
|
||||
Options modSettings = manager.getModule(ModSettingModule.class).getOptions();
|
||||
modSettings.set(ModReplaymod.ENABLED, false); // TODO check if restrictions working
|
||||
modSettings.set(ModFreelook.ENABLED, false);
|
||||
modSettings.set(ModHypixelMod.ENABLED, false);
|
||||
modSettings.set(ModMinimap.ENABLED, false);
|
||||
modSettings.set(ModNametag.ENABLED, false);
|
||||
modSettings.set(ModTeamView.ENABLED, false);
|
||||
modSettings.set(ModTntCountdown.ENABLED, false);
|
||||
modSettings.set(ModToggleSneak.TOGGLE_SNEAK_CONTAINER, false);
|
||||
}
|
||||
|
||||
public void sendRestrictions(ProxiedPlayer player) {
|
||||
NetworkOptions.sendOptions(manager.getModules(), true, new SWApolloPlayer(player));
|
||||
}
|
||||
|
||||
public void handlePluginMessage(PluginMessageEvent event) {
|
||||
ProxiedPlayer player = (ProxiedPlayer) event.getSender();
|
||||
Any packet;
|
||||
|
||||
try {
|
||||
packet = Any.parseFrom(event.getData());
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
|
||||
handle(PlayerHandshakeMessage.class, packet, handshake -> {
|
||||
List<Mod> mods = new ArrayList<>();
|
||||
|
||||
for(ModMessage mod : handshake.getInstalledModsList()) {
|
||||
switch(mod.getType()) {
|
||||
case TYPE_FABRIC_INTERNAL:
|
||||
case TYPE_FORGE_INTERNAL:
|
||||
// Controlled with ModSettings
|
||||
break;
|
||||
case TYPE_FABRIC_EXTERNAL:
|
||||
mods.add(Mod.getOrCreate(mod.getName(), Mod.Platform.FABRIC));
|
||||
break;
|
||||
case TYPE_FORGE_EXTERNAL:
|
||||
mods.add(Mod.getOrCreate(mod.getName(), Mod.Platform.FORGE));
|
||||
break;
|
||||
case TYPE_UNSPECIFIED:
|
||||
case UNRECOGNIZED:
|
||||
default:
|
||||
BungeeCore.get().getLogger().log(Level.INFO, () -> player.getName() + " uses Lunar mod with unknown type " + mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ModUtils.handleMods(player, mods);
|
||||
});
|
||||
}
|
||||
|
||||
private <T extends Message> void handle(Class<T> type, Any packet, Consumer<T> handler) {
|
||||
try {
|
||||
handler.accept(packet.unpack(type));
|
||||
} catch (InvalidProtocolBufferException ignored) { /*ignored*/ }
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
private static class SWApolloPlayer extends AbstractApolloPlayer {
|
||||
|
||||
private final ProxiedPlayer player;
|
||||
|
||||
@Override
|
||||
public void sendPacket(Message message) {
|
||||
sendPacket(Any.pack(message).toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(byte[] bytes) {
|
||||
player.sendData(ApolloManager.PLUGIN_MESSAGE_CHANNEL, bytes);
|
||||
}
|
||||
|
||||
@Override public UUID getUniqueId() { return player.getUniqueId(); }
|
||||
@Override public String getName() { return player.getName(); }
|
||||
@Override public boolean hasPermission(String s) { return player.hasPermission(s); }
|
||||
@Override public Object getPlayer() { return player; }
|
||||
}
|
||||
}
|
@ -1,23 +1,23 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 SteamWar.de-Serverteam
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners.mods;
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.Message;
|
||||
@ -27,6 +27,8 @@ import de.steamwar.messages.ChatSender;
|
||||
import de.steamwar.sql.Mod;
|
||||
import de.steamwar.sql.Mod.ModType;
|
||||
import de.steamwar.sql.UserPerm;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
@ -39,35 +41,17 @@ import java.util.function.Consumer;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Utils {
|
||||
@UtilityClass
|
||||
public class ModUtils {
|
||||
|
||||
public static final Map<UUID,List<Mod>> playerModMap = new HashMap<>();
|
||||
@Getter
|
||||
private static final Map<UUID,List<Mod>> playerModMap = new HashMap<>();
|
||||
|
||||
private Utils(){}
|
||||
|
||||
static VarInt readVarInt(byte[] array, int startPos) {
|
||||
int numRead = 0;
|
||||
int result = 0;
|
||||
byte read;
|
||||
do {
|
||||
read = array[startPos + numRead];
|
||||
int value = (read & 0b01111111);
|
||||
result |= (value << (7 * numRead));
|
||||
|
||||
numRead++;
|
||||
if (numRead > 5) {
|
||||
break;
|
||||
}
|
||||
} while ((read & 0b10000000) != 0);
|
||||
|
||||
return new VarInt(numRead, result);
|
||||
}
|
||||
|
||||
static boolean handleMods(ProxiedPlayer player, List<Mod> mods) {
|
||||
public static boolean handleMods(ProxiedPlayer player, List<Mod> mods) {
|
||||
return handleMods(player.getUniqueId(), ChatSender.of(player).getLocale(), player::disconnect, mods);
|
||||
}
|
||||
|
||||
static boolean handleMods(UUID uuid, Locale locale, Consumer<BaseComponent[]> disconnect, List<Mod> mods){
|
||||
public static boolean handleMods(UUID uuid, Locale locale, Consumer<BaseComponent> disconnect, List<Mod> mods){
|
||||
SteamwarUser user = SteamwarUser.get(uuid);
|
||||
playerModMap.put(uuid,new ArrayList<>(mods));
|
||||
|
||||
@ -101,17 +85,7 @@ public class Utils {
|
||||
BungeeCore.log(Level.SEVERE, user.getUserName() + " " + user.getId() + " wurde automatisch wegen der Mods " + modList + " gebannt.");
|
||||
}
|
||||
|
||||
disconnect.accept(TextComponent.fromLegacyText(message));
|
||||
disconnect.accept(TextComponent.fromLegacy(message));
|
||||
return false;
|
||||
}
|
||||
|
||||
static class VarInt{
|
||||
final int length;
|
||||
final int value;
|
||||
|
||||
VarInt(int length, int value){
|
||||
this.length = length;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
73
src/de/steamwar/bungeecore/mods/ReplayMod.java
Normale Datei
73
src/de/steamwar/bungeecore/mods/ReplayMod.java
Normale Datei
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import de.steamwar.bungeecore.Bauserver;
|
||||
import de.steamwar.bungeecore.Builderserver;
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.Subserver;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import de.steamwar.bungeecore.listeners.PluginMessage;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ReplayMod extends BasicListener {
|
||||
// https://gist.github.com/Johni0702/2547c463e51f65f312cb
|
||||
// https://github.com/ReplayMod/replay-restrictions/blob/master/bungeecord/src/main/java/de/johni0702/replay/restrictions/BungeeCordPlugin.java
|
||||
// https://github.com/ReplayMod/ReplayMod/blob/stable/src/main/java/com/replaymod/core/utils/Restrictions.java
|
||||
|
||||
private final byte[] restrict;
|
||||
|
||||
public ReplayMod() {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
try {
|
||||
for(String restriction : Arrays.asList("no_xray", "no_noclip", "only_first_person", "only_recording_player")) {
|
||||
byte[] bytes = restriction.getBytes();
|
||||
stream.write(bytes.length);
|
||||
stream.write(bytes);
|
||||
stream.write(1); // restrict
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException(e);
|
||||
}
|
||||
restrict = stream.toByteArray();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(ServerSwitchEvent event) {
|
||||
ProxiedPlayer player = event.getPlayer();
|
||||
ServerInfo server = player.getServer().getInfo();
|
||||
if(ProxyServer.getInstance().getServerInfo(BungeeCore.LOBBY_SERVER) == server)
|
||||
return;
|
||||
|
||||
Subserver subserver = Subserver.getSubserver(server);
|
||||
if(subserver instanceof Builderserver || (subserver instanceof Bauserver && ((Bauserver) subserver).getOwner().equals(player.getUniqueId())))
|
||||
return;
|
||||
|
||||
PluginMessage.send(player, "Replay|Restrict", "replaymod:restrict", restrict);
|
||||
}
|
||||
}
|
40
src/de/steamwar/bungeecore/mods/Schematica.java
Normale Datei
40
src/de/steamwar/bungeecore/mods/Schematica.java
Normale Datei
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
public class Schematica extends BasicListener {
|
||||
// https://github.com/Lunatrius/SchematicaPlugin/blob/master/src/main/java/com/github/lunatrius/schematica/plugin/SchematicaPlugin.java
|
||||
|
||||
private final byte[] packet = new byte[] {
|
||||
/* ProtocolVersion? */ 0,
|
||||
/* PERM_PRINTER */ 1,
|
||||
/* PERM_SAVE */ 0,
|
||||
/* PERM_LOAD */ 1
|
||||
};
|
||||
|
||||
@EventHandler
|
||||
public void onPostLogin(PostLoginEvent event) {
|
||||
event.getPlayer().sendData("schematica", packet);
|
||||
}
|
||||
}
|
63
src/de/steamwar/bungeecore/mods/ServerListPing.java
Normale Datei
63
src/de/steamwar/bungeecore/mods/ServerListPing.java
Normale Datei
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import com.google.gson.*;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public class ServerListPing extends BasicListener implements JsonSerializer<ServerPing>, JsonDeserializer<ServerPing> {
|
||||
// https://github.com/Aizistral-Studios/No-Chat-Reports/discussions/206
|
||||
// https://github.com/Aizistral-Studios/No-Chat-Reports/wiki/How-to-Get-Safe-Server-Status
|
||||
|
||||
private final Gson gson;
|
||||
|
||||
public ServerListPing() {
|
||||
BungeeCord bungeeCord = BungeeCord.getInstance();
|
||||
gson = bungeeCord.gson;
|
||||
|
||||
try {
|
||||
Field gsonField = BungeeCord.class.getDeclaredField("gson");
|
||||
gsonField.setAccessible(true);
|
||||
gsonField.set(bungeeCord, gson.newBuilder().registerTypeAdapter(ServerPing.class, this).create());
|
||||
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new SecurityException("Failed to inject ServerListPing", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(ServerPing ping, Type type, JsonSerializationContext context) {
|
||||
JsonElement element = gson.toJsonTree(ping, type);
|
||||
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
object.addProperty("preventsChatReports", true);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerPing deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException {
|
||||
return gson.fromJson(element, ServerPing.class);
|
||||
}
|
||||
}
|
59
src/de/steamwar/bungeecore/mods/WorldDownloader.java
Normale Datei
59
src/de/steamwar/bungeecore/mods/WorldDownloader.java
Normale Datei
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.mods;
|
||||
|
||||
import de.steamwar.bungeecore.listeners.PluginMessage;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class WorldDownloader {
|
||||
// https://wiki.vg/Plugin_channels/World_downloader
|
||||
// https://github.com/Pokechu22/WorldDownloader-Serverside-Companion
|
||||
// https://github.com/Pokechu22/WorldDownloader
|
||||
|
||||
private final byte[] controlPacket;
|
||||
|
||||
public WorldDownloader() {
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
DataOutputStream out = new DataOutputStream(stream);
|
||||
|
||||
try {
|
||||
out.writeInt(1); // basic data packet
|
||||
out.writeBoolean(false); // General download enabled
|
||||
out.writeInt(-1); // Save radius
|
||||
out.writeBoolean(false); // Chunk caching enabled
|
||||
out.writeBoolean(false); // Entity saving enabled
|
||||
out.writeBoolean(false); // Tile entity saving disabled
|
||||
out.writeBoolean(false); // Container saving disabled
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not create AntiWDL packet", e);
|
||||
}
|
||||
|
||||
controlPacket = stream.toByteArray();
|
||||
}
|
||||
|
||||
public void handlePluginMessage(PluginMessageEvent event) {
|
||||
PluginMessage.send((ProxiedPlayer) event.getSender(), "WDL|CONTROL", "wdl:control", controlPacket);
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.network;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.commands.TeamCommand;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import de.steamwar.sql.SWException;
|
||||
import de.steamwar.network.packets.NetworkPacket;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.connection.Server;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
public class NetworkReceiver extends BasicListener {
|
||||
|
||||
private static final List<String> blockedTags = Arrays.asList("bungeecord:main", "BungeeCord", "sw:bridge");
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPluginMessage(PluginMessageEvent event) {
|
||||
if (blockedTags.contains(event.getTag()) && !TeamCommand.isLocalhost(((InetSocketAddress) event.getSender().getSocketAddress()).getAddress())) {
|
||||
SWException.log(((InetSocketAddress) event.getSender().getSocketAddress()).getHostString() + " tried to send a plugin message with tag " + event.getTag(), Base64.getEncoder().encodeToString(event.getData()));
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
if(!event.getTag().equals("sw:bridge"))
|
||||
return;
|
||||
|
||||
event.setCancelled(true);
|
||||
if(!(event.getSender() instanceof Server))
|
||||
return;
|
||||
|
||||
ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> NetworkPacket.handle(new ServerMetaInfo(((Server) event.getSender()).getInfo()), event.getData()));
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.network;
|
||||
|
||||
import de.steamwar.bungeecore.commands.TeamCommand;
|
||||
import de.steamwar.bungeecore.listeners.BasicListener;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.connection.Server;
|
||||
import net.md_5.bungee.api.event.PluginMessageEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
import net.md_5.bungee.event.EventPriority;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class SWScriptSyntaxForwarder extends BasicListener {
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onPluginMessage(PluginMessageEvent event) {
|
||||
if (!event.getTag().equals("sw:script_syntax")) {
|
||||
return;
|
||||
}
|
||||
event.setCancelled(true);
|
||||
if (!(event.getSender() instanceof Server)) {
|
||||
return;
|
||||
}
|
||||
if (!TeamCommand.isLocalhost(((InetSocketAddress) event.getSender().getSocketAddress()).getAddress())) {
|
||||
return;
|
||||
}
|
||||
((ProxiedPlayer) event.getReceiver()).sendData("sw:script_syntax", event.getData());
|
||||
}
|
||||
}
|
@ -20,9 +20,6 @@ DISABLED=§cCurrently disabled.
|
||||
|
||||
SERVER_START_OVERLOAD=§cServer start cancelled due to overload. Please try again later.
|
||||
|
||||
#ModLoader blocker
|
||||
MODLOADER_DENIED=§cYou cannot join arenas with LiteLoader or Fabric without the FabricModSender https://steamwar.de/downloads installed.
|
||||
|
||||
#Help command
|
||||
HELP_LOBBY=§7Return from anywhere to the lobby using §8/§el§7!
|
||||
HELP_LOBBY_HOVER=§eBack to the lobby
|
||||
@ -118,10 +115,6 @@ MOD_RED_PLUR=Attempted use of mods:\n{0}
|
||||
MOD_YELLOW_SING=§7Deactivate the mod §e{0}§7 to continue playing on §eSteam§8War§7.
|
||||
MOD_YELLOW_PLUR=§7Deactivate the mods\n§e{0}\n§7to continue playing on §eSteam§8War§7.
|
||||
|
||||
MOD_LOADER_LUNAR_CLIENT=§eLunar Client§7 is not supported on §eSteam§8War§7.
|
||||
|
||||
MOD_USE_MODSENDER=§cPlease use the §c§lFabricModSender§c (https://steamwar.de/downloads/) or remove the mod that is rebranding your installation.
|
||||
|
||||
#Various commands
|
||||
ALERT=§f{0}
|
||||
STAT_SERVER=§7Server §e{0}§8: §7Below limit §e{1} §7Server count §e{2}
|
||||
|
@ -16,9 +16,6 @@ DISABLED=§cDerzeit deaktiviert.
|
||||
|
||||
SERVER_START_OVERLOAD=§cDer Serverstart wurde aufgrund von Überlastung abgebrochen. Versuche es später erneut.
|
||||
|
||||
#ModLoader blocker
|
||||
MODLOADER_DENIED=§cMit LiteLoader oder Fabric kannst du keinen Arenen ohne den FabricModSender https://steamwar.de/downloads beitreten.
|
||||
|
||||
#Help command
|
||||
HELP_LOBBY=§7Kehre von überall mit §8/§el §7zur Lobby zurück!
|
||||
HELP_LOBBY_HOVER=§eZurück zur Lobby
|
||||
@ -103,10 +100,6 @@ MOD_RED_PLUR=Versuchte Benutzung der Mods:\n{0}
|
||||
MOD_YELLOW_SING=§7Deaktiviere den Mod §e{0}§7, um weiter auf §eSteam§8War §7spielen zu können.
|
||||
MOD_YELLOW_PLUR=§7Deaktiviere die Mods\n§e{0}\n§7um weiter auf §eSteam§8War §7spielen zu können.
|
||||
|
||||
MOD_LOADER_LUNAR_CLIENT=§eLunar Client§7 ist auf §eSteam§8War§7 nicht unterstützt.
|
||||
|
||||
MOD_USE_MODSENDER=§cBitte nutze den §c§lFabricModSender§c (https://steamwar.de/downloads/) oder entferne den Mod, der deine Fabric-Installation tarnt.
|
||||
|
||||
#Various commands
|
||||
STAT_SERVER=§7Server §e{0}§8: §7Startfähig §e{1} §7Serveranzahl §e{2}
|
||||
|
||||
|
In neuem Issue referenzieren
Einen Benutzer sperren