aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.gradle10
-rw-r--r--config/spotbugs/suppressions.xml3
-rw-r--r--src/main/java/net/elytrium/limboauth/LimboAuth.java127
-rw-r--r--src/main/java/net/elytrium/limboauth/Settings.java29
-rw-r--r--src/main/java/net/elytrium/limboauth/command/LimboAuthCommand.java8
-rw-r--r--src/main/java/net/elytrium/limboauth/config/Config.java18
-rw-r--r--src/main/java/net/elytrium/limboauth/floodgate/FloodgateApiHolder.java37
-rw-r--r--src/main/java/net/elytrium/limboauth/listener/AuthListener.java36
-rw-r--r--src/main/java/net/elytrium/limboauth/utils/UpdatesChecker.java2
-rw-r--r--src/main/templates/net/elytrium/limboauth/BuildConstants.java2
10 files changed, 201 insertions, 71 deletions
diff --git a/build.gradle b/build.gradle
index 36c0bc3..fab4327 100644
--- a/build.gradle
+++ b/build.gradle
@@ -9,7 +9,7 @@ plugins {
}
setGroup("net.elytrium")
-setVersion("1.0.3-rc1")
+setVersion("1.0.3-rc2")
compileJava {
getOptions().setEncoding("UTF-8")
@@ -28,17 +28,23 @@ repositories {
setUrl("https://papermc.io/repo/repository/maven-public/")
}
maven {
+ setName("opencollab-repo")
+ setUrl("https://repo.opencollab.dev/maven-snapshots/")
+ }
+ maven {
setName("elytrium-repo")
setUrl("https://maven.elytrium.net/repo/")
}
}
dependencies {
- compileOnly("net.elytrium:limboapi-api:1.0.3-rc1")
+ compileOnly("net.elytrium:limboapi-api:1.0.3-rc2")
compileOnly("com.velocitypowered:velocity-api:3.1.2-SNAPSHOT")
annotationProcessor("com.velocitypowered:velocity-api:3.1.2-SNAPSHOT")
+ compileOnly("org.geysermc.floodgate:api:2.1.1-SNAPSHOT")
+
implementation("at.favre.lib:bcrypt:0.9.0")
implementation("dev.samstevens.totp:totp:1.7.1")
diff --git a/config/spotbugs/suppressions.xml b/config/spotbugs/suppressions.xml
index 3b4b6f6..eb21bfb 100644
--- a/config/spotbugs/suppressions.xml
+++ b/config/spotbugs/suppressions.xml
@@ -2,6 +2,9 @@
<FindBugsFilter>
<Match>
+ <Bug pattern="EI_EXPOSE_REP"/>
+ </Match>
+ <Match>
<Bug pattern="EI_EXPOSE_REP2"/>
</Match>
</FindBugsFilter>
diff --git a/src/main/java/net/elytrium/limboauth/LimboAuth.java b/src/main/java/net/elytrium/limboauth/LimboAuth.java
index a86f3c5..85c3b08 100644
--- a/src/main/java/net/elytrium/limboauth/LimboAuth.java
+++ b/src/main/java/net/elytrium/limboauth/LimboAuth.java
@@ -18,7 +18,6 @@
package net.elytrium.limboauth;
import com.google.inject.Inject;
-import com.google.inject.name.Named;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.field.FieldType;
@@ -34,7 +33,6 @@ 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;
@@ -54,6 +52,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@@ -73,12 +72,14 @@ import net.elytrium.limboauth.command.LimboAuthCommand;
import net.elytrium.limboauth.command.PremiumCommand;
import net.elytrium.limboauth.command.TotpCommand;
import net.elytrium.limboauth.command.UnregisterCommand;
+import net.elytrium.limboauth.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.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+import net.kyori.adventure.title.Title;
import org.bstats.velocity.Metrics;
import org.slf4j.Logger;
@@ -87,13 +88,20 @@ import org.slf4j.Logger;
name = "LimboAuth",
version = BuildConstants.AUTH_VERSION,
url = "https://elytrium.net/",
- authors = {"hevav", "mdxd44"},
- dependencies = {@Dependency(id = "limboapi")}
+ authors = {
+ "hevav",
+ "mdxd44"
+ },
+ dependencies = {
+ @Dependency(id = "limboapi"),
+ @Dependency(id = "floodgate", optional = true)
+ }
)
-@SuppressFBWarnings({"EI_EXPOSE_REP", "MS_EXPOSE_REP"})
public class LimboAuth {
- private static LimboAuth instance;
+ private final Map<String, CachedUser> cachedAuthChecks = 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;
@@ -101,25 +109,27 @@ public class LimboAuth {
private final Metrics.Factory metricsFactory;
private final Path dataDirectory;
private final LimboFactory factory;
+ private final FloodgateApiHolder floodgateApi;
- private final Set<String> unsafePasswords = new HashSet<>();
- private Map<String, CachedUser> cachedAuthChecks;
private Dao<RegisteredPlayer, String> playerDao;
private Pattern nicknameValidationPattern;
private Limbo authServer;
private Component nicknameInvalid;
@Inject
- @SuppressWarnings("OptionalGetWithoutIsPresent")
- public LimboAuth(ProxyServer server, Logger logger, Metrics.Factory metricsFactory,
- @Named("limboapi") PluginContainer factory, @DataDirectory Path dataDirectory) {
- setInstance(this);
-
+ public LimboAuth(ProxyServer server, Logger logger, Metrics.Factory metricsFactory, @DataDirectory Path dataDirectory) {
this.server = server;
this.logger = logger;
this.metricsFactory = metricsFactory;
this.dataDirectory = dataDirectory;
- this.factory = (LimboFactory) factory.getInstance().get();
+
+ this.factory = (LimboFactory) this.server.getPluginManager().getPlugin("limboapi").flatMap(PluginContainer::getInstance).orElseThrow();
+
+ if (this.server.getPluginManager().getPlugin("floodgate").isPresent()) {
+ this.floodgateApi = new FloodgateApiHolder();
+ } else {
+ this.floodgateApi = null;
+ }
}
@Subscribe
@@ -136,17 +146,21 @@ public class LimboAuth {
public void reload() throws Exception {
Settings.IMP.reload(new File(this.dataDirectory.toFile().getAbsoluteFile(), "config.yml"));
+ 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.");
+ }
+
if (Settings.IMP.MAIN.CHECK_PASSWORD_STRENGTH) {
this.unsafePasswords.clear();
- Path unsafePasswordsFile = Paths.get(this.dataDirectory.toFile().getAbsolutePath(), Settings.IMP.MAIN.UNSAFE_PASSWORDS_FILE);
- if (!unsafePasswordsFile.toFile().exists()) {
- Files.copy(Objects.requireNonNull(this.getClass().getResourceAsStream("/unsafe_passwords.txt")), unsafePasswordsFile);
+ Path unsafePasswordsPath = Paths.get(this.dataDirectory.toFile().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(unsafePasswordsFile).collect(Collectors.toSet()));
+ this.unsafePasswords.addAll(Files.lines(unsafePasswordsPath).collect(Collectors.toSet()));
}
- this.cachedAuthChecks = new ConcurrentHashMap<>();
+ this.cachedAuthChecks.clear();
Settings.DATABASE dbConfig = Settings.IMP.DATABASE;
JdbcPooledConnectionSource connectionSource;
@@ -205,7 +219,7 @@ public class LimboAuth {
if (Settings.IMP.MAIN.ENABLE_TOTP) {
manager.register("2fa", new TotpCommand(this.playerDao), "totp");
}
- manager.register("limboauth", new LimboAuthCommand(), "la", "auth", "lauth");
+ manager.register("limboauth", new LimboAuthCommand(this), "la", "auth", "lauth");
Settings.MAIN.AUTH_COORDS authCoords = Settings.IMP.MAIN.AUTH_COORDS;
VirtualWorld authWorld = this.factory.createVirtualWorld(
@@ -242,7 +256,7 @@ public class LimboAuth {
this.nicknameInvalid = LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.NICKNAME_INVALID_KICK);
this.server.getEventManager().unregisterListeners(this);
- this.server.getEventManager().register(this, new AuthListener(this.playerDao));
+ this.server.getEventManager().register(this, new AuthListener(this, this.playerDao));
Executors.newScheduledThreadPool(1, task -> new Thread(task, "purge-cache")).scheduleAtFixedRate(() ->
this.checkCache(this.cachedAuthChecks, Settings.IMP.MAIN.PURGE_CACHE_MILLIS),
@@ -282,7 +296,7 @@ public class LimboAuth {
tables.forEach(t -> {
try {
String columnDefinition = t.getColumnDefinition();
- StringBuilder builder = new StringBuilder("ALTER TABLE `auth` ADD ");
+ StringBuilder builder = new StringBuilder("ALTER TABLE `AUTH` ADD ");
List<String> dummy = new ArrayList<>();
if (columnDefinition == null) {
playerDao.getConnectionSource().getDatabaseType().appendColumnArg(t.getTableName(), builder, t, dummy, dummy, dummy, dummy);
@@ -313,12 +327,11 @@ public class LimboAuth {
public boolean needAuth(Player player) {
String username = player.getUsername();
-
if (!this.cachedAuthChecks.containsKey(username)) {
return true;
+ } else {
+ return !this.cachedAuthChecks.get(username).getInetAddress().equals(player.getRemoteAddress().getAddress());
}
-
- return !this.cachedAuthChecks.get(username).getInetAddress().equals(player.getRemoteAddress().getAddress());
}
public void authPlayer(Player player) {
@@ -329,10 +342,41 @@ public class LimboAuth {
}
RegisteredPlayer registeredPlayer = AuthSessionHandler.fetchInfo(this.playerDao, nickname);
- if (player.isOnlineMode()) {
+ boolean onlineMode = player.isOnlineMode();
+ if (onlineMode || (!Settings.IMP.MAIN.FLOODGATE_NEED_AUTH && this.floodgateApi.isFloodgatePlayer(player.getUniqueId()))) {
if (registeredPlayer == null || registeredPlayer.getHash().isEmpty()) {
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 (!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)
+ )
+ );
+ }
+ } else {
+ if (!Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE.isEmpty()) {
+ player.sendMessage(LegacyComponentSerializer.legacyAmpersand().deserialize(Settings.IMP.MAIN.STRINGS.LOGIN_FLOODGATE));
+ }
+ 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)
+ )
+ );
+ }
+ }
+ });
+
this.factory.passLoginLimbo(player);
return;
}
@@ -364,23 +408,24 @@ public class LimboAuth {
public boolean isPremium(String nickname) {
try {
if (this.isPremiumExternal(nickname)) {
- QueryBuilder<RegisteredPlayer, String> query = this.playerDao.queryBuilder();
- query.where()
+ QueryBuilder<RegisteredPlayer, String> premiumRegisteredQuery = this.playerDao.queryBuilder();
+ premiumRegisteredQuery.where()
.eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT))
.and()
.ne("HASH", "");
- query.setCountOf(true);
- QueryBuilder<RegisteredPlayer, String> query2 = this.playerDao.queryBuilder();
- query2.where()
+ premiumRegisteredQuery.setCountOf(true);
+
+ QueryBuilder<RegisteredPlayer, String> premiumUnregisteredQuery = this.playerDao.queryBuilder();
+ premiumUnregisteredQuery.where()
.eq("LOWERCASENICKNAME", nickname.toLowerCase(Locale.ROOT))
.and()
.eq("HASH", "");
- query2.setCountOf(true);
+ premiumUnregisteredQuery.setCountOf(true);
+
if (Settings.IMP.MAIN.ONLINE_MODE_NEED_AUTH) {
- return this.playerDao.countOf(query.prepare()) == 0
- && this.playerDao.countOf(query2.prepare()) != 0;
+ return this.playerDao.countOf(premiumRegisteredQuery.prepare()) == 0 && this.playerDao.countOf(premiumUnregisteredQuery.prepare()) != 0;
} else {
- return this.playerDao.countOf(query.prepare()) == 0;
+ return this.playerDao.countOf(premiumRegisteredQuery.prepare()) == 0;
}
} else {
return false;
@@ -398,18 +443,14 @@ public class LimboAuth {
.forEach(userMap::remove);
}
- private static void setInstance(LimboAuth instance) {
- LimboAuth.instance = instance;
- }
-
- public static LimboAuth getInstance() {
- return instance;
- }
-
public Set<String> getUnsafePasswords() {
return this.unsafePasswords;
}
+ public Map<UUID, Runnable> getPostLoginTasks() {
+ return this.postLoginTasks;
+ }
+
public Logger getLogger() {
return this.logger;
}
diff --git a/src/main/java/net/elytrium/limboauth/Settings.java b/src/main/java/net/elytrium/limboauth/Settings.java
index f32279b..bbae307 100644
--- a/src/main/java/net/elytrium/limboauth/Settings.java
+++ b/src/main/java/net/elytrium/limboauth/Settings.java
@@ -48,7 +48,11 @@ public class Settings extends Config {
public boolean CHECK_PASSWORD_STRENGTH = true;
public String UNSAFE_PASSWORDS_FILE = "unsafe_passwords.txt";
public boolean ONLINE_MODE_NEED_AUTH = true;
+ @Comment("Needs floodgate plugin.")
+ public boolean FLOODGATE_NEED_AUTH = true;
public boolean FORCE_OFFLINE_UUID = false;
+ @Comment("Delay in milliseconds before sending auth-confirming titles and messages to the player. (login-premium-title, login-floodgate, etc.)")
+ public int PREMIUM_AND_FLOODGATE_MESSAGES_DELAY = 1250;
@Comment({
"Forcibly set player's UUID to the value from the database",
"If the player had the cracked account, and switched to the premium account, the cracked UUID will be used."
@@ -122,7 +126,7 @@ public class Settings extends Config {
@Create
public MAIN.STRINGS STRINGS;
- @Comment("Leave title fields empty to disable.")
+ @Comment("You can left blank the fields marked with \"*\" comment.")
public static class STRINGS {
public String RELOAD = "{PRFX} &aReloaded successfully!";
@@ -142,13 +146,30 @@ public class Settings extends Config {
public String BOSSBAR = "{PRFX} You have &6{0} &fseconds left to log in.";
public String TIMES_UP = "{PRFX}{NL}&cAuthorization time is up.";
+ @Comment("*")
+ public String LOGIN_PREMIUM = "{PRFX} You've been logged in automatically using the premium account!";
+ @Comment("*")
+ public String LOGIN_PREMIUM_TITLE = "{PRFX} Welcome!";
+ @Comment("*")
+ public String LOGIN_PREMIUM_SUBTITLE = "&aYou has been logged in as premium player!";
+ @Comment("*")
+ public String LOGIN_FLOODGATE = "{PRFX} You've been logged in automatically using the bedrock account!";
+ @Comment("*")
+ public String LOGIN_FLOODGATE_TITLE = "{PRFX} Welcome!";
+ @Comment("*")
+ 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("*")
public String LOGIN_TITLE = "&fPlease, login using &6/login <password>&a.";
+ @Comment("*")
public String LOGIN_SUBTITLE = "&aYou have &6{0} &aattempts.";
+ @Comment("*")
public String LOGIN_SUCCESSFUL_TITLE = "{PRFX}";
+ @Comment("*")
public String LOGIN_SUCCESSFUL_SUBTITLE = "&aSuccessfully logged in!";
@Comment("Or if register-need-repeat-password set to false remove the \"<repeat password>\" part.")
@@ -158,9 +179,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("*")
public String REGISTER_TITLE = "{PRFX}";
+ @Comment("*")
public String REGISTER_SUBTITLE = "&aPlease, register using &6/register <password> <repeat password>";
+ @Comment("*")
public String REGISTER_SUCCESSFUL_TITLE = "{PRFX}";
+ @Comment("*")
public String REGISTER_SUCCESSFUL_SUBTITLE = "&aSuccessfully registered!";
public String UNREGISTER_SUCCESSFUL = "{PRFX}{NL}&aSuccessfully unregistered!";
@@ -186,7 +211,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("*")
public String TOTP_TITLE = "{PRFX}";
+ @Comment("*")
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!";
diff --git a/src/main/java/net/elytrium/limboauth/command/LimboAuthCommand.java b/src/main/java/net/elytrium/limboauth/command/LimboAuthCommand.java
index 611b1c3..1465023 100644
--- a/src/main/java/net/elytrium/limboauth/command/LimboAuthCommand.java
+++ b/src/main/java/net/elytrium/limboauth/command/LimboAuthCommand.java
@@ -30,6 +30,12 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
public class LimboAuthCommand implements SimpleCommand {
+ private final LimboAuth plugin;
+
+ public LimboAuthCommand(LimboAuth plugin) {
+ this.plugin = plugin;
+ }
+
@Override
public List<String> suggest(SimpleCommand.Invocation invocation) {
CommandSource source = invocation.source();
@@ -57,7 +63,7 @@ public class LimboAuthCommand implements SimpleCommand {
if (args.length == 1) {
if (args[0].equalsIgnoreCase("reload") && source.hasPermission("limboauth.admin.reload")) {
try {
- LimboAuth.getInstance().reload();
+ 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));
diff --git a/src/main/java/net/elytrium/limboauth/config/Config.java b/src/main/java/net/elytrium/limboauth/config/Config.java
index 1cb9803..6effa5d 100644
--- a/src/main/java/net/elytrium/limboauth/config/Config.java
+++ b/src/main/java/net/elytrium/limboauth/config/Config.java
@@ -39,13 +39,14 @@ import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
-import net.elytrium.limboauth.LimboAuth;
import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.yaml.snakeyaml.Yaml;
public class Config {
- private static final Logger LOGGER = LimboAuth.getInstance().getLogger();
+ private final Logger logger = LoggerFactory.getLogger(Config.class);
+
private String oldPrefix = "";
private String currentPrefix = "";
@@ -76,7 +77,7 @@ public class Config {
}
}
- LOGGER.debug("Failed to set config option: " + key + ": " + value + " | " + instance + " | " + root.getSimpleName() + ".yml");
+ this.logger.debug("Failed to set config option: " + key + ": " + value + " | " + instance + " | " + root.getSimpleName() + ".yml");
}
@SuppressWarnings("unchecked")
@@ -109,7 +110,7 @@ public class Config {
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
this.set(new Yaml().load(reader), "");
} catch (IOException e) {
- LOGGER.warn("Unable to load config ", e);
+ this.logger.warn("Unable to load config", e);
return false;
}
@@ -211,7 +212,7 @@ public class Config {
private void save(PrintWriter writer, Class<?> clazz, Object instance, int indent) {
try {
String lineSeparator = System.lineSeparator();
- String spacing = this.repeat(" ", indent);
+ String spacing = IntStream.range(0, indent).mapToObj(i -> " ").collect(Collectors.joining());
for (Field field : clazz.getFields()) {
if (field.getAnnotation(Ignore.class) != null) {
@@ -271,7 +272,7 @@ public class Config {
this.setAccessible(field);
return field;
} catch (Throwable ignored) {
- LOGGER.debug("Invalid config field: " + this.join(split, ".") + " for " + this.toNodeName(instance.getClass().getSimpleName()));
+ this.logger.debug("Invalid config field: " + this.join(split, ".") + " for " + this.toNodeName(instance.getClass().getSimpleName()));
return null;
}
}
@@ -368,11 +369,6 @@ public class Config {
}
@SuppressWarnings("SameParameterValue")
- private String repeat(String s, int n) {
- return IntStream.range(0, n).mapToObj(i -> s).collect(Collectors.joining());
- }
-
- @SuppressWarnings("SameParameterValue")
private String join(Object[] array, String delimiter) {
switch (array.length) {
case 0: {
diff --git a/src/main/java/net/elytrium/limboauth/floodgate/FloodgateApiHolder.java b/src/main/java/net/elytrium/limboauth/floodgate/FloodgateApiHolder.java
new file mode 100644
index 0000000..8832d4b
--- /dev/null
+++ b/src/main/java/net/elytrium/limboauth/floodgate/FloodgateApiHolder.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 Elytrium
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.elytrium.limboauth.floodgate;
+
+import java.util.UUID;
+import org.geysermc.floodgate.api.FloodgateApi;
+
+/**
+ * Holder class for optional floodgate feature, we can't inject of optional plugins without holders due to Velocity structure.
+ */
+public class FloodgateApiHolder {
+
+ private final FloodgateApi floodgateApi;
+
+ public FloodgateApiHolder() {
+ this.floodgateApi = FloodgateApi.getInstance();
+ }
+
+ public boolean isFloodgatePlayer(UUID uuid) {
+ return this.floodgateApi.isFloodgatePlayer(uuid);
+ }
+}
diff --git a/src/main/java/net/elytrium/limboauth/listener/AuthListener.java b/src/main/java/net/elytrium/limboauth/listener/AuthListener.java
index 0b0db2c..62d001c 100644
--- a/src/main/java/net/elytrium/limboauth/listener/AuthListener.java
+++ b/src/main/java/net/elytrium/limboauth/listener/AuthListener.java
@@ -20,10 +20,13 @@ package net.elytrium.limboauth.listener;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.UpdateBuilder;
import com.velocitypowered.api.event.Subscribe;
+import com.velocitypowered.api.event.connection.PostLoginEvent;
import com.velocitypowered.api.event.connection.PreLoginEvent;
import com.velocitypowered.api.util.UuidUtils;
import java.sql.SQLException;
+import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.TimeUnit;
import net.elytrium.limboapi.api.event.LoginLimboRegisterEvent;
import net.elytrium.limboapi.api.event.SafeGameProfileRequestEvent;
import net.elytrium.limboauth.LimboAuth;
@@ -34,16 +37,18 @@ import net.elytrium.limboauth.model.RegisteredPlayer;
// TODO: Customizable events priority
public class AuthListener {
+ private final LimboAuth plugin;
private final Dao<RegisteredPlayer, String> playerDao;
- public AuthListener(Dao<RegisteredPlayer, String> playerDao) {
+ public AuthListener(LimboAuth plugin, Dao<RegisteredPlayer, String> playerDao) {
+ this.plugin = plugin;
this.playerDao = playerDao;
}
@Subscribe
- public void onProxyConnect(PreLoginEvent event) {
+ public void onPreLoginEvent(PreLoginEvent event) {
if (!event.getResult().isForceOfflineMode()) {
- if (!LimboAuth.getInstance().isPremium(event.getUsername())) {
+ if (!this.plugin.isPremium(event.getUsername())) {
event.setResult(PreLoginEvent.PreLoginComponentResult.forceOfflineMode());
} else {
event.setResult(PreLoginEvent.PreLoginComponentResult.forceOnlineMode());
@@ -52,14 +57,26 @@ public class AuthListener {
}
@Subscribe
- public void onLogin(LoginLimboRegisterEvent event) {
- if (LimboAuth.getInstance().needAuth(event.getPlayer())) {
- event.addCallback(() -> LimboAuth.getInstance().authPlayer(event.getPlayer()));
+ public void onPostLogin(PostLoginEvent event) {
+ Map<UUID, Runnable> postLoginTasks = this.plugin.getPostLoginTasks();
+ UUID uuid = event.getPlayer().getUniqueId();
+ if (postLoginTasks.containsKey(uuid)) {
+ // We need to delay for player's client to finish switching the server, it takes a little time.
+ this.plugin.getServer().getScheduler().buildTask(
+ this.plugin, () -> postLoginTasks.get(uuid).run()
+ ).delay(Settings.IMP.MAIN.PREMIUM_AND_FLOODGATE_MESSAGES_DELAY, TimeUnit.MILLISECONDS).schedule();
}
}
@Subscribe
- public void onProfile(SafeGameProfileRequestEvent event) {
+ public void onLoginLimboRegister(LoginLimboRegisterEvent event) {
+ if (this.plugin.needAuth(event.getPlayer())) {
+ event.addCallback(() -> this.plugin.authPlayer(event.getPlayer()));
+ }
+ }
+
+ @Subscribe
+ public void onGameProfileRequest(SafeGameProfileRequestEvent event) {
if (Settings.IMP.MAIN.SAVE_UUID) {
RegisteredPlayer registeredPlayer = AuthSessionHandler.fetchInfo(this.playerDao, event.getOriginalProfile().getId());
@@ -67,15 +84,12 @@ public class AuthListener {
event.setGameProfile(event.getOriginalProfile().withId(UUID.fromString(registeredPlayer.getUuid())));
return;
}
-
registeredPlayer = AuthSessionHandler.fetchInfo(this.playerDao, event.getUsername());
if (registeredPlayer != null) {
String currentUuid = registeredPlayer.getUuid();
- if (event.isOnlineMode()
- && registeredPlayer.getHash().isEmpty()
- && registeredPlayer.getPremiumUuid().isEmpty()) {
+ if (event.isOnlineMode() && registeredPlayer.getHash().isEmpty() && registeredPlayer.getPremiumUuid().isEmpty()) {
try {
registeredPlayer.setPremiumUuid(event.getOriginalProfile().getId().toString());
this.playerDao.update(registeredPlayer);
diff --git a/src/main/java/net/elytrium/limboauth/utils/UpdatesChecker.java b/src/main/java/net/elytrium/limboauth/utils/UpdatesChecker.java
index 71af1bb..79a2998 100644
--- a/src/main/java/net/elytrium/limboauth/utils/UpdatesChecker.java
+++ b/src/main/java/net/elytrium/limboauth/utils/UpdatesChecker.java
@@ -67,7 +67,7 @@ public class UpdatesChecker {
private static String getCleanVersion(String version) {
int indexOf = version.indexOf("-");
if (indexOf > 0) {
- return version.substring(0, indexOf) + "$"; // "$" - Indicates that the version is snapshot
+ return version.substring(0, indexOf) + "$"; // "$" - Indicates that the version is not release.
} else {
return version;
}
diff --git a/src/main/templates/net/elytrium/limboauth/BuildConstants.java b/src/main/templates/net/elytrium/limboauth/BuildConstants.java
index b8d7966..855bc88 100644
--- a/src/main/templates/net/elytrium/limboauth/BuildConstants.java
+++ b/src/main/templates/net/elytrium/limboauth/BuildConstants.java
@@ -17,7 +17,7 @@
package net.elytrium.limboauth;
-// The constants are replaced before compilation
+// The constants are replaced before compilation.
public class BuildConstants {
public static final String AUTH_VERSION = "${version}";