Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alts registration per server #248

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package space.arim.libertybans.core.selector;

import java.util.List;
import java.util.Set;

import space.arim.dazzleconf.annote.ConfComments;
Expand Down Expand Up @@ -138,4 +139,28 @@ interface AltAccountExpiration {
long expirationTimeDays();

}

SnakeAmazing marked this conversation as resolved.
Show resolved Hide resolved
@SubSection
AltsRegistry altsRegistry();

@ConfHeader({"Controls if all servers should register the IP address of the player connecting."})
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",
SnakeAmazing marked this conversation as resolved.
Show resolved Hide resolved
"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."
SnakeAmazing marked this conversation as resolved.
Show resolved Hide resolved
})
@ConfKey("servers-without-ip-registration")
@DefaultStrings("")
List<String> servers();
SnakeAmazing marked this conversation as resolved.
Show resolved Hide resolved

@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, ",
SnakeAmazing marked this conversation as resolved.
Show resolved Hide resolved
"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."})
SnakeAmazing marked this conversation as resolved.
Show resolved Hide resolved
@ConfKey("should-register-on-connection)")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove ) in should-register-on-connection)

@ConfDefault.DefaultBoolean(true)
boolean shouldRegisterOnConnection();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
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;
import space.arim.libertybans.api.punish.Punishment;
Expand Down Expand Up @@ -74,10 +76,11 @@ CentralisedFuture<Component> executeAndCheckConnection(UUID uuid, String name, N
Set<ServerScope> scopes, SelectorImpl selector) {
return queryExecutor.get().queryWithRetry((context, transaction) -> {
Instant currentTime = time.currentTimestamp();
EnforcementConfig config = configs.getMainConfig().enforcement();

Association association = new Association(uuid, context);
association.associateCurrentName(name, currentTime);
association.associateCurrentAddress(address, currentTime);
if (config.altsRegistry().shouldRegisterOnConnection()) {
doAssociation(uuid, name, address, currentTime, context);
}

Punishment ban = selector.selectionByApplicabilityBuilder(uuid, address)
.type(PunishmentType.BAN)
Expand Down Expand Up @@ -113,4 +116,40 @@ CentralisedFuture<Component> executeAndCheckConnection(UUID uuid, String name, N
return futuresFactory.completedFuture(null);
});
}

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<String> servers = configs.getMainConfig().enforcement().altsRegistry().servers();
SnakeAmazing marked this conversation as resolved.
Show resolved Hide resolved

if (!shouldRegister && !servers.contains(destinationServer)) {
doAssociation(uuid, name, address, time.currentTimestamp(), context);
SnakeAmazing marked this conversation as resolved.
Show resolved Hide resolved
}

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);
association.associateCurrentName(name, currentTime);
association.associateCurrentAddress(address, currentTime);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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. <br>
* <br>
* 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. <br>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -98,23 +96,13 @@ private static <R> Function<Throwable, R> 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"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Component> executeAndCheckConnection(UUID uuid, String name, NetworkAddress address,
Set<ServerScope> 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<Component> executeAndCheckServerSwitch(UUID uuid, String name, NetworkAddress address,
ServerScope scope, String destinationServer);
SnakeAmazing marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ public CentralisedFuture<Component> executeAndCheckConnection(UUID uuid, String
return gatekeeper.executeAndCheckConnection(uuid, name, address, scopes, this);
}

@Override
public CentralisedFuture<Component> executeAndCheckServerSwitch(UUID uuid, String name, NetworkAddress address,
ServerScope scope, String destinationServer) {
return gatekeeper.checkServerSwitch(uuid, name, address, destinationServer, scope, this);
}

@Override
public ReactionStage<Optional<Punishment>> getCachedMute(UUID uuid, NetworkAddress address) {
Objects.requireNonNull(uuid, "uuid");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) -> {
Expand All @@ -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());
Expand Down
Loading