From 9f873826fce22bdb316586d46bbf393b4beb763a Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Sun, 21 Sep 2025 17:13:49 -0500 Subject: [PATCH 1/2] users: wrap JSON parsing error of existing ops/whitelist --- .../helpers/users/ManageUsersCommand.java | 81 +++++++++---------- 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/src/main/java/me/itzg/helpers/users/ManageUsersCommand.java b/src/main/java/me/itzg/helpers/users/ManageUsersCommand.java index 69cfa714..6ad4cf28 100644 --- a/src/main/java/me/itzg/helpers/users/ManageUsersCommand.java +++ b/src/main/java/me/itzg/helpers/users/ManageUsersCommand.java @@ -1,14 +1,18 @@ package me.itzg.helpers.users; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -17,7 +21,6 @@ import java.util.UUID; import java.util.concurrent.Callable; import java.util.stream.Collectors; - import lombok.extern.slf4j.Slf4j; import me.itzg.helpers.errors.GenericException; import me.itzg.helpers.errors.InvalidParameterException; @@ -29,10 +32,7 @@ import me.itzg.helpers.users.model.JavaOp; import me.itzg.helpers.users.model.JavaUser; import me.itzg.helpers.users.model.UserDef; - -import org.apache.commons.codec.digest.DigestUtils; import org.apache.maven.artifact.versioning.ComparableVersion; - import picocli.CommandLine.ArgGroup; import picocli.CommandLine.Command; import picocli.CommandLine.ExitCode; @@ -53,7 +53,7 @@ public class ManageUsersCommand implements Callable { @Option(names = {"--help", "-h"}, usageHelp = true) boolean help; - @Option(names = {"--offline"}, required = false, description = "Use for offline server, UUIDs are generated") + @Option(names = {"--offline"}, description = "Use for offline server, UUIDs are generated") boolean offline; @Option(names = "--output-directory", defaultValue = ".") @@ -117,7 +117,7 @@ public Integer call() throws Exception { } private void processJavaUserIdList(SharedFetch sharedFetch, List inputs) throws IOException { - List userDefs = inputs.stream().map(input -> new UserDef(input)).collect(Collectors.toList()); + List userDefs = inputs.stream().map(UserDef::new).collect(Collectors.toList()); if (usesTextUserList()) { verifyNotUuids(userDefs); @@ -268,18 +268,7 @@ private JavaUser resolveJavaUserId(SharedFetch sharedFetch, List loadExistingJavaJson(Path userFile) throws IOException { if (!Files.exists(userFile)) { return Collections.emptyList(); } - if (type == Type.JAVA_OPS) { - return objectMapper.readValue(userFile.toFile(), LIST_OF_JAVA_OP); - } - else { - return objectMapper.readValue(userFile.toFile(), LIST_OF_JAVA_USER); + try { + if (type == Type.JAVA_OPS) { + return objectMapper.readValue(userFile.toFile(), LIST_OF_JAVA_OP); + } + else { + return objectMapper.readValue(userFile.toFile(), LIST_OF_JAVA_USER); + } + } catch (JsonProcessingException e) { + throw new GenericException("Failed to parse existing file " + userFile + ", fix or remove it", e); } } @@ -365,27 +373,14 @@ private boolean usesTextUserList() { } private static String getOfflineUUID(String username) { - byte[] bytes = DigestUtils.md5("OfflinePlayer:" + username); - - // Force version = 3 (bits 12-15 of time_hi_and_version) - bytes[6] &= 0x0F; - bytes[6] |= 0x30; - - // Force variant = 2 (bits 6-7 of clock_seq_hi_and_reserved) - bytes[8] &= 0x3F; - bytes[8] |= 0x80; - - long msb = 0; - long lsb = 0; - - for (int i = 0; i < 8; i++) { - msb = (msb << 8) | (bytes[i] & 0xFF); - } - - for (int i = 8; i < 16; i++) { - lsb = (lsb << 8) | (bytes[i] & 0xFF); + final MessageDigest digester; + try { + digester = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new GenericException("Failed to create MD5 digester to generate offline player UUID", e); } + final byte[] bytes = digester.digest(("OfflinePlayer:"+username).getBytes(StandardCharsets.UTF_8)); - return new UUID(msb, lsb).toString(); + return UUID.nameUUIDFromBytes(bytes).toString(); } } From d59c142281e359d4dc0f2118a6ffc84daaefdddb Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Sun, 21 Sep 2025 18:36:20 -0500 Subject: [PATCH 2/2] Updated offline UUIDs in test --- .../java/me/itzg/helpers/users/ManageUsersCommandTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/me/itzg/helpers/users/ManageUsersCommandTest.java b/src/test/java/me/itzg/helpers/users/ManageUsersCommandTest.java index 7df6893d..a95b5e03 100644 --- a/src/test/java/me/itzg/helpers/users/ManageUsersCommandTest.java +++ b/src/test/java/me/itzg/helpers/users/ManageUsersCommandTest.java @@ -25,10 +25,10 @@ class ManageUsersCommandTest { private static final String USER1_ID = "3f5f20286a85445fa7b46100e70c2b3a"; private static final String USER1_UUID = "3f5f2028-6a85-445f-a7b4-6100e70c2b3a"; - private static final String USER1_OFFLINE_UUID = "fb4cdad9-642b-358f-8f6f-717981c9f42b"; + private static final String USER1_OFFLINE_UUID = "95825a72-847d-3e1f-983a-e144b90ec1c9"; private static final String USER2_ID = "5e5a1b2294b14f5892466062597e4c91"; private static final String USER2_UUID = "5e5a1b22-94b1-4f58-9246-6062597e4c91"; - private static final String USER2_OFFLINE_UUID = "6e7d9aa0-0da2-390c-ab6a-377df9d77518"; + private static final String USER2_OFFLINE_UUID = "357f8b0a-3577-32e9-aafd-6602bb4b6cbf"; @TempDir Path tempDir;