getCurrentServer() {
+ Server server = getHandle().getServer();
+ if (server == null) {
+ return Optional.empty();
+ }
+ return Optional.of(server.getInfo().getName());
+ }
+
+ @Override
+ public void sendBungeeMessage(byte[] data) {
+ Server server = getHandle().getServer();
+ if (server == null) {
+ return;
+ }
+ server.sendData("BungeeCord", data);
+ }
+
+ @Override
+ public void sendMessage(String message) {
+ getHandle().sendMessage(TextComponent.fromLegacyText(message));
+ }
+
+ @Override
+ public ProxiedPlayer getHandle() {
+ return (ProxiedPlayer) super.getHandle();
+ }
+
+ public static BungeePlayer fromPlayer(ProxiedPlayer player) {
+ return new BungeePlayer(player);
+ }
+}
diff --git a/bungee/src/main/resources/bungee.yml b/bungee/src/main/resources/bungee.yml
new file mode 100644
index 0000000..79cbd8b
--- /dev/null
+++ b/bungee/src/main/resources/bungee.yml
@@ -0,0 +1,4 @@
+name: ${project.parent.name}
+main: fr.xephi.authmeproxy.bungee.AuthMeProxyBungee
+version: ${project.version}
+author: AuthMeTeam
diff --git a/common/pom.xml b/common/pom.xml
new file mode 100644
index 0000000..b450f4c
--- /dev/null
+++ b/common/pom.xml
@@ -0,0 +1,28 @@
+
+
+ 4.0.0
+
+ fr.xephi
+ authmeproxy-parent
+ 2.3.0-SNAPSHOT
+
+
+ authmeproxy-common
+ AuthMeProxy-Common
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+
+
+
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/AbstractAuthMeLogger.java b/common/src/main/java/fr/xephi/authmeproxy/common/AbstractAuthMeLogger.java
new file mode 100644
index 0000000..9170b66
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/AbstractAuthMeLogger.java
@@ -0,0 +1,9 @@
+package fr.xephi.authmeproxy.common;
+
+public abstract class AbstractAuthMeLogger {
+
+ public abstract void send(String message);
+ public abstract void info(String... messages);
+ public abstract void warn(String... messages);
+ public abstract void error(String... messages);
+}
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/AbstractAuthMeProxy.java b/common/src/main/java/fr/xephi/authmeproxy/common/AbstractAuthMeProxy.java
new file mode 100644
index 0000000..6426984
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/AbstractAuthMeProxy.java
@@ -0,0 +1,82 @@
+package fr.xephi.authmeproxy.common;
+
+import ch.jalu.configme.SettingsManager;
+import ch.jalu.injector.Injector;
+import ch.jalu.injector.InjectorBuilder;
+import fr.xephi.authmeproxy.common.annotations.DataFolder;
+import fr.xephi.authmeproxy.common.config.ProxyConfigProperties;
+import fr.xephi.authmeproxy.common.config.ProxySettingsProvider;
+import fr.xephi.authmeproxy.common.platform.AbstractPlatform;
+import fr.xephi.authmeproxy.common.platform.AbstractPlayer;
+import fr.xephi.authmeproxy.common.services.AuthStateService;
+import fr.xephi.authmeproxy.common.services.MessageHandleService;
+import fr.xephi.authmeproxy.common.services.MessageSenderService;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+public abstract class AbstractAuthMeProxy> {
+
+ protected P platform;
+ protected AbstractAuthMeLogger logger;
+ protected File dataFolder;
+
+ protected Injector injector;
+ protected SettingsManager settings;
+
+ protected AuthStateService authStateService;
+ protected MessageHandleService messageHandleService;
+ protected MessageSenderService messageSenderService;
+
+ public AbstractAuthMeProxy(P platform, AbstractAuthMeLogger logger, File dataFolder) {
+ this.platform = platform;
+ this.logger = logger;
+ this.dataFolder = dataFolder;
+
+ injector = new InjectorBuilder().addDefaultHandlers("").create();
+
+ injector.register(AbstractAuthMeProxy.class, this);
+ injector.register(AbstractAuthMeLogger.class, logger);
+ injector.provide(DataFolder.class, dataFolder);
+
+ injector.registerProvider(SettingsManager.class, ProxySettingsProvider.class);
+ }
+
+ protected abstract void registerCommands();
+
+ protected abstract void registerListeners();
+
+ protected abstract void registerMetrics();
+
+ public final void initialize() {
+ try {
+ Files.createDirectories(dataFolder.toPath());
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to create the plugin folder", e);
+ }
+
+ // Get singletons from the injector
+ settings = injector.getSingleton(SettingsManager.class);
+
+ // Initialize services
+ authStateService = injector.getSingleton(AuthStateService.class);
+ messageHandleService = injector.getSingleton(MessageHandleService.class);
+ messageSenderService = injector.getSingleton(MessageSenderService.class);
+
+ // Print some config information
+ logger.info("Current auth servers:");
+ for (String authServer : settings.getProperty(ProxyConfigProperties.AUTH_SERVERS)) {
+ logger.info("> " + authServer.toLowerCase());
+ }
+
+ // Add online players (plugin hotswap, just in case)
+ for (AbstractPlayer player : platform.getAllPlayers()) {
+ authStateService.trackUser(player.getUsername());
+ }
+
+ registerCommands();
+ registerListeners();
+ registerMetrics();
+ }
+}
diff --git a/src/main/java/fr/xephi/authmebungee/annotations/DataFolder.java b/common/src/main/java/fr/xephi/authmeproxy/common/annotations/DataFolder.java
similarity index 87%
rename from src/main/java/fr/xephi/authmebungee/annotations/DataFolder.java
rename to common/src/main/java/fr/xephi/authmeproxy/common/annotations/DataFolder.java
index 69fb6b2..93ad89a 100644
--- a/src/main/java/fr/xephi/authmebungee/annotations/DataFolder.java
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/annotations/DataFolder.java
@@ -1,4 +1,4 @@
-package fr.xephi.authmebungee.annotations;
+package fr.xephi.authmeproxy.common.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/commands/AbstractCommand.java b/common/src/main/java/fr/xephi/authmeproxy/common/commands/AbstractCommand.java
new file mode 100644
index 0000000..be88ed7
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/commands/AbstractCommand.java
@@ -0,0 +1,24 @@
+package fr.xephi.authmeproxy.common.commands;
+
+import fr.xephi.authmeproxy.common.platform.AbstractPlayer;
+
+public abstract class AbstractCommand {
+
+ protected final String command;
+ protected final String permission;
+
+ public AbstractCommand(String command, String permission) {
+ this.command = command;
+ this.permission = permission;
+ }
+
+ public abstract void execute(AbstractPlayer sender, String[] strings);
+
+ public String getCommand() {
+ return command;
+ }
+
+ public String getPermission() {
+ return permission;
+ }
+}
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/commands/ReloadCommand.java b/common/src/main/java/fr/xephi/authmeproxy/common/commands/ReloadCommand.java
new file mode 100644
index 0000000..b4098ee
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/commands/ReloadCommand.java
@@ -0,0 +1,36 @@
+package fr.xephi.authmeproxy.common.commands;
+
+import ch.jalu.configme.SettingsManager;
+import ch.jalu.injector.factory.SingletonStore;
+import fr.xephi.authmeproxy.common.AbstractAuthMeLogger;
+import fr.xephi.authmeproxy.common.config.SettingsDependent;
+import fr.xephi.authmeproxy.common.platform.AbstractPlayer;
+
+import javax.inject.Inject;
+
+public class ReloadCommand extends AbstractCommand {
+
+ private final AbstractAuthMeLogger logger;
+ private final SettingsManager settings;
+ private final SingletonStore settingsDependentStore;
+
+ @Inject
+ public ReloadCommand(AbstractAuthMeLogger logger, SettingsManager settings, SingletonStore settingsDependentStore) {
+ super("authmeproxyreload", "authmeproxy.reload");
+ this.logger = logger;
+ this.settings = settings;
+ this.settingsDependentStore = settingsDependentStore;
+ }
+
+ @Override
+ public void execute(AbstractPlayer sender, String[] strings) {
+ settings.reload();
+ settingsDependentStore.retrieveAllOfType().forEach(settingsDependent -> settingsDependent.reload(settings));
+ String message = "&2AuthMeBungee configuration reloaded!";
+ if (sender != null) {
+ sender.sendMessage(message);
+ } else {
+ logger.send(message);
+ }
+ }
+}
diff --git a/src/main/java/fr/xephi/authmebungee/config/BungeeConfigProperties.java b/common/src/main/java/fr/xephi/authmeproxy/common/config/ProxyConfigProperties.java
similarity index 90%
rename from src/main/java/fr/xephi/authmebungee/config/BungeeConfigProperties.java
rename to common/src/main/java/fr/xephi/authmeproxy/common/config/ProxyConfigProperties.java
index 600d447..10cf492 100644
--- a/src/main/java/fr/xephi/authmebungee/config/BungeeConfigProperties.java
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/config/ProxyConfigProperties.java
@@ -1,4 +1,4 @@
-package fr.xephi.authmebungee.config;
+package fr.xephi.authmeproxy.common.config;
import ch.jalu.configme.Comment;
import ch.jalu.configme.SettingsHolder;
@@ -9,7 +9,7 @@
import static ch.jalu.configme.properties.PropertyInitializer.newListProperty;
import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
-public class BungeeConfigProperties implements SettingsHolder {
+public class ProxyConfigProperties implements SettingsHolder {
@Comment("List of servers in the network where authme is installed")
public static final Property> AUTH_SERVERS =
@@ -30,7 +30,7 @@ public class BungeeConfigProperties implements SettingsHolder {
public static final Property SERVER_SWITCH_REQUIRES_AUTH =
newProperty("serverSwitch.requiresAuth", true);
public static final Property SERVER_SWITCH_KICK_MESSAGE =
- newProperty("serverSwitch.kickMessage", "Authentication required.");
+ newProperty("serverSwitch.kickMessage", "&4Authentication required.");
@Comment("Enable auto-login between servers")
public static final Property AUTOLOGIN =
newProperty("autoLogin", false);
@@ -41,7 +41,7 @@ public class BungeeConfigProperties implements SettingsHolder {
public static final Property SEND_ON_LOGOUT_TARGET =
newProperty("unloggedUserServer", "");
- private BungeeConfigProperties() {
+ private ProxyConfigProperties() {
}
}
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/config/ProxySettingsProvider.java b/common/src/main/java/fr/xephi/authmeproxy/common/config/ProxySettingsProvider.java
new file mode 100644
index 0000000..de8e54f
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/config/ProxySettingsProvider.java
@@ -0,0 +1,15 @@
+package fr.xephi.authmeproxy.common.config;
+
+import fr.xephi.authmeproxy.common.annotations.DataFolder;
+
+import javax.inject.Inject;
+import java.io.File;
+
+public class ProxySettingsProvider extends SettingsProvider {
+
+ @Inject
+ public ProxySettingsProvider(@DataFolder File dataFolder) {
+ super(dataFolder, ProxyConfigProperties.class);
+ }
+
+}
diff --git a/src/main/java/fr/xephi/authmebungee/config/SettingsDependent.java b/common/src/main/java/fr/xephi/authmeproxy/common/config/SettingsDependent.java
similarity index 88%
rename from src/main/java/fr/xephi/authmebungee/config/SettingsDependent.java
rename to common/src/main/java/fr/xephi/authmeproxy/common/config/SettingsDependent.java
index a038f7a..4b9c4da 100644
--- a/src/main/java/fr/xephi/authmebungee/config/SettingsDependent.java
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/config/SettingsDependent.java
@@ -1,4 +1,4 @@
-package fr.xephi.authmebungee.config;
+package fr.xephi.authmeproxy.common.config;
import ch.jalu.configme.SettingsManager;
diff --git a/src/main/java/fr/xephi/authmebungee/config/SettingsProvider.java b/common/src/main/java/fr/xephi/authmeproxy/common/config/SettingsProvider.java
similarity index 86%
rename from src/main/java/fr/xephi/authmebungee/config/SettingsProvider.java
rename to common/src/main/java/fr/xephi/authmeproxy/common/config/SettingsProvider.java
index f9b5dee..f3a5e50 100644
--- a/src/main/java/fr/xephi/authmebungee/config/SettingsProvider.java
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/config/SettingsProvider.java
@@ -1,4 +1,4 @@
-package fr.xephi.authmebungee.config;
+package fr.xephi.authmeproxy.common.config;
import ch.jalu.configme.SettingsHolder;
import ch.jalu.configme.SettingsManager;
@@ -12,9 +12,9 @@
*/
public abstract class SettingsProvider implements Provider {
- private File dataFolder;
+ private final File dataFolder;
- private Class extends SettingsHolder> properties;
+ private final Class extends SettingsHolder> properties;
protected SettingsProvider(File dataFolder, Class extends SettingsHolder> properties) {
this.dataFolder = dataFolder;
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/data/AuthUserState.java b/common/src/main/java/fr/xephi/authmeproxy/common/data/AuthUserState.java
new file mode 100644
index 0000000..7d58495
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/data/AuthUserState.java
@@ -0,0 +1,29 @@
+package fr.xephi.authmeproxy.common.data;
+
+public class AuthUserState {
+
+ private final String name;
+ private boolean isLogged;
+
+ public AuthUserState(String name, boolean isLogged) {
+ this.name = name.toLowerCase();
+ this.isLogged = isLogged;
+ }
+
+ public AuthUserState(String name) {
+ this(name, false);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isLogged() {
+ return isLogged;
+ }
+
+ public void setLogged(boolean isLogged) {
+ this.isLogged = isLogged;
+ }
+
+}
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/platform/AbstractPlatform.java b/common/src/main/java/fr/xephi/authmeproxy/common/platform/AbstractPlatform.java
new file mode 100644
index 0000000..92923ee
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/platform/AbstractPlatform.java
@@ -0,0 +1,9 @@
+package fr.xephi.authmeproxy.common.platform;
+
+import java.util.Collection;
+
+public abstract class AbstractPlatform {
+
+ public abstract Collection
getAllPlayers();
+ public abstract boolean connect(P player, String server);
+}
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/platform/AbstractPlayer.java b/common/src/main/java/fr/xephi/authmeproxy/common/platform/AbstractPlayer.java
new file mode 100644
index 0000000..cfd1e6e
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/platform/AbstractPlayer.java
@@ -0,0 +1,24 @@
+package fr.xephi.authmeproxy.common.platform;
+
+import java.util.Optional;
+
+public abstract class AbstractPlayer {
+ protected final Object handle;
+
+ public AbstractPlayer(Object handle) {
+ this.handle = handle;
+ }
+
+ public abstract String getUsername();
+
+ public abstract Optional getCurrentServer();
+
+ public Object getHandle() {
+ return handle;
+ }
+
+ public abstract void sendBungeeMessage(byte[] data);
+
+ public abstract void sendMessage(String message);
+
+}
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/services/AuthStateService.java b/common/src/main/java/fr/xephi/authmeproxy/common/services/AuthStateService.java
new file mode 100644
index 0000000..75ef1ca
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/services/AuthStateService.java
@@ -0,0 +1,176 @@
+package fr.xephi.authmeproxy.common.services;
+
+import ch.jalu.configme.SettingsManager;
+import fr.xephi.authmeproxy.common.AbstractAuthMeLogger;
+import fr.xephi.authmeproxy.common.config.ProxyConfigProperties;
+import fr.xephi.authmeproxy.common.config.SettingsDependent;
+import fr.xephi.authmeproxy.common.data.AuthUserState;
+import fr.xephi.authmeproxy.common.platform.AbstractPlatform;
+import fr.xephi.authmeproxy.common.platform.AbstractPlayer;
+
+import javax.inject.Inject;
+import java.util.*;
+
+public class AuthStateService implements SettingsDependent {
+
+ private final AbstractPlatform platform;
+ private final AbstractAuthMeLogger logger;
+ private final MessageSenderService messageSenderService;
+
+ private final Map players;
+
+ // Settings
+ private boolean isAutoLoginEnabled;
+ private boolean isServerSwitchRequiresAuth;
+ private String requiresAuthKickMessage;
+ private List authServers;
+ private boolean allServersAreAuthServers;
+ private boolean isCommandsRequireAuth;
+ private List commandWhitelist;
+ private boolean chatRequiresAuth;
+ private boolean isSendOnLogoutEnabled;
+ private String sendOnLogoutTarget;
+
+ @Inject
+ public AuthStateService(
+ AbstractPlatform platform,
+ AbstractAuthMeLogger logger,
+ MessageSenderService messageSenderService,
+ SettingsManager settings
+ ) {
+ this.platform = platform;
+ this.logger = logger;
+ this.messageSenderService = messageSenderService;
+ players = new HashMap<>();
+ reload(settings);
+ }
+
+ @Override
+ public void reload(SettingsManager settings) {
+ isAutoLoginEnabled = settings.getProperty(ProxyConfigProperties.AUTOLOGIN);
+ isServerSwitchRequiresAuth = settings.getProperty(ProxyConfigProperties.SERVER_SWITCH_REQUIRES_AUTH);
+ requiresAuthKickMessage = settings.getProperty(ProxyConfigProperties.SERVER_SWITCH_KICK_MESSAGE);
+ authServers = new ArrayList<>();
+ for (String server : settings.getProperty(ProxyConfigProperties.AUTH_SERVERS)) {
+ authServers.add(server.toLowerCase());
+ }
+ allServersAreAuthServers = settings.getProperty(ProxyConfigProperties.ALL_SERVERS_ARE_AUTH_SERVERS);
+ isCommandsRequireAuth = settings.getProperty(ProxyConfigProperties.COMMANDS_REQUIRE_AUTH);
+ commandWhitelist = new ArrayList<>();
+ for (String command : settings.getProperty(ProxyConfigProperties.COMMANDS_WHITELIST)) {
+ commandWhitelist.add(command.toLowerCase());
+ }
+ chatRequiresAuth = settings.getProperty(ProxyConfigProperties.CHAT_REQUIRES_AUTH);
+ isSendOnLogoutEnabled = settings.getProperty(ProxyConfigProperties.ENABLE_SEND_ON_LOGOUT);
+ sendOnLogoutTarget = settings.getProperty(ProxyConfigProperties.SEND_ON_LOGOUT_TARGET);
+ }
+
+ private boolean isAuthServer(String serverName) {
+ return allServersAreAuthServers || authServers.contains(serverName.toLowerCase());
+ }
+
+ public AuthUserState trackUser(String name) {
+ name = name.toLowerCase();
+ if (players.containsKey(name)) {
+ logger.warn("Player " + name + " was already being tracked! Removing previous instance from the memory store...");
+ }
+ AuthUserState authUserState = new AuthUserState(name);
+ players.put(name, authUserState);
+ return authUserState;
+ }
+
+ public void untrackUser(String name) {
+ name = name.toLowerCase();
+ players.remove(name);
+ }
+
+ public Optional getAuthUserState(String name) {
+ name = name.toLowerCase();
+ return Optional.ofNullable(players.get(name));
+ }
+
+ public Optional toPlayer(AuthUserState authUserState) {
+ for (AbstractPlayer current : platform.getAllPlayers()) {
+ if (current.getUsername().equalsIgnoreCase(authUserState.getName())) {
+ return Optional.of(current);
+ }
+ }
+ return Optional.empty();
+ }
+
+ public void login(String name) {
+ getAuthUserState(name)
+ .ifPresent(authUserState -> authUserState.setLogged(true));
+ }
+
+ public void logout(String name) {
+ getAuthUserState(name)
+ .ifPresent(authUserState -> {
+ authUserState.setLogged(false);
+ if (!isSendOnLogoutEnabled) {
+ return;
+ }
+ toPlayer(authUserState)
+ .ifPresent(player -> platform.connect(player, sendOnLogoutTarget));
+ });
+ }
+
+ private boolean shouldBeRestricted(AbstractPlayer player) {
+ // Filter only unauthenticated players
+ AuthUserState authUserState = getAuthUserState(player.getUsername()).orElse(null);
+ if (authUserState != null && authUserState.isLogged()) {
+ return false;
+ }
+ String currentServer = player.getCurrentServer().orElse(null);
+ if (currentServer == null) {
+ return true;
+ }
+ // Only in auth servers
+ return isAuthServer(currentServer);
+ }
+
+ public boolean shouldAllowChat(AbstractPlayer player) {
+ return !chatRequiresAuth || !shouldBeRestricted(player);
+ }
+
+ public boolean shouldAllowCommand(AbstractPlayer player, String command) {
+ if (!isCommandsRequireAuth) {
+ return true;
+ }
+ return !shouldBeRestricted(player) || commandWhitelist.contains(command.split(" ")[0].toLowerCase());
+ }
+
+ public void handleServerConnected(AbstractPlayer player, String server) {
+ AuthUserState authUserState = getAuthUserState(player.getUsername()).orElse(null);
+ boolean isAuthenticated = authUserState != null && authUserState.isLogged();
+
+ if (isAuthenticated && isAuthServer(server)) {
+ // If AutoLogin enabled, notify the server
+ if (isAutoLoginEnabled) {
+ messageSenderService.sendAutoLoginMessage(player);
+ }
+ }
+ }
+
+ public Optional shouldAllowServerSwitch(AbstractPlayer player, String server) {
+ if (!isServerSwitchRequiresAuth) {
+ return Optional.empty();
+ }
+
+ AuthUserState authUserState = getAuthUserState(player.getUsername()).orElse(null);
+ boolean isAuthenticated = authUserState != null && authUserState.isLogged();
+
+ // Skip logged users
+ if (isAuthenticated) {
+ return Optional.empty();
+ }
+
+ // Only check non auth servers
+ if (isAuthServer(server)) {
+ return Optional.empty();
+ }
+
+ // If the player is not logged in and serverSwitchRequiresAuth is enabled, cancel the connection
+ return Optional.of(requiresAuthKickMessage);
+ }
+}
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/services/MessageHandleService.java b/common/src/main/java/fr/xephi/authmeproxy/common/services/MessageHandleService.java
new file mode 100644
index 0000000..6eec3ae
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/services/MessageHandleService.java
@@ -0,0 +1,65 @@
+package fr.xephi.authmeproxy.common.services;
+
+import com.google.common.io.ByteArrayDataInput;
+import com.google.common.io.ByteStreams;
+
+import javax.inject.Inject;
+
+public class MessageHandleService {
+
+ @Inject
+ private AuthStateService authStateService;
+
+ public void handleMessage(boolean fromPlayer, String channel, byte[] data) {
+ // Check if a player is not trying to send us a fake message
+ if (fromPlayer) {
+ return;
+ }
+
+ // Check if the message is for a server (ignore client messages)
+ if (!channel.equals("bungeecord:main") && !channel.equals("BungeeCord")) {
+ return;
+ }
+
+ // Read the plugin message
+ ByteArrayDataInput in = ByteStreams.newDataInput(data);
+
+ // Accept only broadcasts
+ if (!in.readUTF().equals("Forward")) {
+ return;
+ }
+ in.readUTF(); // Skip ONLINE/ALL parameter
+
+ // Let's check the subchannel
+ if (!in.readUTF().equals("AuthMe.v2.Broadcast")) {
+ return;
+ }
+
+ // Read data byte array
+ short dataLength = in.readShort();
+ byte[] dataBytes = new byte[dataLength];
+ in.readFully(dataBytes);
+ ByteArrayDataInput dataIn = ByteStreams.newDataInput(dataBytes);
+
+ // For now that's the only type of message the server is able to receive
+ String type = dataIn.readUTF();
+ switch (type) {
+ case "login":
+ handleOnLogin(dataIn);
+ break;
+ case "logout":
+ handleOnLogout(dataIn);
+ break;
+ }
+ }
+
+ private void handleOnLogin(ByteArrayDataInput in) {
+ String name = in.readUTF();
+ authStateService.login(name);
+ }
+
+ private void handleOnLogout(ByteArrayDataInput in) {
+ String name = in.readUTF();
+ authStateService.logout(name);
+ }
+}
diff --git a/common/src/main/java/fr/xephi/authmeproxy/common/services/MessageSenderService.java b/common/src/main/java/fr/xephi/authmeproxy/common/services/MessageSenderService.java
new file mode 100644
index 0000000..83e1510
--- /dev/null
+++ b/common/src/main/java/fr/xephi/authmeproxy/common/services/MessageSenderService.java
@@ -0,0 +1,22 @@
+package fr.xephi.authmeproxy.common.services;
+
+import com.google.common.io.ByteArrayDataOutput;
+import com.google.common.io.ByteStreams;
+import fr.xephi.authmeproxy.common.platform.AbstractPlayer;
+
+import javax.inject.Inject;
+
+public class MessageSenderService {
+
+ @Inject
+ public MessageSenderService() {
+ }
+
+ public void sendAutoLoginMessage(AbstractPlayer player) {
+ ByteArrayDataOutput out = ByteStreams.newDataOutput();
+ out.writeUTF("AuthMe.v2");
+ out.writeUTF("perform.login");
+ out.writeUTF(player.getUsername());
+ player.sendBungeeMessage(out.toByteArray());
+ }
+}
diff --git a/pom.xml b/pom.xml
index d120ea1..458ac06 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,10 +5,18 @@
4.0.0
fr.xephi
- authmebungee
- 2.2.0-SNAPSHOT
+ authmeproxy-parent
+ 2.3.0-SNAPSHOT
+ pom
- AuthMeBungee
+
+ common
+ bungee
+ velocity
+ universal
+
+
+ AuthMeProxy
Bungeecord addon for AuthMe!
2017
https://www.spigotmc.org/resources/authmebungee.50219/
@@ -54,13 +62,13 @@
+ 11
UTF-8
UTF-8
clean install
- ${project.name}-${project.version}-noshade
false
@@ -74,161 +82,171 @@
src/main/resources
-
-
- org.apache.maven.plugins
- maven-clean-plugin
- 3.2.0
-
-
- org.apache.maven.plugins
- maven-resources-plugin
- 3.3.1
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.11.0
-
- 1.8
- 1.8
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 3.1.0
-
- false
-
-
-
- org.apache.maven.plugins
- maven-jar-plugin
- 3.3.0
-
-
- org.apache.maven.plugins
- maven-javadoc-plugin
- 3.5.0
-
-
- attach-javadoc
-
- jar
-
-
-
-
- ${project.name}-${project.version}
- public
- false
-
-
-
- org.apache.maven.plugins
- maven-source-plugin
- 3.2.1
-
-
- attach-sources
-
- jar
-
-
-
-
- ${project.name}-${project.version}
-
-
-
- org.apache.maven.plugins
- maven-shade-plugin
- 3.4.1
-
-
- package
-
- shade
-
-
-
-
- false
- true
- ${project.name}-${project.version}
-
-
- javax.annotation
- fr.xephi.authmebungee.libs.javax.annotation
-
-
- javax.inject
- fr.xephi.authmebungee.libs.javax.inject
-
-
- ch.jalu.injector
- fr.xephi.authmebungee.libs.jalu.injector
-
-
- org.yaml.snakeyaml
- fr.xephi.authmebungee.libs.yaml.snakeyaml
-
-
- ch.jalu.configme
- fr.xephi.authmebungee.libs.jalu.configme
-
-
- org.bstats
- fr.xephi.authmebungee.libs.org.bstats
-
-
+
+
+
+ org.apache.maven.plugins
+ maven-clean-plugin
+ 3.2.0
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+ 3.3.1
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.11.0
+
+ ${java.version}
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.1.0
+
+ false
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.3.0
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.5.0
+
+
+ attach-javadoc
+
+ jar
+
+
+
+
+ ${project.name}-${project.version}
+ public
+ false
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 3.2.1
+
+
+ attach-sources
+
+ jar
+
+
+
+
+ ${project.name}-${project.version}
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.4.1
+
+
+ package
+
+ shade
+
+
+
+
+ false
+ true
+ ${project.name}-${project.version}
+
+
+ javax.annotation
+ fr.xephi.authmeproxy.libs.javax.annotation
+
+
+ javax.inject
+ fr.xephi.authmeproxy.libs.javax.inject
+
+
+ ch.jalu.injector
+ fr.xephi.authmeproxy.libs.jalu.injector
+
+
+ org.yaml.snakeyaml
+ fr.xephi.authmeproxy.libs.yaml.snakeyaml
+
+
+ ch.jalu.configme
+ fr.xephi.authmeproxy.libs.jalu.configme
+
+
+ org.bstats
+ fr.xephi.authmeproxy.libs.org.bstats
+
+
-
-
-
-
- *:*
-
- META-INF/*.SF
- META-INF/*.DSA
- META-INF/*.RSA
- META-INF/*.RSA
- META-INF/*.MF
- META-INF/DEPENDENCIES
- META-INF/**/module-info.class
-
-
-
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+ META-INF/*.RSA
+ META-INF/*.MF
+ META-INF/DEPENDENCIES
+ META-INF/**/module-info.class
+
+
+
-
-
-
- false
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-install-plugin
- 3.1.1
-
-
- org.apache.maven.plugins
- maven-deploy-plugin
- 3.1.1
-
-
+
+
+
+ false
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-install-plugin
+ 3.1.1
+
+
+ org.apache.maven.plugins
+ maven-deploy-plugin
+ 3.1.1
+
+
+ org.codehaus.mojo
+ templating-maven-plugin
+ 1.0.0
+
+
+ filter-src
+
+ filter-sources
+
+
+
+
+
+
-
-
- oss-repo
- https://oss.sonatype.org/content/groups/public
-
codemc-repo
@@ -253,28 +271,12 @@
compile
-
-
- net.md-5
- bungeecord-api
- 1.19-R0.1-SNAPSHOT
- jar
- provided
-
+
- net.md-5
- bungeecord-api
- 1.19-R0.1-SNAPSHOT
- javadoc
+ com.google.guava
+ guava
+ 25.1-jre
provided
-
-
-
- org.bstats
- bstats-bungeecord
- 3.0.2
- compile
-
diff --git a/src/main/java/fr/xephi/authmebungee/AuthMeBungee.java b/src/main/java/fr/xephi/authmebungee/AuthMeBungee.java
deleted file mode 100644
index 9b7ed47..0000000
--- a/src/main/java/fr/xephi/authmebungee/AuthMeBungee.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package fr.xephi.authmebungee;
-
-import ch.jalu.configme.SettingsManager;
-import ch.jalu.injector.Injector;
-import ch.jalu.injector.InjectorBuilder;
-import fr.xephi.authmebungee.annotations.DataFolder;
-import fr.xephi.authmebungee.commands.BungeeReloadCommand;
-import fr.xephi.authmebungee.config.BungeeConfigProperties;
-import fr.xephi.authmebungee.config.BungeeSettingsProvider;
-import fr.xephi.authmebungee.listeners.BungeeMessageListener;
-import fr.xephi.authmebungee.listeners.BungeePlayerListener;
-import fr.xephi.authmebungee.services.AuthPlayerManager;
-import net.md_5.bungee.api.ProxyServer;
-import net.md_5.bungee.api.connection.ProxiedPlayer;
-import net.md_5.bungee.api.plugin.Plugin;
-import net.md_5.bungee.api.plugin.PluginManager;
-import net.md_5.bungee.api.scheduler.TaskScheduler;
-import org.bstats.bungeecord.Metrics;
-
-import java.util.logging.Logger;
-
-public class AuthMeBungee extends Plugin {
-
- // Instances
- private Injector injector;
- private SettingsManager settings;
- private AuthPlayerManager authPlayerManager;
-
- public AuthMeBungee() {
- }
-
- @Override
- public void onEnable() {
- // Prepare the injector and register stuff
- setupInjector();
-
- // Get singletons from the injector
- settings = injector.getSingleton(SettingsManager.class);
- authPlayerManager = injector.getSingleton(AuthPlayerManager.class);
-
- // Print some config information
- getLogger().info("Current auth servers:");
- for (String authServer : settings.getProperty(BungeeConfigProperties.AUTH_SERVERS)) {
- getLogger().info("> " + authServer.toLowerCase());
- }
-
- // Add online players (plugin hotswap, just in case)
- for (ProxiedPlayer player : getProxy().getPlayers()) {
- authPlayerManager.addAuthPlayer(player);
- }
-
- // Register commands
- getProxy().getPluginManager().registerCommand(this, injector.getSingleton(BungeeReloadCommand.class));
-
- // Registering event listeners
- getProxy().getPluginManager().registerListener(this, injector.getSingleton(BungeeMessageListener.class));
- getProxy().getPluginManager().registerListener(this, injector.getSingleton(BungeePlayerListener.class));
-
- // Send metrics data
- new Metrics(this, 1880);
- }
-
- private void setupInjector() {
- // Setup injector
- injector = new InjectorBuilder().addDefaultHandlers("").create();
- injector.register(Logger.class, getLogger());
- injector.register(AuthMeBungee.class, this);
- injector.register(ProxyServer.class, getProxy());
- injector.register(PluginManager.class, getProxy().getPluginManager());
- injector.register(TaskScheduler.class, getProxy().getScheduler());
- injector.provide(DataFolder.class, getDataFolder());
- injector.registerProvider(SettingsManager.class, BungeeSettingsProvider.class);
- }
-
-}
diff --git a/src/main/java/fr/xephi/authmebungee/commands/BungeeReloadCommand.java b/src/main/java/fr/xephi/authmebungee/commands/BungeeReloadCommand.java
deleted file mode 100644
index bfd42a7..0000000
--- a/src/main/java/fr/xephi/authmebungee/commands/BungeeReloadCommand.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package fr.xephi.authmebungee.commands;
-
-import ch.jalu.configme.SettingsManager;
-import ch.jalu.injector.factory.SingletonStore;
-import fr.xephi.authmebungee.config.SettingsDependent;
-import net.md_5.bungee.api.ChatColor;
-import net.md_5.bungee.api.CommandSender;
-import net.md_5.bungee.api.chat.ComponentBuilder;
-import net.md_5.bungee.api.plugin.Command;
-
-import javax.inject.Inject;
-
-public class BungeeReloadCommand extends Command {
-
- private SettingsManager settings;
- private SingletonStore settingsDependentStore;
-
- @Inject
- public BungeeReloadCommand(SettingsManager settings, SingletonStore settingsDependentStore) {
- super("abreloadproxy", "authmebungee.reload");
- this.settings = settings;
- this.settingsDependentStore = settingsDependentStore;
- }
-
- @Override
- public void execute(CommandSender commandSender, String[] strings) {
- settings.reload();
- settingsDependentStore.retrieveAllOfType().forEach(settingsDependent -> settingsDependent.reload(settings));
- commandSender.sendMessage(
- new ComponentBuilder("AuthMeBungee configuration reloaded!").color(ChatColor.GREEN).create()
- );
- }
-}
diff --git a/src/main/java/fr/xephi/authmebungee/config/BungeeSettingsProvider.java b/src/main/java/fr/xephi/authmebungee/config/BungeeSettingsProvider.java
deleted file mode 100644
index 03d5931..0000000
--- a/src/main/java/fr/xephi/authmebungee/config/BungeeSettingsProvider.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package fr.xephi.authmebungee.config;
-
-import fr.xephi.authmebungee.annotations.DataFolder;
-
-import javax.inject.Inject;
-import java.io.File;
-
-public class BungeeSettingsProvider extends SettingsProvider {
-
- @Inject
- public BungeeSettingsProvider(@DataFolder File dataFolder) {
- super(dataFolder, BungeeConfigProperties.class);
- }
-
-}
diff --git a/src/main/java/fr/xephi/authmebungee/data/AuthPlayer.java b/src/main/java/fr/xephi/authmebungee/data/AuthPlayer.java
deleted file mode 100644
index 1eb6680..0000000
--- a/src/main/java/fr/xephi/authmebungee/data/AuthPlayer.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package fr.xephi.authmebungee.data;
-
-import net.md_5.bungee.api.ProxyServer;
-import net.md_5.bungee.api.connection.ProxiedPlayer;
-
-public class AuthPlayer {
-
- private String name;
- private boolean isLogged;
-
- public AuthPlayer(String name, boolean isLogged) {
- this.name = name.toLowerCase();
- this.isLogged = isLogged;
- }
-
- public AuthPlayer(String name) {
- this(name, false);
- }
-
- public String getName() {
- return name;
- }
-
- public boolean isLogged() {
- return isLogged;
- }
-
- public void setLogged(boolean isLogged) {
- this.isLogged = isLogged;
- }
-
- public ProxiedPlayer getPlayer() {
- for (ProxiedPlayer current : ProxyServer.getInstance().getPlayers()) {
- if (current.getName().equalsIgnoreCase(name)) {
- return current;
- }
- }
- return null;
- }
-
- public boolean isOnline() {
- return getPlayer() != null;
- }
-
-}
diff --git a/src/main/java/fr/xephi/authmebungee/listeners/BungeeMessageListener.java b/src/main/java/fr/xephi/authmebungee/listeners/BungeeMessageListener.java
deleted file mode 100644
index a0322cf..0000000
--- a/src/main/java/fr/xephi/authmebungee/listeners/BungeeMessageListener.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package fr.xephi.authmebungee.listeners;
-
-import ch.jalu.configme.SettingsManager;
-import com.google.common.io.ByteArrayDataInput;
-import com.google.common.io.ByteStreams;
-import fr.xephi.authmebungee.config.BungeeConfigProperties;
-import fr.xephi.authmebungee.config.SettingsDependent;
-import fr.xephi.authmebungee.data.AuthPlayer;
-import fr.xephi.authmebungee.services.AuthPlayerManager;
-import net.md_5.bungee.api.ProxyServer;
-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.api.plugin.Listener;
-import net.md_5.bungee.event.EventHandler;
-
-import javax.inject.Inject;
-
-public class BungeeMessageListener implements Listener, SettingsDependent {
-
- // Services
- private final AuthPlayerManager authPlayerManager;
-
- // Settings
- private boolean isSendOnLogoutEnabled;
- private String sendOnLogoutTarget;
-
- @Inject
- public BungeeMessageListener(final SettingsManager settings, final AuthPlayerManager authPlayerManager) {
- this.authPlayerManager = authPlayerManager;
- reload(settings);
- }
-
- @Override
- public void reload(final SettingsManager settings) {
- isSendOnLogoutEnabled = settings.getProperty(BungeeConfigProperties.ENABLE_SEND_ON_LOGOUT);
- sendOnLogoutTarget = settings.getProperty(BungeeConfigProperties.SEND_ON_LOGOUT_TARGET);
- }
-
- @EventHandler
- public void onPluginMessage(final PluginMessageEvent event) {
- if (event.isCancelled()) {
- return;
- }
-
- // Check if the message is for a server (ignore client messages)
- if (!event.getTag().equals("BungeeCord")) {
- return;
- }
-
- // Check if a player is not trying to send us a fake message
- if (!(event.getSender() instanceof Server)) {
- return;
- }
-
- // Read the plugin message
- final ByteArrayDataInput in = ByteStreams.newDataInput(event.getData());
-
- // Accept only broadcasts
- if(!in.readUTF().equals("Forward")) {
- return;
- }
- in.readUTF(); // Skip ONLINE/ALL parameter
-
- // Let's check the subchannel
- if (!in.readUTF().equals("AuthMe.v2.Broadcast")) {
- return;
- }
-
- // Read data byte array
- final short dataLength = in.readShort();
- final byte[] dataBytes = new byte[dataLength];
- in.readFully(dataBytes);
- final ByteArrayDataInput dataIn = ByteStreams.newDataInput(dataBytes);
-
- // For now that's the only type of message the server is able to receive
- final String type = dataIn.readUTF();
- switch (type) {
- case "login":
- handleOnLogin(dataIn);
- break;
- case "logout":
- handleOnLogout(dataIn);
- break;
- }
- }
-
- private void handleOnLogin(final ByteArrayDataInput in) {
- final String name = in.readUTF();
- final AuthPlayer authPlayer = authPlayerManager.getAuthPlayer(name);
- if (authPlayer != null) {
- authPlayer.setLogged(true);
- }
- }
-
- private void handleOnLogout(final ByteArrayDataInput in) {
- final String name = in.readUTF();
- final AuthPlayer authPlayer = authPlayerManager.getAuthPlayer(name);
- if (authPlayer != null) {
- authPlayer.setLogged(false);
- if (isSendOnLogoutEnabled) {
- final ProxiedPlayer player = authPlayer.getPlayer();
- if (player != null) {
- player.connect(ProxyServer.getInstance().getServerInfo(sendOnLogoutTarget));
- }
- }
- }
- }
-
-}
diff --git a/src/main/java/fr/xephi/authmebungee/listeners/BungeePlayerListener.java b/src/main/java/fr/xephi/authmebungee/listeners/BungeePlayerListener.java
deleted file mode 100644
index b2aae2e..0000000
--- a/src/main/java/fr/xephi/authmebungee/listeners/BungeePlayerListener.java
+++ /dev/null
@@ -1,189 +0,0 @@
-package fr.xephi.authmebungee.listeners;
-
-import ch.jalu.configme.SettingsManager;
-import com.google.common.io.ByteArrayDataOutput;
-import com.google.common.io.ByteStreams;
-import fr.xephi.authmebungee.config.BungeeConfigProperties;
-import fr.xephi.authmebungee.config.SettingsDependent;
-import fr.xephi.authmebungee.data.AuthPlayer;
-import fr.xephi.authmebungee.services.AuthPlayerManager;
-import net.md_5.bungee.api.ChatColor;
-import net.md_5.bungee.api.chat.TextComponent;
-import net.md_5.bungee.api.config.ServerInfo;
-import net.md_5.bungee.api.connection.ProxiedPlayer;
-import net.md_5.bungee.api.event.*;
-import net.md_5.bungee.api.plugin.Listener;
-import net.md_5.bungee.event.EventHandler;
-import net.md_5.bungee.event.EventPriority;
-
-import javax.inject.Inject;
-import java.util.ArrayList;
-import java.util.List;
-
-public class BungeePlayerListener implements Listener, SettingsDependent {
-
- // Services
- private final AuthPlayerManager authPlayerManager;
-
- // Settings
- private boolean isAutoLoginEnabled;
- private boolean isServerSwitchRequiresAuth;
- private String requiresAuthKickMessage;
- private List authServers;
- private boolean allServersAreAuthServers;
- private boolean isCommandsRequireAuth;
- private List commandWhitelist;
- private boolean chatRequiresAuth;
-
- @Inject
- public BungeePlayerListener(final SettingsManager settings, final AuthPlayerManager authPlayerManager) {
- this.authPlayerManager = authPlayerManager;
- reload(settings);
- }
-
- @Override
- public void reload(final SettingsManager settings) {
- isAutoLoginEnabled = settings.getProperty(BungeeConfigProperties.AUTOLOGIN);
- isServerSwitchRequiresAuth = settings.getProperty(BungeeConfigProperties.SERVER_SWITCH_REQUIRES_AUTH);
- requiresAuthKickMessage = settings.getProperty(BungeeConfigProperties.SERVER_SWITCH_KICK_MESSAGE);
- authServers = new ArrayList<>();
- for (final String server : settings.getProperty(BungeeConfigProperties.AUTH_SERVERS)) {
- authServers.add(server.toLowerCase());
- }
- allServersAreAuthServers = settings.getProperty(BungeeConfigProperties.ALL_SERVERS_ARE_AUTH_SERVERS);
- isCommandsRequireAuth = settings.getProperty(BungeeConfigProperties.COMMANDS_REQUIRE_AUTH);
- commandWhitelist = new ArrayList<>();
- for (final String command : settings.getProperty(BungeeConfigProperties.COMMANDS_WHITELIST)) {
- commandWhitelist.add(command.toLowerCase());
- }
- chatRequiresAuth = settings.getProperty(BungeeConfigProperties.CHAT_REQUIRES_AUTH);
- }
-
- @EventHandler
- public void onPlayerJoin(final PostLoginEvent event) {
- // Register player in our list
- authPlayerManager.addAuthPlayer(event.getPlayer());
- }
-
- @EventHandler
- public void onPlayerDisconnect(final PlayerDisconnectEvent event) {
- // Remove player from out list
- authPlayerManager.removeAuthPlayer(event.getPlayer());
- }
-
- @EventHandler(priority = EventPriority.LOWEST)
- public void onCommand(final ChatEvent event) {
- if (event.isCancelled() || !event.isCommand() || !isCommandsRequireAuth) {
- return;
- }
-
- // Check if it's a player
- if (!(event.getSender() instanceof ProxiedPlayer)) {
- return;
- }
- final ProxiedPlayer player = (ProxiedPlayer) event.getSender();
-
- // Filter only unauthenticated players
- final AuthPlayer authPlayer = authPlayerManager.getAuthPlayer(player);
- if (authPlayer != null && authPlayer.isLogged()) {
- return;
- }
- // Only in auth servers
- if (!isAuthServer(player.getServer().getInfo())) {
- return;
- }
- // Check if command is whitelisted command
- if (commandWhitelist.contains(event.getMessage().split(" ")[0].toLowerCase())) {
- return;
- }
- event.setCancelled(true);
- }
-
- // Priority is set to lowest to keep compatibility with some chat plugins
- @EventHandler(priority = EventPriority.LOWEST)
- public void onPlayerChat(final ChatEvent event) {
- if (event.isCancelled() || event.isCommand()) {
- return;
- }
-
- // Check if it's a player
- if (!(event.getSender() instanceof ProxiedPlayer)) {
- return;
- }
- final ProxiedPlayer player = (ProxiedPlayer) event.getSender();
-
- // Filter only unauthenticated players
- final AuthPlayer authPlayer = authPlayerManager.getAuthPlayer(player);
- if (authPlayer != null && authPlayer.isLogged()) {
- return;
- }
- // Only in auth servers
- if (!isAuthServer(player.getServer().getInfo())) {
- return;
- }
-
- if (!chatRequiresAuth) {
- return;
- }
- event.setCancelled(true);
- }
-
- private boolean isAuthServer(ServerInfo serverInfo) {
- return allServersAreAuthServers || authServers.contains(serverInfo.getName().toLowerCase());
- }
-
- @EventHandler(priority = EventPriority.LOWEST)
- public void onPlayerConnectedToServer(final ServerSwitchEvent event) {
- final ProxiedPlayer player = event.getPlayer();
- final ServerInfo server = player.getServer().getInfo();
- final AuthPlayer authPlayer = authPlayerManager.getAuthPlayer(player);
- final boolean isAuthenticated = authPlayer != null && authPlayer.isLogged();
-
- if (isAuthenticated && isAuthServer(server)) {
- // If AutoLogin enabled, notify the server
- if (isAutoLoginEnabled) {
- final ByteArrayDataOutput out = ByteStreams.newDataOutput();
- out.writeUTF("AuthMe.v2");
- out.writeUTF("perform.login");
- out.writeUTF(event.getPlayer().getName());
- server.sendData("BungeeCord", out.toByteArray(), false);
- }
- }
- }
-
- @EventHandler(priority = EventPriority.HIGHEST)
- public void onPlayerConnectingToServer(final ServerConnectEvent event) {
- if (event.isCancelled()) {
- return;
- }
-
- final ProxiedPlayer player = event.getPlayer();
- final AuthPlayer authPlayer = authPlayerManager.getAuthPlayer(player);
- final boolean isAuthenticated = authPlayer != null && authPlayer.isLogged();
-
- // Skip logged users
- if (isAuthenticated) {
- return;
- }
-
- // Only check non auth servers
- if (isAuthServer(event.getTarget())) {
- return;
- }
-
- // If the player is not logged in and serverSwitchRequiresAuth is enabled, cancel the connection
- if (isServerSwitchRequiresAuth) {
- event.setCancelled(true);
-
- final TextComponent reasonMessage = new TextComponent(requiresAuthKickMessage);
- reasonMessage.setColor(ChatColor.RED);
-
- // Handle race condition on player join on a misconfigured network
- if (player.getServer() == null) {
- player.disconnect(reasonMessage);
- } else {
- player.sendMessage(reasonMessage);
- }
- }
- }
-}
diff --git a/src/main/java/fr/xephi/authmebungee/services/AuthPlayerManager.java b/src/main/java/fr/xephi/authmebungee/services/AuthPlayerManager.java
deleted file mode 100644
index 9988a33..0000000
--- a/src/main/java/fr/xephi/authmebungee/services/AuthPlayerManager.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package fr.xephi.authmebungee.services;
-
-import fr.xephi.authmebungee.data.AuthPlayer;
-import net.md_5.bungee.api.connection.ProxiedPlayer;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/*
- * Players manager - store all references to AuthPlayer objects through an HashMap
- */
-public class AuthPlayerManager {
-
- private Map players;
-
- public AuthPlayerManager() {
- players = new HashMap<>();
- }
-
- public void addAuthPlayer(AuthPlayer player) {
- players.put(player.getName(), player);
- }
-
- public void addAuthPlayer(ProxiedPlayer player) {
- addAuthPlayer(new AuthPlayer(player.getName().toLowerCase()));
- }
-
- public void removeAuthPlayer(String name) {
- players.remove(name.toLowerCase());
- }
-
- public void removeAuthPlayer(ProxiedPlayer player) {
- removeAuthPlayer(player.getName());
- }
-
- public AuthPlayer getAuthPlayer(String name) {
- return players.get(name.toLowerCase());
- }
-
- public AuthPlayer getAuthPlayer(ProxiedPlayer player) {
- return getAuthPlayer(player.getName());
- }
-}
diff --git a/src/main/java/fr/xephi/authmebungee/utils/FileUtils.java b/src/main/java/fr/xephi/authmebungee/utils/FileUtils.java
deleted file mode 100644
index 51f31c3..0000000
--- a/src/main/java/fr/xephi/authmebungee/utils/FileUtils.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package fr.xephi.authmebungee.utils;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * File utilities.
- */
-public final class FileUtils {
-
- // Utility class
- private FileUtils() {
- }
-
- /**
- * Creates the given file or throws an exception.
- *
- * @param file the file to create
- */
- public static void create(File file) {
- try {
- file.getParentFile().mkdirs();
- boolean result = file.createNewFile();
- if (!result) {
- throw new IllegalStateException("Could not create file '" + file + "'");
- }
- } catch (IOException e) {
- throw new IllegalStateException("Error while creating file '" + file + "'", e);
- }
- }
-}
diff --git a/src/main/resources/bungee.yml b/src/main/resources/bungee.yml
deleted file mode 100644
index 3ad3771..0000000
--- a/src/main/resources/bungee.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-name: ${project.name}
-main: fr.xephi.authmebungee.AuthMeBungee
-version: ${project.version}
-author: AuthMeTeam
diff --git a/universal/pom.xml b/universal/pom.xml
new file mode 100644
index 0000000..ecd4a15
--- /dev/null
+++ b/universal/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+
+ fr.xephi
+ authmeproxy-parent
+ 2.3.0-SNAPSHOT
+
+
+ authmeproxy-universal
+ AuthMeProxy-Universal
+
+
+ ${project.name}-${project.version}-noshade
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+
+
+
+
+ fr.xephi
+ authmeproxy-bungee
+ 2.3.0-SNAPSHOT
+ compile
+
+
+ fr.xephi
+ authmeproxy-velocity
+ 2.3.0-SNAPSHOT
+ compile
+
+
+
+
diff --git a/velocity/pom.xml b/velocity/pom.xml
new file mode 100644
index 0000000..275eceb
--- /dev/null
+++ b/velocity/pom.xml
@@ -0,0 +1,68 @@
+
+
+ 4.0.0
+
+
+ fr.xephi
+ authmeproxy-parent
+ 2.3.0-SNAPSHOT
+
+
+ authmeproxy-velocity
+ AuthMeProxy-Velocity
+
+
+ ${project.name}-${project.version}-noshade
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+
+ org.codehaus.mojo
+ templating-maven-plugin
+
+
+
+
+
+
+ papermc-repo
+ https://repo.papermc.io/repository/maven-public/
+
+
+
+
+
+ fr.xephi
+ authmeproxy-common
+ 2.3.0-SNAPSHOT
+
+
+
+
+ com.velocitypowered
+ velocity-api
+ 3.2.0-SNAPSHOT
+ provided
+
+
+
+
+ org.bstats
+ bstats-velocity
+ 3.0.2
+ compile
+
+
+
diff --git a/velocity/src/main/java-templates/fr/xephi/authmeproxy/velocity/PluginDescriptor.java b/velocity/src/main/java-templates/fr/xephi/authmeproxy/velocity/PluginDescriptor.java
new file mode 100644
index 0000000..53259c7
--- /dev/null
+++ b/velocity/src/main/java-templates/fr/xephi/authmeproxy/velocity/PluginDescriptor.java
@@ -0,0 +1,10 @@
+package fr.xephi.authmeproxy.velocity;
+
+public final class PluginDescriptor {
+ private PluginDescriptor() {
+ }
+
+ public static final String ID = "authmeproxy";
+ public static final String NAME = "${project.parent.name}";
+ public static final String VERSION = "${project.version}";
+}
diff --git a/velocity/src/main/java/fr/xephi/authmeproxy/velocity/AuthMeProxyVelocity.java b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/AuthMeProxyVelocity.java
new file mode 100644
index 0000000..18e1ea1
--- /dev/null
+++ b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/AuthMeProxyVelocity.java
@@ -0,0 +1,88 @@
+package fr.xephi.authmeproxy.velocity;
+
+import com.velocitypowered.api.command.SimpleCommand;
+import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
+import com.velocitypowered.api.event.Subscribe;
+import com.velocitypowered.api.plugin.Plugin;
+import com.velocitypowered.api.plugin.annotation.DataDirectory;
+import com.velocitypowered.api.proxy.Player;
+import com.velocitypowered.api.proxy.ProxyServer;
+import fr.xephi.authmeproxy.common.AbstractAuthMeProxy;
+import fr.xephi.authmeproxy.common.commands.AbstractCommand;
+import fr.xephi.authmeproxy.common.commands.ReloadCommand;
+import fr.xephi.authmeproxy.common.platform.AbstractPlayer;
+import fr.xephi.authmeproxy.velocity.listeners.PlayerListener;
+import fr.xephi.authmeproxy.velocity.listeners.MessageListener;
+import fr.xephi.authmeproxy.velocity.platform.VelocityPlatform;
+import fr.xephi.authmeproxy.velocity.platform.VelocityPlayer;
+import org.bstats.velocity.Metrics;
+
+import javax.inject.Inject;
+import java.nio.file.Path;
+
+@Plugin(
+ id = PluginDescriptor.ID,
+ name = PluginDescriptor.NAME,
+ version = PluginDescriptor.VERSION
+)
+public class AuthMeProxyVelocity extends AbstractAuthMeProxy {
+
+ private final ProxyServer proxyServer;
+ private final Metrics.Factory metricsFactory;
+
+ @Inject
+ public AuthMeProxyVelocity(
+ com.google.inject.Injector proxyInjector,
+ ProxyServer proxyServer,
+ Metrics.Factory metricsFactory,
+ @DataDirectory Path dataDirectory
+ ) {
+ super(
+ proxyInjector.getInstance(VelocityPlatform.class),
+ proxyInjector.getInstance(AuthMeVelocityLogger.class),
+ dataDirectory.toFile()
+ );
+ this.proxyServer = proxyServer;
+ this.metricsFactory = metricsFactory;
+ }
+
+ @Subscribe
+ public void onProxyInitialization(ProxyInitializeEvent event) {
+ initialize();
+ }
+
+ @Override
+ protected void registerCommands() {
+ registerCommand(injector.getSingleton(ReloadCommand.class));
+ }
+
+ @Override
+ protected void registerListeners() {
+ proxyServer.getEventManager().register(this, injector.getSingleton(MessageListener.class));
+ proxyServer.getEventManager().register(this, injector.getSingleton(PlayerListener.class));
+ }
+
+ @Override
+ protected void registerMetrics() {
+ //metricsFactory.make(this, 1880); TODO: generate a new project id on bstats
+ }
+
+ private void registerCommand(AbstractCommand command) {
+ proxyServer.getCommandManager().register(command.getCommand(), new SimpleCommand() {
+ @Override
+ public void execute(Invocation invocation) {
+ Player player = null;
+ if (invocation.source() instanceof Player) {
+ player = (Player) invocation.source();
+ }
+ AbstractPlayer abstractPlayer = player == null ? null : VelocityPlayer.fromPlayer(player);
+ command.execute(abstractPlayer, invocation.arguments());
+ }
+
+ @Override
+ public boolean hasPermission(Invocation invocation) {
+ return invocation.source().hasPermission(command.getPermission());
+ }
+ });
+ }
+}
diff --git a/velocity/src/main/java/fr/xephi/authmeproxy/velocity/AuthMeVelocityLogger.java b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/AuthMeVelocityLogger.java
new file mode 100644
index 0000000..a9b0c2c
--- /dev/null
+++ b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/AuthMeVelocityLogger.java
@@ -0,0 +1,40 @@
+package fr.xephi.authmeproxy.velocity;
+
+import com.velocitypowered.api.proxy.ProxyServer;
+import fr.xephi.authmeproxy.common.AbstractAuthMeLogger;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+import org.slf4j.Logger;
+
+import javax.inject.Inject;
+
+public class AuthMeVelocityLogger extends AbstractAuthMeLogger {
+
+ private final org.slf4j.Logger logger;
+ private final ProxyServer proxyServer;
+
+ @Inject
+ public AuthMeVelocityLogger(Logger logger, ProxyServer proxyServer) {
+ this.logger = logger;
+ this.proxyServer = proxyServer;
+ }
+
+ @Override
+ public void send(String message) {
+ proxyServer.getConsoleCommandSource().sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(message));
+ }
+
+ @Override
+ public void info(String... messages) {
+ this.logger.info(String.join(" ", messages));
+ }
+
+ @Override
+ public void warn(String... messages) {
+ this.logger.warn(String.join(" ", messages));
+ }
+
+ @Override
+ public void error(String... messages) {
+ this.logger.error(String.join(" ", messages));
+ }
+}
diff --git a/velocity/src/main/java/fr/xephi/authmeproxy/velocity/listeners/MessageListener.java b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/listeners/MessageListener.java
new file mode 100644
index 0000000..3b73b27
--- /dev/null
+++ b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/listeners/MessageListener.java
@@ -0,0 +1,26 @@
+package fr.xephi.authmeproxy.velocity.listeners;
+
+import com.velocitypowered.api.event.Subscribe;
+import com.velocitypowered.api.event.connection.PluginMessageEvent;
+import com.velocitypowered.api.proxy.ServerConnection;
+import fr.xephi.authmeproxy.common.services.MessageHandleService;
+
+import javax.inject.Inject;
+
+public class MessageListener {
+
+ @Inject
+ private MessageHandleService messageHandleService;
+
+ @Subscribe
+ public void onPluginMessage(PluginMessageEvent event) {
+ if (!event.getResult().isAllowed()) {
+ // Ignore cancelled messages
+ return;
+ }
+
+ boolean fromPlayer = !(event.getSource() instanceof ServerConnection);
+ messageHandleService.handleMessage(fromPlayer, event.getIdentifier().getId(), event.getData());
+ }
+
+}
diff --git a/velocity/src/main/java/fr/xephi/authmeproxy/velocity/listeners/PlayerListener.java b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/listeners/PlayerListener.java
new file mode 100644
index 0000000..1cf5810
--- /dev/null
+++ b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/listeners/PlayerListener.java
@@ -0,0 +1,101 @@
+package fr.xephi.authmeproxy.velocity.listeners;
+
+import com.velocitypowered.api.event.PostOrder;
+import com.velocitypowered.api.event.Subscribe;
+import com.velocitypowered.api.event.command.CommandExecuteEvent;
+import com.velocitypowered.api.event.connection.DisconnectEvent;
+import com.velocitypowered.api.event.connection.PostLoginEvent;
+import com.velocitypowered.api.event.player.PlayerChatEvent;
+import com.velocitypowered.api.event.player.ServerConnectedEvent;
+import com.velocitypowered.api.event.player.ServerPreConnectEvent;
+import com.velocitypowered.api.proxy.Player;
+import com.velocitypowered.api.proxy.server.RegisteredServer;
+import fr.xephi.authmeproxy.common.services.AuthStateService;
+import fr.xephi.authmeproxy.velocity.platform.VelocityPlayer;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+
+import javax.inject.Inject;
+
+public class PlayerListener {
+
+ @Inject
+ private AuthStateService authStateService;
+
+ @Subscribe
+ public void onPlayerJoin(PostLoginEvent event) {
+ authStateService.trackUser(event.getPlayer().getUsername());
+ }
+
+ @Subscribe
+ public void onPlayerDisconnect(DisconnectEvent event) {
+ authStateService.untrackUser(event.getPlayer().getUsername());
+ }
+
+ @Subscribe(order = PostOrder.EARLY)
+ public void onCommand(CommandExecuteEvent event) {
+ if (!event.getResult().isAllowed()) {
+ return;
+ }
+ if (!(event.getCommandSource() instanceof Player)) {
+ return;
+ }
+ Player player = (Player) event.getCommandSource();
+ if (!authStateService.shouldAllowCommand(VelocityPlayer.fromPlayer(player), "/" + event.getCommand())) {
+ event.setResult(CommandExecuteEvent.CommandResult.denied());
+ }
+ }
+
+ @Subscribe(order = PostOrder.EARLY)
+ public void onDownstreamCommand(PlayerChatEvent event) {
+ if (!event.getResult().isAllowed() || !event.getMessage().startsWith("/")) {
+ return;
+ }
+ String command = event.getMessage().split(" ")[0].toLowerCase();
+ if (!authStateService.shouldAllowCommand(VelocityPlayer.fromPlayer(event.getPlayer()), command)) {
+ event.setResult(PlayerChatEvent.ChatResult.denied());
+ }
+ }
+
+ // Priority is set to lowest to keep compatibility with some chat plugins
+ @Subscribe(order = PostOrder.EARLY)
+ public void onPlayerChat(PlayerChatEvent event) {
+ if (!event.getResult().isAllowed() || event.getMessage().startsWith("/")) {
+ return;
+ }
+
+ if (!authStateService.shouldAllowChat(VelocityPlayer.fromPlayer(event.getPlayer()))) {
+ event.setResult(PlayerChatEvent.ChatResult.denied());
+ }
+ }
+
+ @Subscribe(order = PostOrder.LAST)
+ public void onPlayerConnectedToServer(ServerConnectedEvent event) {
+ Player player = event.getPlayer();
+ RegisteredServer server = event.getServer();
+ authStateService.handleServerConnected(VelocityPlayer.fromPlayer(player), server.getServerInfo().getName());
+ }
+
+ @Subscribe(order = PostOrder.EARLY)
+ public void onPlayerConnectingToServer(ServerPreConnectEvent event) {
+ if (!event.getResult().isAllowed()) {
+ return;
+ }
+
+ Player player = event.getPlayer();
+ String cancelReason = authStateService.shouldAllowServerSwitch(
+ VelocityPlayer.fromPlayer(player),
+ event.getOriginalServer().getServerInfo().getName()
+ ).orElse(null);
+ if (cancelReason == null) {
+ return;
+ }
+ event.setResult(ServerPreConnectEvent.ServerResult.denied());
+ Component parsedCancelReason = LegacyComponentSerializer.legacyAmpersand().deserialize(cancelReason);
+ if (event.getPreviousServer() == null) {
+ player.disconnect(parsedCancelReason);
+ } else {
+ player.sendMessage(parsedCancelReason);
+ }
+ }
+}
diff --git a/velocity/src/main/java/fr/xephi/authmeproxy/velocity/platform/VelocityPlatform.java b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/platform/VelocityPlatform.java
new file mode 100644
index 0000000..8719589
--- /dev/null
+++ b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/platform/VelocityPlatform.java
@@ -0,0 +1,32 @@
+package fr.xephi.authmeproxy.velocity.platform;
+
+import com.velocitypowered.api.proxy.ProxyServer;
+import com.velocitypowered.api.proxy.server.RegisteredServer;
+import fr.xephi.authmeproxy.common.platform.AbstractPlatform;
+
+import javax.inject.Inject;
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+public class VelocityPlatform extends AbstractPlatform {
+
+ @Inject
+ private ProxyServer proxyServer;
+
+ @Override
+ public Collection getAllPlayers() {
+ return proxyServer.getAllPlayers().stream()
+ .map(VelocityPlayer::fromPlayer)
+ .collect(Collectors.toUnmodifiableList());
+ }
+
+ @Override
+ public boolean connect(VelocityPlayer player, String serverName) {
+ RegisteredServer registeredServer = proxyServer.getServer(serverName).orElse(null);
+ if (registeredServer == null) {
+ return false;
+ }
+ player.getHandle().createConnectionRequest(registeredServer).connect();
+ return true;
+ }
+}
diff --git a/velocity/src/main/java/fr/xephi/authmeproxy/velocity/platform/VelocityPlayer.java b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/platform/VelocityPlayer.java
new file mode 100644
index 0000000..6753b53
--- /dev/null
+++ b/velocity/src/main/java/fr/xephi/authmeproxy/velocity/platform/VelocityPlayer.java
@@ -0,0 +1,44 @@
+package fr.xephi.authmeproxy.velocity.platform;
+
+import com.velocitypowered.api.proxy.Player;
+import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
+import fr.xephi.authmeproxy.common.platform.AbstractPlayer;
+import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+
+import java.util.Optional;
+
+public class VelocityPlayer extends AbstractPlayer {
+ public VelocityPlayer(Player player) {
+ super(player);
+ }
+
+ @Override
+ public String getUsername() {
+ return getHandle().getUsername();
+ }
+
+ @Override
+ public Optional getCurrentServer() {
+ return getHandle().getCurrentServer().map(server -> server.getServerInfo().getName());
+ }
+
+ @Override
+ public void sendBungeeMessage(byte[] data) {
+ getHandle().getCurrentServer()
+ .ifPresent(connection -> connection.sendPluginMessage(MinecraftChannelIdentifier.create("bungeecord", "main"), data));
+ }
+
+ @Override
+ public void sendMessage(String message) {
+ getHandle().sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(message));
+ }
+
+ @Override
+ public Player getHandle() {
+ return (Player) super.getHandle();
+ }
+
+ public static VelocityPlayer fromPlayer(Player player) {
+ return new VelocityPlayer(player);
+ }
+}