aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/net')
-rw-r--r--src/main/java/net/elytrium/limboauth/LimboAuth.java51
-rw-r--r--src/main/java/net/elytrium/limboauth/Settings.java76
-rw-r--r--src/main/java/net/elytrium/limboauth/command/DestroySessionCommand.java2
-rw-r--r--src/main/java/net/elytrium/limboauth/command/ForceUnregisterCommand.java8
-rw-r--r--src/main/java/net/elytrium/limboauth/command/UnregisterCommand.java7
-rw-r--r--src/main/java/net/elytrium/limboauth/config/Config.java15
-rw-r--r--src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java182
-rw-r--r--src/main/java/net/elytrium/limboauth/listener/AuthListener.java1
8 files changed, 254 insertions, 88 deletions
diff --git a/src/main/java/net/elytrium/limboauth/LimboAuth.java b/src/main/java/net/elytrium/limboauth/LimboAuth.java
index a901bc2..ba29a20 100644
--- a/src/main/java/net/elytrium/limboauth/LimboAuth.java
+++ b/src/main/java/net/elytrium/limboauth/LimboAuth.java
@@ -33,6 +33,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;
@@ -40,7 +41,9 @@ import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
+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.Collections;
@@ -54,6 +57,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import net.elytrium.limboapi.api.Limbo;
import net.elytrium.limboapi.api.LimboFactory;
import net.elytrium.limboapi.api.chunk.Dimension;
@@ -82,6 +86,7 @@ import org.slf4j.Logger;
authors = {"hevav", "mdxd44"},
dependencies = {@Dependency(id = "limboapi")}
)
+@SuppressFBWarnings({"EI_EXPOSE_REP", "MS_EXPOSE_REP"})
public class LimboAuth {
private static LimboAuth instance;
@@ -92,11 +97,12 @@ public class LimboAuth {
private final ProxyServer server;
private final LimboFactory factory;
+ private final Set<String> unsafePasswords = new HashSet<>();
+ private Map<String, CachedUser> cachedAuthChecks;
private Dao<RegisteredPlayer, String> playerDao;
+ private Pattern nicknameValidationPattern;
private Limbo authServer;
- private Map<String, CachedUser> cachedAuthChecks;
private Component nicknameInvalid;
- private Pattern nicknameValidationPattern;
@Inject
@SuppressWarnings("OptionalGetWithoutIsPresent")
@@ -110,7 +116,7 @@ public class LimboAuth {
}
@Subscribe
- public void onProxyInitialization(ProxyInitializeEvent event) throws SQLException {
+ public void onProxyInitialization(ProxyInitializeEvent event) throws Exception {
System.setProperty("com.j256.simplelogging.level", "ERROR");
this.reload();
@@ -119,20 +125,29 @@ public class LimboAuth {
}
@SuppressWarnings("SwitchStatementWithTooFewBranches")
- public void reload() throws SQLException {
+ public void reload() throws Exception {
Settings.IMP.reload(new File(this.dataDirectory.toFile().getAbsoluteFile(), "config.yml"));
+ if (Settings.IMP.MAIN.CHECK_PASSWORD_STRENGTH) {
+ this.unsafePasswords.clear();
+ Path unsafePasswordsFile = Paths.get(this.dataDirectory.toFile().getAbsolutePath(), Settings.IMP.MAIN.UNSAFE_PASSWORDS_FILE);
+ if (!unsafePasswordsFile.toFile().exists()) {
+ Files.copy(Objects.requireNonNull(this.getClass().getResourceAsStream("/unsafe_passwords.txt")), unsafePasswordsFile);
+ }
+
+ this.unsafePasswords.addAll(Files.lines(unsafePasswordsFile).collect(Collectors.toSet()));
+ }
+
this.cachedAuthChecks = new ConcurrentHashMap<>();
Settings.DATABASE dbConfig = Settings.IMP.DATABASE;
-
JdbcPooledConnectionSource connectionSource;
// 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);
- connectionSource = new JdbcPooledConnectionSource("jdbc:h2:" + this.dataDirectory.toFile().getAbsoluteFile() + "/" + "limboauth");
+ connectionSource = new JdbcPooledConnectionSource("jdbc:h2:" + this.dataDirectory.toFile().getAbsoluteFile() + "/limboauth");
break;
}
case "mysql": {
@@ -212,7 +227,7 @@ public class LimboAuth {
this.authServer = this.factory.createLimbo(authWorld);
- this.nicknameInvalid = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NICKNAME_INVALID);
+ this.nicknameInvalid = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NICKNAME_INVALID_KICK);
this.server.getEventManager().unregisterListeners(this);
this.server.getEventManager().register(this, new AuthListener(this.playerDao));
@@ -280,8 +295,8 @@ public class LimboAuth {
this.cachedAuthChecks.put(username, new CachedUser(player.getRemoteAddress().getAddress(), System.currentTimeMillis()));
}
- public void removePlayerFromCache(Player player) {
- this.cachedAuthChecks.remove(player.getUsername());
+ public void removePlayerFromCache(String username) {
+ this.cachedAuthChecks.remove(username);
}
public boolean needAuth(Player player) {
@@ -312,7 +327,7 @@ public class LimboAuth {
// Send player to auth virtual server.
try {
- this.authServer.spawnPlayer(player, new AuthSessionHandler(this.playerDao, player, nickname));
+ this.authServer.spawnPlayer(player, new AuthSessionHandler(this.playerDao, player, this, nickname));
} catch (Throwable t) {
this.getLogger().error("Error", t);
}
@@ -331,10 +346,6 @@ public class LimboAuth {
}
}
- public Logger getLogger() {
- return this.logger;
- }
-
private void checkCache(Map<String, CachedUser> userMap, long time) {
userMap.entrySet().stream()
.filter(u -> u.getValue().getCheckTime() + time <= System.currentTimeMillis())
@@ -350,6 +361,18 @@ public class LimboAuth {
return instance;
}
+ public Set<String> getUnsafePasswords() {
+ return this.unsafePasswords;
+ }
+
+ public Logger getLogger() {
+ return this.logger;
+ }
+
+ public ProxyServer getServer() {
+ return this.server;
+ }
+
private static class CachedUser {
private final InetAddress inetAddress;
diff --git a/src/main/java/net/elytrium/limboauth/Settings.java b/src/main/java/net/elytrium/limboauth/Settings.java
index 9e59830..0886cdf 100644
--- a/src/main/java/net/elytrium/limboauth/Settings.java
+++ b/src/main/java/net/elytrium/limboauth/Settings.java
@@ -35,7 +35,18 @@ public class Settings extends Config {
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.")
+ public int AUTH_TIME = 60000;
public boolean ENABLE_BOSSBAR = true;
+ @Comment("Available colors: PINK, BLUE, RED, GREEN, YELLOW, PURPLE, WHITE")
+ public String BOSSBAR_COLOR = "RED";
+ @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 символу.")
+ public int MAX_PASSWORD_LENGTH = 71;
+ public boolean CHECK_PASSWORD_STRENGTH = true;
+ public String UNSAFE_PASSWORDS_FILE = "unsafe_passwords.txt";
public boolean ONLINE_MODE_NEED_AUTH = true;
public boolean FORCE_OFFLINE_UUID = false;
@Comment({
@@ -48,8 +59,8 @@ public class Settings extends Config {
public boolean REGISTER_NEED_REPEAT_PASSWORD = true;
public boolean CHANGE_PASSWORD_NEED_OLD_PASSWORD = true;
@Comment({
- "If you want to migrate your database from another plugin, which is not using BCrypt",
- "You can set an old hash algorithm to migrate from. Currently, only AUTHME is supported yet"
+ "If you want to migrate your database from another plugin, which is not using BCrypt.",
+ "You can set an old hash algorithm to migrate from. Currently, only AUTHME is supported yet."
})
public String MIGRATION_HASH = "";
@Comment("Available dimensions: OVERWORLD, NETHER, THE_END")
@@ -62,7 +73,7 @@ public class Settings extends Config {
public int LOGIN_ATTEMPTS = 3;
public int IP_LIMIT_REGISTRATIONS = 3;
public int TOTP_RECOVERY_CODES_AMOUNT = 16;
- @Comment("Time in milliseconds, when ip limit works, set to 0 for disable")
+ @Comment("Time in milliseconds, when ip limit works, set to 0 for disable.")
public long IP_LIMIT_VALID_TIME = 21600000;
@Comment({
"Regex of allowed nicknames",
@@ -95,10 +106,23 @@ public class Settings extends Config {
public int Z = 0;
}
+ /*
+ @Create
+ public Settings.MAIN.EVENTS_PRIORITIES EVENTS_PRIORITIES;
+
+ @Comment("Available priorities: FIRST, EARLY, NORMAL, LATE, LAST")
+ public static class EVENTS_PRIORITIES {
+
+ public String PRE_LOGIN = "NORMAL";
+ public String LOGIN_LIMBO_REGISTER = "NORMAL";
+ public String SAFE_GAME_PROFILE_REQUEST = "NORMAL";
+ }
+ */
+
@Create
public MAIN.STRINGS STRINGS;
- //@Comment("Leave empty to disable.")
+ @Comment("Leave title fields empty to disable.")
public static class STRINGS {
public String RELOAD = "{PRFX} &aReloaded successfully!";
@@ -109,31 +133,41 @@ public class Settings extends Config {
public String NOT_REGISTERED = "{PRFX} &cYou are not registered!";
public String WRONG_PASSWORD = "{PRFX} &cPassword is wrong!";
- public String NICKNAME_INVALID = "{NL}{NL}&cYour nickname contains forbidden characters. Please, change your nickname!";
+ 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 WRONG_NICKNAME_CASE = "{NL}{NL}&cThe case of your nickname is wrong. Nickname is CaSe SeNsItIvE.";
+ public String WRONG_NICKNAME_CASE_KICK = "{PRFX}{NL}&cThe case of your nickname is wrong. Nickname is CaSe SeNsItIvE.";
- public String LOGIN = "{PRFX} Please, login using &6/login &6<password>. You have &6{0} &cattempts.";
- public String LOGIN_SUCCESS = "{PRFX} &aSuccessfully logged in!";
- public String LOGIN_WRONG_PASSWORD = "{PRFX} &cYou've entered the wrong password. You have &6{0} &cattempts left.";
- public String LOGIN_TITLE = "";
- public String LOGIN_SUBTITLE = "";
- public String LOGIN_SUCCESS_TITLE = "";
- public String LOGIN_SUCCESS_SUBTITLE = "";
+ public String BOSSBAR = "{PRFX} У вас осталось &6{0} &fсекунд чтобы авторизироваться.";
+ public String TIMES_UP = "{PRFX}{NL}&cВремя авторизации вышло.";
+
+ 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.";
+ public String LOGIN_WRONG_PASSWORD_KICK = "{PRFX}{NL}&cYou've entered the wrong password numerous times!";
+ public String LOGIN_SUCCESSFUL = "{PRFX} &aSuccessfully logged in!";
+ public String LOGIN_TITLE = "&fPlease, login using &6/login <password>&a.";
+ public String LOGIN_SUBTITLE = "&aYou have &6{0} &aattempts.";
+ public String LOGIN_SUCCESSFUL_TITLE = "{PRFX}";
+ public String LOGIN_SUCCESSFUL_SUBTITLE = "&aSuccessfully logged in!";
@Comment("Or if register-need-repeat-password set to false remove the \"<repeat password>\" part.")
public String REGISTER = "{PRFX} Please, register using &6/register <password> <repeat password>";
- public String REGISTER_TITLE = "";
- public String REGISTER_SUBTITLE = "";
- public String DIFFERENT_PASSWORDS = "{PRFX} The entered passwords differ from each other.";
- public String KICK_PASSWORD_WRONG = "{NL}{NL}&cYou've entered the wrong password numerous times!";
-
- public String UNREGISTER_SUCCESSFUL = "{PRFX}{NL}{NL}&aSuccessfully unregistered!";
+ public String REGISTER_DIFFERENT_PASSWORDS = "{PRFX} &cThe entered passwords differ from each other!";
+ public String REGISTER_PASSWORD_TOO_SHORT = "{PRFX} &cYou entered too short password, use a different one!";
+ 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!";
+ public String REGISTER_TITLE = "{PRFX}";
+ public String REGISTER_SUBTITLE = "&aPlease, register using &6/register <password> <repeat password>";
+ public String REGISTER_SUCCESSFUL_TITLE = "{PRFX}";
+ public String REGISTER_SUCCESSFUL_SUBTITLE = "&aSuccessfully registered!";
+
+ public String UNREGISTER_SUCCESSFUL = "{PRFX}{NL}&aSuccessfully unregistered!";
public String UNREGISTER_USAGE = "{PRFX} Usage: &6/unregister <current password> confirm";
public String FORCE_UNREGISTER_SUCCESSFUL = "{PRFX} &a{0} successfully unregistered!";
- public String FORCE_UNREGISTER_SUCCESSFUL_PLAYER = "{PRFX}{NL}{NL}&aYou have been unregistered by administrator!";
+ 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.";
public String FORCE_UNREGISTER_USAGE = "{PRFX} Usage: &6/forceunregister <nickname>";
@@ -142,6 +176,8 @@ public class Settings extends Config {
public String CHANGE_PASSWORD_USAGE = "{PRFX} Usage: &6/changepassword <old password> <new password>";
public String TOTP = "{PRFX} Please, enter your 2FA key using &6/2fa <key>";
+ public String TOTP_TITLE = "{PRFX}";
+ public String TOTP_SUBTITLE = "&aEnter your 2FA key using &6/2fa <key>";
public String TOTP_SUCCESSFUL = "{PRFX} &aSuccessfully enabled 2FA!";
public String TOTP_DISABLED = "{PRFX} &aSuccessfully disabled 2FA!";
@Comment("Or if totp-need-pass set to false remove the \"<current password>\" part.")
diff --git a/src/main/java/net/elytrium/limboauth/command/DestroySessionCommand.java b/src/main/java/net/elytrium/limboauth/command/DestroySessionCommand.java
index 27dff72..b0e6cf4 100644
--- a/src/main/java/net/elytrium/limboauth/command/DestroySessionCommand.java
+++ b/src/main/java/net/elytrium/limboauth/command/DestroySessionCommand.java
@@ -49,7 +49,7 @@ public class DestroySessionCommand implements SimpleCommand {
return;
}
- this.plugin.removePlayerFromCache((Player) source);
+ this.plugin.removePlayerFromCache(((Player) source).getUsername());
source.sendMessage(this.successful);
}
diff --git a/src/main/java/net/elytrium/limboauth/command/ForceUnregisterCommand.java b/src/main/java/net/elytrium/limboauth/command/ForceUnregisterCommand.java
index d45eae9..2b97143 100644
--- a/src/main/java/net/elytrium/limboauth/command/ForceUnregisterCommand.java
+++ b/src/main/java/net/elytrium/limboauth/command/ForceUnregisterCommand.java
@@ -40,7 +40,7 @@ public class ForceUnregisterCommand implements SimpleCommand {
private final ProxyServer server;
private final Dao<RegisteredPlayer, String> playerDao;
- private final Component successfulPlayer;
+ private final Component kick;
private final String successful;
private final String notSuccessful;
private final Component usage;
@@ -50,7 +50,7 @@ public class ForceUnregisterCommand implements SimpleCommand {
this.server = server;
this.playerDao = playerDao;
- this.successfulPlayer = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.FORCE_UNREGISTER_SUCCESSFUL_PLAYER);
+ this.kick = LegacyComponentSerializer.legacyAmpersand().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);
@@ -83,9 +83,9 @@ public class ForceUnregisterCommand implements SimpleCommand {
String playerNick = args[0];
try {
this.playerDao.deleteById(playerNick.toLowerCase(Locale.ROOT));
+ this.plugin.removePlayerFromCache(playerNick);
this.server.getPlayer(playerNick).ifPresent(player -> {
- this.plugin.removePlayerFromCache(player);
- player.disconnect(this.successfulPlayer);
+ player.disconnect(this.kick);
});
source.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(MessageFormat.format(this.successful, playerNick)));
} catch (SQLException e) {
diff --git a/src/main/java/net/elytrium/limboauth/command/UnregisterCommand.java b/src/main/java/net/elytrium/limboauth/command/UnregisterCommand.java
index aeab6ec..5fe8643 100644
--- a/src/main/java/net/elytrium/limboauth/command/UnregisterCommand.java
+++ b/src/main/java/net/elytrium/limboauth/command/UnregisterCommand.java
@@ -67,13 +67,14 @@ public class UnregisterCommand implements SimpleCommand {
if (args.length == 2) {
if (args[1].equalsIgnoreCase("confirm")) {
- RegisteredPlayer player = AuthSessionHandler.fetchInfo(this.playerDao, ((Player) source).getUsername());
+ String username = ((Player) source).getUsername();
+ RegisteredPlayer player = AuthSessionHandler.fetchInfo(this.playerDao, username);
if (player == null) {
source.sendMessage(this.notRegistered);
} else if (AuthSessionHandler.checkPassword(args[0], player, this.playerDao)) {
try {
- this.playerDao.deleteById(((Player) source).getUsername().toLowerCase(Locale.ROOT));
- this.plugin.removePlayerFromCache((Player) source);
+ this.playerDao.deleteById(username.toLowerCase(Locale.ROOT));
+ this.plugin.removePlayerFromCache(username);
((Player) source).disconnect(this.successful);
} catch (SQLException e) {
source.sendMessage(this.errorOccurred);
diff --git a/src/main/java/net/elytrium/limboauth/config/Config.java b/src/main/java/net/elytrium/limboauth/config/Config.java
index ed5b007..1cb9803 100644
--- a/src/main/java/net/elytrium/limboauth/config/Config.java
+++ b/src/main/java/net/elytrium/limboauth/config/Config.java
@@ -208,7 +208,7 @@ public class Config {
}
}
- private void save(PrintWriter writer, Class<?> clazz, final Object instance, int indent) {
+ private void save(PrintWriter writer, Class<?> clazz, Object instance, int indent) {
try {
String lineSeparator = System.lineSeparator();
String spacing = this.repeat(" ", indent);
@@ -356,9 +356,14 @@ public class Config {
private void setAccessible(Field field) throws NoSuchFieldException, IllegalAccessException {
field.setAccessible(true);
if (Modifier.isFinal(field.getModifiers())) {
- Field modifiersField = Field.class.getDeclaredField("modifiers");
- modifiersField.setAccessible(true);
- modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+ if (Runtime.version().feature() < 12) {
+ Field modifiersField = Field.class.getDeclaredField("modifiers");
+ modifiersField.setAccessible(true);
+ modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+ } else {
+ // TODO: Maybe use sun.misc.Unsafe?...
+ throw new UnsupportedOperationException();
+ }
}
}
@@ -377,7 +382,7 @@ public class Config {
return array[0].toString();
}
default: {
- final StringBuilder result = new StringBuilder();
+ StringBuilder result = new StringBuilder();
for (int i = 0, j = array.length; i < j; ++i) {
if (i > 0) {
result.append(delimiter);
diff --git a/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java b/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java
index 38a464d..59f5074 100644
--- a/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java
+++ b/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java
@@ -20,6 +20,7 @@ package net.elytrium.limboauth.handler;
import at.favre.lib.crypto.bcrypt.BCrypt;
import com.j256.ormlite.dao.Dao;
import com.velocitypowered.api.proxy.Player;
+import com.velocitypowered.api.scheduler.ScheduledTask;
import dev.samstevens.totp.code.CodeVerifier;
import dev.samstevens.totp.code.DefaultCodeGenerator;
import dev.samstevens.totp.code.DefaultCodeVerifier;
@@ -30,6 +31,7 @@ import java.text.MessageFormat;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import net.elytrium.limboapi.api.Limbo;
import net.elytrium.limboapi.api.LimboSessionHandler;
@@ -38,7 +40,10 @@ import net.elytrium.limboauth.LimboAuth;
import net.elytrium.limboauth.Settings;
import net.elytrium.limboauth.migration.MigrationHash;
import net.elytrium.limboauth.model.RegisteredPlayer;
+import net.kyori.adventure.bossbar.BossBar;
+import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+import net.kyori.adventure.title.Title;
public class AuthSessionHandler implements LimboSessionHandler {
@@ -47,16 +52,27 @@ public class AuthSessionHandler implements LimboSessionHandler {
private final Dao<RegisteredPlayer, String> playerDao;
private final Player proxyPlayer;
private final RegisteredPlayer playerInfo;
+ private final LimboAuth plugin;
+
+ private final long joinTime = System.currentTimeMillis();
+ private final BossBar bossBar = BossBar.bossBar(
+ Component.empty(),
+ 1,
+ BossBar.Color.valueOf(Settings.IMP.MAIN.BOSSBAR_COLOR.toUpperCase(Locale.ROOT)),
+ BossBar.Overlay.valueOf(Settings.IMP.MAIN.BOSSBAR_OVERLAY.toUpperCase(Locale.ROOT))
+ );
+ private ScheduledTask authMainTask;
private LimboPlayer player;
private String ip;
private int attempts = Settings.IMP.MAIN.LOGIN_ATTEMPTS;
private boolean totp = false;
- public AuthSessionHandler(Dao<RegisteredPlayer, String> playerDao, Player proxyPlayer, String lowercaseNickname) {
+ public AuthSessionHandler(Dao<RegisteredPlayer, String> playerDao, Player proxyPlayer, LimboAuth plugin, String lowercaseNickname) {
this.playerDao = playerDao;
this.proxyPlayer = proxyPlayer;
this.playerInfo = this.fetchInfo(lowercaseNickname);
+ this.plugin = plugin;
}
@Override
@@ -71,7 +87,24 @@ public class AuthSessionHandler implements LimboSessionHandler {
this.checkCase();
}
- this.sendMessage();
+ boolean bossBarEnabled = Settings.IMP.MAIN.ENABLE_BOSSBAR;
+ float bossBarMultiplier = 1000F / Settings.IMP.MAIN.AUTH_TIME;
+ if (bossBarEnabled) {
+ this.proxyPlayer.showBossBar(this.bossBar);
+ }
+ this.authMainTask = this.plugin.getServer().getScheduler().buildTask(this.plugin, () -> {
+ if (System.currentTimeMillis() - this.joinTime > Settings.IMP.MAIN.AUTH_TIME) {
+ this.proxyPlayer.disconnect(this.deserialize(Settings.IMP.MAIN.STRINGS.TIMES_UP));
+ return;
+ }
+ if (bossBarEnabled) {
+ long timeSinceJoin = Settings.IMP.MAIN.AUTH_TIME - (System.currentTimeMillis() - AuthSessionHandler.this.joinTime);
+ this.bossBar.name(this.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.BOSSBAR, (int) (timeSinceJoin / 1000))));
+ this.bossBar.progress((timeSinceJoin * bossBarMultiplier) / 1000);
+ }
+ }).repeat(1, TimeUnit.SECONDS).schedule();
+
+ this.sendMessage(true);
}
@Override
@@ -82,11 +115,22 @@ public class AuthSessionHandler implements LimboSessionHandler {
case "/reg":
case "/register":
case "/r": {
- if (!this.totp && this.playerInfo == null && this.checkPasswordsRepeat(args)) {
- this.register(args[1]);
- this.finishAuth();
+ if (!this.totp && this.playerInfo == null) {
+ if (this.checkPasswordsRepeat(args) && this.checkPasswordLength(args[1]) && this.checkPasswordStrength(args[1])) {
+ this.register(args[1]);
+ this.proxyPlayer.sendMessage(this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_SUCCESSFUL));
+ if (!Settings.IMP.MAIN.STRINGS.REGISTER_SUCCESSFUL_TITLE.isEmpty() && !Settings.IMP.MAIN.STRINGS.REGISTER_SUCCESSFUL_SUBTITLE.isEmpty()) {
+ this.proxyPlayer.showTitle(
+ Title.title(
+ this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_SUCCESSFUL_TITLE),
+ this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_SUCCESSFUL_SUBTITLE)
+ )
+ );
+ }
+ this.finishAuth();
+ }
} else {
- this.sendMessage();
+ this.sendMessage(false);
}
break;
}
@@ -95,18 +139,14 @@ public class AuthSessionHandler implements LimboSessionHandler {
case "/l": {
if (!this.totp && this.playerInfo != null) {
if (this.checkPassword(args[1])) {
- this.finishOrTotp();
+ this.loginOrTotp();
} else if (--this.attempts != 0) {
- this.proxyPlayer.sendMessage(
- LegacyComponentSerializer.legacyAmpersand().deserialize(
- MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN_WRONG_PASSWORD, this.attempts)
- )
- );
+ this.proxyPlayer.sendMessage(this.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN_WRONG_PASSWORD, this.attempts)));
} else {
- this.proxyPlayer.disconnect(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.KICK_PASSWORD_WRONG));
+ this.proxyPlayer.disconnect(this.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_WRONG_PASSWORD_KICK));
}
} else {
- this.sendMessage();
+ this.sendMessage(false);
}
break;
}
@@ -114,23 +154,31 @@ public class AuthSessionHandler implements LimboSessionHandler {
case "/2fa": {
if (this.totp) {
if (verifier.isValidCode(this.playerInfo.getTotpToken(), args[1])) {
- this.finishAuth();
+ this.finishLogin();
} else {
- this.sendMessage();
+ this.sendMessage(false);
}
} else {
- this.sendMessage();
+ this.sendMessage(false);
}
break;
}
default: {
- this.sendMessage();
- break;
+ this.sendMessage(false);
}
}
} else {
- this.sendMessage();
+ this.sendMessage(false);
+ }
+ }
+
+ @Override
+ public void onDisconnect() {
+ if (this.authMainTask != null) {
+ this.authMainTask.cancel();
}
+
+ this.proxyPlayer.hideBossBar(this.bossBar);
}
public static RegisteredPlayer fetchInfo(Dao<RegisteredPlayer, String> playerDao, String nickname) {
@@ -163,10 +211,12 @@ public class AuthSessionHandler implements LimboSessionHandler {
return verifier;
}
+ private boolean checkPassword(String password) {
+ return checkPassword(password, this.playerInfo, this.playerDao);
+ }
+
public static boolean checkPassword(String password, RegisteredPlayer player, Dao<RegisteredPlayer, String> playerDao) {
- boolean isCorrect = BCrypt.verifyer().verify(
- password.getBytes(StandardCharsets.UTF_8), player.getHash().getBytes(StandardCharsets.UTF_8)
- ).verified;
+ boolean isCorrect = BCrypt.verifyer().verify(password.getBytes(StandardCharsets.UTF_8), player.getHash().getBytes(StandardCharsets.UTF_8)).verified;
if (!isCorrect && !Settings.IMP.MAIN.MIGRATION_HASH.isEmpty()) {
isCorrect = MigrationHash.valueOf(Settings.IMP.MAIN.MIGRATION_HASH).checkPassword(player.getHash(), password);
@@ -184,10 +234,6 @@ public class AuthSessionHandler implements LimboSessionHandler {
return isCorrect;
}
- private boolean checkPassword(String password) {
- return checkPassword(password, this.playerInfo, this.playerDao);
- }
-
private void checkIp() {
try {
List<RegisteredPlayer> alreadyRegistered = this.playerDao.queryForEq("IP", this.ip);
@@ -215,7 +261,7 @@ public class AuthSessionHandler implements LimboSessionHandler {
}
if (sizeOfValid.get() >= Settings.IMP.MAIN.IP_LIMIT_REGISTRATIONS) {
- this.proxyPlayer.disconnect(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.IP_LIMIT));
+ this.proxyPlayer.disconnect(this.deserialize(Settings.IMP.MAIN.STRINGS.IP_LIMIT));
}
} catch (SQLException e) {
e.printStackTrace();
@@ -224,7 +270,7 @@ public class AuthSessionHandler implements LimboSessionHandler {
private void checkCase() {
if (!this.proxyPlayer.getUsername().equals(this.playerInfo.getNickname())) {
- this.proxyPlayer.disconnect(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.WRONG_NICKNAME_CASE));
+ this.proxyPlayer.disconnect(this.deserialize(Settings.IMP.MAIN.STRINGS.WRONG_NICKNAME_CASE_KICK));
}
}
@@ -247,36 +293,86 @@ public class AuthSessionHandler implements LimboSessionHandler {
}
}
- private void finishOrTotp() {
+ private void loginOrTotp() {
if (this.playerInfo.getTotpToken().isEmpty()) {
- this.finishAuth();
+ this.finishLogin();
} else {
this.totp = true;
- this.sendMessage();
+ this.sendMessage(true);
}
}
+ private void finishLogin() {
+ this.proxyPlayer.sendMessage(this.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESSFUL));
+ if (!Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESSFUL_TITLE.isEmpty() && !Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESSFUL_SUBTITLE.isEmpty()) {
+ this.proxyPlayer.showTitle(
+ Title.title(
+ this.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESSFUL_TITLE),
+ this.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESSFUL_SUBTITLE)
+ )
+ );
+ }
+ this.finishAuth();
+ }
+
private void finishAuth() {
- this.proxyPlayer.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESS));
- LimboAuth.getInstance().cacheAuthUser(this.proxyPlayer);
+ this.plugin.cacheAuthUser(this.proxyPlayer);
this.player.disconnect();
}
- private void sendMessage() {
+ private void sendMessage(boolean sendTitle) {
if (this.totp) {
- this.proxyPlayer.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.TOTP));
+ this.proxyPlayer.sendMessage(this.deserialize(Settings.IMP.MAIN.STRINGS.TOTP));
+ if (sendTitle && !Settings.IMP.MAIN.STRINGS.TOTP_TITLE.isEmpty() && !Settings.IMP.MAIN.STRINGS.TOTP_SUBTITLE.isEmpty()) {
+ this.proxyPlayer.showTitle(
+ Title.title(this.deserialize(Settings.IMP.MAIN.STRINGS.TOTP_TITLE), this.deserialize(Settings.IMP.MAIN.STRINGS.TOTP_SUBTITLE))
+ );
+ }
} else if (this.playerInfo == null) {
- this.proxyPlayer.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.REGISTER));
+ this.proxyPlayer.sendMessage(this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER));
+ if (sendTitle && !Settings.IMP.MAIN.STRINGS.REGISTER_TITLE.isEmpty() && !Settings.IMP.MAIN.STRINGS.REGISTER_SUBTITLE.isEmpty()) {
+ this.proxyPlayer.showTitle(
+ Title.title(this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_TITLE), this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_SUBTITLE))
+ );
+ }
} else {
- this.proxyPlayer.sendMessage(
- LegacyComponentSerializer.legacyAmpersand().deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN, this.attempts))
- );
+ this.proxyPlayer.sendMessage(this.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN, this.attempts)));
+ if (sendTitle && !Settings.IMP.MAIN.STRINGS.LOGIN_TITLE.isEmpty() && !Settings.IMP.MAIN.STRINGS.LOGIN_SUBTITLE.isEmpty()) {
+ this.proxyPlayer.showTitle(
+ Title.title(
+ this.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN_TITLE, this.attempts)),
+ this.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN_SUBTITLE, this.attempts))
+ )
+ );
+ }
}
}
+ private boolean checkPasswordLength(String password) {
+ int length = password.length();
+ if (length > Settings.IMP.MAIN.MAX_PASSWORD_LENGTH) {
+ this.proxyPlayer.sendMessage(this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_PASSWORD_TOO_LONG));
+ return false;
+ } else if (length < Settings.IMP.MAIN.MIN_PASSWORD_LENGTH) {
+ this.proxyPlayer.sendMessage(this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_PASSWORD_TOO_SHORT));
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean checkPasswordStrength(String password) {
+ if (Settings.IMP.MAIN.CHECK_PASSWORD_STRENGTH && this.plugin.getUnsafePasswords().contains(password)) {
+ this.proxyPlayer.sendMessage(this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_PASSWORD_UNSAFE));
+ return false;
+ }
+
+ return true;
+ }
+
private boolean checkPasswordsRepeat(String[] args) {
if (Settings.IMP.MAIN.REGISTER_NEED_REPEAT_PASSWORD && !args[1].equals(args[2])) {
- this.proxyPlayer.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.DIFFERENT_PASSWORDS));
+ this.proxyPlayer.sendMessage(this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_DIFFERENT_PASSWORDS));
return false;
}
@@ -291,6 +387,10 @@ public class AuthSessionHandler implements LimboSessionHandler {
}
}
+ private Component deserialize(String text) {
+ return LegacyComponentSerializer.legacyAmpersand().deserialize(text);
+ }
+
public static String genHash(String password) {
return BCrypt.withDefaults().hashToString(Settings.IMP.MAIN.BCRYPT_COST, password.toCharArray());
}
diff --git a/src/main/java/net/elytrium/limboauth/listener/AuthListener.java b/src/main/java/net/elytrium/limboauth/listener/AuthListener.java
index 2892d79..4189c12 100644
--- a/src/main/java/net/elytrium/limboauth/listener/AuthListener.java
+++ b/src/main/java/net/elytrium/limboauth/listener/AuthListener.java
@@ -31,6 +31,7 @@ import net.elytrium.limboauth.Settings;
import net.elytrium.limboauth.handler.AuthSessionHandler;
import net.elytrium.limboauth.model.RegisteredPlayer;
+// TODO: Customizable events priority
public class AuthListener {
private final Dao<RegisteredPlayer, String> playerDao;