From 85b5811d3f71928f6f243e039a8bf112c0142b12 Mon Sep 17 00:00:00 2001 From: mdxd44 Date: Fri, 20 May 2022 02:46:31 +0900 Subject: Massive code refactor, update dependencies, etc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Лень фулл писать. Closes #26 --- .../java/net/elytrium/limboauth/LimboAuth.java | 416 ++++++++------- src/main/java/net/elytrium/limboauth/Settings.java | 64 +-- .../limboauth/command/ChangePasswordCommand.java | 81 ++- .../limboauth/command/DestroySessionCommand.java | 20 +- .../command/ForceChangePasswordCommand.java | 24 +- .../limboauth/command/ForceUnregisterCommand.java | 22 +- .../limboauth/command/LimboAuthCommand.java | 123 +++-- .../elytrium/limboauth/command/PremiumCommand.java | 84 +-- .../elytrium/limboauth/command/TotpCommand.java | 125 ++--- .../limboauth/command/UnregisterCommand.java | 76 +-- .../java/net/elytrium/limboauth/config/Config.java | 393 -------------- .../limboauth/event/AuthPluginReloadEvent.java | 1 + .../limboauth/event/AuthUnregisterEvent.java | 1 - .../limboauth/event/PostAuthorizationEvent.java | 7 +- .../net/elytrium/limboauth/event/PostEvent.java | 14 +- .../limboauth/event/PostRegisterEvent.java | 7 +- .../limboauth/event/PreAuthorizationEvent.java | 9 +- .../net/elytrium/limboauth/event/PreEvent.java | 9 +- .../elytrium/limboauth/event/PreRegisterEvent.java | 7 +- .../net/elytrium/limboauth/event/TaskEvent.java | 58 ++- .../limboauth/handler/AuthSessionHandler.java | 564 +++++++++++---------- .../elytrium/limboauth/listener/AuthListener.java | 8 +- .../limboauth/migration/MigrationHash.java | 65 ++- .../elytrium/limboauth/model/RegisteredPlayer.java | 3 +- .../net/elytrium/limboauth/utils/SuggestUtils.java | 42 -- .../elytrium/limboauth/utils/UpdatesChecker.java | 75 --- 26 files changed, 937 insertions(+), 1361 deletions(-) delete mode 100644 src/main/java/net/elytrium/limboauth/config/Config.java delete mode 100644 src/main/java/net/elytrium/limboauth/utils/SuggestUtils.java delete mode 100644 src/main/java/net/elytrium/limboauth/utils/UpdatesChecker.java (limited to 'src/main/java/net/elytrium') diff --git a/src/main/java/net/elytrium/limboauth/LimboAuth.java b/src/main/java/net/elytrium/limboauth/LimboAuth.java index afce924..55fee88 100644 --- a/src/main/java/net/elytrium/limboauth/LimboAuth.java +++ b/src/main/java/net/elytrium/limboauth/LimboAuth.java @@ -20,15 +20,15 @@ package net.elytrium.limboauth; import com.google.inject.Inject; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; +import com.j256.ormlite.dao.GenericRawResults; +import com.j256.ormlite.db.DatabaseType; import com.j256.ormlite.field.FieldType; import com.j256.ormlite.jdbc.JdbcPooledConnectionSource; import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.table.TableInfo; import com.j256.ormlite.table.TableUtils; -import com.mojang.brigadier.tree.CommandNode; import com.velocitypowered.api.command.CommandManager; -import com.velocitypowered.api.command.CommandMeta; -import com.velocitypowered.api.command.CommandSource; -import com.velocitypowered.api.command.SimpleCommand; +import com.velocitypowered.api.event.EventManager; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.plugin.Dependency; @@ -37,6 +37,7 @@ import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.plugin.annotation.DataDirectory; import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.ProxyServer; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.File; import java.io.IOException; import java.net.InetAddress; @@ -50,8 +51,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -66,10 +65,15 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; +import net.elytrium.java.commons.mc.serialization.Serializer; +import net.elytrium.java.commons.mc.serialization.Serializers; +import net.elytrium.java.commons.updates.UpdatesChecker; import net.elytrium.limboapi.api.Limbo; import net.elytrium.limboapi.api.LimboFactory; import net.elytrium.limboapi.api.chunk.Dimension; import net.elytrium.limboapi.api.chunk.VirtualWorld; +import net.elytrium.limboapi.api.command.LimboCommandMeta; import net.elytrium.limboapi.api.file.SchematicFile; import net.elytrium.limboapi.api.file.StructureFile; import net.elytrium.limboapi.api.file.WorldFile; @@ -90,12 +94,13 @@ import net.elytrium.limboauth.floodgate.FloodgateApiHolder; import net.elytrium.limboauth.handler.AuthSessionHandler; import net.elytrium.limboauth.listener.AuthListener; import net.elytrium.limboauth.model.RegisteredPlayer; -import net.elytrium.limboauth.utils.UpdatesChecker; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.ComponentSerializer; import net.kyori.adventure.title.Title; import org.bstats.charts.SimplePie; import org.bstats.charts.SingleLineChart; import org.bstats.velocity.Metrics; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; @@ -115,32 +120,52 @@ import org.slf4j.Logger; ) public class LimboAuth { + @MonotonicNonNull + private static Logger LOGGER; + @MonotonicNonNull + private static Serializer SERIALIZER; + private final Map cachedAuthChecks = new ConcurrentHashMap<>(); private final Map premiumCache = new ConcurrentHashMap<>(); private final Map postLoginTasks = new ConcurrentHashMap<>(); private final Set unsafePasswords = new HashSet<>(); private final HttpClient client = HttpClient.newHttpClient(); + private final ProxyServer server; - private final Logger logger; private final Metrics.Factory metricsFactory; private final Path dataDirectory; + private final File dataDirectoryFile; + private final File configFile; private final LimboFactory factory; private final FloodgateApiHolder floodgateApi; - private JdbcPooledConnectionSource connectionSource; + @Nullable + private Component loginPremium; + @Nullable + private Title loginPremiumTitle; + @Nullable + private Component loginFloodgate; + @Nullable + private Title loginFloodgateTitle; + private Component nicknameInvalidKick; + private JdbcPooledConnectionSource connectionSource; private Dao playerDao; private Pattern nicknameValidationPattern; private Limbo authServer; @Inject - public LimboAuth(ProxyServer server, Logger logger, Metrics.Factory metricsFactory, @DataDirectory Path dataDirectory) { + public LimboAuth(Logger logger, ProxyServer server, Metrics.Factory metricsFactory, @DataDirectory Path dataDirectory) { + setLogger(logger); + this.server = server; - this.logger = logger; this.metricsFactory = metricsFactory; this.dataDirectory = dataDirectory; + this.dataDirectoryFile = dataDirectory.toFile(); + this.configFile = new File(this.dataDirectoryFile, "config.yml"); + this.factory = (LimboFactory) this.server.getPluginManager().getPlugin("limboapi").flatMap(PluginContainer::getInstance).orElseThrow(); if (this.server.getPluginManager().getPlugin("floodgate").isPresent()) { @@ -152,11 +177,11 @@ public class LimboAuth { @Subscribe public void onProxyInitialization(ProxyInitializeEvent event) throws Exception { - Metrics metrics = this.metricsFactory.make(this, 13700); System.setProperty("com.j256.simplelogging.level", "ERROR"); this.reload(); + Metrics metrics = this.metricsFactory.make(this, 13700); metrics.addCustomChart(new SimplePie("floodgate_auth", () -> String.valueOf(Settings.IMP.MAIN.FLOODGATE_NEED_AUTH))); metrics.addCustomChart(new SimplePie("premium_auth", () -> String.valueOf(Settings.IMP.MAIN.ONLINE_MODE_NEED_AUTH))); metrics.addCustomChart(new SimplePie("db_type", () -> Settings.IMP.DATABASE.STORAGE_TYPE)); @@ -166,54 +191,92 @@ public class LimboAuth { metrics.addCustomChart(new SimplePie("save_uuid", () -> String.valueOf(Settings.IMP.MAIN.SAVE_UUID))); metrics.addCustomChart(new SingleLineChart("registered_players", () -> Math.toIntExact(this.playerDao.countOf()))); - UpdatesChecker.checkForUpdates(this.getLogger()); + if (!UpdatesChecker.checkVersionByURL("https://raw.githubusercontent.com/Elytrium/LimboAuth/master/VERSION", Settings.IMP.VERSION)) { + LOGGER.error("****************************************"); + LOGGER.warn("The new LimboAuth update was found, please update."); + LOGGER.error("https://github.com/Elytrium/LimboAuth/releases/"); + LOGGER.error("****************************************"); + } } + @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "LEGACY_AMPERSAND can't be null in velocity.") public void reload() throws Exception { - Settings.IMP.reload(new File(this.dataDirectory.toFile().getAbsoluteFile(), "config.yml")); + Settings.IMP.reload(this.configFile, Settings.IMP.PREFIX); if (this.floodgateApi == null && !Settings.IMP.MAIN.FLOODGATE_NEED_AUTH) { - throw new IllegalStateException("If you don't need to auth floodgate players please install floodgate plugin."); + throw new IllegalStateException("If you want floodgate players to automatically pass auth (floodgate-need-auth: false)," + + " please install floodgate plugin."); + } + + ComponentSerializer serializer = Serializers.valueOf(Settings.IMP.SERIALIZER.toUpperCase(Locale.ROOT)).getSerializer(); + if (serializer == null) { + LOGGER.warn("The specified serializer could not be founded, using default. (LEGACY_AMPERSAND)"); + setSerializer(new Serializer(Objects.requireNonNull(Serializers.LEGACY_AMPERSAND.getSerializer()))); + } else { + setSerializer(new Serializer(serializer)); } + TaskEvent.reload(); + AuthSessionHandler.reload(); + + this.loginPremium = Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM.isEmpty() ? null : SERIALIZER.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM); + if (Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM_TITLE.isEmpty() && Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM_SUBTITLE.isEmpty()) { + this.loginPremiumTitle = null; + } else { + this.loginPremiumTitle = Title.title( + SERIALIZER.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM_TITLE), + SERIALIZER.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM_SUBTITLE), + Settings.IMP.MAIN.PREMIUM_TITLE_SETTINGS.toTimes() + ); + } + + this.loginFloodgate = Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE.isEmpty() ? null : SERIALIZER.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE); + if (Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE_TITLE.isEmpty() && Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE_SUBTITLE.isEmpty()) { + this.loginFloodgateTitle = null; + } else { + this.loginFloodgateTitle = Title.title( + SERIALIZER.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE_TITLE), + SERIALIZER.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE_SUBTITLE), + Settings.IMP.MAIN.PREMIUM_TITLE_SETTINGS.toTimes() + ); + } + + this.nicknameInvalidKick = SERIALIZER.deserialize(Settings.IMP.MAIN.STRINGS.NICKNAME_INVALID_KICK); + if (Settings.IMP.MAIN.CHECK_PASSWORD_STRENGTH) { this.unsafePasswords.clear(); - Path unsafePasswordsPath = Paths.get(this.dataDirectory.toFile().getAbsolutePath(), Settings.IMP.MAIN.UNSAFE_PASSWORDS_FILE); + Path unsafePasswordsPath = Paths.get(this.dataDirectoryFile.getAbsolutePath(), Settings.IMP.MAIN.UNSAFE_PASSWORDS_FILE); if (!unsafePasswordsPath.toFile().exists()) { Files.copy(Objects.requireNonNull(this.getClass().getResourceAsStream("/unsafe_passwords.txt")), unsafePasswordsPath); } - this.unsafePasswords.addAll(Files.lines(unsafePasswordsPath).collect(Collectors.toSet())); + try (Stream unsafePasswordsStream = Files.lines(unsafePasswordsPath)) { + this.unsafePasswords.addAll(unsafePasswordsStream.collect(Collectors.toList())); + } } this.cachedAuthChecks.clear(); Settings.DATABASE dbConfig = Settings.IMP.DATABASE; - // requireNonNull prevents the shade plugin from excluding the drivers in minimized jar. switch (dbConfig.STORAGE_TYPE.toLowerCase(Locale.ROOT)) { case "h2": { - Objects.requireNonNull(org.h2.Driver.class); - Objects.requireNonNull(org.h2.engine.Engine.class); - this.connectionSource = new JdbcPooledConnectionSource("jdbc:h2:" + this.dataDirectory.toFile().getAbsoluteFile() + "/limboauth"); + this.connectionSource = new JdbcPooledConnectionSource("jdbc:h2:" + this.dataDirectoryFile.getAbsoluteFile() + "/limboauth"); break; } case "mysql": { - Objects.requireNonNull(com.mysql.cj.jdbc.Driver.class); - Objects.requireNonNull(com.mysql.cj.conf.url.SingleConnectionUrl.class); this.connectionSource = new JdbcPooledConnectionSource( "jdbc:mysql://" + dbConfig.HOSTNAME + "/" + dbConfig.DATABASE + dbConfig.CONNECTION_PARAMETERS, dbConfig.USER, dbConfig.PASSWORD ); break; } case "postgresql": { - Objects.requireNonNull(org.postgresql.Driver.class); this.connectionSource = new JdbcPooledConnectionSource( "jdbc:postgresql://" + dbConfig.HOSTNAME + "/" + dbConfig.DATABASE + dbConfig.CONNECTION_PARAMETERS, dbConfig.USER, dbConfig.PASSWORD ); break; } default: { - this.getLogger().error("WRONG DATABASE TYPE."); + LOGGER.error("Wrong database type."); this.server.shutdown(); return; } @@ -271,7 +334,7 @@ public class LimboAuth { break; } default: { - this.getLogger().error("Incorrect world file type."); + LOGGER.error("Incorrect world file type."); this.server.shutdown(); return; } @@ -287,74 +350,84 @@ public class LimboAuth { this.authServer = this.factory .createLimbo(authWorld) .setName("LimboAuth") - .registerCommand(new AuthCommandMeta(this, this.filterCommands(Settings.IMP.MAIN.REGISTER_COMMAND)), new AuthCommand()) - .registerCommand(new AuthCommandMeta(this, this.filterCommands(Settings.IMP.MAIN.LOGIN_COMMAND)), new AuthCommand()) - .registerCommand(new AuthCommandMeta(this, this.filterCommands(Settings.IMP.MAIN.TOTP_COMMAND)), new AuthCommand()); + .registerCommand(new LimboCommandMeta(this.filterCommands(Settings.IMP.MAIN.REGISTER_COMMAND))) + .registerCommand(new LimboCommandMeta(this.filterCommands(Settings.IMP.MAIN.LOGIN_COMMAND))) + .registerCommand(new LimboCommandMeta(this.filterCommands(Settings.IMP.MAIN.TOTP_COMMAND))); - this.server.getEventManager().unregisterListeners(this); - this.server.getEventManager().register(this, new AuthListener(this, this.playerDao, this.floodgateApi)); + EventManager eventManager = this.server.getEventManager(); + eventManager.unregisterListeners(this); + eventManager.register(this, new AuthListener(this, this.playerDao, this.floodgateApi)); - Executors.newScheduledThreadPool(1, task -> new Thread(task, "purge-cache")).scheduleAtFixedRate(() -> - this.checkCache(this.cachedAuthChecks, Settings.IMP.MAIN.PURGE_CACHE_MILLIS), + Executors.newScheduledThreadPool(1, task -> new Thread(task, "purge-cache")).scheduleAtFixedRate( + () -> this.checkCache(this.cachedAuthChecks, Settings.IMP.MAIN.PURGE_CACHE_MILLIS), Settings.IMP.MAIN.PURGE_CACHE_MILLIS, Settings.IMP.MAIN.PURGE_CACHE_MILLIS, TimeUnit.MILLISECONDS ); - Executors.newScheduledThreadPool(1, task -> new Thread(task, "purge-premium-cache")).scheduleAtFixedRate(() -> - this.checkCache(this.premiumCache, Settings.IMP.MAIN.PURGE_PREMIUM_CACHE_MILLIS), + Executors.newScheduledThreadPool(1, task -> new Thread(task, "purge-premium-cache")).scheduleAtFixedRate( + () -> this.checkCache(this.premiumCache, Settings.IMP.MAIN.PURGE_PREMIUM_CACHE_MILLIS), Settings.IMP.MAIN.PURGE_PREMIUM_CACHE_MILLIS, Settings.IMP.MAIN.PURGE_PREMIUM_CACHE_MILLIS, TimeUnit.MILLISECONDS ); - this.server.getEventManager().fireAndForget(new AuthPluginReloadEvent()); + eventManager.fireAndForget(new AuthPluginReloadEvent()); } private List filterCommands(List commands) { - return commands.stream().filter(e -> e.startsWith("/")).map(e -> e.substring(1)).collect(Collectors.toList()); + return commands.stream().filter(command -> command.startsWith("/")).map(command -> command.substring(1)).collect(Collectors.toList()); + } + + private void checkCache(Map userMap, long time) { + userMap.entrySet().stream() + .filter(userEntry -> userEntry.getValue().getCheckTime() + time <= System.currentTimeMillis()) + .map(Map.Entry::getKey) + .forEach(userMap::remove); } public void migrateDb(Dao dao) { + TableInfo tableInfo = dao.getTableInfo(); + Set tables = new HashSet<>(); - Collections.addAll(tables, dao.getTableInfo().getFieldTypes()); + Collections.addAll(tables, tableInfo.getFieldTypes()); String findSql; + String database = Settings.IMP.DATABASE.DATABASE; + String tableName = tableInfo.getTableName(); switch (Settings.IMP.DATABASE.STORAGE_TYPE) { case "h2": { - findSql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" - + dao.getTableInfo().getTableName() + "';"; + findSql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + tableName + "';"; break; } case "postgresql": { - findSql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG = '" + Settings.IMP.DATABASE.DATABASE - + "' AND TABLE_NAME = '" + dao.getTableInfo().getTableName() + "';"; + findSql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_CATALOG = '" + database + "' AND TABLE_NAME = '" + tableName + "';"; break; } case "mysql": { - findSql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '" + Settings.IMP.DATABASE.DATABASE - + "' AND TABLE_NAME = '" + dao.getTableInfo().getTableName() + "';"; + findSql = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '" + database + "' AND TABLE_NAME = '" + tableName + "';"; break; } default: { - this.getLogger().error("WRONG DATABASE TYPE."); + LOGGER.error("WRONG DATABASE TYPE."); this.server.shutdown(); return; } } - try { - dao.queryRaw(findSql).forEach(e -> tables.removeIf(q -> q.getColumnName().equalsIgnoreCase(e[0]))); + try (GenericRawResults queryResult = dao.queryRaw(findSql)) { + queryResult.forEach(result -> tables.removeIf(table -> table.getColumnName().equalsIgnoreCase(result[0]))); - tables.forEach(t -> { + tables.forEach(table -> { try { - String columnDefinition = t.getColumnDefinition(); - StringBuilder builder = new StringBuilder("ALTER TABLE \"" + dao.getTableInfo().getTableName() + "\" ADD "); - List dummy = new ArrayList<>(); + StringBuilder builder = new StringBuilder("ALTER TABLE \"" + tableName + "\" ADD "); + String columnDefinition = table.getColumnDefinition(); + DatabaseType databaseType = dao.getConnectionSource().getDatabaseType(); if (columnDefinition == null) { - dao.getConnectionSource().getDatabaseType().appendColumnArg(t.getTableName(), builder, t, dummy, dummy, dummy, dummy); + List dummy = List.of(); + databaseType.appendColumnArg(table.getTableName(), builder, table, dummy, dummy, dummy, dummy); } else { - dao.getConnectionSource().getDatabaseType().appendEscapedEntityName(builder, t.getColumnName()); + databaseType.appendEscapedEntityName(builder, table.getColumnName()); builder.append(" ").append(columnDefinition).append(" "); } @@ -363,7 +436,7 @@ public class LimboAuth { e.printStackTrace(); } }); - } catch (SQLException e) { + } catch (Exception e) { e.printStackTrace(); } } @@ -372,7 +445,7 @@ public class LimboAuth { String username = player.getUsername(); String lowercaseUsername = username.toLowerCase(Locale.ROOT); this.cachedAuthChecks.remove(lowercaseUsername); - this.cachedAuthChecks.put(lowercaseUsername, new CachedSessionUser(player.getRemoteAddress().getAddress(), username, System.currentTimeMillis())); + this.cachedAuthChecks.put(lowercaseUsername, new CachedSessionUser(System.currentTimeMillis(), player.getRemoteAddress().getAddress(), username)); } public void removePlayerFromCache(String username) { @@ -391,67 +464,52 @@ public class LimboAuth { } public void authPlayer(Player player) { - String nickname = player.getUsername(); boolean isFloodgate = !Settings.IMP.MAIN.FLOODGATE_NEED_AUTH && this.floodgateApi.isFloodgatePlayer(player.getUniqueId()); + String nickname = player.getUsername(); + if (this.nicknameValidationPattern.matcher((isFloodgate) ? nickname.substring(this.floodgateApi.getPrefixLength()) : nickname).matches()) { + RegisteredPlayer registeredPlayer = AuthSessionHandler.fetchInfo(this.playerDao, nickname); + boolean onlineMode = player.isOnlineMode(); + TaskEvent.Result result = TaskEvent.Result.NORMAL; - String validatorNickname = (isFloodgate) ? nickname.substring(this.floodgateApi.getPrefixLength()) : nickname; - - if (!this.nicknameValidationPattern.matcher(validatorNickname).matches()) { - player.disconnect(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NICKNAME_INVALID_KICK)); - return; - } - - RegisteredPlayer registeredPlayer = AuthSessionHandler.fetchInfo(this.playerDao, nickname); - boolean onlineMode = player.isOnlineMode(); - TaskEvent.Result result = TaskEvent.Result.NORMAL; - - if (onlineMode || isFloodgate) { - if (registeredPlayer == null || registeredPlayer.getHash().isEmpty()) { - registeredPlayer = AuthSessionHandler.fetchInfo(this.playerDao, player.getUniqueId()); + if (onlineMode || isFloodgate) { if (registeredPlayer == null || registeredPlayer.getHash().isEmpty()) { - // Due to the current connection state, which is set to LOGIN there, we cannot send the packets. - // We need to wait for the PLAY connection state to set. - this.postLoginTasks.put(player.getUniqueId(), () -> { - if (onlineMode) { - if (!Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM.isEmpty()) { - player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM)); - } - if (!Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM_TITLE.isEmpty() && !Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM_SUBTITLE.isEmpty()) { - player.showTitle( - Title.title( - LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM_TITLE), - LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_PREMIUM_SUBTITLE), - Settings.IMP.MAIN.PREMIUM_TITLE_SETTINGS.toTimes() - ) - ); - } - } else { - if (!Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE.isEmpty()) { - player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE)); + registeredPlayer = AuthSessionHandler.fetchInfo(this.playerDao, player.getUniqueId()); + if (registeredPlayer == null || registeredPlayer.getHash().isEmpty()) { + // Due to the current connection state, which is set to LOGIN there, we cannot send the packets. + // We need to wait for the PLAY connection state to set. + this.postLoginTasks.put(player.getUniqueId(), () -> { + if (onlineMode) { + if (this.loginPremium != null) { + player.sendMessage(this.loginPremium); + } + if (this.loginPremiumTitle != null) { + player.showTitle(this.loginPremiumTitle); + } + } else { + if (this.loginFloodgate != null) { + player.sendMessage(this.loginFloodgate); + } + if (this.loginFloodgateTitle != null) { + player.showTitle(this.loginFloodgateTitle); + } } - if (!Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE_TITLE.isEmpty() && !Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE_SUBTITLE.isEmpty()) { - player.showTitle( - Title.title( - LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE_TITLE), - LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE_SUBTITLE), - Settings.IMP.MAIN.PREMIUM_TITLE_SETTINGS.toTimes() - ) - ); - } - } - }); + }); - result = TaskEvent.Result.BYPASS; + result = TaskEvent.Result.BYPASS; + } } } - } - if (registeredPlayer == null) { - Consumer eventConsumer = (event) -> this.sendPlayer(event, null); - this.server.getEventManager().fire(new PreRegisterEvent(result, player, eventConsumer)).thenAcceptAsync(eventConsumer); + EventManager eventManager = this.server.getEventManager(); + if (registeredPlayer == null) { + Consumer eventConsumer = (event) -> this.sendPlayer(event, null); + eventManager.fire(new PreRegisterEvent(eventConsumer, result, player)).thenAcceptAsync(eventConsumer); + } else { + Consumer eventConsumer = (event) -> this.sendPlayer(event, ((PreAuthorizationEvent) event).getPlayerInfo()); + eventManager.fire(new PreAuthorizationEvent(eventConsumer, result, player, registeredPlayer)).thenAcceptAsync(eventConsumer); + } } else { - Consumer eventConsumer = (event) -> this.sendPlayer(event, ((PreAuthorizationEvent) event).getPlayerInfo()); - this.server.getEventManager().fire(new PreAuthorizationEvent(result, player, registeredPlayer, eventConsumer)).thenAcceptAsync(eventConsumer); + player.disconnect(this.nicknameInvalidKick); } } @@ -475,7 +533,7 @@ public class LimboAuth { try { this.authServer.spawnPlayer(player, new AuthSessionHandler(this.playerDao, player, this, registeredPlayer)); } catch (Throwable t) { - this.getLogger().error("Error", t); + t.printStackTrace(); } break; @@ -492,26 +550,23 @@ public class LimboAuth { try { int statusCode = this.client.send( HttpRequest.newBuilder() - .uri(URI.create( - String.format( - Settings.IMP.MAIN.ISPREMIUM_AUTH_URL, - URLEncoder.encode(lowercaseNickname, StandardCharsets.UTF_8)))) + .uri(URI.create(String.format(Settings.IMP.MAIN.ISPREMIUM_AUTH_URL, URLEncoder.encode(lowercaseNickname, StandardCharsets.UTF_8)))) .build(), HttpResponse.BodyHandlers.ofString() ).statusCode(); boolean isPremium = statusCode == 200; - // 429 Too Many Requests + // 429 Too Many Requests. if (statusCode != 429) { - this.premiumCache.put(lowercaseNickname, new CachedPremiumUser(isPremium, System.currentTimeMillis())); + this.premiumCache.put(lowercaseNickname, new CachedPremiumUser(System.currentTimeMillis(), isPremium)); } else { return Settings.IMP.MAIN.ON_RATE_LIMIT_PREMIUM; } return isPremium; } catch (IOException | InterruptedException e) { - this.getLogger().error("Unable to authenticate with Mojang", e); + LOGGER.error("Unable to authenticate with Mojang.", e); return Settings.IMP.MAIN.ON_RATE_LIMIT_PREMIUM; } } @@ -519,43 +574,48 @@ public class LimboAuth { public boolean isPremium(String nickname) { if (Settings.IMP.MAIN.FORCE_OFFLINE_MODE) { return false; - } - - try { - if (this.isPremiumExternal(nickname)) { - QueryBuilder premiumRegisteredQuery = this.playerDao.queryBuilder(); - premiumRegisteredQuery.where() - .eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT)) - .and() - .ne("HASH", ""); - premiumRegisteredQuery.setCountOf(true); - - QueryBuilder premiumUnregisteredQuery = this.playerDao.queryBuilder(); - premiumUnregisteredQuery.where() - .eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT)) - .and() - .eq("HASH", ""); - premiumUnregisteredQuery.setCountOf(true); - - if (Settings.IMP.MAIN.ONLINE_MODE_NEED_AUTH) { - return this.playerDao.countOf(premiumRegisteredQuery.prepare()) == 0 && this.playerDao.countOf(premiumUnregisteredQuery.prepare()) != 0; + } else { + try { + if (this.isPremiumExternal(nickname)) { + QueryBuilder premiumRegisteredQuery = this.playerDao.queryBuilder(); + premiumRegisteredQuery.where() + .eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT)) + .and() + .ne("HASH", ""); + premiumRegisteredQuery.setCountOf(true); + + QueryBuilder premiumUnregisteredQuery = this.playerDao.queryBuilder(); + premiumUnregisteredQuery.where() + .eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT)) + .and() + .eq("HASH", ""); + premiumUnregisteredQuery.setCountOf(true); + + if (Settings.IMP.MAIN.ONLINE_MODE_NEED_AUTH) { + return this.playerDao.countOf(premiumRegisteredQuery.prepare()) == 0 && this.playerDao.countOf(premiumUnregisteredQuery.prepare()) != 0; + } else { + return this.playerDao.countOf(premiumRegisteredQuery.prepare()) == 0; + } } else { - return this.playerDao.countOf(premiumRegisteredQuery.prepare()) == 0; + return false; } - } else { - return false; + } catch (Exception e) { + LOGGER.error("Unable to authenticate with Mojang.", e); + return Settings.IMP.MAIN.ON_RATE_LIMIT_PREMIUM; } - } catch (SQLException e) { - this.getLogger().error("Unable to authenticate with Mojang", e); - return Settings.IMP.MAIN.ON_RATE_LIMIT_PREMIUM; } } - private void checkCache(Map userMap, long time) { - userMap.entrySet().stream() - .filter(u -> u.getValue().getCheckTime() + time <= System.currentTimeMillis()) - .map(Map.Entry::getKey) - .forEach(userMap::remove); + public Map getPostLoginTasks() { + return this.postLoginTasks; + } + + public Set getUnsafePasswords() { + return this.unsafePasswords; + } + + public ProxyServer getServer() { + return this.server; } public JdbcPooledConnectionSource getConnectionSource() { @@ -566,20 +626,27 @@ public class LimboAuth { return this.playerDao; } - public Set getUnsafePasswords() { - return this.unsafePasswords; + static { + // requireNonNull prevents the shade plugin from excluding the drivers in minimized jar. + Objects.requireNonNull(com.mysql.cj.jdbc.Driver.class); + Objects.requireNonNull(com.mysql.cj.conf.url.SingleConnectionUrl.class); + + Objects.requireNonNull(org.h2.Driver.class); + Objects.requireNonNull(org.h2.engine.Engine.class); + + Objects.requireNonNull(org.postgresql.Driver.class); } - public Map getPostLoginTasks() { - return this.postLoginTasks; + private static void setLogger(Logger logger) { + LOGGER = logger; } - public Logger getLogger() { - return this.logger; + private static void setSerializer(Serializer serializer) { + SERIALIZER = serializer; } - public ProxyServer getServer() { - return this.server; + public static Serializer getSerializer() { + return SERIALIZER; } private static class CachedUser { @@ -600,8 +667,9 @@ public class LimboAuth { private final InetAddress inetAddress; private final String username; - public CachedSessionUser(InetAddress inetAddress, String username, long checkTime) { + public CachedSessionUser(long checkTime, InetAddress inetAddress, String username) { super(checkTime); + this.inetAddress = inetAddress; this.username = username; } @@ -619,8 +687,9 @@ public class LimboAuth { private final boolean isPremium; - public CachedPremiumUser(boolean isPremium, long checkTime) { + public CachedPremiumUser(long checkTime, boolean isPremium) { super(checkTime); + this.isPremium = isPremium; } @@ -628,37 +697,4 @@ public class LimboAuth { return this.isPremium; } } - - private static class AuthCommandMeta implements CommandMeta { - - private final LimboAuth plugin; - private final Collection aliases; - - AuthCommandMeta(LimboAuth plugin, Collection aliases) { - this.plugin = plugin; - this.aliases = aliases; - } - - @Override - public Collection getAliases() { - return this.aliases; - } - - @Override - public Collection> getHints() { - return Collections.emptyList(); - } - - @Override - public @Nullable Object getPlugin() { - return this.plugin; - } - } - - private static class AuthCommand implements SimpleCommand { - @Override - public void execute(Invocation invocation) { - - } - } } diff --git a/src/main/java/net/elytrium/limboauth/Settings.java b/src/main/java/net/elytrium/limboauth/Settings.java index 9dbbcc4..43e1fe6 100644 --- a/src/main/java/net/elytrium/limboauth/Settings.java +++ b/src/main/java/net/elytrium/limboauth/Settings.java @@ -17,13 +17,12 @@ package net.elytrium.limboauth; -import java.io.File; import java.util.List; -import net.elytrium.limboauth.config.Config; +import net.elytrium.java.commons.config.YamlConfig; import net.kyori.adventure.title.Title; import net.kyori.adventure.util.Ticks; -public class Settings extends Config { +public class Settings extends YamlConfig { @Ignore public static final Settings IMP = new Settings(); @@ -31,11 +30,21 @@ public class Settings extends Config { @Final public String VERSION = BuildConstants.AUTH_VERSION; + @Comment({ + "Available serializers:", + "LEGACY_AMPERSAND - \"&c&lExample &c&9Text\".", + "LEGACY_SECTION - \"§c§lExample §c§9Text\".", + "MINIMESSAGE - \"Example Text\". (https://webui.adventure.kyori.net/)", + "GSON - \"[{\"text\":\"Example\",\"bold\":true,\"color\":\"red\"},{\"text\":\" \",\"bold\":true},{\"text\":\"Text\",\"bold\":true,\"color\":\"blue\"}]\". (https://minecraft.tools/en/json_text.php/)", + "GSON_COLOR_DOWNSAMPLING - Same as GSON, but uses downsampling." + }) + public String SERIALIZER = "LEGACY_AMPERSAND"; public String PREFIX = "LimboAuth &6>>&f"; @Create public MAIN MAIN; + @Comment("Don't use \\n, use {NL} for new line, and {PRFX} for prefix.") public static class MAIN { @Comment("Maximum time for player to authenticate in milliseconds. If the player stays on the auth limbo for longer than this time, then the player will be kicked.") @@ -68,6 +77,8 @@ public class Settings extends Config { public boolean TOTP_NEED_PASSWORD = true; public boolean REGISTER_NEED_REPEAT_PASSWORD = true; public boolean CHANGE_PASSWORD_NEED_OLD_PASSWORD = true; + @Comment("Used in unregister and premium commands.") + public String CONFIRM_KEYWORD = "confirm"; @Comment("This prefix will be added to offline mode players nickname") public String OFFLINE_MODE_PREFIX = ""; @Comment("This prefix will be added to online mode players nickname") @@ -157,7 +168,6 @@ public class Settings extends Config { public Title.Times toTimes() { return Title.Times.times(Ticks.duration(this.FADE_IN), Ticks.duration(this.STAY), Ticks.duration(this.FADE_OUT)); } - } @Create @@ -190,12 +200,12 @@ public class Settings extends Config { @Create public MAIN.STRINGS STRINGS; - @Comment("You can left blank the fields marked with \"*\" comment.") public static class STRINGS { public String RELOAD = "{PRFX} &aReloaded successfully!"; public String RELOAD_FAILED = "{PRFX} &cReload failed, check console for details."; public String ERROR_OCCURRED = "{PRFX} &cAn internal error has occurred!"; + public String DATABASE_ERROR_KICK = "{PRFX} &cA database error has occurred!"; public String NOT_PLAYER = "{PRFX} &cСonsole is not allowed to execute this command!"; public String NOT_REGISTERED = "{PRFX} &cYou are not registered or your account is &6PREMIUM!"; @@ -205,36 +215,36 @@ public class Settings extends Config { public String NICKNAME_INVALID_KICK = "{PRFX}{NL}&cYour nickname contains forbidden characters. Please, change your nickname!"; @Comment("6 hours by default in ip-limit-valid-time") - public String IP_LIMIT = "{PRFX} &cYour IP has reached max registered accounts. If this is an error, restart your router, or wait about 6 hours."; + public String IP_LIMIT_KICK = "{PRFX}{NL}{NL}&cYour IP has reached max registered accounts. If this is an error, restart your router, or wait about 6 hours."; public String WRONG_NICKNAME_CASE_KICK = "{PRFX}{NL}&cThe case of your nickname is wrong. Nickname is CaSe SeNsItIvE."; public String BOSSBAR = "{PRFX} You have &6{0} &fseconds left to log in."; public String TIMES_UP = "{PRFX}{NL}&cAuthorization time is up."; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String LOGIN_PREMIUM = "{PRFX} You've been logged in automatically using the premium account!"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String LOGIN_PREMIUM_TITLE = "{PRFX} Welcome!"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String LOGIN_PREMIUM_SUBTITLE = "&aYou has been logged in as premium player!"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String LOGIN_FLOODGATE = "{PRFX} You've been logged in automatically using the bedrock account!"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String LOGIN_FLOODGATE_TITLE = "{PRFX} Welcome!"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String LOGIN_FLOODGATE_SUBTITLE = "&aYou has been logged in as bedrock player!"; public String LOGIN = "{PRFX} &aPlease, login using &6/login &a, you have &6{0} &aattempts."; public String LOGIN_WRONG_PASSWORD = "{PRFX} &cYou''ve entered the wrong password, you have &6{0} &cattempts left."; public String LOGIN_WRONG_PASSWORD_KICK = "{PRFX}{NL}&cYou've entered the wrong password numerous times!"; public String LOGIN_SUCCESSFUL = "{PRFX} &aSuccessfully logged in!"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String LOGIN_TITLE = "&fPlease, login using &6/login &a."; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String LOGIN_SUBTITLE = "&aYou have &6{0} &aattempts."; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String LOGIN_SUCCESSFUL_TITLE = "{PRFX}"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String LOGIN_SUCCESSFUL_SUBTITLE = "&aSuccessfully logged in!"; @Comment("Or if register-need-repeat-password set to false remove the \"\" part.") @@ -244,13 +254,13 @@ public class Settings extends Config { public String REGISTER_PASSWORD_TOO_LONG = "{PRFX} &cYou entered too long password, use a different one!"; public String REGISTER_PASSWORD_UNSAFE = "{PRFX} &cYour password is unsafe, use a different one!"; public String REGISTER_SUCCESSFUL = "{PRFX} &aSuccessfully registered!"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String REGISTER_TITLE = "{PRFX}"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String REGISTER_SUBTITLE = "&aPlease, register using &6/register "; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String REGISTER_SUCCESSFUL_TITLE = "{PRFX}"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String REGISTER_SUCCESSFUL_SUBTITLE = "&aSuccessfully registered!"; public String UNREGISTER_SUCCESSFUL = "{PRFX}{NL}&aSuccessfully unregistered!"; @@ -278,9 +288,9 @@ public class Settings extends Config { public String FORCE_CHANGE_PASSWORD_USAGE = "{PRFX} Usage: &6/forcechangepassword "; public String TOTP = "{PRFX} Please, enter your 2FA key using &6/2fa "; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String TOTP_TITLE = "{PRFX}"; - @Comment("*") + @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE) public String TOTP_SUBTITLE = "&aEnter your 2FA key using &6/2fa "; public String TOTP_SUCCESSFUL = "{PRFX} &aSuccessfully enabled 2FA!"; public String TOTP_DISABLED = "{PRFX} &aSuccessfully disabled 2FA!"; @@ -292,7 +302,6 @@ public class Settings extends Config { public String TOTP_TOKEN = "{PRFX} &aYour 2FA token &7(Click to copy)&a: &6{0}"; public String TOTP_RECOVERY = "{PRFX} &aYour recovery codes &7(Click to copy)&a: &6{0}"; - public String DB_ERROR = "{PRFX} &aA database error has occurred."; public String DESTROY_SESSION_SUCCESSFUL = "{PRFX} &eYour session is now destroyed, you'll need to log in again after reconnecting."; } @@ -325,13 +334,4 @@ public class Settings extends Config { public String DATABASE = "limboauth"; public String CONNECTION_PARAMETERS = "?autoReconnect=true&initialTimeout=1&useSSL=false"; } - - public void reload(File file) { - if (this.load(file, this.PREFIX)) { - this.save(file); - } else { - this.save(file); - this.load(file, this.PREFIX); - } - } } diff --git a/src/main/java/net/elytrium/limboauth/command/ChangePasswordCommand.java b/src/main/java/net/elytrium/limboauth/command/ChangePasswordCommand.java index 806add0..f280053 100644 --- a/src/main/java/net/elytrium/limboauth/command/ChangePasswordCommand.java +++ b/src/main/java/net/elytrium/limboauth/command/ChangePasswordCommand.java @@ -24,36 +24,38 @@ import com.velocitypowered.api.command.SimpleCommand; import com.velocitypowered.api.permission.Tristate; import com.velocitypowered.api.proxy.Player; import java.sql.SQLException; +import net.elytrium.java.commons.mc.serialization.Serializer; +import net.elytrium.limboauth.LimboAuth; import net.elytrium.limboauth.Settings; import net.elytrium.limboauth.handler.AuthSessionHandler; import net.elytrium.limboauth.model.RegisteredPlayer; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; public class ChangePasswordCommand implements SimpleCommand { private final Dao playerDao; - private final Component notPlayer; private final boolean needOldPass; private final Component notRegistered; + private final Component crackedCommand; private final Component wrongPassword; private final Component successful; private final Component errorOccurred; private final Component usage; - private final Component crackedCommand; + private final Component notPlayer; public ChangePasswordCommand(Dao playerDao) { this.playerDao = playerDao; - this.notPlayer = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_PLAYER); + Serializer serializer = LimboAuth.getSerializer(); this.needOldPass = Settings.IMP.MAIN.CHANGE_PASSWORD_NEED_OLD_PASSWORD; - this.notRegistered = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_REGISTERED); - this.wrongPassword = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.WRONG_PASSWORD); - this.successful = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.CHANGE_PASSWORD_SUCCESSFUL); - this.errorOccurred = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.ERROR_OCCURRED); - this.usage = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.CHANGE_PASSWORD_USAGE); - this.crackedCommand = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.CRACKED_COMMAND); + this.notRegistered = serializer.deserialize(Settings.IMP.MAIN.STRINGS.NOT_REGISTERED); + this.crackedCommand = serializer.deserialize(Settings.IMP.MAIN.STRINGS.CRACKED_COMMAND); + this.wrongPassword = serializer.deserialize(Settings.IMP.MAIN.STRINGS.WRONG_PASSWORD); + this.successful = serializer.deserialize(Settings.IMP.MAIN.STRINGS.CHANGE_PASSWORD_SUCCESSFUL); + this.errorOccurred = serializer.deserialize(Settings.IMP.MAIN.STRINGS.ERROR_OCCURRED); + this.usage = serializer.deserialize(Settings.IMP.MAIN.STRINGS.CHANGE_PASSWORD_USAGE); + this.notPlayer = serializer.deserialize(Settings.IMP.MAIN.STRINGS.NOT_PLAYER); } @Override @@ -61,45 +63,42 @@ public class ChangePasswordCommand implements SimpleCommand { CommandSource source = invocation.source(); String[] args = invocation.arguments(); - if (!(source instanceof Player)) { - source.sendMessage(this.notPlayer); - return; - } - - if (this.needOldPass ? args.length == 2 : args.length == 1) { - if (this.needOldPass) { - RegisteredPlayer player = AuthSessionHandler.fetchInfo(this.playerDao, ((Player) source).getUsername()); - if (player == null) { - source.sendMessage(this.notRegistered); - return; - } else if (player.getHash().isEmpty()) { - source.sendMessage(this.crackedCommand); - } else if (!AuthSessionHandler.checkPassword(args[0], player, this.playerDao)) { - source.sendMessage(this.wrongPassword); - return; + if (source instanceof Player) { + if (this.needOldPass ? args.length == 2 : args.length == 1) { + if (this.needOldPass) { + RegisteredPlayer player = AuthSessionHandler.fetchInfo(this.playerDao, ((Player) source).getUsername()); + if (player == null) { + source.sendMessage(this.notRegistered); + return; + } else if (player.getHash().isEmpty()) { + source.sendMessage(this.crackedCommand); + } else if (!AuthSessionHandler.checkPassword(args[0], player, this.playerDao)) { + source.sendMessage(this.wrongPassword); + return; + } } - } - try { - UpdateBuilder updateBuilder = this.playerDao.updateBuilder(); - updateBuilder.where().eq("NICKNAME", ((Player) source).getUsername()); - updateBuilder.updateColumnValue("HASH", AuthSessionHandler.genHash(this.needOldPass ? args[1] : args[0])); - updateBuilder.update(); + try { + UpdateBuilder updateBuilder = this.playerDao.updateBuilder(); + updateBuilder.where().eq("NICKNAME", ((Player) source).getUsername()); + updateBuilder.updateColumnValue("HASH", AuthSessionHandler.genHash(this.needOldPass ? args[1] : args[0])); + updateBuilder.update(); - source.sendMessage(this.successful); - } catch (SQLException e) { - source.sendMessage(this.errorOccurred); - e.printStackTrace(); + source.sendMessage(this.successful); + } catch (SQLException e) { + source.sendMessage(this.errorOccurred); + e.printStackTrace(); + } + } else { + source.sendMessage(this.usage); } - - return; + } else { + source.sendMessage(this.notPlayer); } - - source.sendMessage(this.usage); } @Override public boolean hasPermission(SimpleCommand.Invocation invocation) { - return invocation.source().getPermissionValue("limboauth.commands.changepassword") != Tristate.FALSE; + return invocation.source().getPermissionValue("limboauth.commands.changepassword") == Tristate.TRUE; } } diff --git a/src/main/java/net/elytrium/limboauth/command/DestroySessionCommand.java b/src/main/java/net/elytrium/limboauth/command/DestroySessionCommand.java index 5cabe9b..95e002c 100644 --- a/src/main/java/net/elytrium/limboauth/command/DestroySessionCommand.java +++ b/src/main/java/net/elytrium/limboauth/command/DestroySessionCommand.java @@ -21,40 +21,40 @@ import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.SimpleCommand; import com.velocitypowered.api.permission.Tristate; import com.velocitypowered.api.proxy.Player; +import net.elytrium.java.commons.mc.serialization.Serializer; import net.elytrium.limboauth.LimboAuth; import net.elytrium.limboauth.Settings; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; public class DestroySessionCommand implements SimpleCommand { private final LimboAuth plugin; - private final Component notPlayer; private final Component successful; + private final Component notPlayer; public DestroySessionCommand(LimboAuth plugin) { this.plugin = plugin; - this.notPlayer = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_PLAYER); - this.successful = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.DESTROY_SESSION_SUCCESSFUL); + Serializer serializer = LimboAuth.getSerializer(); + this.successful = serializer.deserialize(Settings.IMP.MAIN.STRINGS.DESTROY_SESSION_SUCCESSFUL); + this.notPlayer = serializer.deserialize(Settings.IMP.MAIN.STRINGS.NOT_PLAYER); } @Override public void execute(SimpleCommand.Invocation invocation) { CommandSource source = invocation.source(); - if (!(source instanceof Player)) { + if (source instanceof Player) { + this.plugin.removePlayerFromCache(((Player) source).getUsername()); + source.sendMessage(this.successful); + } else { source.sendMessage(this.notPlayer); - return; } - - this.plugin.removePlayerFromCache(((Player) source).getUsername()); - source.sendMessage(this.successful); } @Override public boolean hasPermission(SimpleCommand.Invocation invocation) { - return invocation.source().getPermissionValue("limboauth.commands.destroysession") != Tristate.FALSE; + return invocation.source().getPermissionValue("limboauth.commands.destroysession") == Tristate.TRUE; } } diff --git a/src/main/java/net/elytrium/limboauth/command/ForceChangePasswordCommand.java b/src/main/java/net/elytrium/limboauth/command/ForceChangePasswordCommand.java index dd2ee4d..2d47b61 100644 --- a/src/main/java/net/elytrium/limboauth/command/ForceChangePasswordCommand.java +++ b/src/main/java/net/elytrium/limboauth/command/ForceChangePasswordCommand.java @@ -26,12 +26,13 @@ import java.sql.SQLException; import java.text.MessageFormat; import java.util.List; import java.util.Locale; +import net.elytrium.java.commons.mc.serialization.Serializer; +import net.elytrium.java.commons.mc.velocity.commands.SuggestUtils; +import net.elytrium.limboauth.LimboAuth; import net.elytrium.limboauth.Settings; import net.elytrium.limboauth.handler.AuthSessionHandler; import net.elytrium.limboauth.model.RegisteredPlayer; -import net.elytrium.limboauth.utils.SuggestUtils; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; public class ForceChangePasswordCommand implements SimpleCommand { @@ -50,12 +51,12 @@ public class ForceChangePasswordCommand implements SimpleCommand { this.message = Settings.IMP.MAIN.STRINGS.FORCE_CHANGE_PASSWORD_MESSAGE; this.successful = Settings.IMP.MAIN.STRINGS.FORCE_CHANGE_PASSWORD_SUCCESSFUL; this.notSuccessful = Settings.IMP.MAIN.STRINGS.FORCE_CHANGE_PASSWORD_NOT_SUCCESSFUL; - this.usage = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.FORCE_CHANGE_PASSWORD_USAGE); + this.usage = LimboAuth.getSerializer().deserialize(Settings.IMP.MAIN.STRINGS.FORCE_CHANGE_PASSWORD_USAGE); } @Override public List suggest(SimpleCommand.Invocation invocation) { - return SuggestUtils.suggestPlayers(invocation.arguments(), this.server); + return SuggestUtils.suggestPlayers(this.server, invocation.arguments(), 0); } @Override @@ -67,26 +68,23 @@ public class ForceChangePasswordCommand implements SimpleCommand { String nickname = args[0]; String newPassword = args[1]; + Serializer serializer = LimboAuth.getSerializer(); try { UpdateBuilder updateBuilder = this.playerDao.updateBuilder(); updateBuilder.where().eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT)); updateBuilder.updateColumnValue("HASH", AuthSessionHandler.genHash(newPassword)); updateBuilder.update(); - this.server.getPlayer(nickname).ifPresent(player -> - player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(MessageFormat.format(this.message, newPassword))) - ); + this.server.getPlayer(nickname).ifPresent(player -> player.sendMessage(serializer.deserialize(MessageFormat.format(this.message, newPassword)))); - source.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(MessageFormat.format(this.successful, nickname))); + source.sendMessage(serializer.deserialize(MessageFormat.format(this.successful, nickname))); } catch (SQLException e) { - source.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(MessageFormat.format(this.notSuccessful, nickname))); + source.sendMessage(serializer.deserialize(MessageFormat.format(this.notSuccessful, nickname))); e.printStackTrace(); } - - return; + } else { + source.sendMessage(this.usage); } - - source.sendMessage(this.usage); } @Override diff --git a/src/main/java/net/elytrium/limboauth/command/ForceUnregisterCommand.java b/src/main/java/net/elytrium/limboauth/command/ForceUnregisterCommand.java index dabe70b..2fd12ca 100644 --- a/src/main/java/net/elytrium/limboauth/command/ForceUnregisterCommand.java +++ b/src/main/java/net/elytrium/limboauth/command/ForceUnregisterCommand.java @@ -25,12 +25,12 @@ import java.sql.SQLException; import java.text.MessageFormat; import java.util.List; import java.util.Locale; +import net.elytrium.java.commons.mc.serialization.Serializer; +import net.elytrium.java.commons.mc.velocity.commands.SuggestUtils; import net.elytrium.limboauth.LimboAuth; import net.elytrium.limboauth.Settings; import net.elytrium.limboauth.model.RegisteredPlayer; -import net.elytrium.limboauth.utils.SuggestUtils; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; public class ForceUnregisterCommand implements SimpleCommand { @@ -48,15 +48,16 @@ public class ForceUnregisterCommand implements SimpleCommand { this.server = server; this.playerDao = playerDao; - this.kick = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.FORCE_UNREGISTER_KICK); + Serializer serializer = LimboAuth.getSerializer(); + this.kick = serializer.deserialize(Settings.IMP.MAIN.STRINGS.FORCE_UNREGISTER_KICK); this.successful = Settings.IMP.MAIN.STRINGS.FORCE_UNREGISTER_SUCCESSFUL; this.notSuccessful = Settings.IMP.MAIN.STRINGS.FORCE_UNREGISTER_NOT_SUCCESSFUL; - this.usage = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.FORCE_UNREGISTER_USAGE); + this.usage = serializer.deserialize(Settings.IMP.MAIN.STRINGS.FORCE_UNREGISTER_USAGE); } @Override public List suggest(SimpleCommand.Invocation invocation) { - return SuggestUtils.suggestPlayers(invocation.arguments(), this.server); + return SuggestUtils.suggestPlayers(this.server, invocation.arguments(), 0); } @Override @@ -67,20 +68,19 @@ public class ForceUnregisterCommand implements SimpleCommand { if (args.length == 1) { String playerNick = args[0]; + Serializer serializer = LimboAuth.getSerializer(); try { this.playerDao.deleteById(playerNick.toLowerCase(Locale.ROOT)); this.plugin.removePlayerFromCache(playerNick); this.server.getPlayer(playerNick).ifPresent(player -> player.disconnect(this.kick)); - source.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(MessageFormat.format(this.successful, playerNick))); + source.sendMessage(serializer.deserialize(MessageFormat.format(this.successful, playerNick))); } catch (SQLException e) { - source.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(MessageFormat.format(this.notSuccessful, playerNick))); + source.sendMessage(serializer.deserialize(MessageFormat.format(this.notSuccessful, playerNick))); e.printStackTrace(); } - - return; + } else { + source.sendMessage(this.usage); } - - source.sendMessage(this.usage); } @Override diff --git a/src/main/java/net/elytrium/limboauth/command/LimboAuthCommand.java b/src/main/java/net/elytrium/limboauth/command/LimboAuthCommand.java index 49a5079..3dd4c8d 100644 --- a/src/main/java/net/elytrium/limboauth/command/LimboAuthCommand.java +++ b/src/main/java/net/elytrium/limboauth/command/LimboAuthCommand.java @@ -21,15 +21,44 @@ import com.google.common.collect.ImmutableList; import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.command.SimpleCommand; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; -import java.util.stream.Stream; +import net.elytrium.java.commons.mc.serialization.Serializer; import net.elytrium.limboauth.LimboAuth; import net.elytrium.limboauth.Settings; import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import net.kyori.adventure.text.format.NamedTextColor; public class LimboAuthCommand implements SimpleCommand { + private static final List HELP_MESSAGE = List.of( + Component.text("This server is using LimboAuth and LimboAPI.", NamedTextColor.YELLOW), + Component.text("(C) 2021 - 2022 Elytrium", NamedTextColor.YELLOW), + Component.text("https://elytrium.net/github/", NamedTextColor.GREEN), + Component.empty() + ); + private static final Map SUBCOMMANDS = Map.of( + /* + "serverstats", Component.textOfChildren( + Component.text(" /limboauth serverstats", NamedTextColor.GREEN), + Component.text(" - ", NamedTextColor.DARK_GRAY), + Component.text("Query for server stats.", NamedTextColor.YELLOW) + ), + "playerstats", Component.textOfChildren( + Component.text(" /limboauth playerstats ", NamedTextColor.GREEN), + Component.text(" - ", NamedTextColor.DARK_GRAY), + Component.text("Query for stats of specified player.", NamedTextColor.YELLOW) + ), + */ + "reload", Component.textOfChildren( + Component.text(" /limboauth reload", NamedTextColor.GREEN), + Component.text(" - ", NamedTextColor.DARK_GRAY), + Component.text("Reload config.", NamedTextColor.YELLOW) + ) + ); + private static final Component AVAILABLE_SUBCOMMANDS_MESSAGE = Component.text("Available subcommands:", NamedTextColor.WHITE); + private static final Component NO_AVAILABLE_SUBCOMMANDS_MESSAGE = Component.text("There is no available subcommands for you.", NamedTextColor.WHITE); + private final LimboAuth plugin; public LimboAuthCommand(LimboAuth plugin) { @@ -42,17 +71,22 @@ public class LimboAuthCommand implements SimpleCommand { String[] args = invocation.arguments(); if (args.length == 0) { - return this.getSubCommands() + return SUBCOMMANDS.keySet().stream() .filter(cmd -> source.hasPermission("limboauth.admin." + cmd)) .collect(Collectors.toList()); } else if (args.length == 1) { - return this.getSubCommands() + String argument = args[0]; + return SUBCOMMANDS.keySet().stream() .filter(cmd -> source.hasPermission("limboauth.admin." + cmd)) - .filter(str -> str.regionMatches(true, 0, args[0], 0, args[0].length())) + .filter(str -> str.regionMatches(true, 0, argument, 0, argument.length())) .collect(Collectors.toList()); + /* + } else if (args[0].equalsIgnoreCase("playerstats") && source.hasPermission("limboauth.admin.playerstats")) { + return SuggestUtils.suggestPlayers(this.plugin.getServer(), args, 2); + */ + } else { + return ImmutableList.of(); } - - return ImmutableList.of(); } @Override @@ -60,40 +94,63 @@ public class LimboAuthCommand implements SimpleCommand { CommandSource source = invocation.source(); String[] args = invocation.arguments(); - if (args.length == 1) { - if (args[0].equalsIgnoreCase("reload") && source.hasPermission("limboauth.admin.reload")) { - try { - this.plugin.reload(); - source.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.RELOAD)); - } catch (Exception e) { - source.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.RELOAD_FAILED)); - e.printStackTrace(); + int argsAmount = args.length; + if (argsAmount > 0) { + String command = args[0]; + Serializer serializer = LimboAuth.getSerializer(); + if (argsAmount == 1) { + if (command.equalsIgnoreCase("reload") && source.hasPermission("limboauth.admin.reload")) { + try { + this.plugin.reload(); + source.sendMessage(serializer.deserialize(Settings.IMP.MAIN.STRINGS.RELOAD)); + } catch (Exception e) { + e.printStackTrace(); + source.sendMessage(serializer.deserialize(Settings.IMP.MAIN.STRINGS.RELOAD_FAILED)); + } + + return; + } + /* + else if (command.equalsIgnoreCase("serverstats") && source.hasPermission("limboauth.admin.serverstats")) { + return; +