diff options
Diffstat (limited to 'src/main/java')
7 files changed, 179 insertions, 36 deletions
diff --git a/src/main/java/net/elytrium/limboauth/LimboAuth.java b/src/main/java/net/elytrium/limboauth/LimboAuth.java index ba29a20..f0fcda0 100644 --- a/src/main/java/net/elytrium/limboauth/LimboAuth.java +++ b/src/main/java/net/elytrium/limboauth/LimboAuth.java @@ -23,6 +23,7 @@ import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.field.FieldType; import com.j256.ormlite.jdbc.JdbcPooledConnectionSource; +import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.table.TableUtils; import com.velocitypowered.api.command.CommandManager; import com.velocitypowered.api.event.Subscribe; @@ -68,6 +69,7 @@ import net.elytrium.limboauth.command.ChangePasswordCommand; import net.elytrium.limboauth.command.DestroySessionCommand; import net.elytrium.limboauth.command.ForceUnregisterCommand; import net.elytrium.limboauth.command.LimboAuthCommand; +import net.elytrium.limboauth.command.PremiumCommand; import net.elytrium.limboauth.command.TotpCommand; import net.elytrium.limboauth.command.UnregisterCommand; import net.elytrium.limboauth.handler.AuthSessionHandler; @@ -187,6 +189,7 @@ public class LimboAuth { manager.unregister("limboauth"); manager.register("unregister", new UnregisterCommand(this, this.playerDao), "unreg"); + manager.register("premium", new PremiumCommand(this, this.playerDao)); manager.register("forceunregister", new ForceUnregisterCommand(this, this.server, this.playerDao), "forceunreg"); manager.register("changepassword", new ChangePasswordCommand(this.playerDao), "changepass"); manager.register("destroysession", new DestroySessionCommand(this)); @@ -233,7 +236,7 @@ public class LimboAuth { this.server.getEventManager().register(this, new AuthListener(this.playerDao)); Executors.newScheduledThreadPool(1, task -> new Thread(task, "purge-cache")).scheduleAtFixedRate(() -> - this.checkCache(this.cachedAuthChecks, Settings.IMP.MAIN.PURGE_CACHE_MILLIS), + this.checkCache(this.cachedAuthChecks, Settings.IMP.MAIN.PURGE_CACHE_MILLIS), Settings.IMP.MAIN.PURGE_CACHE_MILLIS, Settings.IMP.MAIN.PURGE_CACHE_MILLIS, TimeUnit.MILLISECONDS @@ -316,28 +319,31 @@ public class LimboAuth { return; } - if (!Settings.IMP.MAIN.ONLINE_MODE_NEED_AUTH && player.isOnlineMode()) { - RegisteredPlayer registeredPlayer = AuthSessionHandler.fetchInfo(this.playerDao, player.getUsername()); + RegisteredPlayer registeredPlayer = AuthSessionHandler.fetchInfo(this.playerDao, nickname); + if (player.isOnlineMode()) { if (registeredPlayer == null || registeredPlayer.getHash().isEmpty()) { - this.factory.passLoginLimbo(player); - return; + registeredPlayer = AuthSessionHandler.fetchInfo(this.playerDao, player.getUniqueId()); + if (registeredPlayer == null || registeredPlayer.getHash().isEmpty()) { + this.factory.passLoginLimbo(player); + return; + } } } - // Send player to auth virtual server. try { - this.authServer.spawnPlayer(player, new AuthSessionHandler(this.playerDao, player, this, nickname)); + this.authServer.spawnPlayer(player, new AuthSessionHandler(this.playerDao, player, this, registeredPlayer)); } catch (Throwable t) { this.getLogger().error("Error", t); } } - public boolean isPremium(String nickname) { + public boolean isPremiumExternal(String nickname) { try { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(String.format(Settings.IMP.MAIN.ISPREMIUM_AUTH_URL, nickname))) .build(); + HttpResponse<String> response = this.client.send(request, HttpResponse.BodyHandlers.ofString()); return response.statusCode() == 200; } catch (IOException | InterruptedException e) { @@ -346,6 +352,36 @@ public class LimboAuth { } } + public boolean isPremium(String nickname) { + try { + if (this.isPremiumExternal(nickname)) { + QueryBuilder<RegisteredPlayer, String> query = this.playerDao.queryBuilder(); + query.where() + .eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT)) + .and() + .ne("HASH", ""); + query.setCountOf(true); + QueryBuilder<RegisteredPlayer, String> query2 = this.playerDao.queryBuilder(); + query2.where() + .eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT)) + .and() + .eq("HASH", ""); + query2.setCountOf(true); + if (Settings.IMP.MAIN.ONLINE_MODE_NEED_AUTH) { + return this.playerDao.countOf(query.prepare()) == 0 + && this.playerDao.countOf(query2.prepare()) != 0; + } else { + return this.playerDao.countOf(query.prepare()) == 0; + } + } else { + return false; + } + } catch (SQLException e) { + this.getLogger().error("Unable to authenticate with Mojang", e); + return true; + } + } + private void checkCache(Map<String, CachedUser> userMap, long time) { userMap.entrySet().stream() .filter(u -> u.getValue().getCheckTime() + time <= System.currentTimeMillis()) diff --git a/src/main/java/net/elytrium/limboauth/Settings.java b/src/main/java/net/elytrium/limboauth/Settings.java index 0886cdf..42cb470 100644 --- a/src/main/java/net/elytrium/limboauth/Settings.java +++ b/src/main/java/net/elytrium/limboauth/Settings.java @@ -43,7 +43,7 @@ public class Settings extends Config { @Comment("Available overlays: PROGRESS, NOTCHED_6, NOTCHED_10, NOTCHED_12, NOTCHED_20") public String BOSSBAR_OVERLAY = "NOTCHED_20"; public int MIN_PASSWORD_LENGTH = 4; - @Comment("Максимальная длинна пароля для BCrypt равняется 71 символу.") + @Comment("Max password length for the BCrypt hashing algorithm, which is used in this plugin, can't be higher than 71. You can set a lower value than 71.") public int MAX_PASSWORD_LENGTH = 71; public boolean CHECK_PASSWORD_STRENGTH = true; public String UNSAFE_PASSWORDS_FILE = "unsafe_passwords.txt"; @@ -139,8 +139,8 @@ public class Settings extends Config { 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 WRONG_NICKNAME_CASE_KICK = "{PRFX}{NL}&cThe case of your nickname is wrong. Nickname is CaSe SeNsItIvE."; - public String BOSSBAR = "{PRFX} У вас осталось &6{0} &fсекунд чтобы авторизироваться."; - public String TIMES_UP = "{PRFX}{NL}&cВремя авторизации вышло."; + public String BOSSBAR = "{PRFX} You have &6{0} &fseconds left to log in."; + public String TIMES_UP = "{PRFX}{NL}&cAuthorization time is up."; public String LOGIN = "{PRFX} &aPlease, login using &6/login <password>&a, you have &6{0} &aattempts."; public String LOGIN_WRONG_PASSWORD = "{PRFX} &cYou''ve entered the wrong password, you have &6{0} &cattempts left."; @@ -166,6 +166,11 @@ public class Settings extends Config { public String UNREGISTER_SUCCESSFUL = "{PRFX}{NL}&aSuccessfully unregistered!"; public String UNREGISTER_USAGE = "{PRFX} Usage: &6/unregister <current password> confirm"; + public String PREMIUM_SUCCESSFUL = "{PRFX}{NL}&aSuccessfully changed account state to PREMIUM!"; + public String PREMIUM_USAGE = "{PRFX} Usage: &6/premium <current password> confirm"; + public String NOT_PREMIUM = "{PRFX} Your account is not PREMIUM"; + public String ALREADY_PREMIUM = "{PRFX} Your account is already PREMIUM"; + public String FORCE_UNREGISTER_SUCCESSFUL = "{PRFX} &a{0} successfully unregistered!"; public String FORCE_UNREGISTER_KICK = "{PRFX}{NL}&aYou have been unregistered by administrator!"; public String FORCE_UNREGISTER_NOT_SUCCESSFUL = "{PRFX} &cUnable to unregister {0}. Most likely this player has never been on this server."; diff --git a/src/main/java/net/elytrium/limboauth/command/ChangePasswordCommand.java b/src/main/java/net/elytrium/limboauth/command/ChangePasswordCommand.java index 2373938..abda93d 100644 --- a/src/main/java/net/elytrium/limboauth/command/ChangePasswordCommand.java +++ b/src/main/java/net/elytrium/limboauth/command/ChangePasswordCommand.java @@ -78,8 +78,8 @@ public class ChangePasswordCommand implements SimpleCommand { try { UpdateBuilder<RegisteredPlayer, String> updateBuilder = this.playerDao.updateBuilder(); - updateBuilder.where().eq("nickname", ((Player) source).getUsername()); - updateBuilder.updateColumnValue("hash", AuthSessionHandler.genHash(this.needOldPass ? args[1] : args[0])); + updateBuilder.where().eq("NICKNAME", ((Player) source).getUsername()); + updateBuilder.updateColumnValue("HASH", AuthSessionHandler.genHash(this.needOldPass ? args[1] : args[0])); updateBuilder.update(); source.sendMessage(this.successful); diff --git a/src/main/java/net/elytrium/limboauth/command/PremiumCommand.java b/src/main/java/net/elytrium/limboauth/command/PremiumCommand.java new file mode 100644 index 0000000..7b209c5 --- /dev/null +++ b/src/main/java/net/elytrium/limboauth/command/PremiumCommand.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2021 Elytrium + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package net.elytrium.limboauth.command; + +import com.j256.ormlite.dao.Dao; +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 java.sql.SQLException; +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 PremiumCommand implements SimpleCommand { + + private final LimboAuth plugin; + private final Dao<RegisteredPlayer, String> playerDao; + + private final Component notPlayer; + private final Component notPremium; + private final Component alreadyPremium; + private final Component notRegistered; + private final Component successful; + private final Component errorOccurred; + private final Component wrongPassword; + private final Component usage; + + public PremiumCommand(LimboAuth plugin, Dao<RegisteredPlayer, String> playerDao) { + this.plugin = plugin; + this.playerDao = playerDao; + + this.notPlayer = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_PLAYER); + this.notPremium = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_PREMIUM); + this.alreadyPremium = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.ALREADY_PREMIUM); + this.notRegistered = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_REGISTERED); + this.successful = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.PREMIUM_SUCCESSFUL); + this.errorOccurred = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.ERROR_OCCURRED); + this.wrongPassword = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.WRONG_PASSWORD); + this.usage = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.PREMIUM_USAGE); + } + + @Override + public void execute(SimpleCommand.Invocation invocation) { + CommandSource source = invocation.source(); + String[] args = invocation.arguments(); + + if (!(source instanceof Player)) { + source.sendMessage(this.notPlayer); + return; + } + + if (args.length == 2) { + if (args[1].equalsIgnoreCase("confirm")) { + String username = ((Player) source).getUsername(); + RegisteredPlayer player = AuthSessionHandler.fetchInfo(this.playerDao, username); + if (player == null) { + source.sendMessage(this.notRegistered); + } else if (player.getHash().isEmpty()) { + source.sendMessage(this.alreadyPremium); + } else if (AuthSessionHandler.checkPassword(args[0], player, this.playerDao)) { + if (this.plugin.isPremiumExternal(username)) { + try { + player.setHash(""); + this.playerDao.update(player); + this.plugin.removePlayerFromCache(username); + ((Player) source).disconnect(this.successful); + } catch (SQLException e) { + source.sendMessage(this.errorOccurred); + e.printStackTrace(); + } + } else { + source.sendMessage(this.notPremium); + } + } else { + source.sendMessage(this.wrongPassword); + } + + return; + } + } + + source.sendMessage(this.usage); + } + + @Override + public boolean hasPermission(SimpleCommand.Invocation invocation) { + return invocation.source().getPermissionValue("limboauth.commands.unregister") != Tristate.FALSE; + } +} diff --git a/src/main/java/net/elytrium/limboauth/command/TotpCommand.java b/src/main/java/net/elytrium/limboauth/command/TotpCommand.java index d51da7d..d7306bd 100644 --- a/src/main/java/net/elytrium/limboauth/command/TotpCommand.java +++ b/src/main/java/net/elytrium/limboauth/command/TotpCommand.java @@ -121,8 +121,8 @@ public class TotpCommand implements SimpleCommand { try { updateBuilder = this.playerDao.updateBuilder(); - updateBuilder.where().eq("nickname", username); - updateBuilder.updateColumnValue("totpToken", secret); + updateBuilder.where().eq("NICKNAME", username); + updateBuilder.updateColumnValue("TOTPTOKEN", secret); updateBuilder.update(); } catch (SQLException e) { source.sendMessage(this.errorOccurred); @@ -175,8 +175,8 @@ public class TotpCommand implements SimpleCommand { if (AuthSessionHandler.getVerifier().isValidCode(playerInfo.getTotpToken(), args[1])) { try { updateBuilder = this.playerDao.updateBuilder(); - updateBuilder.where().eq("nickname", username); - updateBuilder.updateColumnValue("totpToken", ""); + updateBuilder.where().eq("NICKNAME", username); + updateBuilder.updateColumnValue("TOTPTOKEN", ""); updateBuilder.update(); source.sendMessage(this.disabled); diff --git a/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java b/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java index 59f5074..9619b2d 100644 --- a/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java +++ b/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java @@ -68,11 +68,11 @@ public class AuthSessionHandler implements LimboSessionHandler { private int attempts = Settings.IMP.MAIN.LOGIN_ATTEMPTS; private boolean totp = false; - public AuthSessionHandler(Dao<RegisteredPlayer, String> playerDao, Player proxyPlayer, LimboAuth plugin, String lowercaseNickname) { + public AuthSessionHandler(Dao<RegisteredPlayer, String> playerDao, Player proxyPlayer, LimboAuth plugin, RegisteredPlayer playerInfo) { this.playerDao = playerDao; this.proxyPlayer = proxyPlayer; - this.playerInfo = this.fetchInfo(lowercaseNickname); this.plugin = plugin; + this.playerInfo = playerInfo; } @Override @@ -203,10 +203,6 @@ public class AuthSessionHandler implements LimboSessionHandler { return (playerList != null ? playerList.size() : 0) == 0 ? null : playerList.get(0); } - private RegisteredPlayer fetchInfo(String nickname) { - return fetchInfo(this.playerDao, nickname); - } - public static CodeVerifier getVerifier() { return verifier; } diff --git a/src/main/java/net/elytrium/limboauth/listener/AuthListener.java b/src/main/java/net/elytrium/limboauth/listener/AuthListener.java index 4189c12..0b0db2c 100644 --- a/src/main/java/net/elytrium/limboauth/listener/AuthListener.java +++ b/src/main/java/net/elytrium/limboauth/listener/AuthListener.java @@ -43,7 +43,7 @@ public class AuthListener { @Subscribe public void onProxyConnect(PreLoginEvent event) { if (!event.getResult().isForceOfflineMode()) { - if (Settings.IMP.MAIN.ONLINE_MODE_NEED_AUTH || !LimboAuth.getInstance().isPremium(event.getUsername())) { + if (!LimboAuth.getInstance().isPremium(event.getUsername())) { event.setResult(PreLoginEvent.PreLoginComponentResult.forceOfflineMode()); } else { event.setResult(PreLoginEvent.PreLoginComponentResult.forceOnlineMode()); @@ -73,22 +73,18 @@ public class AuthListener { if (registeredPlayer != null) { String currentUuid = registeredPlayer.getUuid(); - if (event.isOnlineMode()) { + if (event.isOnlineMode() + && registeredPlayer.getHash().isEmpty() + && registeredPlayer.getPremiumUuid().isEmpty()) { try { registeredPlayer.setPremiumUuid(event.getOriginalProfile().getId().toString()); - registeredPlayer.setHash(""); - - if (currentUuid.isEmpty()) { - registeredPlayer.setUuid(UuidUtils.generateOfflinePlayerUuid(event.getUsername()).toString()); - } - this.playerDao.update(registeredPlayer); } catch (SQLException e) { e.printStackTrace(); } + } - event.setGameProfile(event.getOriginalProfile().withId(UUID.fromString(currentUuid))); - } else if (currentUuid.isEmpty()) { + if (currentUuid.isEmpty()) { try { registeredPlayer.setUuid(event.getGameProfile().getId().toString()); this.playerDao.update(registeredPlayer); @@ -96,19 +92,21 @@ public class AuthListener { ex.printStackTrace(); } } + + event.setGameProfile(event.getOriginalProfile().withId(UUID.fromString(currentUuid))); } } else if (event.isOnlineMode()) { try { UpdateBuilder<RegisteredPlayer, String> updateBuilder = this.playerDao.updateBuilder(); - updateBuilder.where().eq("nickname", event.getUsername()); - updateBuilder.updateColumnValue("hash", ""); + updateBuilder.where().eq("NICKNAME", event.getUsername()); + updateBuilder.updateColumnValue("HASH", ""); updateBuilder.update(); } catch (SQLException e) { e.printStackTrace(); } } - if (!Settings.IMP.MAIN.FORCE_OFFLINE_UUID) { + if (Settings.IMP.MAIN.FORCE_OFFLINE_UUID) { event.setGameProfile(event.getOriginalProfile().withId(UuidUtils.generateOfflinePlayerUuid(event.getUsername()))); } } |