@@ -47,8 +47,10 @@ public final class ContainerPdcLockManager {
4747 private static final String CLONE_NAME_KEY_STRING = "lockettepro:perm_clone_name" ;
4848 private static final String CLONE_NAME_DEFAULT_PATH = "perm_clone_name" ;
4949 private static final String CLONE_PERMISSION_KEY_PATH_PREFIX = "clone_perm." ;
50+ private static final String SUBJECT_HEX_ENCODING_PREFIX = "h_" ;
5051
5152 private static final String ENTITY_HOPPER = "#hopper" ;
53+ private static final char [] HEX_DIGITS = "0123456789abcdef" .toCharArray ();
5254 private static volatile Cache <String , LockData > runtimeLockDataCache = createRuntimeLockDataCache ();
5355 private static volatile int runtimeCacheConfigSignature = Integer .MIN_VALUE ;
5456
@@ -826,10 +828,37 @@ private static void addHolderBlock(InventoryHolder holder, Set<Block> blocks) {
826828 }
827829
828830 private static String encodeSubject (String value ) {
829- return Base64 .getUrlEncoder ().withoutPadding ().encodeToString (value .getBytes (StandardCharsets .UTF_8 ));
831+ byte [] bytes = value .getBytes (StandardCharsets .UTF_8 );
832+ StringBuilder builder = new StringBuilder (SUBJECT_HEX_ENCODING_PREFIX .length () + bytes .length * 2 );
833+ builder .append (SUBJECT_HEX_ENCODING_PREFIX );
834+ for (byte b : bytes ) {
835+ int v = b & 0xFF ;
836+ builder .append (HEX_DIGITS [v >>> 4 ]);
837+ builder .append (HEX_DIGITS [v & 0x0F ]);
838+ }
839+ return builder .toString ();
830840 }
831841
832842 private static String decodeSubject (String encoded ) {
843+ if (encoded == null || encoded .isBlank ()) {
844+ return null ;
845+ }
846+
847+ if (encoded .startsWith (SUBJECT_HEX_ENCODING_PREFIX )) {
848+ return decodeHexSubject (encoded .substring (SUBJECT_HEX_ENCODING_PREFIX .length ()));
849+ }
850+
851+ // Backward compatibility for previous base64-url encoding.
852+ String legacyDecoded = decodeLegacyBase64Subject (encoded );
853+ if (legacyDecoded != null ) {
854+ return legacyDecoded ;
855+ }
856+
857+ // Safety fallback for potential prefix-less hex payloads.
858+ return decodeHexSubject (encoded );
859+ }
860+
861+ private static String decodeLegacyBase64Subject (String encoded ) {
833862 try {
834863 byte [] bytes = Base64 .getUrlDecoder ().decode (encoded );
835864 return new String (bytes , StandardCharsets .UTF_8 );
@@ -838,6 +867,30 @@ private static String decodeSubject(String encoded) {
838867 }
839868 }
840869
870+ private static String decodeHexSubject (String hex ) {
871+ if (hex == null || hex .isEmpty () || (hex .length () & 1 ) == 1 ) {
872+ return null ;
873+ }
874+
875+ byte [] bytes = new byte [hex .length () / 2 ];
876+ for (int i = 0 ; i < bytes .length ; i ++) {
877+ int high = hexValue (hex .charAt (i * 2 ));
878+ int low = hexValue (hex .charAt (i * 2 + 1 ));
879+ if (high < 0 || low < 0 ) {
880+ return null ;
881+ }
882+ bytes [i ] = (byte ) ((high << 4 ) | low );
883+ }
884+ return new String (bytes , StandardCharsets .UTF_8 );
885+ }
886+
887+ private static int hexValue (char c ) {
888+ if (c >= '0' && c <= '9' ) return c - '0' ;
889+ if (c >= 'a' && c <= 'f' ) return c - 'a' + 10 ;
890+ if (c >= 'A' && c <= 'F' ) return c - 'A' + 10 ;
891+ return -1 ;
892+ }
893+
841894 private static boolean isUuid (String text ) {
842895 if (text == null ) return false ;
843896 try {
0 commit comments