diff options
| author | Petr Ilin <hevav@hevav.dev> | 2021-12-24 19:06:43 +0300 | 
|---|---|---|
| committer | mdxd44 <ogurec332@mail.ru> | 2021-12-27 18:27:50 +0900 | 
| commit | cc2ccfbe22044e98a66257488cf5bd26e21ca340 (patch) | |
| tree | f451d85b385788f8ed906e89c34c714b1d35b57f /src/main/java/net/elytrium | |
| parent | 6ff5931596633aa842877c9f7bea04b11c5353a8 (diff) | |
| download | LimboAuth-cc2ccfbe22044e98a66257488cf5bd26e21ca340.tar.gz LimboAuth-cc2ccfbe22044e98a66257488cf5bd26e21ca340.tar.bz2 LimboAuth-cc2ccfbe22044e98a66257488cf5bd26e21ca340.zip | |
Fixes of PREMIUM feature. (Closed LimboAPI#31)
Diffstat (limited to 'src/main/java/net/elytrium')
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())));      }    } | 
