aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.gradle101
-rw-r--r--config/spotbugs/suppressions.xml7
-rw-r--r--gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--src/main/java/net/elytrium/limboauth/LimboAuth.java416
-rw-r--r--src/main/java/net/elytrium/limboauth/Settings.java64
-rw-r--r--src/main/java/net/elytrium/limboauth/command/ChangePasswordCommand.java81
-rw-r--r--src/main/java/net/elytrium/limboauth/command/DestroySessionCommand.java20
-rw-r--r--src/main/java/net/elytrium/limboauth/command/ForceChangePasswordCommand.java24
-rw-r--r--src/main/java/net/elytrium/limboauth/command/ForceUnregisterCommand.java22
-rw-r--r--src/main/java/net/elytrium/limboauth/command/LimboAuthCommand.java123
-rw-r--r--src/main/java/net/elytrium/limboauth/command/PremiumCommand.java84
-rw-r--r--src/main/java/net/elytrium/limboauth/command/TotpCommand.java125
-rw-r--r--src/main/java/net/elytrium/limboauth/command/UnregisterCommand.java76
-rw-r--r--src/main/java/net/elytrium/limboauth/config/Config.java393
-rw-r--r--src/main/java/net/elytrium/limboauth/event/AuthPluginReloadEvent.java1
-rw-r--r--src/main/java/net/elytrium/limboauth/event/AuthUnregisterEvent.java1
-rw-r--r--src/main/java/net/elytrium/limboauth/event/PostAuthorizationEvent.java7
-rw-r--r--src/main/java/net/elytrium/limboauth/event/PostEvent.java14
-rw-r--r--src/main/java/net/elytrium/limboauth/event/PostRegisterEvent.java7
-rw-r--r--src/main/java/net/elytrium/limboauth/event/PreAuthorizationEvent.java9
-rw-r--r--src/main/java/net/elytrium/limboauth/event/PreEvent.java9
-rw-r--r--src/main/java/net/elytrium/limboauth/event/PreRegisterEvent.java7
-rw-r--r--src/main/java/net/elytrium/limboauth/event/TaskEvent.java58
-rw-r--r--src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java564
-rw-r--r--src/main/java/net/elytrium/limboauth/listener/AuthListener.java8
-rw-r--r--src/main/java/net/elytrium/limboauth/migration/MigrationHash.java65
-rw-r--r--src/main/java/net/elytrium/limboauth/model/RegisteredPlayer.java3
-rw-r--r--src/main/java/net/elytrium/limboauth/utils/SuggestUtils.java42
-rw-r--r--src/main/java/net/elytrium/limboauth/utils/UpdatesChecker.java75
29 files changed, 1004 insertions, 1404 deletions
diff --git a/build.gradle b/build.gradle
index 30dedde..f5069f6 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,24 +3,24 @@
plugins {
id("java")
id("checkstyle")
- id("com.github.spotbugs").version("5.0.6")
+ id("maven-publish")
+ id("com.github.spotbugs").version("5.0.7")
id("org.cadixdev.licenser").version("0.6.1")
id("com.github.johnrengelman.shadow").version("7.1.2")
- id("maven-publish")
}
setGroup("net.elytrium")
setVersion("1.0.4-SNAPSHOT")
-compileJava {
- getOptions().setEncoding("UTF-8")
-}
-
java {
setSourceCompatibility(JavaVersion.VERSION_11)
setTargetCompatibility(JavaVersion.VERSION_11)
}
+compileJava {
+ getOptions().setEncoding("UTF-8")
+}
+
repositories {
mavenCentral()
@@ -38,39 +38,6 @@ repositories {
}
}
-task javadocJar(type: Jar) {
- getArchiveClassifier().set("javadoc")
- from(javadoc)
-}
-
-task sourcesJar(type: Jar) {
- getArchiveClassifier().set("sources")
- from(sourceSets.main.getAllSource())
-}
-
-publishing {
- repositories {
- maven {
- credentials {
- setUsername(System.getenv("PUBLISH_USERNAME"))
- setPassword(System.getenv("PUBLISH_PASSWORD"))
- }
-
- setName("elytrium-repo")
- setUrl("https://maven.elytrium.net/repo/")
- }
- }
-
- publications {
- maven(MavenPublication) {
- from(components.java)
-
- artifact(javadocJar)
- artifact(sourcesJar)
- }
- }
-}
-
dependencies {
compileOnly("net.elytrium:limboapi-api:1.0.4-SNAPSHOT")
@@ -85,13 +52,13 @@ dependencies {
implementation("com.j256.ormlite:ormlite-jdbc:6.1")
implementation("com.h2database:h2:1.4.200")
- implementation("mysql:mysql-connector-java:8.0.28")
- implementation("org.postgresql:postgresql:42.3.3")
+ implementation("mysql:mysql-connector-java:8.0.29")
+ implementation("org.postgresql:postgresql:42.3.5")
implementation("org.bstats:bstats-velocity:3.0.0")
implementation("de.mkammerer:argon2-jvm-nolibs:2.11")
- compileOnly("com.github.spotbugs:spotbugs-annotations:4.6.0")
+ compileOnly("com.github.spotbugs:spotbugs-annotations:4.7.0")
}
shadowJar {
@@ -171,6 +138,56 @@ spotbugsMain {
}
}
+task javadocJar(type: Jar) {
+ getArchiveClassifier().set("javadoc")
+ from(javadoc)
+}
+
+task sourcesJar(type: Jar) {
+ getArchiveClassifier().set("sources")
+ from(sourceSets.main.getAllSource())
+}
+
+publishing {
+ repositories {
+ maven {
+ credentials {
+ setUsername(System.getenv("PUBLISH_USERNAME"))
+ setPassword(System.getenv("PUBLISH_PASSWORD"))
+ }
+
+ setName("elytrium-repo")
+ setUrl("https://maven.elytrium.net/repo/")
+ }
+ }
+
+ publications {
+ maven(MavenPublication) {
+ from(getComponents().java)
+
+ artifact(javadocJar)
+ artifact(sourcesJar)
+ }
+ }
+}
+
+javadoc {
+ getOptions().setEncoding("UTF-8")
+ getOptions().setCharSet("UTF-8")
+ getOptions().setSource("11")
+ getOptions().links("https://docs.oracle.com/en/java/javase/11/docs/api/")
+
+ // Remove "undefined" from search paths when generating javadoc for a non-modular project. (JDK-8215291)
+ if (JavaVersion.current() == JavaVersion.VERSION_11) {
+ getOptions().addBooleanOption("-no-module-directories", true)
+ }
+}
+
+artifacts {
+ archives(javadocJar)
+ archives(sourcesJar)
+}
+
sourceSets.main.getJava().srcDir(getTasks().register("generateTemplates", Copy) { task ->
task.getInputs().properties("version": getVersion())
diff --git a/config/spotbugs/suppressions.xml b/config/spotbugs/suppressions.xml
index eb21bfb..833396e 100644
--- a/config/spotbugs/suppressions.xml
+++ b/config/spotbugs/suppressions.xml
@@ -7,4 +7,11 @@
<Match>
<Bug pattern="EI_EXPOSE_REP2"/>
</Match>
+ <Match>
+ <Bug pattern="THROWS_METHOD_THROWS_CLAUSE_BASIC_EXCEPTION"/>
+ </Match>
+ <!-- False-positive check for Try-Catch Block With Resources. -->
+ <Match>
+ <Bug pattern="RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE"/>
+ </Match>
</FindBugsFilter>
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 00e33ed..aa991fc 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
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<String, CachedSessionUser> cachedAuthChecks = new ConcurrentHashMap<>();
private final Map<String, CachedPremiumUser> premiumCache = new ConcurrentHashMap<>();
private final Map<UUID, Runnable> postLoginTasks = new ConcurrentHashMap<>();
private final Set<String> 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<RegisteredPlayer, String> 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<Component, Component, String> 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<String> 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<String> filterCommands(List<String> 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<String, ? extends CachedUser> 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<FieldType> 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<String[]> 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<String> 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<String> 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<TaskEvent> 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<TaskEvent> eventConsumer = (event) -> this.sendPlayer(event, null);
+ eventManager.fire(new PreRegisterEvent(eventConsumer, result, player)).thenAcceptAsync(eventConsumer);
+ } else {
+ Consumer<TaskEvent> eventConsumer = (event) -> this.sendPlayer(event, ((PreAuthorizationEvent) event).getPlayerInfo());
+ eventManager.fire(new PreAuthorizationEvent(eventConsumer, result, player, registeredPlayer)).thenAcceptAsync(eventConsumer);
+ }
} else {
- Consumer<TaskEvent> 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<RegisteredPlayer, String> premiumRegisteredQuery = this.playerDao.queryBuilder();
- premiumRegisteredQuery.where()
- .eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT))
- .and()
- .ne("HASH", "");
- premiumRegisteredQuery.setCountOf(true);
-
- QueryBuilder<RegisteredPlayer, String> 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<RegisteredPlayer, String> premiumRegisteredQuery = this.playerDao.queryBuilder();
+ premiumRegisteredQuery.where()
+ .eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT))
+ .and()
+ .ne("HASH", "");
+ premiumRegisteredQuery.setCountOf(true);
+
+ QueryBuilder<RegisteredPlayer, String> 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<String, ? extends CachedUser> userMap, long time) {
- userMap.entrySet().stream()
- .filter(u -> u.getValue().getCheckTime() + time <= System.currentTimeMillis())
- .map(Map.Entry::getKey)
- .forEach(userMap::remove);
+ public Map<UUID, Runnable> getPostLoginTasks() {
+ return this.postLoginTasks;
+ }
+
+ public Set<String> 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<String> 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<UUID, Runnable> 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<String> aliases;
-
- AuthCommandMeta(LimboAuth plugin, Collection<String> aliases) {
- this.plugin = plugin;
- this.aliases = aliases;
- }
-
- @Override
- public Collection<String> getAliases() {
- return this.aliases;
- }
-
- @Override
- public Collection<CommandNode<CommandSource>> 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 - \"<bold><red>Example</red> <blue>Text</blue></bold>\". (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 <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!";
- @Comment("*")
+ @Comment(value = "Can be empty.", at = Comment.At.SAME_LINE)
public String LOGIN_TITLE = "&fPlease, login using &6/login <password>&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 \"<repeat password>\" 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 <password> <repeat password>";
- @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 <nickname> <new password>";
public String TOTP = "{PRFX} Please, enter your 2FA key using &6/2fa <key>";
- @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 <key>";
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<RegisteredPlayer, String> 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<RegisteredPlayer, String> 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<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.update();
+ 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.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<String> 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<RegisteredPlayer, String> 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<String> 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<Component> 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<String, Component> 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 <player>", 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;
+ } else if (command.equalsIgnoreCase("playerstats") && source.hasPermission("limboauth.admin.playerstats")) {
+ source.sendMessage(Component.text("Please specify a player."));
+ return;
}
+ */
+ }
+ /*
+ else if (argsAmount == 2) {
+ if (command.equalsIgnoreCase("playerstats") && source.hasPermission("limboauth.admin.playerstats")) {
+ RegisteredPlayer player = AuthSessionHandler.fetchInfo(this.plugin.getPlayerDao(), args[1]);
+ if (player == null) {
+ source.sendMessage(Component.text("Игрок даезент екзистс."));
+ } else {
+ source.sendMessage(Component.text("Стата геймера под ником {player}:"));
+ source.sendMessage(Component.empty());
+ source.sendMessage(Component.text("Ласт айпи: " + player.getIP()));
+ source.sendMessage(Component.text("2fa: " + (player.getTotpToken().isEmpty() ? "Нет" : "Есть")));
+ }
- return;
+ return;
+ }
}
+ */
}
this.showHelp(source);
}
private void showHelp(CommandSource source) {
- source.sendMessage(Component.text("§eThis server is using LimboAuth and LimboAPI"));
- source.sendMessage(Component.text("§e(С) 2021 - 2022 Elytrium"));
- source.sendMessage(Component.text("§ahttps://ely.su/github/"));
- source.sendMessage(Component.text("§r"));
- source.sendMessage(Component.text("§fAvailable subcommands:"));
- // Java moment
- this.getSubCommands()
- .filter(cmd -> source.hasPermission("limboauth.admin." + cmd))
- .forEach(cmd -> {
- if (cmd.equals("reload")) {
- source.sendMessage(Component.text(" §a/limboauth reload §8- §eReload config"));
- }
- });
- }
-
- private Stream<String> getSubCommands() {
- return Stream.of("reload");
+ HELP_MESSAGE.forEach(source::sendMessage);
+ List<Map.Entry<String, Component>> availableSubcommands = SUBCOMMANDS.entrySet().stream()
+ .filter(command -> source.hasPermission("limboauth.admin." + command.getKey()))
+ .collect(Collectors.toList());
+ if (availableSubcommands.size() > 0) {
+ source.sendMessage(AVAILABLE_SUBCOMMANDS_MESSAGE);
+ availableSubcommands.forEach(command -> source.sendMessage(command.getValue()));
+ } else {
+ source.sendMessage(NO_AVAILABLE_SUBCOMMANDS_MESSAGE);
+ }
}
}
diff --git a/src/main/java/net/elytrium/limboauth/command/PremiumCommand.java b/src/main/java/net/elytrium/limboauth/command/PremiumCommand.java
index fd62a00..78674d0 100644
--- a/src/main/java/net/elytrium/limboauth/command/PremiumCommand.java
+++ b/src/main/java/net/elytrium/limboauth/command/PremiumCommand.java
@@ -23,19 +23,19 @@ 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 PremiumCommand implements SimpleCommand {
private final LimboAuth plugin;
private final Dao<RegisteredPlayer, String> playerDao;
- private final Component notPlayer;
+ private final String confirmKeyword;
private final Component notRegistered;
private final Component alreadyPremium;
private final Component successful;
@@ -43,19 +43,22 @@ public class PremiumCommand implements SimpleCommand {
private final Component notPremium;
private final Component wrongPassword;
private final Component usage;
+ private final Component notPlayer;
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.notRegistered = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_REGISTERED);
- this.alreadyPremium = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.ALREADY_PREMIUM);
- this.successful = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.PREMIUM_SUCCESSFUL);
- this.errorOccurred = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.ERROR_OCCURRED);
- this.notPremium = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_PREMIUM);
- this.wrongPassword = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.WRONG_PASSWORD);
- this.usage = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.PREMIUM_USAGE);
+ Serializer serializer = LimboAuth.getSerializer();
+ this.confirmKeyword = Settings.IMP.MAIN.CONFIRM_KEYWORD;
+ this.notRegistered = serializer.deserialize(Settings.IMP.MAIN.STRINGS.NOT_REGISTERED);
+ this.alreadyPremium = serializer.deserialize(Settings.IMP.MAIN.STRINGS.ALREADY_PREMIUM);
+ this.successful = serializer.deserialize(Settings.IMP.MAIN.STRINGS.PREMIUM_SUCCESSFUL);
+ this.errorOccurred = serializer.deserialize(Settings.IMP.MAIN.STRINGS.ERROR_OCCURRED);
+ this.notPremium = serializer.deserialize(Settings.IMP.MAIN.STRINGS.NOT_PREMIUM);
+ this.wrongPassword = serializer.deserialize(Settings.IMP.MAIN.STRINGS.WRONG_PASSWORD);
+ this.usage = serializer.deserialize(Settings.IMP.MAIN.STRINGS.PREMIUM_USAGE);
+ this.notPlayer = serializer.deserialize(Settings.IMP.MAIN.STRINGS.NOT_PLAYER);
}
@Override
@@ -63,46 +66,45 @@ public class PremiumCommand implements SimpleCommand {
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();
+ if (source instanceof Player) {
+ if (args.length == 2) {
+ if (this.confirmKeyword.equalsIgnoreCase(args[1])) {
+ 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.notPremium);
+ source.sendMessage(this.wrongPassword);
}
- } else {
- source.sendMessage(this.wrongPassword);
- }
- return;
+ return;
+ }
}
- }
- source.sendMessage(this.usage);
+ source.sendMessage(this.usage);
+ } else {
+ source.sendMessage(this.notPlayer);
+ }
}
@Override
public boolean hasPermission(SimpleCommand.Invocation invocation) {
- return invocation.source().getPermissionValue("limboauth.commands.premium") != Tristate.FALSE;
+ return invocation.source().getPermissionValue("limboauth.commands.premium") == Tristate.TRUE;
}
}
diff --git a/src/main/java/net/elytrium/limboauth/command/TotpCommand.java b/src/main/java/net/elytrium/limboauth/command/TotpCommand.java
index e9693ae..54d9c3e 100644
--- a/src/main/java/net/elytrium/limboauth/command/TotpCommand.java
+++ b/src/main/java/net/elytrium/limboauth/command/TotpCommand.java
@@ -31,12 +31,13 @@ import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.text.MessageFormat;
+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.event.ClickEvent;
-import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
public class TotpCommand implements SimpleCommand {
@@ -65,52 +66,49 @@ public class TotpCommand implements SimpleCommand {
public TotpCommand(Dao<RegisteredPlayer, String> playerDao) {
this.playerDao = playerDao;
- this.notPlayer = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_PLAYER);
- this.usage = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.TOTP_USAGE);
+ Serializer serializer = LimboAuth.getSerializer();
+ this.notPlayer = serializer.deserialize(Settings.IMP.MAIN.STRINGS.NOT_PLAYER);
+ this.usage = serializer.deserialize(Settings.IMP.MAIN.STRINGS.TOTP_USAGE);
this.needPassword = Settings.IMP.MAIN.TOTP_NEED_PASSWORD;
- this.notRegistered = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_REGISTERED);
- this.wrongPassword = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.WRONG_PASSWORD);
- this.alreadyEnabled = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.TOTP_ALREADY_ENABLED);
- this.errorOccurred = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.ERROR_OCCURRED);
- this.successful = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.TOTP_SUCCESSFUL);
+ this.notRegistered = serializer.deserialize(Settings.IMP.MAIN.STRINGS.NOT_REGISTERED);
+ this.wrongPassword = serializer.deserialize(Settings.IMP.MAIN.STRINGS.WRONG_PASSWORD);
+ this.alreadyEnabled = serializer.deserialize(Settings.IMP.MAIN.STRINGS.TOTP_ALREADY_ENABLED);
+ this.errorOccurred = serializer.deserialize(Settings.IMP.MAIN.STRINGS.ERROR_OCCURRED);
+ this.successful = serializer.deserialize(Settings.IMP.MAIN.STRINGS.TOTP_SUCCESSFUL);
this.issuer = Settings.IMP.MAIN.TOTP_ISSUER;
this.qrGeneratorUrl = Settings.IMP.MAIN.QR_GENERATOR_URL;
- this.qr = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.TOTP_QR);
+ this.qr = serializer.deserialize(Settings.IMP.MAIN.STRINGS.TOTP_QR);
this.token = Settings.IMP.MAIN.STRINGS.TOTP_TOKEN;
this.recoveryCodesAmount = Settings.IMP.MAIN.TOTP_RECOVERY_CODES_AMOUNT;
this.recovery = Settings.IMP.MAIN.STRINGS.TOTP_RECOVERY;
- this.disabled = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.TOTP_DISABLED);
- this.wrong = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.TOTP_WRONG);
- this.crackedCommand = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.CRACKED_COMMAND);
+ this.disabled = serializer.deserialize(Settings.IMP.MAIN.STRINGS.TOTP_DISABLED);
+ this.wrong = serializer.deserialize(Settings.IMP.MAIN.STRINGS.TOTP_WRONG);
+ this.crackedCommand = serializer.deserialize(Settings.IMP.MAIN.STRINGS.CRACKED_COMMAND);
}
+ // TODO: Rewrite.
@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 (source instanceof Player) {
+ if (args.length == 0) {
+ source.sendMessage(this.usage);
+ } else {
+ String username = ((Player) source).getUsername();
- if (args.length == 0) {
- source.sendMessage(this.usage);
- } else {
- String username = ((Player) source).getUsername();
-
- RegisteredPlayer playerInfo;
- UpdateBuilder<RegisteredPlayer, String> updateBuilder;
- switch (args[0]) {
- case "enable": {
+ RegisteredPlayer playerInfo;
+ UpdateBuilder<RegisteredPlayer, String> updateBuilder;
+ if (args[0].equalsIgnoreCase("enable")) {
if (this.needPassword ? args.length == 2 : args.length == 1) {
playerInfo = AuthSessionHandler.fetchInfo(this.playerDao, username);
-
if (playerInfo == null) {
source.sendMessage(this.notRegistered);
return;
} else if (playerInfo.getHash().isEmpty()) {
source.sendMessage(this.crackedCommand);
+ return;
} else if (this.needPassword && !AuthSessionHandler.checkPassword(args[1], playerInfo, this.playerDao)) {
source.sendMessage(this.wrongPassword);
return;
@@ -122,7 +120,6 @@ public class TotpCommand implements SimpleCommand {
}
String secret = this.secretGenerator.generate();
-
try {
updateBuilder = this.playerDao.updateBuilder();
updateBuilder.where().eq("NICKNAME", username);
@@ -132,7 +129,6 @@ public class TotpCommand implements SimpleCommand {
source.sendMessage(this.errorOccurred);
e.printStackTrace();
}
-
source.sendMessage(this.successful);
QrData data = new QrData.Builder()
@@ -140,69 +136,54 @@ public class TotpCommand implements SimpleCommand {
.secret(secret)
.issuer(this.issuer)
.build();
-
String qrUrl = this.qrGeneratorUrl.replace("{data}", URLEncoder.encode(data.getUri(), StandardCharsets.UTF_8));
-
source.sendMessage(this.qr.clickEvent(ClickEvent.openUrl(qrUrl)));
- source.sendMessage(
- LegacyComponentSerializer.legacyAmpersand().deserialize(
- MessageFormat.format(this.token, secret)
- ).clickEvent(ClickEvent.copyToClipboard(secret))
- );
-
+ Serializer serializer = LimboAuth.getSerializer();
+ source.sendMessage(serializer.deserialize(MessageFormat.format(this.token, secret)).clickEvent(ClickEvent.copyToClipboard(secret)));
String codes = String.join(", ", this.codesGenerator.generateCodes(this.recoveryCodesAmount));
-
- source.sendMessage(
- LegacyComponentSerializer.legacyAmpersand().deserialize(
- MessageFormat.format(this.recovery, codes)
- ).clickEvent(ClickEvent.copyToClipboard(codes))
- );
+ source.sendMessage(serializer.deserialize(MessageFormat.format(this.recovery, codes)).clickEvent(ClickEvent.copyToClipboard(codes)));
} else {
source.sendMessage(this.usage);
}
- break;
- }
- case "disable": {
- if (args.length != 2) {
- source.sendMessage(this.usage);
- return;
- }
-
- playerInfo = AuthSessionHandler.fetchInfo(this.playerDao, username);
-
- if (playerInfo == null) {
- source.sendMessage(this.notRegistered);
- return;
- }
+ } else if (args[0].equalsIgnoreCase("disable")) {
+ if (args.length == 2) {
+ playerInfo = AuthSessionHandler.fetchInfo(this.playerDao, username);
- if (AuthSessionHandler.getVerifier().isValidCode(playerInfo.getTotpToken(), args[1])) {
- try {
- updateBuilder = this.playerDao.updateBuilder();
- updateBuilder.where().eq("NICKNAME", username);
- updateBuilder.updateColumnValue("TOTPTOKEN", "");
- updateBuilder.update();
+ if (playerInfo == null) {
+ source.sendMessage(this.notRegistered);
+ return;
+ }
- source.sendMessage(this.disabled);
- } catch (SQLException e) {
- source.sendMessage(this.errorOccurred);
- e.printStackTrace();
+ if (AuthSessionHandler.getTotpCodeVerifier().isValidCode(playerInfo.getTotpToken(), args[1])) {
+ try {
+ updateBuilder = this.playerDao.updateBuilder();
+ updateBuilder.where().eq("NICKNAME", username);
+ updateBuilder.updateColumnValue("TOTPTOKEN", "");
+ updateBuilder.update();
+
+ source.sendMessage(this.disabled);
+ } catch (SQLException e) {
+ source.sendMessage(this.errorOccurred);
+ e.printStackTrace();
+ }
+ } else {
+ source.sendMessage(this.wrong);
}
} else {
- source.sendMessage(this.wrong);
+ source.sendMessage(this.usage);
}
- break;
- }
- default: {
+ } else {
source.sendMessage(this.usage);
- break;
}
}
+ } else {
+ source.sendMessage(this.notPlayer);
}
}
@Override
public boolean hasPermission(SimpleCommand.Invocation invocation) {
- return invocation.source().getPermissionValue("limboauth.commands.totp") != Tristate.FALSE;
+ return invocation.source().getPermissionValue("limboauth.commands.totp") == Tristate.TRUE;
}
}
diff --git a/src/main/java/net/elytrium/limboauth/command/UnregisterCommand.java b/src/main/java/net/elytrium/limboauth/command/UnregisterCommand.java
index 62edd0b..b6c11ff 100644
--- a/src/main/java/net/elytrium/limboauth/command/UnregisterCommand.java
+++ b/src/main/java/net/elytrium/limboauth/command/UnregisterCommand.java
@@ -24,19 +24,20 @@ import com.velocitypowered.api.permission.Tristate;
import com.velocitypowered.api.proxy.Player;
import java.sql.SQLException;
import java.util.Locale;
+import net.elytrium.java.commons.mc.serialization.Serializer;
import net.elytrium.limboauth.LimboAuth;
import net.elytrium.limboauth.Settings;
import net.elytrium.limboauth.event.AuthUnregisterEvent;
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 UnregisterCommand implements SimpleCommand {
private final LimboAuth plugin;
private final Dao<RegisteredPlayer, String> playerDao;
+ private final String confirmKeyword;
private final Component notPlayer;
private final Component notRegistered;
private final Component successful;
@@ -49,13 +50,15 @@ public class UnregisterCommand implements SimpleCommand {
this.plugin = plugin;
this.playerDao = playerDao;
- this.notPlayer = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_PLAYER);
- this.notRegistered = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NOT_REGISTERED);
- this.successful = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.UNREGISTER_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.UNREGISTER_USAGE);
- this.crackedCommand = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.CRACKED_COMMAND);
+ Serializer serializer = LimboAuth.getSerializer();
+ this.confirmKeyword = Settings.IMP.MAIN.CONFIRM_KEYWORD;
+ this.notPlayer = serializer.deserialize(Settings.IMP.MAIN.STRINGS.NOT_PLAYER);
+ this.notRegistered = serializer.deserialize(Settings.IMP.MAIN.STRINGS.NOT_REGISTERED);
+ this.successful = serializer.deserialize(Settings.IMP.MAIN.STRINGS.UNREGISTER_SUCCESSFUL);
+ this.errorOccurred = serializer.deserialize(Settings.IMP.MAIN.STRINGS.ERROR_OCCURRED);
+ this.wrongPassword = serializer.deserialize(Settings.IMP.MAIN.STRINGS.WRONG_PASSWORD);
+ this.usage = serializer.deserialize(Settings.IMP.MAIN.STRINGS.UNREGISTER_USAGE);
+ this.crackedCommand = serializer.deserialize(Settings.IMP.MAIN.STRINGS.CRACKED_COMMAND);
}
@Override
@@ -63,42 +66,41 @@ public class UnregisterCommand implements SimpleCommand {
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.crackedCommand);
- } else if (AuthSessionHandler.checkPassword(args[0], player, this.playerDao)) {
- try {
- this.plugin.getServer().getEventManager().fireAndForget(new AuthUnregisterEvent(username));
- this.playerDao.deleteById(username.toLowerCase(Locale.ROOT));
- this.plugin.removePlayerFromCache(username);
- ((Player) source).disconnect(this.successful);
- } catch (SQLException e) {
- source.sendMessage(this.errorOccurred);
- e.printStackTrace();
+ if (source instanceof Player) {
+ if (args.length == 2) {
+ if (this.confirmKeyword.equalsIgnoreCase(args[1])) {
+ 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.crackedCommand);
+ } else if (AuthSessionHandler.checkPassword(args[0], player, this.playerDao)) {
+ try {
+ this.plugin.getServer().getEventManager().fireAndForget(new AuthUnregisterEvent(username));
+ this.playerDao.deleteById(username.toLowerCase(Locale.ROOT));
+ this.plugin.removePlayerFromCache(username);
+ ((Player) source).disconnect(this.successful);
+ } catch (SQLException e) {
+ source.sendMessage(this.errorOccurred);
+ e.printStackTrace();
+ }
+ } else {
+ source.sendMessage(this.wrongPassword);
}
- } else {
- source.sendMessage(this.wrongPassword);
- }
- return;
+ return;
+ }
}
- }
- source.sendMessage(this.usage);
+ source.sendMessage(this.usage);
+ } else {
+ source.sendMessage(this.notPlayer);
+ }
}
@Override
public boolean hasPermission(SimpleCommand.Invocation invocation) {
- return invocation.source().getPermissionValue("limboauth.commands.unregister") != Tristate.FALSE;
+ return invocation.source().getPermissionValue("limboauth.commands.unregister") == Tristate.TRUE;
}
}
diff --git a/src/main/java/net/elytrium/limboauth/config/Config.java b/src/main/java/net/elytrium/limboauth/config/Config.java
deleted file mode 100644
index 48912c6..0000000
--- a/src/main/java/net/elytrium/limboauth/config/Config.java
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * Copyright (C) 2021 - 2022 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.config;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.invoke.MethodHandles;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.yaml.snakeyaml.Yaml;
-
-public class Config {
-
- private final Logger logger = LoggerFactory.getLogger(Config.class);
-
- private String oldPrefix = "";
- private String currentPrefix = "";
-
- /**
- * Set the value of a specific node. Probably throws some error if you supply non-existing keys or invalid values.
- *
- * @param key config node
- * @param value value
- */
- private void set(String key, Object value, Class<?> root) {
- String[] split = key.split("\\.");
- Object instance = this.getInstance(split, root);
- if (instance != null) {
- Field field = this.getField(split, instance);
- if (field != null) {
- try {
- if (field.getAnnotation(Final.class) != null) {
- return;
- }
- if (field.getType() == String.class && !(value instanceof String)) {
- value = value + "";
- }
- field.set(instance, value);
- return;
- } catch (Throwable e) {
- e.printStackTrace();
- }
- }
- }
-
- this.logger.debug("Failed to set config option: " + key + ": " + value + " | " + instance + " | " + root.getSimpleName() + ".yml");
- }
-
- @SuppressWarnings("unchecked")
- public void set(Map<String, Object> input, String oldPath) {
- for (Map.Entry<String, Object> entry : input.entrySet()) {
- String key = oldPath + (oldPath.isEmpty() ? "" : ".") + entry.getKey();
- Object value = entry.getValue();
-
- if (value instanceof Map) {
- this.set((Map<String, Object>) value, key);
- } else if (value instanceof String) {
- if (key.equalsIgnoreCase("prefix") && !this.currentPrefix.equals(value)) {
- this.currentPrefix = (String) value;
- }
-
- this.set(key, ((String) value).replace("{NL}", "\n").replace("{PRFX}", this.currentPrefix), this.getClass());
- } else {
- this.set(key, value, this.getClass());
- }
- }
- }
-
- public boolean load(File file, String prefix) {
- this.oldPrefix = this.currentPrefix.isEmpty() ? prefix : this.currentPrefix;
- this.currentPrefix = prefix;
- if (!file.exists()) {
- return false;
- }
-
- try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
- this.set(new Yaml().load(reader), "");
- } catch (IOException e) {
- this.logger.warn("Unable to load config", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Indicates that a field should be instantiated / created.
- */
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.FIELD})
- public @interface Create {
-
- }
-
- /**
- * Indicates that a field cannot be modified.
- */
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.FIELD})
- public @interface Final {
-
- }
-
- /**
- * Creates a comment.
- */
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.FIELD, ElementType.TYPE})
- public @interface Comment {
-
- String[] value();
- }
-
- /**
- * Any field or class with is not part of the config.
- */
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.FIELD, ElementType.TYPE})
- public @interface Ignore {
-
- }
-
- private String toYamlString(Object value, String spacing, String fieldName) {
- if (value instanceof List) {
- Collection<?> listValue = (Collection<?>) value;
- if (listValue.isEmpty()) {
- return "[]";
- }
- StringBuilder m = new StringBuilder();
- for (Object obj : listValue) {
- m.append(System.lineSeparator()).append(spacing).append("- ").append(this.toYamlString(obj, spacing, fieldName));
- }
-
- return m.toString();
- }
-
- if (value instanceof String) {
- String stringValue = (String) value;
- if (stringValue.isEmpty()) {
- return "\"\"";
- }
-
- String quoted = "\"" + stringValue + "\"";
- if (fieldName.equalsIgnoreCase("prefix")) {
- return quoted;
- } else {
- return quoted.replace("\n", "{NL}").replace(this.currentPrefix.equals(this.oldPrefix) ? this.oldPrefix : this.currentPrefix, "{PRFX}");
- }
- }
-
- return value != null ? value.toString() : "null";
- }
-
- /**
- * Set all values in the file (load first to avoid overwriting).
- */
- @SuppressWarnings("ResultOfMethodCallIgnored")
- @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
- public void save(File file) {
- try {
- if (!file.exists()) {
- File parent = file.getParentFile();
- if (parent != null) {
- file.getParentFile().mkdirs();
- }
- file.createNewFile();
- }
-
- PrintWriter writer = new PrintWriter(file, StandardCharsets.UTF_8);
- Object instance = this;
- this.save(writer, this.getClass(), instance, 0);
- writer.close();
- } catch (Throwable e) {
- e.printStackTrace();
- }
- }
-
- private void save(PrintWriter writer, Class<?> clazz, Object instance, int indent) {
- try {
- String lineSeparator = System.lineSeparator();
- String spacing = IntStream.range(0, indent).mapToObj(i -> " ").collect(Collectors.joining());
-
- for (Field field : clazz.getFields()) {
- if (field.getAnnotation(Ignore.class) != null) {
- continue;
- }
- Class<?> current = field.getType();
- if (field.getAnnotation(Ignore.class) != null) {
- continue;
- }
-
- Comment comment = field.getAnnotation(Comment.class);
- if (comment != null) {
- for (String commentLine : comment.value()) {
- writer.write(spacing + "# " + commentLine + lineSeparator);
- }
- }
-
- Create create = field.getAnnotation(Create.class);
- if (create != null) {
- Object value = field.get(instance);
- this.setAccessible(field);
- if (indent == 0) {
- writer.write(lineSeparator);
- }
- comment = current.getAnnotation(Comment.class);
- if (comment != null) {
- for (String commentLine : comment.value()) {
- writer.write(spacing + "# " + commentLine + lineSeparator);
- }
- }
- writer.write(spacing + this.toNodeName(current.getSimpleName()) + ":" + lineSeparator);
- if (value == null) {
- field.set(instance, value = current.getDeclaredConstructor().newInstance());
- }
- this.save(writer, current, value, indent + 2);
- } else {
- String value = this.toYamlString(field.get(instance), spacing, field.getName());
- writer.write(spacing + this.toNodeName(field.getName() + ": ") + value + lineSeparator);
- }
- }
- } catch (Throwable e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Get the field for a specific config node and instance.
- *
- * <p>As expiry can have multiple blocks there will be multiple instances
- *
- * @param split the node (split by period)
- * @param instance the instance
- */
- private Field getField(String[] split, Object instance) {
- try {
- Field field = instance.getClass().getField(this.toFieldName(split[split.length - 1]));
- this.setAccessible(field);
- return field;
- } catch (Throwable ignored) {
- this.logger.debug("Invalid config field: " + this.join(split, ".") + " for " + this.toNodeName(instance.getClass().getSimpleName()));
- return null;
- }
- }
-
- /**
- * Get the instance for a specific config node.
- *
- * @param split the node (split by period)
- * @return The instance or null
- */
- private Object getInstance(String[] split, Class<?> root) {
- try {
- Class<?> clazz = root == null ? MethodHandles.lookup().lookupClass() : root;
- Object instance = this;
- while (split.length > 0) {
- if (split.length == 1) {
- return instance;
- } else {
- Class<?> found = null;
- if (clazz == null) {
- return null;
- }
-
- Class<?>[] classes = clazz.getDeclaredClasses();
- for (Class<?> current : classes) {
- if (Objects.equals(current.getSimpleName(), this.toFieldName(split[0]))) {
- found = current;
- break;
- }
- }
-
- if (found == null) {
- return null;
- }
-
- try {
- Field instanceField = clazz.getDeclaredField(this.toFieldName(split[0]));
- this.setAccessible(instanceField);
- Object value = instanceField.get(instance);
- if (value == null) {
- value = found.getDeclaredConstructor().newInstance();
- instanceField.set(instance, value);
- }
-
- clazz = found;
- instance = value;
- split = Arrays.copyOfRange(split, 1, split.length);
- continue;
- } catch (NoSuchFieldException e) {
- //
- }
-
- split = Arrays.copyOfRange(split, 1, split.length);
- clazz = found;
- instance = clazz.getDeclaredConstructor().newInstance();
- }
- }
- } catch (Throwable e) {
- e.printStackTrace();
- }
-
- return null;
- }
-
- /**
- * Translate a node to a java field name.
- */
- private String toFieldName(String node) {
- return node.toUpperCase(Locale.ROOT).replaceAll("-", "_");
- }
-
- /**
- * Translate a field to a config node.
- */
- private String toNodeName(String field) {
- return field.toLowerCase(Locale.ROOT).replace("_", "-");
- }
-
- /**
- * Set some field to be accessible.
- */
- private void setAccessible(Field field) throws NoSuchFieldException, IllegalAccessException {
- field.setAccessible(true);
- if (Modifier.isFinal(field.getModifiers())) {
- 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();
- }
- }
- }
-
- @SuppressWarnings("SameParameterValue")
- private String join(Object[] array, String delimiter) {
- switch (array.length) {
- case 0: {
- return "";
- }
- case 1: {
- return array[0].toString();
- }
- default: {
- StringBuilder result = new StringBuilder();
- for (int i = 0, j = array.length; i < j; ++i) {
- if (i > 0) {
- result.append(delimiter);
- }
- result.append(array[i]);
- }
-
- return result.toString();
- }
- }
- }
-}
diff --git a/src/main/java/net/elytrium/limboauth/event/AuthPluginReloadEvent.java b/src/main/java/net/elytrium/limboauth/event/AuthPluginReloadEvent.java
index c166e2d..049de11 100644
--- a/src/main/java/net/elytrium/limboauth/event/AuthPluginReloadEvent.java
+++ b/src/main/java/net/elytrium/limboauth/event/AuthPluginReloadEvent.java
@@ -18,4 +18,5 @@
package net.elytrium.limboauth.event;
public class AuthPluginReloadEvent {
+
}
diff --git a/src/main/java/net/elytrium/limboauth/event/AuthUnregisterEvent.java b/src/main/java/net/elytrium/limboauth/event/AuthUnregisterEvent.java
index 9895d08..6a5b348 100644
--- a/src/main/java/net/elytrium/limboauth/event/AuthUnregisterEvent.java
+++ b/src/main/java/net/elytrium/limboauth/event/AuthUnregisterEvent.java
@@ -28,5 +28,4 @@ public class AuthUnregisterEvent {
public String getNickname() {
return this.nickname;
}
-
}
diff --git a/src/main/java/net/elytrium/limboauth/event/PostAuthorizationEvent.java b/src/main/java/net/elytrium/limboauth/event/PostAuthorizationEvent.java
index 342c8ca..0fed613 100644
--- a/src/main/java/net/elytrium/limboauth/event/PostAuthorizationEvent.java
+++ b/src/main/java/net/elytrium/limboauth/event/PostAuthorizationEvent.java
@@ -22,11 +22,8 @@ import net.elytrium.limboapi.api.player.LimboPlayer;
import net.elytrium.limboauth.model.RegisteredPlayer;
public class PostAuthorizationEvent extends PostEvent {
- public PostAuthorizationEvent(LimboPlayer player, RegisteredPlayer playerInfo, Consumer<TaskEvent> onComplete) {
- super(player, playerInfo, onComplete);
- }
- public PostAuthorizationEvent(Result result, LimboPlayer player, RegisteredPlayer playerInfo, Consumer<TaskEvent> onComplete) {
- super(result, player, playerInfo, onComplete);
+ public PostAuthorizationEvent(Consumer<TaskEvent> onComplete, LimboPlayer player, RegisteredPlayer playerInfo) {
+ super(onComplete, player, playerInfo);
}
}
diff --git a/src/main/java/net/elytrium/limboauth/event/PostEvent.java b/src/main/java/net/elytrium/limboauth/event/PostEvent.java
index 9902ab5..e3f590a 100644
--- a/src/main/java/net/elytrium/limboauth/event/PostEvent.java
+++ b/src/main/java/net/elytrium/limboauth/event/PostEvent.java
@@ -26,25 +26,25 @@ public abstract class PostEvent extends TaskEvent {
private final LimboPlayer player;
private final RegisteredPlayer playerInfo;
- protected PostEvent(LimboPlayer player, RegisteredPlayer playerInfo, Consumer<TaskEvent> onComplete) {
+ protected PostEvent(Consumer<TaskEvent> onComplete, LimboPlayer player, RegisteredPlayer playerInfo) {
super(onComplete);
this.player = player;
this.playerInfo = playerInfo;
}
- protected PostEvent(Result result, LimboPlayer player, RegisteredPlayer playerInfo, Consumer<TaskEvent> onComplete) {
- super(result, onComplete);
+ protected PostEvent(Consumer<TaskEvent> onComplete, Result result, LimboPlayer player, RegisteredPlayer playerInfo) {
+ super(onComplete, result);
this.player = player;
this.playerInfo = playerInfo;
}
- public RegisteredPlayer getPlayerInfo() {
- return this.playerInfo;
- }
-
public LimboPlayer getPlayer() {
return this.player;
}
+
+ public RegisteredPlayer getPlayerInfo() {
+ return this.playerInfo;
+ }
}
diff --git a/src/main/java/net/elytrium/limboauth/event/PostRegisterEvent.java b/src/main/java/net/elytrium/limboauth/event/PostRegisterEvent.java
index c0e0504..9c3a6d5 100644
--- a/src/main/java/net/elytrium/limboauth/event/PostRegisterEvent.java
+++ b/src/main/java/net/elytrium/limboauth/event/PostRegisterEvent.java
@@ -22,11 +22,8 @@ import net.elytrium.limboapi.api.player.LimboPlayer;
import net.elytrium.limboauth.model.RegisteredPlayer;
public class PostRegisterEvent extends PostEvent {
- public PostRegisterEvent(LimboPlayer player, RegisteredPlayer playerInfo, Consumer<TaskEvent> onComplete) {
- super(player, playerInfo, onComplete);
- }
- public PostRegisterEvent(Result result, LimboPlayer player, RegisteredPlayer playerInfo, Consumer<TaskEvent> onComplete) {
- super(result, player, playerInfo, onComplete);
+ public PostRegisterEvent(Consumer<TaskEvent> onComplete, LimboPlayer player, RegisteredPlayer playerInfo) {
+ super(onComplete, player, playerInfo);
}
}
diff --git a/src/main/java/net/elytrium/limboauth/event/PreAuthorizationEvent.java b/src/main/java/net/elytrium/limboauth/event/PreAuthorizationEvent.java
index 295c767..e96b0d0 100644
--- a/src/main/java/net/elytrium/limboauth/event/PreAuthorizationEvent.java
+++ b/src/main/java/net/elytrium/limboauth/event/PreAuthorizationEvent.java
@@ -22,15 +22,12 @@ import java.util.function.Consumer;
import net.elytrium.limboauth.model.RegisteredPlayer;
public class PreAuthorizationEvent extends PreEvent {
+
private final RegisteredPlayer playerInfo;
- public PreAuthorizationEvent(Player player, RegisteredPlayer playerInfo, Consumer<TaskEvent> onComplete) {
- super(player, onComplete);
- this.playerInfo = playerInfo;
- }
+ public PreAuthorizationEvent(Consumer<TaskEvent> onComplete, Result result, Player player, RegisteredPlayer playerInfo) {
+ super(onComplete, result, player);
- public PreAuthorizationEvent(Result result, Player player, RegisteredPlayer playerInfo, Consumer<TaskEvent> onComplete) {
- super(result, player, onComplete);
this.playerInfo = playerInfo;
}
diff --git a/src/main/java/net/elytrium/limboauth/event/PreEvent.java b/src/main/java/net/elytrium/limboauth/event/PreEvent.java
index a925c5d..1fab6ab 100644
--- a/src/main/java/net/elytrium/limboauth/event/PreEvent.java
+++ b/src/main/java/net/elytrium/limboauth/event/PreEvent.java
@@ -21,15 +21,12 @@ import com.velocitypowered.api.proxy.Player;
import java.util.function.Consumer;
public abstract class PreEvent extends TaskEvent {
+
private final Player player;
- protected PreEvent(Player player, Consumer<TaskEvent> onComplete) {
- super(onComplete);
- this.player = player;
- }
+ protected PreEvent(Consumer<TaskEvent> onComplete, Result result, Player player) {
+ super(onComplete, result);
- protected PreEvent(Result result, Player player, Consumer<TaskEvent> onComplete) {
- super(result, onComplete);
this.player = player;
}
diff --git a/src/main/java/net/elytrium/limboauth/event/PreRegisterEvent.java b/src/main/java/net/elytrium/limboauth/event/PreRegisterEvent.java
index 7d6aa15..e340fe0 100644
--- a/src/main/java/net/elytrium/limboauth/event/PreRegisterEvent.java
+++ b/src/main/java/net/elytrium/limboauth/event/PreRegisterEvent.java
@@ -21,11 +21,8 @@ import com.velocitypowered.api.proxy.Player;
import java.util.function.Consumer;
public class PreRegisterEvent extends PreEvent {
- public PreRegisterEvent(Player player, Consumer<TaskEvent> onComplete) {
- super(player, onComplete);
- }
- public PreRegisterEvent(Result result, Player player, Consumer<TaskEvent> onComplete) {
- super(result, player, onComplete);
+ public PreRegisterEvent(Consumer<TaskEvent> onComplete, Result result, Player player) {
+ super(onComplete, result, player);
}
}
diff --git a/src/main/java/net/elytrium/limboauth/event/TaskEvent.java b/src/main/java/net/elytrium/limboauth/event/TaskEvent.java
index 1f37e0f..5562cb2 100644
--- a/src/main/java/net/elytrium/limboauth/event/TaskEvent.java
+++ b/src/main/java/net/elytrium/limboauth/event/TaskEvent.java
@@ -18,46 +18,30 @@
package net.elytrium.limboauth.event;
import java.util.function.Consumer;
+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 org.jetbrains.annotations.NotNull;
public abstract class TaskEvent {
- private static final Component defaultReason
- = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.EVENT_CANCELLED);
- private Result result = Result.NORMAL;
- private Component reason = defaultReason;
+
+ private static Component DEFAULT_REASON;
private final Consumer<TaskEvent> onComplete;
+ private Result result = Result.NORMAL;
+ private Component reason = DEFAULT_REASON;
+
public TaskEvent(Consumer<TaskEvent> onComplete) {
this.onComplete = onComplete;
}
- public TaskEvent(Result result, Consumer<TaskEvent> onComplete) {
- this.result = result;
+ public TaskEvent(Consumer<TaskEvent> onComplete, Result result) {
this.onComplete = onComplete;
- }
-
- public Result getResult() {
- return this.result;
- }
-
- public void setResult(@NotNull Result result) {
this.result = result;
}
- public void cancel(@NotNull Component reason) {
- this.result = Result.CANCEL;
- this.reason = reason;
- }
-
- public Component getReason() {
- return this.reason;
- }
-
- public void complete(Result result) {
+ public void complete(@NotNull Result result) {
if (this.result != Result.WAIT) {
return;
}
@@ -66,16 +50,38 @@ public abstract class TaskEvent {
this.onComplete.accept(this);
}
- public void completeAndCancel(@NotNull Component c) {
+ public void completeAndCancel(@NotNull Component reason) {
if (this.result != Result.WAIT) {
return;
}
- this.cancel(c);
+ this.cancel(reason);
this.onComplete.accept(this);
}
+ public void cancel(@NotNull Component reason) {
+ this.result = Result.CANCEL;
+ this.reason = reason;
+ }
+
+ public void setResult(@NotNull Result result) {
+ this.result = result;
+ }
+
+ public Result getResult() {
+ return this.result;
+ }
+
+ public Component getReason() {
+ return this.reason;
+ }
+
+ public static void reload() {
+ DEFAULT_REASON = LimboAuth.getSerializer().deserialize(Settings.IMP.MAIN.STRINGS.EVENT_CANCELLED);
+ }
+
public enum Result {
+
CANCEL,
BYPASS,
NORMAL,
diff --git a/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java b/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java
index 9a795b5..75fd862 100644
--- a/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java
+++ b/src/main/java/net/elytrium/limboauth/handler/AuthSessionHandler.java
@@ -32,7 +32,8 @@ import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import net.elytrium.java.commons.mc.serialization.Serializer;
import net.elytrium.limboapi.api.Limbo;
import net.elytrium.limboapi.api.LimboSessionHandler;
import net.elytrium.limboapi.api.player.LimboPlayer;
@@ -45,33 +46,67 @@ 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;
+import org.checkerframework.checker.nullness.qual.Nullable;
public class AuthSessionHandler implements LimboSessionHandler {
- private static final CodeVerifier verifier = new DefaultCodeVerifier(new DefaultCodeGenerator(), new SystemTimeProvider());
+ private static final CodeVerifier TOTP_CODE_VERIFIER = new DefaultCodeVerifier(new DefaultCodeGenerator(), new SystemTimeProvider());
+ private static final BCrypt.Verifyer HASH_VERIFIER = BCrypt.verifyer();
+ private static final BCrypt.Hasher HASHER = BCrypt.withDefaults();
+
+ private static BossBar.Color bossbarColor;
+ private static BossBar.Overlay bossbarOverlay;
+ private static Component ipLimitKick;
+ private static Component databaseErrorKick;
+ private static Component wrongNicknameCaseKick;
+ private static Component timesUp;
+ private static Component registerSuccessful;
+ @Nullable
+ private static Title registerSuccessfulTitle;
+ private static Component[] loginWrongPassword;
+ private static Component loginWrongPasswordKick;
+ private static Component totp;
+ @Nullable
+ private static Title totpTitle;
+ private static Component register;
+ @Nullable
+ private static Title registerTitle;
+ private static Component[] login;
+ @Nullable
+ private static Title loginTitle;
+ private static Component registerDifferentPasswords;
+ private static Component registerPasswordTooLong;
+ private static Component registerPasswordTooShort;
+ private static Component registerPasswordUnsafe;
+ private static Component loginSuccessful;
+ @Nullable
+ private static Title loginSuccessfulTitle;
+ private static MigrationHash migrationHash;
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))
+ 1.0F,
+ bossbarColor,
+ bossbarOverlay
);
+
+ @Nullable
+ private RegisteredPlayer playerInfo;
+
private ScheduledTask authMainTask;
private LimboPlayer player;
private String ip;
private int attempts = Settings.IMP.MAIN.LOGIN_ATTEMPTS;
- private boolean totp = false;
+ private boolean totpState;
- public AuthSessionHandler(Dao<RegisteredPlayer, String> playerDao, Player proxyPlayer, LimboAuth plugin, RegisteredPlayer playerInfo) {
+ public AuthSessionHandler(Dao<RegisteredPlayer, String> playerDao, Player proxyPlayer, LimboAuth plugin, @Nullable RegisteredPlayer playerInfo) {
this.playerDao = playerDao;
this.proxyPlayer = proxyPlayer;
this.plugin = plugin;
@@ -81,33 +116,62 @@ public class AuthSessionHandler implements LimboSessionHandler {
@Override
public void onSpawn(Limbo server, LimboPlayer player) {
this.player = player;
- this.player.disableFalling();
this.ip = this.proxyPlayer.getRemoteAddress().getAddress().getHostAddress();
+ this.player.disableFalling();
+
if (this.playerInfo == null) {
- this.checkIp();
+ try {
+ List<RegisteredPlayer> alreadyRegistered = this.playerDao.queryForEq("IP", this.ip);
+ if (alreadyRegistered != null) {
+ int sizeOfValidRegistrations = alreadyRegistered.size();
+ if (Settings.IMP.MAIN.IP_LIMIT_VALID_TIME > 0) {
+ for (RegisteredPlayer registeredPlayer : alreadyRegistered.stream()
+ .filter(registeredPlayer -> registeredPlayer.getRegDate() < System.currentTimeMillis() - Settings.IMP.MAIN.IP_LIMIT_VALID_TIME)
+ .collect(Collectors.toList())) {
+ registeredPlayer.setIP("");
+ this.playerDao.update(registeredPlayer);
+ --sizeOfValidRegistrations;
+ }
+ }
+
+ if (sizeOfValidRegistrations >= Settings.IMP.MAIN.IP_LIMIT_REGISTRATIONS) {
+ this.proxyPlayer.disconnect(ipLimitKick);
+ return;
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ this.proxyPlayer.disconnect(databaseErrorKick);
+ return;
+ }
} else {
- this.checkCase();
+ if (!this.proxyPlayer.getUsername().equals(this.playerInfo.getNickname())) {
+ this.proxyPlayer.disconnect(wrongNicknameCaseKick);
+ return;
+ }
}
boolean bossBarEnabled = Settings.IMP.MAIN.ENABLE_BOSSBAR;
- float bossBarMultiplier = 1000F / Settings.IMP.MAIN.AUTH_TIME;
- if (bossBarEnabled) {
- this.proxyPlayer.showBossBar(this.bossBar);
- }
+ Serializer serializer = LimboAuth.getSerializer();
+ int authTime = Settings.IMP.MAIN.AUTH_TIME;
+ float multiplier = authTime / 1000.0F;
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 / 1000F))));
- // It is possible, that the progress value can overcome 1, e.g. 1.0000001.
- this.bossBar.progress(Math.min((timeSinceJoin * bossBarMultiplier) / 1000F, 1F));
+ if (System.currentTimeMillis() - this.joinTime > authTime) {
+ this.proxyPlayer.disconnect(timesUp);
+ } else {
+ if (bossBarEnabled) {
+ float secondsLeft = ((System.currentTimeMillis() - this.joinTime) - authTime) / 1000.0F;
+ this.bossBar.name(serializer.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.BOSSBAR, (int) secondsLeft)));
+ this.bossBar.progress((int) (secondsLeft * multiplier));
+ }
}
}).repeat(1, TimeUnit.SECONDS).schedule();
+ if (bossBarEnabled) {
+ this.proxyPlayer.showBossBar(this.bossBar);
+ }
+
this.sendMessage(true);
}
@@ -116,62 +180,67 @@ public class AuthSessionHandler implements LimboSessionHandler {
String[] args = message.split(" ");
if (args.length != 0 && this.checkArgsLength(args.length)) {
Command command = Command.parse(args[0]);
- switch (command) {
- case REGISTER: {
- 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),
- Settings.IMP.MAIN.CRACKED_TITLE_SETTINGS.toTimes()
- )
- );
- }
- this.finishRegister();
- }
- } else {
- this.sendMessage(false);
+ if (command == Command.REGISTER && !this.totpState && this.playerInfo == null) {
+ if (this.checkPasswordsRepeat(args) && this.checkPasswordLength(args[1]) && this.checkPasswordStrength(args[1])) {
+ String username = this.proxyPlayer.getUsername();
+ RegisteredPlayer registeredPlayer = new RegisteredPlayer(
+ username,
+ username.toLowerCase(Locale.ROOT),
+ genHash(args[1]),
+ this.ip,
+ "",
+ System.currentTimeMillis(),
+ this.proxyPlayer.getUniqueId().toString(),
+ ""
+ );
+
+ try {
+ this.playerDao.create(registeredPlayer);
+ this.playerInfo = registeredPlayer;
+ } catch (SQLException e) {
+ e.printStackTrace();
+ this.proxyPlayer.disconnect(databaseErrorKick);
}
- break;
- }
- case LOGIN: {
- if (!this.totp && this.playerInfo != null) {
- if (this.checkPassword(args[1])) {
- this.loginOrTotp();
- } else if (--this.attempts != 0) {
- this.proxyPlayer.sendMessage(this.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN_WRONG_PASSWORD, this.attempts)));
- } else {
- this.proxyPlayer.disconnect(this.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_WRONG_PASSWORD_KICK));
- }
- } else {
- this.sendMessage(false);
+
+ this.proxyPlayer.sendMessage(registerSuccessful);
+ if (registerSuccessfulTitle != null) {
+ this.proxyPlayer.showTitle(registerSuccessfulTitle);
}
- break;
+
+ this.plugin.getServer().getEventManager()
+ .fire(new PostRegisterEvent(this::finishAuth, this.player, this.playerInfo))
+ .thenAcceptAsync(this::finishAuth);
}
- case TOTP: {
- if (this.totp) {
- if (verifier.isValidCode(this.playerInfo.getTotpToken(), args[1])) {
- this.finishLogin();
- } else {
- this.sendMessage(false);
- }
+
+ // {@code return} placed here (not above), because
+ // AuthSessionHandler#checkPasswordsRepeat, AuthSessionHandler#checkPasswordLength, and AuthSessionHandler#checkPasswordStrength methods are
+ // invoking Player#sendMessage that sends its own message in case if the return value is false.
+ // If we don't place {@code return} here, an another message (AuthSessionHandler#sendMessage) will be sent.
+ return;
+ } else if (command == Command.LOGIN && !this.totpState && this.playerInfo != null) {
+ if (args[1].length() > 0 && checkPassword(args[1], this.playerInfo, this.playerDao)) {
+ if (this.playerInfo.getTotpToken().isEmpty()) {
+ this.finishLogin();
} else {
- this.sendMessage(false);
+ this.totpState = true;
+ this.sendMessage(true);
}
- break;
+ } else if (--this.attempts != 0) {
+ this.proxyPlayer.sendMessage(loginWrongPassword[this.attempts - 1]);
+ } else {
+ this.proxyPlayer.disconnect(loginWrongPasswordKick);
}
- case INVALID:
- default: {
- this.sendMessage(false);
+
+ return;
+ } else if (command == Command.TOTP && this.totpState && this.playerInfo != null) {
+ if (TOTP_CODE_VERIFIER.isValidCode(this.playerInfo.getTotpToken(), args[1])) {
+ this.finishLogin();
+ return;
}
}
- } else {
- this.sendMessage(false);
}
+
+ this.sendMessage(false);
}
@Override
@@ -183,151 +252,72 @@ public class AuthSessionHandler implements LimboSessionHandler {
this.proxyPlayer.hideBossBar(this.bossBar);
}
- public static RegisteredPlayer fetchInfo(Dao<RegisteredPlayer, String> playerDao, String nickname) {
- List<RegisteredPlayer> playerList = null;
- try {
- playerList = playerDao.queryForEq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT));
- } catch (SQLException e) {
- e.printStackTrace();
- }
-
- return (playerList != null ? playerList.size() : 0) == 0 ? null : playerList.get(0);
- }
-
- public static RegisteredPlayer fetchInfo(Dao<RegisteredPlayer, String> playerDao, UUID uuid) {
- List<RegisteredPlayer> playerList = null;
- try {
- playerList = playerDao.queryForEq("PREMIUMUUID", uuid.toString());
- } catch (SQLException e) {
- e.printStackTrace();
- }
-
- return (playerList != null ? playerList.size() : 0) == 0 ? null : playerList.get(0);
- }
-
- public static CodeVerifier getVerifier() {
- 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().replace("BCRYPT$", "$2a$").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);
-
- if (isCorrect) {
- player.setHash(genHash(password));
- try {
- playerDao.update(player);
- } catch (SQLException e) {
- e.printStackTrace();
- return false;
- }
- }
- }
-
- return isCorrect;
- }
-
- private void checkIp() {
- try {
- List<RegisteredPlayer> alreadyRegistered = this.playerDao.queryForEq("IP", this.ip);
-
- if (alreadyRegistered == null) {
- return;
+ private void sendMessage(boolean sendTitle) {
+ if (this.totpState) {
+ this.proxyPlayer.sendMessage(totp);
+ if (sendTitle && totpTitle != null) {
+ this.proxyPlayer.showTitle(totpTitle);
}
-
- AtomicInteger sizeOfValid = new AtomicInteger(alreadyRegistered.size());
-
- if (Settings.IMP.MAIN.IP_LIMIT_VALID_TIME != 0) {
- long checkDate = System.currentTimeMillis() - Settings.IMP.MAIN.IP_LIMIT_VALID_TIME;
-
- alreadyRegistered.stream()
- .filter(e -> e.getRegDate() != null)
- .filter(e -> e.getRegDate() < checkDate)
- .forEach(e -> {
- try {
- e.setIP("");
- this.playerDao.update(e);
- sizeOfValid.decrementAndGet();
- } catch (SQLException ex) {
- ex.printStackTrace();
- this.proxyPlayer.disconnect(this.deserialize(Settings.IMP.MAIN.STRINGS.DB_ERROR));
- }
- });
+ } else if (this.playerInfo == null) {
+ this.proxyPlayer.sendMessage(register);
+ if (sendTitle && registerTitle != null) {
+ this.proxyPlayer.showTitle(registerTitle);
}
-
- if (sizeOfValid.get() >= Settings.IMP.MAIN.IP_LIMIT_REGISTRATIONS) {
- this.proxyPlayer.disconnect(this.deserialize(Settings.IMP.MAIN.STRINGS.IP_LIMIT));
+ } else {
+ this.proxyPlayer.sendMessage(login[this.attempts - 1]);
+ if (sendTitle && loginTitle != null) {
+ this.proxyPlayer.showTitle(loginTitle);
}
- } catch (SQLException e) {
- e.printStackTrace();
- this.proxyPlayer.disconnect(this.deserialize(Settings.IMP.MAIN.STRINGS.DB_ERROR));
}
}
- private void checkCase() {
- if (!this.proxyPlayer.getUsername().equals(this.playerInfo.getNickname())) {
- this.proxyPlayer.disconnect(this.deserialize(Settings.IMP.MAIN.STRINGS.WRONG_NICKNAME_CASE_KICK));
+ private boolean checkArgsLength(int argsLength) {
+ if (this.playerInfo == null && Settings.IMP.MAIN.REGISTER_NEED_REPEAT_PASSWORD) {
+ return argsLength == 3;
+ } else {
+ return argsLength == 2;
}
}
- private void register(String password) {
- RegisteredPlayer registeredPlayer = new RegisteredPlayer(
- this.proxyPlayer.getUsername(),
- this.proxyPlayer.getUsername().toLowerCase(Locale.ROOT),
- genHash(password),
- this.ip,
- "",
- System.currentTimeMillis(),
- this.proxyPlayer.getUniqueId().toString(),
- ""
- );
+ private boolean checkPasswordsRepeat(String[] args) {
+ if (!Settings.IMP.MAIN.REGISTER_NEED_REPEAT_PASSWORD || args[1].equals(args[2])) {
+ return true;
+ } else {
+ this.proxyPlayer.sendMessage(registerDifferentPasswords);
+ return false;
+ }
+ }
- try {
- this.playerDao.create(registeredPlayer);
- } catch (SQLException e) {
- e.printStackTrace();
- this.proxyPlayer.disconnect(this.deserialize(Settings.IMP.MAIN.STRINGS.DB_ERROR));
+ private boolean checkPasswordLength(String password) {
+ int length = password.length();
+ if (length > Settings.IMP.MAIN.MAX_PASSWORD_LENGTH) {
+ this.proxyPlayer.sendMessage(registerPasswordTooLong);
+ return false;
+ } else if (length < Settings.IMP.MAIN.MIN_PASSWORD_LENGTH) {
+ this.proxyPlayer.sendMessage(registerPasswordTooShort);
+ return false;
+ } else {
+ return true;
}
}
- private void loginOrTotp() {
- if (this.playerInfo.getTotpToken().isEmpty()) {
- this.finishLogin();
+ private boolean checkPasswordStrength(String password) {
+ if (Settings.IMP.MAIN.CHECK_PASSWORD_STRENGTH && this.plugin.getUnsafePasswords().contains(password)) {
+ this.proxyPlayer.sendMessage(registerPasswordUnsafe);
+ return false;
} else {
- this.totp = true;
- this.sendMessage(true);
+ return 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),
- Settings.IMP.MAIN.CRACKED_TITLE_SETTINGS.toTimes()
- )
- );
+ this.proxyPlayer.sendMessage(loginSuccessful);
+ if (loginSuccessfulTitle != null) {
+ this.proxyPlayer.showTitle(loginSuccessfulTitle);
}
this.plugin.getServer().getEventManager()
- .fire(new PostAuthorizationEvent(this.player, this.playerInfo, this::finishAuth))
- .thenAcceptAsync(this::finishAuth);
- }
-
- private void finishRegister() {
- this.plugin.getServer().getEventManager()
- .fire(new PostRegisterEvent(this.player, this.playerInfo, this::finishAuth))
+ .fire(new PostAuthorizationEvent(this::finishAuth, this.player, this.playerInfo))
.thenAcceptAsync(this::finishAuth);
}
@@ -347,89 +337,135 @@ public class AuthSessionHandler implements LimboSessionHandler {
this.player.disconnect();
}
- private void sendMessage(boolean sendTitle) {
- if (this.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),
- Settings.IMP.MAIN.CRACKED_TITLE_SETTINGS.toTimes())
- );
- }
- } else if (this.playerInfo == null) {
- 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),
- Settings.IMP.MAIN.CRACKED_TITLE_SETTINGS.toTimes())
- );
- }
+ public static void reload() {
+ Serializer serializer = LimboAuth.getSerializer();
+ bossbarColor = BossBar.Color.valueOf(Settings.IMP.MAIN.BOSSBAR_COLOR.toUpperCase(Locale.ROOT));
+ bossbarOverlay = BossBar.Overlay.valueOf(Settings.IMP.MAIN.BOSSBAR_OVERLAY.toUpperCase(Locale.ROOT));
+ ipLimitKick = serializer.deserialize(Settings.IMP.MAIN.STRINGS.IP_LIMIT_KICK);
+ databaseErrorKick = serializer.deserialize(Settings.IMP.MAIN.STRINGS.DATABASE_ERROR_KICK);
+ wrongNicknameCaseKick = serializer.deserialize(Settings.IMP.MAIN.STRINGS.WRONG_NICKNAME_CASE_KICK);
+ timesUp = serializer.deserialize(Settings.IMP.MAIN.STRINGS.TIMES_UP);
+ registerSuccessful = serializer.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_SUCCESSFUL);
+ if (Settings.IMP.MAIN.STRINGS.REGISTER_SUCCESSFUL_TITLE.isEmpty() && Settings.IMP.MAIN.STRINGS.REGISTER_SUCCESSFUL_SUBTITLE.isEmpty()) {
+ registerSuccessfulTitle = null;
} else {
- 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)),
- Settings.IMP.MAIN.PREMIUM_TITLE_SETTINGS.toTimes()
- )
- );
- }
+ registerSuccessfulTitle = Title.title(
+ serializer.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_SUCCESSFUL_TITLE),
+ serializer.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_SUCCESSFUL_SUBTITLE),
+ Settings.IMP.MAIN.CRACKED_TITLE_SETTINGS.toTimes()
+ );
}
- }
-
- 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;
+ int loginAttempts = Settings.IMP.MAIN.LOGIN_ATTEMPTS;
+ loginWrongPassword = new Component[loginAttempts];
+ for (int i = 0; i < loginAttempts; ++i) {
+ loginWrongPassword[i] = serializer.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN_WRONG_PASSWORD, i));
}
-
- return true;
+ loginWrongPasswordKick = serializer.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_WRONG_PASSWORD_KICK);
+ totp = serializer.deserialize(Settings.IMP.MAIN.STRINGS.TOTP);
+ if (Settings.IMP.MAIN.STRINGS.TOTP_TITLE.isEmpty() && Settings.IMP.MAIN.STRINGS.TOTP_SUBTITLE.isEmpty()) {
+ totpTitle = null;
+ } else {
+ totpTitle = Title.title(
+ serializer.deserialize(Settings.IMP.MAIN.STRINGS.TOTP_TITLE),
+ serializer.deserialize(Settings.IMP.MAIN.STRINGS.TOTP_SUBTITLE),
+ Settings.IMP.MAIN.CRACKED_TITLE_SETTINGS.toTimes()
+ );
+ }
+ register = serializer.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER);
+ if (Settings.IMP.MAIN.STRINGS.REGISTER_TITLE.isEmpty() && Settings.IMP.MAIN.STRINGS.REGISTER_SUBTITLE.isEmpty()) {
+ registerTitle = null;
+ } else {
+ registerTitle = Title.title(
+ serializer.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_TITLE),
+ serializer.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_SUBTITLE),
+ Settings.IMP.MAIN.CRACKED_TITLE_SETTINGS.toTimes()
+ );
+ }
+ login = new Component[loginAttempts];
+ for (int i = 0; i < loginAttempts; ++i) {
+ login[i] = serializer.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN, i));
+ }
+ if (Settings.IMP.MAIN.STRINGS.LOGIN_TITLE.isEmpty() && Settings.IMP.MAIN.STRINGS.LOGIN_SUBTITLE.isEmpty()) {
+ loginTitle = null;
+ } else {
+ loginTitle = Title.title(
+ serializer.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN_TITLE, loginAttempts)),
+ serializer.deserialize(MessageFormat.format(Settings.IMP.MAIN.STRINGS.LOGIN_SUBTITLE, loginAttempts)),
+ Settings.IMP.MAIN.CRACKED_TITLE_SETTINGS.toTimes()
+ );
+ }
+ registerDifferentPasswords = serializer.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_DIFFERENT_PASSWORDS);
+ registerPasswordTooLong = serializer.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_PASSWORD_TOO_LONG);
+ registerPasswordTooShort = serializer.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_PASSWORD_TOO_SHORT);
+ registerPasswordUnsafe = serializer.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_PASSWORD_UNSAFE);
+ loginSuccessful = serializer.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESSFUL);
+ if (Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESSFUL_TITLE.isEmpty() && Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESSFUL_SUBTITLE.isEmpty()) {
+ loginSuccessfulTitle = null;
+ } else {
+ loginSuccessfulTitle = Title.title(
+ serializer.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESSFUL_TITLE),
+ serializer.deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_SUCCESSFUL_SUBTITLE),
+ Settings.IMP.MAIN.CRACKED_TITLE_SETTINGS.toTimes()
+ );
+ }
+ migrationHash = MigrationHash.valueOf(Settings.IMP.MAIN.MIGRATION_HASH);
}
- 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;
+ public static boolean checkPassword(String password, RegisteredPlayer player, Dao<RegisteredPlayer, String> playerDao) {
+ String hash = player.getHash();
+ boolean isCorrect = HASH_VERIFIER.verify(
+ password.getBytes(StandardCharsets.UTF_8),
+ hash.replace("BCRYPT$", "$2a$").getBytes(StandardCharsets.UTF_8)
+ ).verified;
+
+ if (!isCorrect && !Settings.IMP.MAIN.MIGRATION_HASH.isEmpty()) {
+ isCorrect = migrationHash.checkPassword(hash, password);
+ if (isCorrect) {
+ player.setHash(genHash(password));
+ try {
+ playerDao.update(player);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
}
- return true;
+ return isCorrect;
}
- private boolean checkPasswordsRepeat(String[] args) {
- if (Settings.IMP.MAIN.REGISTER_NEED_REPEAT_PASSWORD && !args[1].equals(args[2])) {
- this.proxyPlayer.sendMessage(this.deserialize(Settings.IMP.MAIN.STRINGS.REGISTER_DIFFERENT_PASSWORDS));
- return false;
+ public static RegisteredPlayer fetchInfo(Dao<RegisteredPlayer, String> playerDao, UUID uuid) {
+ List<RegisteredPlayer> playerList = null;
+ try {
+ playerList = playerDao.queryForEq("PREMIUMUUID", uuid.toString());
+ } catch (SQLException e) {
+ e.printStackTrace();
}
- return true;
+ return (playerList != null ? playerList.size() : 0) == 0 ? null : playerList.get(0);
}
- private boolean checkArgsLength(int argsLength) {
- if (this.playerInfo == null && Settings.IMP.MAIN.REGISTER_NEED_REPEAT_PASSWORD) {
- return argsLength == 3;
- } else {
- return argsLength == 2;
+ public static RegisteredPlayer fetchInfo(Dao<RegisteredPlayer, String> playerDao, String nickname) {
+ List<RegisteredPlayer> playerList = null;
+ try {
+ playerList = playerDao.queryForEq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT));
+ } catch (SQLException e) {
+ e.printStackTrace();
}
- }
- private Component deserialize(String text) {
- return LegacyComponentSerializer.legacyAmpersand().deserialize(text);
+ return (playerList != null ? playerList.size() : 0) == 0 ? null : playerList.get(0);
}
public static String genHash(String password) {
- return BCrypt.withDefaults().hashToString(Settings.IMP.MAIN.BCRYPT_COST, password.toCharArray());
+ return HASHER.hashToString(Settings.IMP.MAIN.BCRYPT_COST, password.toCharArray());
+ }
+
+ public static CodeVerifier getTotpCodeVerifier() {
+ return TOTP_CODE_VERIFIER;
}
private enum Command {
+
INVALID,
REGISTER,
LOGIN,
@@ -438,17 +474,13 @@ public class AuthSessionHandler implements LimboSessionHandler {
static Command parse(String command) {
if (Settings.IMP.MAIN.REGISTER_COMMAND.contains(command)) {
return Command.REGISTER;
- }
-
- if (Settings.IMP.MAIN.LOGIN_COMMAND.contains(command)) {
+ } else if (Settings.IMP.MAIN.LOGIN_COMMAND.contains(command)) {
return Command.LOGIN;
- }
-
- if (Settings.IMP.MAIN.TOTP_COMMAND.contains(command)) {
+ } else if (Settings.IMP.MAIN.TOTP_COMMAND.contains(command)) {
return Command.TOTP;
+ } else {
+ return Command.INVALID;
}
-
- return Command.INVALID;
}
}
}
diff --git a/src/main/java/net/elytrium/limboauth/listener/AuthListener.java b/src/main/java/net/elytrium/limboauth/listener/AuthListener.java
index c06d5f4..2c4b668 100644
--- a/src/main/java/net/elytrium/limboauth/listener/AuthListener.java
+++ b/src/main/java/net/elytrium/limboauth/listener/AuthListener.java
@@ -133,15 +133,11 @@ public class AuthListener {
}
if (!event.isOnlineMode() && !Settings.IMP.MAIN.OFFLINE_MODE_PREFIX.isEmpty()) {
- event.setGameProfile(event.getOriginalProfile().withName(
- Settings.IMP.MAIN.OFFLINE_MODE_PREFIX + event.getUsername()
- ));
+ event.setGameProfile(event.getOriginalProfile().withName(Settings.IMP.MAIN.OFFLINE_MODE_PREFIX + event.getUsername()));
}
if (event.isOnlineMode() && !Settings.IMP.MAIN.ONLINE_MODE_PREFIX.isEmpty()) {
- event.setGameProfile(event.getOriginalProfile().withName(
- Settings.IMP.MAIN.ONLINE_MODE_PREFIX + event.getUsername()
- ));
+ event.setGameProfile(event.getOriginalProfile().withName(Settings.IMP.MAIN.ONLINE_MODE_PREFIX + event.getUsername()));
}
}
}
diff --git a/src/main/java/net/elytrium/limboauth/migration/MigrationHash.java b/src/main/java/net/elytrium/limboauth/migration/MigrationHash.java
index 669a82d..8707a88 100644
--- a/src/main/java/net/elytrium/limboauth/migration/MigrationHash.java
+++ b/src/main/java/net/elytrium/limboauth/migration/MigrationHash.java
@@ -19,61 +19,58 @@ package net.elytrium.limboauth.migration;
import de.mkammerer.argon2.Argon2;
import de.mkammerer.argon2.Argon2Factory;
-import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import org.apache.commons.codec.binary.Hex;
@SuppressWarnings("unused")
public enum MigrationHash {
+
AUTHME((hash, password) -> {
- String[] arr = hash.split("\\$"); // $SHA$salt$hash
- return arr.length == 4
- && arr[3].equals(MigrationHash.getDigest(MigrationHash.getDigest(password, "SHA-256") + arr[2], "SHA-256"));
+ String[] args = hash.split("\\$"); // $SHA$salt$hash
+ return args.length == 4 && args[3].equals(getDigest(getDigest(password, "SHA-256") + args[2], "SHA-256"));
}),
AUTHME_NP((hash, password) -> {
- String[] arr = hash.split("\\$"); // SHA$salt$hash
- return arr.length == 3
- && arr[2].equals(MigrationHash.getDigest(MigrationHash.getDigest(password, "SHA-256") + arr[1], "SHA-256"));
+ String[] args = hash.split("\\$"); // SHA$salt$hash
+ return args.length == 3 && args[2].equals(getDigest(getDigest(password, "SHA-256") + args[1], "SHA-256"));
}),
ARGON2(new Argon2Verifier()),
SHA512_DBA((hash, password) -> {
- String[] arr = hash.split("\\$"); // SHA$salt$hash
- return arr.length == 3 && arr[2].equals(MigrationHash.getDigest(MigrationHash.getDigest(password, "SHA-512") + arr[1], "SHA-512"));
+ String[] args = hash.split("\\$"); // SHA$salt$hash
+ return args.length == 3 && args[2].equals(getDigest(getDigest(password, "SHA-512") + args[1], "SHA-512"));
}),
SHA512_NP((hash, password) -> {
- String[] arr = hash.split("\\$"); // SHA$salt$hash
- return arr.length == 3 && arr[2].equals(MigrationHash.getDigest(password + arr[1], "SHA-512"));
+ String[] args = hash.split("\\$"); // SHA$salt$hash
+ return args.length == 3 && args[2].equals(getDigest(password + args[1], "SHA-512"));
}),
SHA512_P((hash, password) -> {
- String[] arr = hash.split("\\$"); // $SHA$salt$hash
- return arr.length == 4 && arr[3].equals(MigrationHash.getDigest(password + arr[2], "SHA-512"));
+ String[] args = hash.split("\\$"); // $SHA$salt$hash
+ return args.length == 4 && args[3].equals(getDigest(password + args[2], "SHA-512"));
}),
SHA256_NP((hash, password) -> {
- String[] arr = hash.split("\\$"); // SHA$salt$hash
- return arr.length == 3 && arr[2].equals(MigrationHash.getDigest(password + arr[1], "SHA-256"));
+ String[] args = hash.split("\\$"); // SHA$salt$hash
+ return args.length == 3 && args[2].equals(getDigest(password + args[1], "SHA-256"));
}),
SHA256_P((hash, password) -> {
- String[] arr = hash.split("\\$"); // $SHA$salt$hash
- return arr.length == 4 && arr[3].equals(MigrationHash.getDigest(password + arr[2], "SHA-256"));
- }),
- MD5((hash, password) -> {
- return hash.equals(MigrationHash.getDigest(password, "MD5"));
+ String[] args = hash.split("\\$"); // $SHA$salt$hash
+ return args.length == 4 && args[3].equals(getDigest(password + args[2], "SHA-256"));
}),
+ MD5((hash, password) -> hash.equals(getDigest(password, "MD5"))),
MOON_SHA256((hash, password) -> {
- String[] arr = hash.split("\\$"); // $SHA$hash
- return arr.length == 3 && arr[2].equals(MigrationHash.getDigest(MigrationHash.getDigest(password, "SHA-256"), "SHA-256"));
+ String[] args = hash.split("\\$"); // $SHA$hash
+ return args.length == 3 && args[2].equals(getDigest(getDigest(password, "SHA-256"), "SHA-256"));
}),
SHA256_NO_SALT((hash, password) -> {
- String[] arr = hash.split("\\$"); // $SHA$hash
- return arr.length == 3 && arr[2].equals(MigrationHash.getDigest(password, "SHA-256"));
+ String[] args = hash.split("\\$"); // $SHA$hash
+ return args.length == 3 && args[2].equals(getDigest(password, "SHA-256"));
}),
SHA512_NO_SALT((hash, password) -> {
- String[] arr = hash.split("\\$"); // $SHA$hash
- return arr.length == 3 && arr[2].equals(MigrationHash.getDigest(password, "SHA-512"));
+ String[] args = hash.split("\\$"); // $SHA$hash
+ return args.length == 3 && args[2].equals(getDigest(password, "SHA-512"));
});
- final MigrationHashVerifier verifier;
+ private final MigrationHashVerifier verifier;
MigrationHash(MigrationHashVerifier verifier) {
this.verifier = verifier;
@@ -83,27 +80,23 @@ public enum MigrationHash {
return this.verifier.checkPassword(hash, password);
}
- private static String getDigest(String string, String algo) {
+ private static String getDigest(String string, String algorithm) {
try {
- MessageDigest messageDigest = MessageDigest.getInstance(algo);
- messageDigest.reset();
+ MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
messageDigest.update(string.getBytes(StandardCharsets.UTF_8));
byte[] array = messageDigest.digest();
- return String.format("%0" + (array.length << 1) + "x", new BigInteger(1, array));
+ return Hex.encodeHexString(array);
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException(e);
}
}
private static class Argon2Verifier implements MigrationHashVerifier {
- private Argon2 argon2;
+
+ private final Argon2 argon2 = Argon2Factory.create();
@Override
public boolean checkPassword(String hash, String password) {
- if (this.argon2 == null) {
- this.argon2 = Argon2Factory.create();
- }
-
return this.argon2.verify(hash, password.getBytes(StandardCharsets.UTF_8));
}
}
diff --git a/src/main/java/net/elytrium/limboauth/model/RegisteredPlayer.java b/src/main/java/net/elytrium/limboauth/model/RegisteredPlayer.java
index 7567f61..b54f9b8 100644
--- a/src/main/java/net/elytrium/limboauth/model/RegisteredPlayer.java
+++ b/src/main/java/net/elytrium/limboauth/model/RegisteredPlayer.java
@@ -20,7 +20,6 @@ package net.elytrium.limboauth.model;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
-@SuppressWarnings("unused")
@DatabaseTable(tableName = "AUTH")
public class RegisteredPlayer {
@@ -109,7 +108,7 @@ public class RegisteredPlayer {
}
public Long getRegDate() {
- return this.regDate;
+ return this.regDate == null ? (Long) Long.MIN_VALUE : this.regDate;
}
public void setUuid(String uuid) {
diff --git a/src/main/java/net/elytrium/limboauth/utils/SuggestUtils.java b/src/main/java/net/elytrium/limboauth/utils/SuggestUtils.java
deleted file mode 100644
index 83f3687..0000000
--- a/src/main/java/net/elytrium/limboauth/utils/SuggestUtils.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2021 - 2022 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.utils;
-
-import com.google.common.collect.ImmutableList;
-import com.velocitypowered.api.proxy.Player;
-import com.velocitypowered.api.proxy.ProxyServer;
-import java.util.List;
-import java.util.stream.Collectors;
-
-public class SuggestUtils {
-
- public static List<String> suggestPlayers(String[] args, ProxyServer server) {
- if (args.length == 0) {
- return server.getAllPlayers().stream()
- .map(Player::getUsername)
- .collect(Collectors.toList());
- } else if (args.length == 1) {
- return server.getAllPlayers().stream()
- .map(Player::getUsername)
- .filter(str -> str.regionMatches(true, 0, args[0], 0, args[0].length()))
- .collect(Collectors.toList());
- }
-
- return ImmutableList.of();
- }
-}
diff --git a/src/main/java/net/elytrium/limboauth/utils/UpdatesChecker.java b/src/main/java/net/elytrium/limboauth/utils/UpdatesChecker.java
deleted file mode 100644
index f7b7df3..0000000
--- a/src/main/java/net/elytrium/limboauth/utils/UpdatesChecker.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2021 - 2022 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.utils;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.net.URLConnection;
-import java.nio.charset.StandardCharsets;
-import java.util.concurrent.TimeUnit;
-import net.elytrium.limboauth.Settings;
-import org.slf4j.Logger;
-
-public class UpdatesChecker {
-
- public static void checkForUpdates(Logger logger) {
- try {
- URLConnection conn = new URL("https://raw.githubusercontent.com/Elytrium/LimboAuth/master/VERSION").openConnection();
- int timeout = (int) TimeUnit.SECONDS.toMillis(5);
- conn.setConnectTimeout(timeout);
- conn.setReadTimeout(timeout);
- try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
- String latestVersion = in.readLine();
- if (latestVersion == null) {
- logger.warn("Unable to check for updates.");
- return;
- }
- String latestVersion0 = getCleanVersion(latestVersion.trim());
- String currentVersion0 = getCleanVersion(Settings.IMP.VERSION);
- int latestVersionId = Integer.parseInt(latestVersion0.replace(".", "").replace("$", ""));
- int currentVersionId = Integer.parseInt(currentVersion0.replace(".", "").replace("$", ""));
- if (latestVersion0.endsWith("$")) {
- --latestVersionId;
- }
- if (currentVersion0.endsWith("$")) {
- --currentVersionId;
- }
-
- if (currentVersionId < latestVersionId) {
- logger.error("****************************************");
- logger.warn("The new LimboAuth update was found, please update.");
- logger.error("https://github.com/Elytrium/LimboAuth/releases/");
- logger.error("****************************************");
- }
- }
- } catch (IOException e) {
- logger.warn("Unable to check for updates.", e);
- }
- }
-
- private static String getCleanVersion(String version) {
- int indexOf = version.indexOf("-");
- if (indexOf > 0) {
- return version.substring(0, indexOf) + "$"; // "$" - Indicates that the version is not release.
- } else {
- return version;
- }
- }
-}