diff --git a/API/src/main/java/xyz/kyngs/librelogin/api/LibreLoginPlugin.java b/API/src/main/java/xyz/kyngs/librelogin/api/LibreLoginPlugin.java index ce96eae9..459f0bb8 100644 --- a/API/src/main/java/xyz/kyngs/librelogin/api/LibreLoginPlugin.java +++ b/API/src/main/java/xyz/kyngs/librelogin/api/LibreLoginPlugin.java @@ -7,6 +7,7 @@ package xyz.kyngs.librelogin.api; import xyz.kyngs.librelogin.api.authorization.AuthorizationProvider; +import xyz.kyngs.librelogin.api.configuration.CorruptedConfigurationException; import xyz.kyngs.librelogin.api.configuration.Messages; import xyz.kyngs.librelogin.api.crypto.CryptoProvider; import xyz.kyngs.librelogin.api.crypto.HashedPassword; @@ -24,6 +25,7 @@ import xyz.kyngs.librelogin.api.util.ThrowableFunction; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.sql.Timestamp; import java.util.Map; @@ -291,4 +293,9 @@ User createUser( String lastServer, String email ); + + /** + * Reloads the configurations and registers/unregisters new handlers (if possible). + */ + void reloadConfiguration() throws CorruptedConfigurationException, IOException; } diff --git a/API/src/main/java/xyz/kyngs/librelogin/api/authorization/AuthorizationProvider.java b/API/src/main/java/xyz/kyngs/librelogin/api/authorization/AuthorizationProvider.java index 0d36304d..3a582791 100644 --- a/API/src/main/java/xyz/kyngs/librelogin/api/authorization/AuthorizationProvider.java +++ b/API/src/main/java/xyz/kyngs/librelogin/api/authorization/AuthorizationProvider.java @@ -33,6 +33,14 @@ public interface AuthorizationProvider
{ */ boolean isAwaiting2FA(P player); + /** + * Checks whether the player is in the process of disabling 2FA. + * + * @param player The player. + * @return True if the player needs to confirm the action of disabling 2FA, false otherwise. + */ + boolean isAwaiting2FADisable(P player); + /** * Authorizes the player, if the player is not already authorized. Implementation must make sure that {@link #isAuthorized(P)} returns false. * @@ -51,4 +59,14 @@ public interface AuthorizationProvider
{ * @return whether the code is valid. */ boolean confirmTwoFactorAuth(P player, Integer code, User user); + + /** + * Finishes the 2FA disabling process. + * + * @param player The player. + * @param code The code. + * @param user The user. + * @return whether the code is valid. + */ + boolean confirmTwoFactorAuthDisable(P player, Integer code, User user); } diff --git a/API/src/main/java/xyz/kyngs/librelogin/api/server/ServerHandler.java b/API/src/main/java/xyz/kyngs/librelogin/api/server/ServerHandler.java index 7bc363e6..9acfd108 100644 --- a/API/src/main/java/xyz/kyngs/librelogin/api/server/ServerHandler.java +++ b/API/src/main/java/xyz/kyngs/librelogin/api/server/ServerHandler.java @@ -100,4 +100,9 @@ default void registerLobbyServer(S server) { */ void registerLimboServer(S server); + /** + * Shuts down server handler. + */ + void shutdown(); + } diff --git a/Plugin/src/main/java/xyz/kyngs/librelogin/common/AuthenticLibreLogin.java b/Plugin/src/main/java/xyz/kyngs/librelogin/common/AuthenticLibreLogin.java index 5c873072..1c4d1c6a 100644 --- a/Plugin/src/main/java/xyz/kyngs/librelogin/common/AuthenticLibreLogin.java +++ b/Plugin/src/main/java/xyz/kyngs/librelogin/common/AuthenticLibreLogin.java @@ -290,26 +290,12 @@ protected void enable() { connectToDB(); - serverHandler = new AuthenticServerHandler<>(this); - this.loginTryListener = new LoginTryListener<>(this); // Moved to a different class to avoid class loading issues GeneralUtil.checkAndMigrate(configuration, logger, this); - imageProjector = provideImageProjector(); - - if (imageProjector != null) { - if (!configuration.get(TOTP_ENABLED)) { - imageProjector = null; - logger.warn("2FA is disabled in the configuration, aborting..."); - } else { - imageProjector.enable(); - } - } - - totpProvider = imageProjector == null ? null : new AuthenticTOTPProvider(this); - eMailHandler = configuration.get(MAIL_ENABLED) ? new AuthenticEMailHandler(this) : null; + reloadComponents(); authorizationProvider = new AuthenticAuthorizationProvider<>(this); commandProvider = new CommandProvider<>(this); @@ -717,6 +703,30 @@ public void checkDataFolder() { if (!folder.exists()) if (!folder.mkdir()) throw new RuntimeException("Failed to create datafolder"); } + @Override + public void reloadConfiguration() throws CorruptedConfigurationException, IOException { + this.getConfiguration().reload(this); + if (serverHandler != null) serverHandler.shutdown(); + reloadComponents(); + } + + private void reloadComponents() { + serverHandler = new AuthenticServerHandler<>(this); + + imageProjector = provideImageProjector(); + + if (imageProjector != null) { + if (!configuration.get(TOTP_ENABLED)) { + imageProjector = null; + } else { + imageProjector.enable(); + } + } + + totpProvider = configuration.get(TOTP_ENABLED) ? new AuthenticTOTPProvider(this) : null; + eMailHandler = configuration.get(MAIL_ENABLED) ? new AuthenticEMailHandler(this) : null; + } + protected abstract Logger provideLogger(); public abstract CommandManager, ?, ?, ?, ?, ?> provideManager(); diff --git a/Plugin/src/main/java/xyz/kyngs/librelogin/common/authorization/AuthenticAuthorizationProvider.java b/Plugin/src/main/java/xyz/kyngs/librelogin/common/authorization/AuthenticAuthorizationProvider.java index 51e2f5f6..7b8c2c6a 100644 --- a/Plugin/src/main/java/xyz/kyngs/librelogin/common/authorization/AuthenticAuthorizationProvider.java +++ b/Plugin/src/main/java/xyz/kyngs/librelogin/common/authorization/AuthenticAuthorizationProvider.java @@ -33,6 +33,7 @@ public class AuthenticAuthorizationProvider
extends AuthenticHandler
private final Map
unAuthorized; private final Map
awaiting2FA; + private final Map
awaiting2FADisable;
private final Cache plugin) {
super(plugin);
unAuthorized = new ConcurrentHashMap<>();
awaiting2FA = new ConcurrentHashMap<>();
+ awaiting2FADisable = new ConcurrentHashMap<>();
var millis = plugin.getConfiguration().get(ConfigurationKeys.MILLISECONDS_TO_REFRESH_NOTIFICATION);
@@ -69,6 +71,7 @@ public Cache plugin) {
if (plugin.getTOTPProvider() != null) {
manager.registerCommand(new TwoFactorAuthCommand<>(plugin));
manager.registerCommand(new TwoFactorConfirmCommand<>(plugin));
+ manager.registerCommand(new TwoFactorAuthDisableCommand<>(plugin));
}
if (plugin.getEmailHandler() != null) {
diff --git a/Plugin/src/main/java/xyz/kyngs/librelogin/common/command/commands/staff/LibreLoginCommand.java b/Plugin/src/main/java/xyz/kyngs/librelogin/common/command/commands/staff/LibreLoginCommand.java
index a7ef0683..5f7bec3f 100644
--- a/Plugin/src/main/java/xyz/kyngs/librelogin/common/command/commands/staff/LibreLoginCommand.java
+++ b/Plugin/src/main/java/xyz/kyngs/librelogin/common/command/commands/staff/LibreLoginCommand.java
@@ -160,7 +160,7 @@ public CompletionStage extends Command {
+ public TwoFactorAuthDisableCommand(AuthenticLibreLogin plugin) {
+ super(plugin);
+ }
+
+ @Default
+ @Syntax("{@@syntax.2fa-disable}")
+ @CommandCompletion("%autocomplete.2fa-disable")
+ public CompletionStage implements ServerHandler {
private final AuthenticLibreLogin plugin;
private final Collection plugin) {
this.plugin = plugin;
@@ -52,7 +54,7 @@ public AuthenticServerHandler(AuthenticLibreLogin plugin) {
return Optional.ofNullable(plugin.getConfiguration().get(IGNORE_MAX_PLAYERS_FROM_BACKEND_PING) ? new ServerPing(Integer.MAX_VALUE) : ping);
});
- plugin.repeat(() -> pingCache.refreshAll(pingCache.asMap().keySet()), 10000, 10000);
+ pingCacheRefreshTask = plugin.repeat(() -> pingCache.refreshAll(pingCache.asMap().keySet()), 10000, 10000);
var handle = plugin.getPlatformHandle();
@@ -182,4 +184,11 @@ public void registerLimboServer(S server) {
getLatestPing(server);
limboServers.add(server);
}
+
+ @Override
+ public void shutdown() {
+ pingCacheRefreshTask.cancel();
+ pingCache.invalidateAll();
+ pingCache.cleanUp();
+ }
}
diff --git a/Plugin/src/main/java/xyz/kyngs/librelogin/velocity/VelocityListeners.java b/Plugin/src/main/java/xyz/kyngs/librelogin/velocity/VelocityListeners.java
index 9c1c3e32..b0ad3519 100644
--- a/Plugin/src/main/java/xyz/kyngs/librelogin/velocity/VelocityListeners.java
+++ b/Plugin/src/main/java/xyz/kyngs/librelogin/velocity/VelocityListeners.java
@@ -167,9 +167,10 @@ public void onKick(KickedFromServerEvent event) {
if (event.kickedDuringServerConnect()) {
event.setResult(KickedFromServerEvent.Notify.create(message));
} else {
- if (!plugin.getConfiguration().get(ConfigurationKeys.FALLBACK) || plugin.getServerHandler().getLobbyServers().containsValue(event.getServer())) {
+ if (plugin.getServerHandler().getLobbyServers().containsValue(event.getServer())) {
event.setResult(KickedFromServerEvent.DisconnectPlayer.create(message));
} else {
+ if (!plugin.getConfiguration().get(ConfigurationKeys.FALLBACK)) return;
try {
var server = plugin.getServerHandler().chooseLobbyServer(plugin.getDatabaseProvider().getByUUID(player.getUniqueId()), player, false, true);
command to complete the process.
+ Disconnect to abort.""",
+ "This message is displayed when the player is prompted to scan the 2FA QR code but can't show in game graphic.",
+ ConfigurateHelper::getString
+ );
+
+ public static final ConfigurationKey
+ Once 2FA is disabled, you will be able to log in without a 2FA code.
+ This action is irreversible. Once disabled, old codes will no longer work.""",
+ "This message is displayed when the player is prompted to confirm he wants to disable 2fa.",
+ ConfigurateHelper::getString
+ );
+
+ public static final ConfigurationKey",
+ "This message is displayed when the player attempts to disable 2FA with wrong syntax.",
+ ConfigurateHelper::getString
+ );
+
public static final ConfigurationKey limboServers;
private final Multimap