From 21dce815e4517c3227c7233ccca2e3ac1756c518 Mon Sep 17 00:00:00 2001 From: A248 Date: Sat, 27 Jan 2024 12:35:26 -0500 Subject: [PATCH] Resolve UUIDs given as arguments in more places * Lookup the player's address if only a UUID was specified. * Also, improve tab completion by including usage, help, etc. --- .../core/commands/AltCommands.java | 12 +-- .../core/commands/CommandsCore.java | 13 +-- .../extra/StandardArgumentParser.java | 79 +++++++++++-------- .../libertybans/core/env/EnvUserResolver.java | 2 + .../core/env/SimpleEnvUserResolver.java | 7 ++ .../core/uuid/CachingUUIDManager.java | 10 +++ .../libertybans/core/uuid/QueryingImpl.java | 12 +++ .../libertybans/core/uuid/UUIDManager.java | 10 ++- .../core/alts/AltCheckFormatterTest.java | 32 +++++++- .../libertybans/it/env/QuackUserResolver.java | 5 ++ .../env/bungee/BungeeUserResolver.java | 5 ++ .../env/spigot/SpigotUserResolver.java | 5 ++ .../env/sponge/SpongeUserResolver.java | 5 ++ .../env/standalone/StandaloneResolver.java | 5 ++ .../env/velocity/VelocityUserResolver.java | 5 ++ 15 files changed, 161 insertions(+), 46 deletions(-) diff --git a/bans-core/src/main/java/space/arim/libertybans/core/commands/AltCommands.java b/bans-core/src/main/java/space/arim/libertybans/core/commands/AltCommands.java index 049243f3a..d7156c1dc 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/commands/AltCommands.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/commands/AltCommands.java @@ -27,7 +27,6 @@ import space.arim.libertybans.core.alts.WhichAlts; import space.arim.libertybans.core.commands.extra.TabCompletion; import space.arim.libertybans.core.env.CmdSender; -import space.arim.libertybans.core.uuid.UUIDManager; import space.arim.omnibus.util.concurrent.ReactionStage; import java.util.stream.Stream; @@ -35,15 +34,13 @@ @Singleton public final class AltCommands extends AbstractSubCommandGroup { - private final UUIDManager uuidManager; private final AltDetection altDetection; private final AltCheckFormatter altCheckFormatter; private final TabCompletion tabCompletion; @Inject - public AltCommands(Dependencies dependencies, UUIDManager uuidManager, AltDetection altDetection, AltCheckFormatter altCheckFormatter, TabCompletion tabCompletion) { + public AltCommands(Dependencies dependencies, AltDetection altDetection, AltCheckFormatter altCheckFormatter, TabCompletion tabCompletion) { super(dependencies, "alts"); - this.uuidManager = uuidManager; this.altDetection = altDetection; this.altCheckFormatter = altCheckFormatter; this.tabCompletion = tabCompletion; @@ -92,12 +89,11 @@ public ReactionStage execute() { return null; } String target = command().next(); - return uuidManager.lookupPlayer(target).thenCompose((userDetails) -> { - if (userDetails.isEmpty()) { - sender().sendMessage(messages().all().notFound().player().replaceText("%TARGET%", target)); + return argumentParser().parsePlayer(sender(), target).thenCompose((userDetails) -> { + if (userDetails == null) { return completedFuture(null); } - return altDetection.detectAlts(userDetails.get(), WhichAlts.ALL_ALTS).thenAccept((detectedAlts) -> { + return altDetection.detectAlts(userDetails, WhichAlts.ALL_ALTS).thenAccept((detectedAlts) -> { if (detectedAlts.isEmpty()) { sender().sendMessage(altsConfig().command().noneFound()); return; diff --git a/bans-core/src/main/java/space/arim/libertybans/core/commands/CommandsCore.java b/bans-core/src/main/java/space/arim/libertybans/core/commands/CommandsCore.java index cd0d36a5c..df202a3d1 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/commands/CommandsCore.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/commands/CommandsCore.java @@ -105,15 +105,18 @@ public void execute(CmdSender sender, CommandPackage command) { */ private List subCommandCompletions(CmdSender sender, Predicate filter) { - return subCommandGroups.stream() - .flatMap((subCommandGroup) -> { + Stream combined = Stream.concat( + subCommandGroups.stream().flatMap((subCommandGroup) -> { return subCommandGroup.matches() .stream() .filter((subCmd) -> subCommandGroup.hasTabCompletePermission(sender, subCmd)); - }) + }), + Stream.of("version", "about", "usage", "help") + ); + return combined .filter(filter) .sorted() - .collect(Collectors.toUnmodifiableList()); + .toList(); } @Override @@ -149,7 +152,7 @@ public List suggest(CmdSender sender, String[] args) { if (!lastArg.isEmpty()) { completions = completions.filter((completion) -> completion.toLowerCase(Locale.ROOT).startsWith(lastArg)); } - return completions.sorted().collect(Collectors.toUnmodifiableList()); + return completions.sorted().toList(); } @Override diff --git a/bans-core/src/main/java/space/arim/libertybans/core/commands/extra/StandardArgumentParser.java b/bans-core/src/main/java/space/arim/libertybans/core/commands/extra/StandardArgumentParser.java index 6a3c21e82..4ed064788 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/commands/extra/StandardArgumentParser.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/commands/extra/StandardArgumentParser.java @@ -43,6 +43,8 @@ import java.util.Optional; import java.util.UUID; +import java.util.function.Function; +import java.util.function.Supplier; public class StandardArgumentParser implements ArgumentParser { @@ -74,41 +76,48 @@ private MessagesConfig.All.NotFound notFound() { return all().notFound(); } - @Override - public CentralisedFuture<@Nullable UUID> parseOrLookupUUID(CmdSender sender, String targetArg) { + private CentralisedFuture<@Nullable R> parseUUIDIfPossible(CmdSender sender, String targetArg, + Function> ifUuid, + Supplier> otherwise) { return switch (targetArg.length()) { - case 36 -> { - UUID uuid; - try { - uuid = UUID.fromString(targetArg); - } catch (IllegalArgumentException ex) { - sender.sendMessage(notFound().uuid().replaceText("%TARGET%", targetArg)); - yield completedFuture(null); - } - yield completedFuture(uuid); - } - case 32 -> { - long mostSigBits; - long leastSigBits; - try { - mostSigBits = Long.parseUnsignedLong(targetArg.substring(0, 16), 16); - leastSigBits = Long.parseUnsignedLong(targetArg.substring(16, 32), 16); - } catch (NumberFormatException ex) { - sender.sendMessage(notFound().uuid().replaceText("%TARGET%", targetArg)); - yield completedFuture(null); + case 36 -> { + UUID uuid; + try { + uuid = UUID.fromString(targetArg); + } catch (IllegalArgumentException ex) { + sender.sendMessage(notFound().uuid().replaceText("%TARGET%", targetArg)); + yield completedFuture(null); + } + yield ifUuid.apply(uuid); } - yield completedFuture(new UUID(mostSigBits, leastSigBits)); - } - default -> uuidManager.lookupUUID(targetArg).thenApply((uuid) -> { - if (uuid.isEmpty()) { - sender.sendMessage(notFound().player().replaceText("%TARGET%", targetArg)); - return null; + case 32 -> { + long mostSigBits; + long leastSigBits; + try { + mostSigBits = Long.parseUnsignedLong(targetArg.substring(0, 16), 16); + leastSigBits = Long.parseUnsignedLong(targetArg.substring(16, 32), 16); + } catch (NumberFormatException ex) { + sender.sendMessage(notFound().uuid().replaceText("%TARGET%", targetArg)); + yield completedFuture(null); + } + yield ifUuid.apply(new UUID(mostSigBits, leastSigBits)); } - return uuid.get(); - }); + default -> otherwise.get(); }; } + @Override + public CentralisedFuture<@Nullable UUID> parseOrLookupUUID(CmdSender sender, String targetArg) { + return parseUUIDIfPossible(sender, targetArg, this::completedFuture, + () -> uuidManager.lookupUUID(targetArg).thenApply((uuid) -> { + if (uuid.isEmpty()) { + sender.sendMessage(notFound().player().replaceText("%TARGET%", targetArg)); + return null; + } + return uuid.get(); + })); + } + @Override public CentralisedFuture<@Nullable Operator> parseOperator(CmdSender sender, String operatorArg) { if (ContainsCI.containsIgnoreCase(configs.getMessagesConfig().formatting().consoleArguments(), operatorArg)) { @@ -148,13 +157,21 @@ private MessagesConfig.All.NotFound notFound() { @Override public CentralisedFuture<@Nullable UUIDAndAddress> parsePlayer(CmdSender sender, String targetArg) { - return uuidManager.lookupPlayer(targetArg).thenApply((optUuidAndAddress) -> { + return parseUUIDIfPossible(sender, targetArg, (uuid) -> { + return uuidManager.lookupLastAddress(uuid).thenApply((optAddress) -> { + if (optAddress.isEmpty()) { + sender.sendMessage(notFound().player().replaceText("%TARGET%", targetArg)); + return null; + } + return new UUIDAndAddress(uuid, optAddress.get()); + }); + }, () -> uuidManager.lookupPlayer(targetArg).thenApply((optUuidAndAddress) -> { if (optUuidAndAddress.isEmpty()) { sender.sendMessage(notFound().player().replaceText("%TARGET%", targetArg)); return null; } return optUuidAndAddress.get(); - }); + })); } @Override diff --git a/bans-core/src/main/java/space/arim/libertybans/core/env/EnvUserResolver.java b/bans-core/src/main/java/space/arim/libertybans/core/env/EnvUserResolver.java index 636cad2e9..1076a0401 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/env/EnvUserResolver.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/env/EnvUserResolver.java @@ -39,4 +39,6 @@ public interface EnvUserResolver { CentralisedFuture> lookupPlayer(String name); + CentralisedFuture> lookupCurrentAddress(UUID uuid); + } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/env/SimpleEnvUserResolver.java b/bans-core/src/main/java/space/arim/libertybans/core/env/SimpleEnvUserResolver.java index b796df985..ebe4d80d3 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/env/SimpleEnvUserResolver.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/env/SimpleEnvUserResolver.java @@ -62,6 +62,11 @@ public final CentralisedFuture> lookupPlayer(String nam return performLookup(() -> lookupPlayer0(name)); } + @Override + public final CentralisedFuture> lookupCurrentAddress(UUID uuid) { + return performLookup(() -> lookupCurrentAddress0(uuid)); + } + protected abstract Optional lookupUUID0(String name); protected abstract Optional lookupName0(UUID uuid); @@ -70,4 +75,6 @@ public final CentralisedFuture> lookupPlayer(String nam protected abstract Optional lookupPlayer0(String name); + protected abstract Optional lookupCurrentAddress0(UUID uuid); + } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/uuid/CachingUUIDManager.java b/bans-core/src/main/java/space/arim/libertybans/core/uuid/CachingUUIDManager.java index c6a437618..7497e2064 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/uuid/CachingUUIDManager.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/uuid/CachingUUIDManager.java @@ -242,4 +242,14 @@ public CentralisedFuture> lookupPlayer(String name) { }); } + @Override + public CentralisedFuture> lookupLastAddress(UUID uuid) { + return envResolver.lookupCurrentAddress(uuid).thenCompose((envResolve) -> { + if (envResolve.isPresent()) { + return completedFuture(envResolve.map(NetworkAddress::of)); + } + return queryingImpl.resolveLastAddress(uuid).thenApply(Optional::ofNullable); + }); + } + } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/uuid/QueryingImpl.java b/bans-core/src/main/java/space/arim/libertybans/core/uuid/QueryingImpl.java index 08163a69a..b54b96b20 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/uuid/QueryingImpl.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/uuid/QueryingImpl.java @@ -107,4 +107,16 @@ CentralisedFuture resolvePlayer(String name) { })); } + CentralisedFuture resolveLastAddress(UUID uuid) { + return dbProvider.get().query(SQLFunction.readOnly((context) -> { + return context + .select(ADDRESSES.ADDRESS) + .from(ADDRESSES) + .where(ADDRESSES.UUID.eq(uuid)) + .orderBy(ADDRESSES.UPDATED.desc()) + .limit(1) + .fetchOne(ADDRESSES.ADDRESS); + })); + } + } diff --git a/bans-core/src/main/java/space/arim/libertybans/core/uuid/UUIDManager.java b/bans-core/src/main/java/space/arim/libertybans/core/uuid/UUIDManager.java index edb123b3e..06e823a08 100644 --- a/bans-core/src/main/java/space/arim/libertybans/core/uuid/UUIDManager.java +++ b/bans-core/src/main/java/space/arim/libertybans/core/uuid/UUIDManager.java @@ -58,5 +58,13 @@ public interface UUIDManager extends UserResolver, Part { * @return a future yielding the user details or an empty optional if not found */ CentralisedFuture> lookupPlayer(String name); - + + /** + * Looks up player details from a UUID + * + * @param uuid the uuid of the player + * @return a future yielding the latest address or an empty optional if not found + */ + CentralisedFuture> lookupLastAddress(UUID uuid); + } diff --git a/bans-core/src/test/java/space/arim/libertybans/core/alts/AltCheckFormatterTest.java b/bans-core/src/test/java/space/arim/libertybans/core/alts/AltCheckFormatterTest.java index 64a39dd7d..eebc947e9 100644 --- a/bans-core/src/test/java/space/arim/libertybans/core/alts/AltCheckFormatterTest.java +++ b/bans-core/src/test/java/space/arim/libertybans/core/alts/AltCheckFormatterTest.java @@ -20,6 +20,7 @@ package space.arim.libertybans.core.alts; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.serializer.plain.PlainComponentSerializer; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -90,7 +91,7 @@ public void formatMessage() throws UnknownHostException { } assertEquals("Alt report for MainUser\n" + "detection_kind: " + alt.detectionKind() + ", address: " + address + ", username: " + username + - ", " + "user_id: " + userId + ", date_recorded: " + date, + ", user_id: " + userId + ", date_recorded: " + date, PlainComponentSerializer.plain().serialize(altCheckFormatter.formatMessage(header, "MainUser", List.of(alt)))); } @@ -134,4 +135,33 @@ public void formatPunishedAltsWithDetectionKind() throws UnknownHostException { kind: NORMAL, username: None(Saint)""", PlainComponentSerializer.plain().serialize(formattedMessage)); } + + @Test + public void replaceUsernameInCommandOfLayout() throws UnknownHostException { + ComponentText header = ComponentText.create(Component.text("Alt report for %TARGET%")); + String address = "207.144.101.102"; + UUID userId = UUID.randomUUID(); + String username = "AltUser"; + Instant date = Instant.parse("2021-07-23T02:15:23.000000Z"); + DetectedAlt alt = new DetectedAlt( + userId, username, NetworkAddress.of(InetAddress.getByName(address)), date, DetectionKind.NORMAL + ); + { + when(conf.layout()).thenReturn(ComponentText.create(Component.text( + "address: %ADDRESS%, date_recorded: %DATE_RECORDED%") + .clickEvent(ClickEvent.runCommand("/msg %RELEVANT_USER% hello")) + )); + when(conf.normal()).thenReturn(Component.text("NORMAL")); + var nameDisplay = mock(AltsSection.Formatting.NameDisplay.class); + when(nameDisplay.notPunished()).thenReturn(ComponentText.create(Component.text("%USERNAME%"))); + when(conf.nameDisplay()).thenReturn(nameDisplay); + when(formatter.prefix(any())).thenAnswer((invocation) -> invocation.getArgument(0)); + when(formatter.formatAbsoluteDate(date)).thenReturn(date.toString()); + } + assertEquals(Component.text( + "Alt report for MainUser\n" + + "address: " + address + ", date_recorded: " + date) + .clickEvent(ClickEvent.runCommand("/msg " + username + " hello")), + altCheckFormatter.formatMessage(header, "MainUser", List.of(alt))); + } } diff --git a/bans-core/src/test/java/space/arim/libertybans/it/env/QuackUserResolver.java b/bans-core/src/test/java/space/arim/libertybans/it/env/QuackUserResolver.java index 2fa2b7f7f..08514296a 100644 --- a/bans-core/src/test/java/space/arim/libertybans/it/env/QuackUserResolver.java +++ b/bans-core/src/test/java/space/arim/libertybans/it/env/QuackUserResolver.java @@ -69,4 +69,9 @@ public Optional lookupPlayer0(String name) { .map((player) -> new UUIDAndAddress(player.getUniqueId(), player.getAddress())); } + @Override + public Optional lookupCurrentAddress0(UUID uuid) { + return platform.getPlayer(uuid).map(QuackPlayer::getAddress); + } + } diff --git a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeUserResolver.java b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeUserResolver.java index 76a01da74..79e836a66 100644 --- a/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeUserResolver.java +++ b/bans-env/bungee/src/main/java/space/arim/libertybans/env/bungee/BungeeUserResolver.java @@ -71,4 +71,9 @@ public Optional lookupPlayer0(String name) { .map((player) -> new UUIDAndAddress(player.getUniqueId(), addressReporter.getAddress(player))); } + @Override + public Optional lookupCurrentAddress0(UUID uuid) { + return Optional.ofNullable(server.getPlayer(uuid)).map(addressReporter::getAddress); + } + } diff --git a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotUserResolver.java b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotUserResolver.java index 8b9751555..05725e302 100644 --- a/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotUserResolver.java +++ b/bans-env/spigot/src/main/java/space/arim/libertybans/env/spigot/SpigotUserResolver.java @@ -75,4 +75,9 @@ public Optional lookupPlayer0(String name) { .map((player) -> new UUIDAndAddress(player.getUniqueId(), player.getAddress().getAddress())); } + @Override + public Optional lookupCurrentAddress0(UUID uuid) { + return Optional.ofNullable(server.getPlayer(uuid)).map((player) -> player.getAddress().getAddress()); + } + } diff --git a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeUserResolver.java b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeUserResolver.java index 0e30f54bc..672eccbe4 100644 --- a/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeUserResolver.java +++ b/bans-env/sponge/src/main/java/space/arim/libertybans/env/sponge/SpongeUserResolver.java @@ -69,4 +69,9 @@ public Optional lookupPlayer0(String name) { .map((player) -> new UUIDAndAddress(player.uniqueId(), player.connection().address().getAddress())); } + @Override + public Optional lookupCurrentAddress0(UUID uuid) { + return game.server().player(uuid).map((player) -> player.connection().address().getAddress()); + } + } diff --git a/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneResolver.java b/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneResolver.java index 475bf940e..eaeb98756 100644 --- a/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneResolver.java +++ b/bans-env/standalone/src/main/java/space/arim/libertybans/env/standalone/StandaloneResolver.java @@ -64,4 +64,9 @@ public Optional lookupPlayer0(String name) { return Optional.empty(); } + @Override + public Optional lookupCurrentAddress0(UUID uuid) { + return Optional.empty(); + } + } diff --git a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityUserResolver.java b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityUserResolver.java index 8d98fa17f..c77a652bb 100644 --- a/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityUserResolver.java +++ b/bans-env/velocity/src/main/java/space/arim/libertybans/env/velocity/VelocityUserResolver.java @@ -69,4 +69,9 @@ public Optional lookupPlayer0(String name) { .map((player) -> new UUIDAndAddress(player.getUniqueId(), player.getRemoteAddress().getAddress())); } + @Override + public Optional lookupCurrentAddress0(UUID uuid) { + return server.getPlayer(uuid).map((player) -> player.getRemoteAddress().getAddress()); + } + }