From b425704cf72baa60f2f738e3b17748cacd2454b3 Mon Sep 17 00:00:00 2001 From: Snake Date: Tue, 14 Nov 2023 18:41:00 +0100 Subject: [PATCH 1/9] feat: now libertybans should support alt registration per server. This means that now you can choose whether all servers will register alts or only the selected ones. For proxies, you need to provide the names of the servers that you have in your configs, and for backends just enable or disable a setting in config. --- .../core/selector/EnforcementConfig.java | 27 ++++++++++++++++ .../libertybans/core/selector/Gatekeeper.java | 31 ++++++++++++++++--- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java index fe27bc98d..5d95fc6e4 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java @@ -19,6 +19,7 @@ package space.arim.libertybans.core.selector; +import java.util.List; import java.util.Set; import space.arim.dazzleconf.annote.ConfComments; @@ -138,4 +139,30 @@ interface AltAccountExpiration { long expirationTimeDays(); } + + @SubSection + AltsRegistry altsRegistry(); + + @ConfHeader({"Controls if all servers should register the IP address of the player connecting."}) + interface AltsRegistry { + + @ConfComments("If true, all servers will register alts.") + @ConfKey("enable-all") + @ConfDefault.DefaultBoolean(true) + boolean enableAll(); + + @ConfComments({"If enableAll is false, this list will be used ", + "to determine which servers will register alts.", + "Please note that the server's name of the list should be the same as the ones in your proxy config", + "This is intended to be used by LibertyBans proxy installations.", + "If this is a backend server, please skip this option."}) + @ConfKey("servers") + @DefaultStrings("") + List servers(); + + @ConfComments({"If true, this backend server will register alts"}) + @ConfKey("should-register") + @ConfDefault.DefaultBoolean(true) + boolean shouldRegister(); + } } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java index a47fadb97..4877e56cb 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java @@ -22,9 +22,11 @@ import jakarta.inject.Inject; import jakarta.inject.Provider; import net.kyori.adventure.text.Component; +import org.jooq.DSLContext; import space.arim.libertybans.api.NetworkAddress; import space.arim.libertybans.api.PunishmentType; import space.arim.libertybans.api.punish.Punishment; +import space.arim.libertybans.api.scope.ScopeManager; import space.arim.libertybans.api.scope.ServerScope; import space.arim.libertybans.api.select.SelectionPredicate; import space.arim.libertybans.api.select.SortPunishments; @@ -55,11 +57,12 @@ public final class Gatekeeper { private final AltDetection altDetection; private final AltNotification altNotification; private final Time time; + private final ScopeManager scopeManager; @Inject public Gatekeeper(Configs configs, FactoryOfTheFuture futuresFactory, Provider queryExecutor, InternalFormatter formatter, ConnectionLimiter connectionLimiter, AltDetection altDetection, - AltNotification altNotification, Time time) { + AltNotification altNotification, Time time, ScopeManager scopeManager) { this.configs = configs; this.futuresFactory = futuresFactory; this.queryExecutor = queryExecutor; @@ -68,6 +71,7 @@ public Gatekeeper(Configs configs, FactoryOfTheFuture futuresFactory, Provider executeAndCheckConnection(UUID uuid, String name, NetworkAddress address, @@ -75,9 +79,21 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N return queryExecutor.get().queryWithRetry((context, transaction) -> { Instant currentTime = time.currentTimestamp(); - Association association = new Association(uuid, context); - association.associateCurrentName(name, currentTime); - association.associateCurrentAddress(address, currentTime); + EnforcementConfig config = configs.getMainConfig().enforcement(); + + if (config.altsRegistry().enableAll()) { + doAssociation(uuid, name, address, currentTime, context); + + } else if (config.altsRegistry().shouldRegister()) { + doAssociation(uuid, name, address, currentTime, context); + + } else { + List servers = config.altsRegistry().servers(); + String serverName = configs.getScopeConfig().serverName().overrideValue(); + if (!servers.isEmpty() && servers.contains(serverName)) { + doAssociation(uuid, name, address, currentTime, context); + } + } Punishment ban = selector.selectionByApplicabilityBuilder(uuid, address) .type(PunishmentType.BAN) @@ -113,4 +129,11 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N return futuresFactory.completedFuture(null); }); } + + private void doAssociation(UUID uuid, String name, NetworkAddress address, + Instant currentTime, DSLContext context) { + Association association = new Association(uuid, context); + association.associateCurrentName(name, currentTime); + association.associateCurrentAddress(address, currentTime); + } } From 45e457f4d20a87a1efaa54482b74858d4d24f40d Mon Sep 17 00:00:00 2001 From: Snake Date: Tue, 14 Nov 2023 18:41:23 +0100 Subject: [PATCH 2/9] feat: now libertybans should support alt registration per server. This means that now you can choose whether all servers will register alts or only the selected ones. For proxies, you need to provide the names of the servers that you have in your configs, and for backends just enable or disable a setting in config. --- .../space/arim/libertybans/core/selector/Gatekeeper.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java index 4877e56cb..bc822f32a 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java @@ -26,7 +26,6 @@ import space.arim.libertybans.api.NetworkAddress; import space.arim.libertybans.api.PunishmentType; import space.arim.libertybans.api.punish.Punishment; -import space.arim.libertybans.api.scope.ScopeManager; import space.arim.libertybans.api.scope.ServerScope; import space.arim.libertybans.api.select.SelectionPredicate; import space.arim.libertybans.api.select.SortPunishments; @@ -57,12 +56,11 @@ public final class Gatekeeper { private final AltDetection altDetection; private final AltNotification altNotification; private final Time time; - private final ScopeManager scopeManager; @Inject public Gatekeeper(Configs configs, FactoryOfTheFuture futuresFactory, Provider queryExecutor, InternalFormatter formatter, ConnectionLimiter connectionLimiter, AltDetection altDetection, - AltNotification altNotification, Time time, ScopeManager scopeManager) { + AltNotification altNotification, Time time) { this.configs = configs; this.futuresFactory = futuresFactory; this.queryExecutor = queryExecutor; @@ -71,7 +69,6 @@ public Gatekeeper(Configs configs, FactoryOfTheFuture futuresFactory, Provider executeAndCheckConnection(UUID uuid, String name, NetworkAddress address, From 8d43d13a218dc6be816131f6d1d77c8537dcb7f1 Mon Sep 17 00:00:00 2001 From: Snake Date: Tue, 14 Nov 2023 18:46:53 +0100 Subject: [PATCH 3/9] refactor --- .../java/space/arim/libertybans/core/selector/Gatekeeper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java index bc822f32a..3f4460088 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java @@ -77,7 +77,6 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N Instant currentTime = time.currentTimestamp(); EnforcementConfig config = configs.getMainConfig().enforcement(); - if (config.altsRegistry().enableAll()) { doAssociation(uuid, name, address, currentTime, context); From 5367dbce1f4ea0a16e1968d6f2b999263ab72c5f Mon Sep 17 00:00:00 2001 From: Snake Date: Sat, 18 Nov 2023 17:43:10 +0100 Subject: [PATCH 4/9] feat: should be working now [not tested yet] --- .../core/selector/EnforcementConfig.java | 23 +++++----- .../libertybans/core/selector/Gatekeeper.java | 43 ++++++++++++++----- .../libertybans/core/selector/Guardian.java | 24 +++++++++-- .../core/selector/IntelligentGuardian.java | 22 +++------- .../core/selector/InternalSelector.java | 23 +++++++--- .../core/selector/SelectorImpl.java | 6 +++ .../env/bungee/ConnectionListener.java | 2 +- .../env/velocity/ConnectionListener.java | 4 +- 8 files changed, 95 insertions(+), 52 deletions(-) diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java index 5d95fc6e4..e82a088b5 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java @@ -146,23 +146,20 @@ interface AltAccountExpiration { @ConfHeader({"Controls if all servers should register the IP address of the player connecting."}) interface AltsRegistry { - @ConfComments("If true, all servers will register alts.") - @ConfKey("enable-all") - @ConfDefault.DefaultBoolean(true) - boolean enableAll(); - - @ConfComments({"If enableAll is false, this list will be used ", - "to determine which servers will register alts.", + @ConfComments({"The server names in this list will be excluded from associating the IP address of the player connecting.", "Please note that the server's name of the list should be the same as the ones in your proxy config", - "This is intended to be used by LibertyBans proxy installations.", - "If this is a backend server, please skip this option."}) - @ConfKey("servers") + "This is intended to be used by LibertyBans proxy installations." + }) + @ConfKey("servers-without-ip-registration") @DefaultStrings("") List servers(); - @ConfComments({"If true, this backend server will register alts"}) - @ConfKey("should-register") + @ConfComments({"If you want to register the IP address of the player connecting, set this to true.", + "If you are running a Proxy and don't want to register the IP when players connect, ", + "set this to false and add the auth server names in the list above.", + "If this is a backend server, then set it to false if it's an auth server, and true otherwise."}) + @ConfKey("should-register-on-connection)") @ConfDefault.DefaultBoolean(true) - boolean shouldRegister(); + boolean shouldRegisterOnConnection(); } } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java index 3f4460088..0b5b696ac 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java @@ -22,6 +22,7 @@ import jakarta.inject.Inject; import jakarta.inject.Provider; import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.Nullable; import org.jooq.DSLContext; import space.arim.libertybans.api.NetworkAddress; import space.arim.libertybans.api.PunishmentType; @@ -75,20 +76,10 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N Set scopes, SelectorImpl selector) { return queryExecutor.get().queryWithRetry((context, transaction) -> { Instant currentTime = time.currentTimestamp(); - EnforcementConfig config = configs.getMainConfig().enforcement(); - if (config.altsRegistry().enableAll()) { - doAssociation(uuid, name, address, currentTime, context); - } else if (config.altsRegistry().shouldRegister()) { + if (config.altsRegistry().shouldRegisterOnConnection()) { doAssociation(uuid, name, address, currentTime, context); - - } else { - List servers = config.altsRegistry().servers(); - String serverName = configs.getScopeConfig().serverName().overrideValue(); - if (!servers.isEmpty() && servers.contains(serverName)) { - doAssociation(uuid, name, address, currentTime, context); - } } Punishment ban = selector.selectionByApplicabilityBuilder(uuid, address) @@ -126,6 +117,36 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N }); } + public CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, String name, NetworkAddress address, + String destinationServer, ServerScope scope, SelectorImpl selector) { + + return queryExecutor.get().queryWithRetry((context, transaction) -> { + boolean shouldRegister = configs.getMainConfig().enforcement().altsRegistry().shouldRegisterOnConnection(); + List servers = configs.getMainConfig().enforcement().altsRegistry().servers(); + + if (shouldRegister || !servers.contains(destinationServer)) { + doAssociation(uuid, name, address, time.currentTimestamp(), context); + } + + if (!configs.getMainConfig().platforms().proxies().enforceServerSwitch()) { + return null; + } + + return selector.selectionByApplicabilityBuilder(uuid, address) + .type(PunishmentType.BAN) + .scope(scope) + .build() + .getFirstSpecificPunishment(SortPunishments.LATEST_END_DATE_FIRST); + + }).thenCompose((punishment) -> { + if (punishment instanceof Punishment) { + return formatter.getPunishmentMessage((Punishment) punishment); + } else { + return futuresFactory.completedFuture(null); + } + }); + } + private void doAssociation(UUID uuid, String name, NetworkAddress address, Instant currentTime, DSLContext context) { Association association = new Association(uuid, context); diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/Guardian.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/Guardian.java index 488bcd127..14c20e01e 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/Guardian.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/Guardian.java @@ -35,9 +35,9 @@ public interface Guardian { * Adds the uuid and name to the local fast cache, queries for an applicable ban, and formats the * ban reason as the punishment message. * - * @param uuid the player's uuid - * @param name the player's name - * @param address the player's network address + * @param uuid the player's uuid + * @param name the player's name + * @param address the player's network address * @return a future which yields the punishment message if denied, else null if allowed */ CentralisedFuture<@Nullable Component> executeAndCheckConnection(UUID uuid, String name, NetworkAddress address); @@ -63,11 +63,27 @@ public interface Guardian { * Queries for an applicable ban, and formats the ban reason as the punishment message. * * @param uuid the player's uuid + * @param name the player's name * @param address the player's network address * @param destinationServer the player's destination server * @return a future which yields the punishment message if denied, else null if allowed */ - CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, InetAddress address, String destinationServer); + CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, String name, NetworkAddress address, String destinationServer); + + /** + * Enforces a server switch, returning a punishment message if denied, null if allowed.
+ *
+ * Queries for an applicable ban, and formats the ban reason as the punishment message. + * + * @param uuid the player's uuid + * @param name the player's name + * @param address the player's network address + * @param destinationServer the player's destination server + * @return a future which yields the punishment message if denied, else null if allowed + */ + default CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, String name, InetAddress address, String destinationServer) { + return checkServerSwitch(uuid, name, NetworkAddress.of(address), destinationServer); + } /** * Enforces a chat message or executed command, returning a punishment message if denied, null if allowed.
diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java index 632dfc7c7..164c0b500 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java @@ -24,9 +24,7 @@ import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; import space.arim.libertybans.api.NetworkAddress; -import space.arim.libertybans.api.PunishmentType; import space.arim.libertybans.api.scope.ScopeManager; -import space.arim.libertybans.api.select.SortPunishments; import space.arim.libertybans.core.config.Configs; import space.arim.libertybans.core.config.InternalFormatter; import space.arim.libertybans.core.selector.cache.MuteCache; @@ -98,23 +96,13 @@ private static Function timeoutHandler(String where) { } @Override - public CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, InetAddress address, + public CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, String name, NetworkAddress address, String destinationServer) { - if (!configs.getMainConfig().platforms().proxies().enforceServerSwitch()) { - return futuresFactory.completedFuture(null); - } return selector - .selectionByApplicabilityBuilder(uuid, address) - .type(PunishmentType.BAN) - .scope(scopeManager.specificScope(destinationServer)) - .build() - .getFirstSpecificPunishment(SortPunishments.LATEST_END_DATE_FIRST) - .thenCompose((punishment) -> { - if (punishment.isEmpty()) { - return futuresFactory.completedFuture(null); - } - return formatter.getPunishmentMessage(punishment.get()); - }) + .executeAndCheckServerSwitch( + uuid, name, address, + scopeManager.specificScope(destinationServer), destinationServer + ) .toCompletableFuture() .orTimeout(12, TimeUnit.SECONDS) .exceptionally(timeoutHandler("server switch")); diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java index bb3a43cad..e54e8e0c9 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java @@ -42,14 +42,27 @@ public interface InternalSelector extends PunishmentSelector { /** * Checks a player connection's in a single connection query, enforcing any applicable bans, * connection limits, and dealing out alt checks - * - * @param uuid the player uuid - * @param name the player name - * @param address the player address - * @param scopes the server scopes to include in the selection query + * + * @param uuid the player uuid + * @param name the player name + * @param address the player address + * @param scopes the server scopes to include in the selection query * @return a future which yields the denial message, or null if there is none */ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, NetworkAddress address, Set scopes); + /** + * Checks a player connection's in a single connection query, enforcing any applicable bans if + * enforce server switch is enabled. + * + * @param uuid the player uuid + * @param name the player name + * @param address the player address + * @param scope the server scope to include in the selection query + * @param destinationServer the server the player is switching to + * @return a future which yields the denial message, or null if there is none + */ + CentralisedFuture executeAndCheckServerSwitch(UUID uuid, String name, NetworkAddress address, + ServerScope scope, String destinationServer); } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java index 630e97fb1..f88cfe06b 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java @@ -112,6 +112,12 @@ public CentralisedFuture executeAndCheckConnection(UUID uuid, String return gatekeeper.executeAndCheckConnection(uuid, name, address, scopes, this); } + @Override + public CentralisedFuture executeAndCheckServerSwitch(UUID uuid, String name, NetworkAddress address, + ServerScope scope, String destinationServer) { + return gatekeeper.checkServerSwitch(uuid, name, address, destinationServer, scope, this); + } + @Override public ReactionStage> getCachedMute(UUID uuid, NetworkAddress address) { Objects.requireNonNull(uuid, "uuid"); diff --git a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/ConnectionListener.java b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/ConnectionListener.java index ef24d4848..231ac9a94 100644 --- a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/ConnectionListener.java +++ b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/ConnectionListener.java @@ -108,7 +108,7 @@ public void onServerSwitch(ServerConnectEvent event) { InetAddress address = addressReporter.getAddress(player); Component message = guardian.checkServerSwitch( - player.getUniqueId(), address, event.getTarget().getName() + player.getUniqueId(), player.getName(), address, event.getTarget().getName() ).join(); if (message != null) { event.setCancelled(true); diff --git a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/ConnectionListener.java b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/ConnectionListener.java index ce019f2c6..a09a74a3f 100644 --- a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/ConnectionListener.java +++ b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/ConnectionListener.java @@ -68,6 +68,7 @@ public EventTask onConnect(LoginEvent event) { return null; } Player player = event.getPlayer(); + return EventTask.resumeWhenComplete(guardian.executeAndCheckConnection( player.getUniqueId(), player.getUsername(), player.getRemoteAddress().getAddress() ).thenAccept((message) -> { @@ -91,7 +92,8 @@ public EventTask onServerSwitch(ServerPreConnectEvent event) { } Player player = event.getPlayer(); return EventTask.resumeWhenComplete(guardian.checkServerSwitch( - player.getUniqueId(), player.getRemoteAddress().getAddress(), destination.getServerInfo().getName() + player.getUniqueId(), player.getUsername(), player.getRemoteAddress().getAddress(), + destination.getServerInfo().getName() ).thenAccept((message) -> { if (message != null) { event.setResult(ServerPreConnectEvent.ServerResult.denied()); From 36e07e3f4cbf2780017ad259d2b84c8ca89e2b1d Mon Sep 17 00:00:00 2001 From: Snake Date: Sat, 18 Nov 2023 19:28:20 +0100 Subject: [PATCH 5/9] fix: moved check outside of db query. --- .../space/arim/libertybans/core/selector/Gatekeeper.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java index 0b5b696ac..210a4df50 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java @@ -119,19 +119,18 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N public CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, String name, NetworkAddress address, String destinationServer, ServerScope scope, SelectorImpl selector) { + if (!configs.getMainConfig().platforms().proxies().enforceServerSwitch()) { + return null; + } return queryExecutor.get().queryWithRetry((context, transaction) -> { boolean shouldRegister = configs.getMainConfig().enforcement().altsRegistry().shouldRegisterOnConnection(); List servers = configs.getMainConfig().enforcement().altsRegistry().servers(); - if (shouldRegister || !servers.contains(destinationServer)) { + if (!shouldRegister && !servers.contains(destinationServer)) { doAssociation(uuid, name, address, time.currentTimestamp(), context); } - if (!configs.getMainConfig().platforms().proxies().enforceServerSwitch()) { - return null; - } - return selector.selectionByApplicabilityBuilder(uuid, address) .type(PunishmentType.BAN) .scope(scope) From 75eaf01d2a5d88641a8d4e64a892afcd00a2e638 Mon Sep 17 00:00:00 2001 From: Snake Date: Sat, 18 Nov 2023 19:28:32 +0100 Subject: [PATCH 6/9] feat: added more precise explanation --- .../arim/libertybans/core/selector/EnforcementConfig.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java index e82a088b5..348e4a823 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java @@ -148,7 +148,8 @@ interface AltsRegistry { @ConfComments({"The server names in this list will be excluded from associating the IP address of the player connecting.", "Please note that the server's name of the list should be the same as the ones in your proxy config", - "This is intended to be used by LibertyBans proxy installations." + "This is intended to be used by LibertyBans proxy installations.", + "If you are planning to use this feature, make sure to have enabled 'enforce-server-switch' option." }) @ConfKey("servers-without-ip-registration") @DefaultStrings("") From 8ad0d65276702f4810e5113430bbed9f69f8843a Mon Sep 17 00:00:00 2001 From: A248 Date: Mon, 4 Mar 2024 19:01:27 -0500 Subject: [PATCH 7/9] Accomodate unrecorded IP address in applicability calculation Plus a couple tweaks to code style --- .../api/select/PunishmentSelector.java | 5 +- .../database/sql/ApplicableViewFields.java | 9 ++- .../core/selector/EnforcementConfig.java | 6 +- .../libertybans/core/selector/Gatekeeper.java | 13 ++-- .../SelectionByApplicabilityBuilderImpl.java | 18 ++++- .../SelectionByApplicabilityImpl.java | 75 ++++++++++++++++++- 6 files changed, 108 insertions(+), 18 deletions(-) diff --git a/bans-api/src/main/java/space/arim/libertybans/api/select/PunishmentSelector.java b/bans-api/src/main/java/space/arim/libertybans/api/select/PunishmentSelector.java index 0e2bb1c44..bf6709bfa 100644 --- a/bans-api/src/main/java/space/arim/libertybans/api/select/PunishmentSelector.java +++ b/bans-api/src/main/java/space/arim/libertybans/api/select/PunishmentSelector.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2022 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -77,6 +77,9 @@ public interface PunishmentSelector { * the player's UUID and IP. It may be, the player's IP is banned, the player's UUID is banned, * or the player has played on a banned IP and that IP is banned while strict address enforcement is enabled.
*
+ * For maximum accuracy, the UUID and IP address pair should be taken from an actual user who has logged on before. + * Due to specifics in terms of how applicability is computed, some punishments + *
* By default, the server's configured address strictness is used, but this may be changed if desired. * * @param uuid the uuid of the user for whom to select applicable punishments diff --git a/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ApplicableViewFields.java b/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ApplicableViewFields.java index 2933361c4..9f42c0a15 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ApplicableViewFields.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/database/sql/ApplicableViewFields.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2023 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -31,7 +31,6 @@ import space.arim.libertybans.core.scope.ScopeType; import java.time.Instant; -import java.util.Objects; import java.util.UUID; public record ApplicableViewFields scopeType() { } public Field uuid() { - return Objects.requireNonNull(fieldSupplier.field11(), "uuid field does not exist"); + return fieldSupplier.field11(); + } + + public Field address() { + return fieldSupplier.field12(); } } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java index 348e4a823..98aeb8981 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2022 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -152,8 +152,8 @@ interface AltsRegistry { "If you are planning to use this feature, make sure to have enabled 'enforce-server-switch' option." }) @ConfKey("servers-without-ip-registration") - @DefaultStrings("") - List servers(); + @DefaultStrings({"auth"}) + List serversWithoutRegistration(); @ConfComments({"If you want to register the IP address of the player connecting, set this to true.", "If you are running a Proxy and don't want to register the IP when players connect, ", diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java index 210a4df50..40c44999b 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2023 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -78,13 +78,15 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N Instant currentTime = time.currentTimestamp(); EnforcementConfig config = configs.getMainConfig().enforcement(); - if (config.altsRegistry().shouldRegisterOnConnection()) { + boolean recordUserAssociation = config.altsRegistry().shouldRegisterOnConnection(); + if (recordUserAssociation) { doAssociation(uuid, name, address, currentTime, context); } Punishment ban = selector.selectionByApplicabilityBuilder(uuid, address) .type(PunishmentType.BAN) .scopes(SelectionPredicate.matchingAnyOf(scopes)) + .canAssumeUserRecorded(recordUserAssociation) .build() .findFirstSpecificPunishment(context, () -> currentTime, SortPunishments.LATEST_END_DATE_FIRST); if (ban != null) { @@ -124,10 +126,11 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N } return queryExecutor.get().queryWithRetry((context, transaction) -> { - boolean shouldRegister = configs.getMainConfig().enforcement().altsRegistry().shouldRegisterOnConnection(); - List servers = configs.getMainConfig().enforcement().altsRegistry().servers(); + var altsRegistry = configs.getMainConfig().enforcement().altsRegistry(); + boolean registerOnConnection = altsRegistry.shouldRegisterOnConnection(); + List serversWithoutAssociation = altsRegistry.serversWithoutRegistration(); - if (!shouldRegister && !servers.contains(destinationServer)) { + if (!registerOnConnection && !serversWithoutAssociation.contains(destinationServer)) { doAssociation(uuid, name, address, time.currentTimestamp(), context); } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityBuilderImpl.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityBuilderImpl.java index cbb0f6747..26551cb4b 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityBuilderImpl.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityBuilderImpl.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2023 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -39,6 +39,7 @@ public final class SelectionByApplicabilityBuilderImpl private final NetworkAddress address; private AddressStrictness strictness; private final AddressStrictness defaultStrictness; + private boolean potentialNewEntrant; SelectionByApplicabilityBuilderImpl(SelectionResources resources, UUID uuid, NetworkAddress address, AddressStrictness defaultStrictness) { @@ -68,7 +69,7 @@ SelectionByApplicabilityBuilder yieldSelf() { @Override SelectionByApplicability buildWith(SelectionBaseImpl.Details details) { return new SelectionByApplicabilityImpl( - details, resources, uuid, address, strictness + details, resources, uuid, address, strictness, potentialNewEntrant ); } @@ -89,4 +90,17 @@ public SelectionByApplicabilityImpl build() { return (SelectionByApplicabilityImpl) super.build(); } + /** + * For internal use, to accomodate a new user whose UUID and IP address combination + * has not yet been entered to the database. Sets whether this scenario is potential. + * + * @param canAssumeUserRecorded if the user is definitely registered, set to true. True by default. + * @return this builder + */ + public SelectionByApplicabilityBuilderImpl canAssumeUserRecorded(boolean canAssumeUserRecorded) { + // A user is a potential new entrant if we can't assume they're recorded + this.potentialNewEntrant = !canAssumeUserRecorded; + return this; + } + } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityImpl.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityImpl.java index 1fc9c87a9..3e95db55d 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityImpl.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectionByApplicabilityImpl.java @@ -1,6 +1,6 @@ /* * LibertyBans - * Copyright © 2023 Anand Beh + * Copyright © 2024 Anand Beh * * LibertyBans is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -38,6 +38,7 @@ import java.util.UUID; import static org.jooq.impl.DSL.inline; +import static org.jooq.impl.DSL.or; import static space.arim.libertybans.core.schema.tables.StrictLinks.STRICT_LINKS; public final class SelectionByApplicabilityImpl extends SelectionBaseSQL implements SelectionByApplicability { @@ -45,13 +46,16 @@ public final class SelectionByApplicabilityImpl extends SelectionBaseSQL impleme private final UUID uuid; private final NetworkAddress address; private final AddressStrictness strictness; + private final boolean potentialNewEntrant; SelectionByApplicabilityImpl(Details details, SelectionResources resources, - UUID uuid, NetworkAddress address, AddressStrictness strictness) { + UUID uuid, NetworkAddress address, AddressStrictness strictness, + boolean potentialNewEntrant) { super(details, resources); this.uuid = Objects.requireNonNull(uuid, "uuid"); this.address = Objects.requireNonNull(address, "address"); this.strictness = Objects.requireNonNull(strictness, "strictness"); + this.potentialNewEntrant = potentialNewEntrant; } @Override @@ -69,6 +73,16 @@ public AddressStrictness getAddressStrictness() { return strictness; } + /* + If the potentialNewEntrant flag is set, our task becomes significantly more complicated. + We now have to account for the enforcement of non-lenient address strictness by acting as if + the user had their IP address recorded already. This means attaching additional predication + to scans for IP-based punishments and patching over the applicability links we are accustomed + to having the database account for. + + Thanks to SnakeAmazing for providing this marvelous intellectual puzzle. + */ + @Override Query requestQuery(QueryParameters parameters) { PunishmentFields fields = null; @@ -83,21 +97,74 @@ Query requestQuery(QueryParameters parameters) { ApplicableViewFields applView = requestApplicableView(); fields = applView; table = fields.table(); + if (potentialNewEntrant) { + // appl.uuid = uuid + // OR victim_type != 'PLAYER' AND victim_address = address + // + // Note: It must be victim_address and not appl.address + // Exercise for understanding: Why? + // + yield or( + applView.uuid().eq(uuid), + applView.victimType().notEqual(inline(VictimType.PLAYER)) + .and(applView.victimAddress().eq(address)) + ); + } yield applView.uuid().eq(uuid); // appl.uuid = uuid } case STERN -> { + if (potentialNewEntrant) { + ApplicableViewFields applView = requestApplicableView(); + fields = applView; + table = fields + .table() + .leftJoin(STRICT_LINKS) + .on(applView.uuid().eq(STRICT_LINKS.UUID1)); + // appl.uuid = uuid # NORMAL + // OR victim_type != 'PLAYER' AND ( + // appl.address = address # NORMAL + STERN + // OR strict_links.uuid2 IS NOT NULL AND strict_links.uuid2 = uuid # STERN + // ) + // + // Note: The last predicate must use appl.address and not victim_address + // Exercise for understanding: Why? + // + yield or( + applView.uuid().eq(uuid), + applView.victimType().notEqual(inline(VictimType.PLAYER)).and(or( + STRICT_LINKS.UUID2.isNotNull().and(STRICT_LINKS.UUID2.eq(uuid)), + applView.address().eq(address) + )) + ); + } ApplicableViewFields applView = requestApplicableView(); fields = applView; table = fields .table() .innerJoin(STRICT_LINKS) .on(applView.uuid().eq(STRICT_LINKS.UUID1)); - // appl.uuid = strict_links.uuid1 = uuid - // OR victim_type != 'PLAYER' AND strict_links.uuid2 = uuid + // appl.uuid = strict_links.uuid1 = uuid # NORMAL + // OR victim_type != 'PLAYER' AND strict_links.uuid2 = uuid # STERN yield STRICT_LINKS.UUID1.eq(uuid).or( STRICT_LINKS.UUID2.eq(uuid).and(applView.victimType().notEqual(inline(VictimType.PLAYER)))); } case STRICT -> { + if (potentialNewEntrant) { + ApplicableViewFields applView = requestApplicableView(); + fields = applView; + table = fields + .table() + .leftJoin(STRICT_LINKS) + .on(applView.uuid().eq(STRICT_LINKS.UUID1)); + // appl.uuid = uuid # NORMAL + // OR appl.address = address # NORMAL + STRICT + // OR strict_links.uuid2 IS NOT NULL AND strict_links.uuid2 = uuid # STRICT + yield or( + applView.uuid().eq(uuid), + applView.address().eq(address), + STRICT_LINKS.UUID2.isNotNull().and(STRICT_LINKS.UUID2.eq(uuid)) + ); + } ApplicableViewFields applView = requestApplicableView(); fields = applView; table = fields From d9240af10bf0b3fabf04b80be884a150f0749547 Mon Sep 17 00:00:00 2001 From: Snake Date: Tue, 5 Mar 2024 12:00:17 +0100 Subject: [PATCH 8/9] refactoring --- .../core/selector/EnforcementConfig.java | 11 ++++++----- .../libertybans/core/selector/Gatekeeper.java | 15 ++++++++------- .../core/selector/IntelligentGuardian.java | 3 +-- .../core/selector/InternalSelector.java | 3 +-- .../libertybans/core/selector/SelectorImpl.java | 11 ++++++++--- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java index 98aeb8981..083c88b70 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/EnforcementConfig.java @@ -140,6 +140,7 @@ interface AltAccountExpiration { } + @ConfKey("alts-registry") @SubSection AltsRegistry altsRegistry(); @@ -147,18 +148,18 @@ interface AltAccountExpiration { interface AltsRegistry { @ConfComments({"The server names in this list will be excluded from associating the IP address of the player connecting.", - "Please note that the server's name of the list should be the same as the ones in your proxy config", + "Please note that the server's name in the list should be the same as the ones in your proxy configuration.", "This is intended to be used by LibertyBans proxy installations.", - "If you are planning to use this feature, make sure to have enabled 'enforce-server-switch' option." + "If you are planning to use this feature, you MUST enable the 'enforce-server-switch' option." }) @ConfKey("servers-without-ip-registration") @DefaultStrings({"auth"}) List serversWithoutRegistration(); @ConfComments({"If you want to register the IP address of the player connecting, set this to true.", - "If you are running a Proxy and don't want to register the IP when players connect, ", - "set this to false and add the auth server names in the list above.", - "If this is a backend server, then set it to false if it's an auth server, and true otherwise."}) + "If you are running a proxy and don't want to register the IP when players connect, ", + "set this to false and add the authentication servers' names in the list above.", + "If this is a backend server, set it to false; if it's an authentication server, set to true."}) @ConfKey("should-register-on-connection)") @ConfDefault.DefaultBoolean(true) boolean shouldRegisterOnConnection(); diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java index 40c44999b..55d0f4c56 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/Gatekeeper.java @@ -120,29 +120,30 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N } public CentralisedFuture<@Nullable Component> checkServerSwitch(UUID uuid, String name, NetworkAddress address, - String destinationServer, ServerScope scope, SelectorImpl selector) { + String destinationServer, ServerScope serverScope, + SelectorImpl selector) { if (!configs.getMainConfig().platforms().proxies().enforceServerSwitch()) { return null; } return queryExecutor.get().queryWithRetry((context, transaction) -> { + Instant currentTime = time.currentTimestamp(); var altsRegistry = configs.getMainConfig().enforcement().altsRegistry(); boolean registerOnConnection = altsRegistry.shouldRegisterOnConnection(); List serversWithoutAssociation = altsRegistry.serversWithoutRegistration(); if (!registerOnConnection && !serversWithoutAssociation.contains(destinationServer)) { - doAssociation(uuid, name, address, time.currentTimestamp(), context); + doAssociation(uuid, name, address, currentTime, context); } return selector.selectionByApplicabilityBuilder(uuid, address) .type(PunishmentType.BAN) - .scope(scope) + .scopes(SelectionPredicate.matchingOnly(serverScope)) .build() - .getFirstSpecificPunishment(SortPunishments.LATEST_END_DATE_FIRST); - + .findFirstSpecificPunishment(context, () -> currentTime, SortPunishments.LATEST_END_DATE_FIRST); }).thenCompose((punishment) -> { - if (punishment instanceof Punishment) { - return formatter.getPunishmentMessage((Punishment) punishment); + if (punishment != null) { + return formatter.getPunishmentMessage(punishment); } else { return futuresFactory.completedFuture(null); } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java index 164c0b500..1741cca6b 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java @@ -100,8 +100,7 @@ private static Function timeoutHandler(String where) { String destinationServer) { return selector .executeAndCheckServerSwitch( - uuid, name, address, - scopeManager.specificScope(destinationServer), destinationServer + uuid, name, address, destinationServer ) .toCompletableFuture() .orTimeout(12, TimeUnit.SECONDS) diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java index e54e8e0c9..82542ae53 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/InternalSelector.java @@ -59,10 +59,9 @@ CentralisedFuture executeAndCheckConnection(UUID uuid, String name, N * @param uuid the player uuid * @param name the player name * @param address the player address - * @param scope the server scope to include in the selection query * @param destinationServer the server the player is switching to * @return a future which yields the denial message, or null if there is none */ CentralisedFuture executeAndCheckServerSwitch(UUID uuid, String name, NetworkAddress address, - ServerScope scope, String destinationServer); + String destinationServer); } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java index f88cfe06b..110e30904 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/SelectorImpl.java @@ -26,6 +26,7 @@ import space.arim.libertybans.api.NetworkAddress; import space.arim.libertybans.api.PunishmentType; import space.arim.libertybans.api.punish.Punishment; +import space.arim.libertybans.api.scope.ScopeManager; import space.arim.libertybans.api.scope.ServerScope; import space.arim.libertybans.api.select.AddressStrictness; import space.arim.libertybans.api.select.SelectionOrderBuilder; @@ -47,15 +48,18 @@ public class SelectorImpl implements InternalSelector { private final Gatekeeper gatekeeper; private final Provider muteCache; private final SelectionResources resources; + private final ScopeManager scopeManager; @Inject public SelectorImpl(Configs configs, IDImpl idImpl, Gatekeeper gatekeeper, - Provider muteCache, SelectionResources resources) { + Provider muteCache, SelectionResources resources, + ScopeManager scopeManager) { this.configs = configs; this.idImpl = idImpl; this.gatekeeper = gatekeeper; this.muteCache = muteCache; this.resources = resources; + this.scopeManager = scopeManager; } @Override @@ -114,8 +118,9 @@ public CentralisedFuture executeAndCheckConnection(UUID uuid, String @Override public CentralisedFuture executeAndCheckServerSwitch(UUID uuid, String name, NetworkAddress address, - ServerScope scope, String destinationServer) { - return gatekeeper.checkServerSwitch(uuid, name, address, destinationServer, scope, this); + String destinationServer) { + return gatekeeper.checkServerSwitch(uuid, name, address, destinationServer, + scopeManager.specificScope(destinationServer), this); } @Override From 6b78126c7069a8757f669759f9a48a1514d37f20 Mon Sep 17 00:00:00 2001 From: Snake Date: Tue, 5 Mar 2024 12:01:35 +0100 Subject: [PATCH 9/9] refactoring --- .../arim/libertybans/core/selector/IntelligentGuardian.java | 1 - 1 file changed, 1 deletion(-) diff --git a/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java b/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java index 1741cca6b..ed7510b88 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/selector/IntelligentGuardian.java @@ -32,7 +32,6 @@ import space.arim.omnibus.util.concurrent.CentralisedFuture; import space.arim.omnibus.util.concurrent.FactoryOfTheFuture; -import java.net.InetAddress; import java.util.UUID; import java.util.concurrent.CompletionException; import java.util.concurrent.TimeUnit;