diff --git a/src/main/java/icu/samnyan/aqua/sega/allnet/AllNetController.java b/src/main/java/icu/samnyan/aqua/sega/allnet/AllNetController.java index cc0f6e6a..5d8c2550 100644 --- a/src/main/java/icu/samnyan/aqua/sega/allnet/AllNetController.java +++ b/src/main/java/icu/samnyan/aqua/sega/allnet/AllNetController.java @@ -6,7 +6,7 @@ import icu.samnyan.aqua.sega.allnet.model.response.DownloadOrderResponse; import icu.samnyan.aqua.sega.allnet.model.response.PowerOnResponse; import icu.samnyan.aqua.sega.allnet.model.response.PowerOnResponseV2; import icu.samnyan.aqua.sega.allnet.model.response.PowerOnResponseV3; -import icu.samnyan.aqua.sega.allnet.util.Decoder; +import icu.samnyan.aqua.sega.util.Decoder; import icu.samnyan.aqua.sega.allnet.util.KeychipChecker; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -80,7 +80,7 @@ public class AllNetController { public String downloadOrder(InputStream dataStream, HttpServletRequest req) throws IOException { byte[] bytes = dataStream.readAllBytes(); - Map reqMap = Decoder.decode(bytes); + Map reqMap = Decoder.decodeAllNet(bytes); logger.info("Request: DownloadOrder, " + mapper.writeValueAsString(reqMap)); @@ -98,7 +98,7 @@ public class AllNetController { String localAddr = req.getLocalAddr(); String localPort = Integer.toString(req.getLocalPort()); byte[] bytes = dataStream.readAllBytes(); - Map reqMap = Decoder.decode(bytes); + Map reqMap = Decoder.decodeAllNet(bytes); String serial = reqMap.getOrDefault("serial", ""); logger.info("Request: PowerOn, " + mapper.writeValueAsString(reqMap)); // TODO: Verify KeyChip id ? diff --git a/src/main/java/icu/samnyan/aqua/sega/allnet/util/Decoder.java b/src/main/java/icu/samnyan/aqua/sega/allnet/util/Decoder.java deleted file mode 100644 index 9c82f6a1..00000000 --- a/src/main/java/icu/samnyan/aqua/sega/allnet/util/Decoder.java +++ /dev/null @@ -1,32 +0,0 @@ -package icu.samnyan.aqua.sega.allnet.util; - -import icu.samnyan.aqua.sega.util.Compression; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; - -/** - * @author samnyan (privateamusement@protonmail.com) - */ -public class Decoder { - - public static Map decode(byte[] src) { - byte[] bytes = Base64.getMimeDecoder().decode(src); - - - byte[] output = Compression.decompress(bytes); - - String outputString = new String(output, StandardCharsets.UTF_8).trim(); - String[] split = outputString.split("&"); - Map resultMap = new HashMap<>(); - for (String s : - split) { - String[] kv = s.split("="); - resultMap.put(kv[0], kv[1]); - } - - return resultMap; - } -} diff --git a/src/main/java/icu/samnyan/aqua/sega/billing/BillingController.java b/src/main/java/icu/samnyan/aqua/sega/billing/BillingController.java index a900c635..5c5e599f 100644 --- a/src/main/java/icu/samnyan/aqua/sega/billing/BillingController.java +++ b/src/main/java/icu/samnyan/aqua/sega/billing/BillingController.java @@ -2,9 +2,7 @@ package icu.samnyan.aqua.sega.billing; import com.fasterxml.jackson.databind.ObjectMapper; -import icu.samnyan.aqua.sega.billing.model.response.BillingResponse; -import icu.samnyan.aqua.sega.billing.util.Decoder; - +import icu.samnyan.aqua.sega.util.Decoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; @@ -44,7 +42,7 @@ public class BillingController { RSAPrivateKey key = loadBillingKey(); byte[] bytes = dataStream.readAllBytes(); - Map reqMap = Decoder.decode(bytes); + Map reqMap = Decoder.decodeBilling(bytes); logger.info("Request: Billing, " + mapper.writeValueAsString(reqMap)); diff --git a/src/main/java/icu/samnyan/aqua/sega/billing/model/response/BillingResponse.java b/src/main/java/icu/samnyan/aqua/sega/billing/BillingResponse.java similarity index 95% rename from src/main/java/icu/samnyan/aqua/sega/billing/model/response/BillingResponse.java rename to src/main/java/icu/samnyan/aqua/sega/billing/BillingResponse.java index a39e07e1..63d6c545 100644 --- a/src/main/java/icu/samnyan/aqua/sega/billing/model/response/BillingResponse.java +++ b/src/main/java/icu/samnyan/aqua/sega/billing/BillingResponse.java @@ -1,4 +1,4 @@ -package icu.samnyan.aqua.sega.billing.model.response; +package icu.samnyan.aqua.sega.billing; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/src/main/java/icu/samnyan/aqua/sega/billing/util/Decoder.java b/src/main/java/icu/samnyan/aqua/sega/billing/util/Decoder.java deleted file mode 100644 index c0cc206a..00000000 --- a/src/main/java/icu/samnyan/aqua/sega/billing/util/Decoder.java +++ /dev/null @@ -1,28 +0,0 @@ -package icu.samnyan.aqua.sega.billing.util; - -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; - -/** - * @author samnyan (privateamusement@protonmail.com) - */ -public class Decoder { - - public static Map decode(byte[] src) { - //byte[] bytes = Base64.getMimeDecoder().decode(src); - - byte[] output = RawCompression.decompress(src); - - String outputString = new String(output, StandardCharsets.UTF_8).trim(); - String[] split = outputString.split("&"); - Map resultMap = new HashMap<>(); - for (String s : - split) { - String[] kv = s.split("="); - resultMap.put(kv[0], kv[1]); - } - - return resultMap; - } -} diff --git a/src/main/java/icu/samnyan/aqua/sega/billing/util/RawCompression.java b/src/main/java/icu/samnyan/aqua/sega/billing/util/RawCompression.java deleted file mode 100644 index 700fe3d1..00000000 --- a/src/main/java/icu/samnyan/aqua/sega/billing/util/RawCompression.java +++ /dev/null @@ -1,40 +0,0 @@ -package icu.samnyan.aqua.sega.billing.util; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -import java.util.zip.DataFormatException; -import java.util.zip.Inflater; - -import icu.samnyan.aqua.sega.util.ByteBufUtil; - -/** - * @author samnyan (privateamusement@protonmail.com) - */ -public class RawCompression { - - public static byte[] decompress(byte[] src) { - ByteBuf result = Unpooled.buffer(); - byte[] buffer = new byte[100]; - Inflater decompressor = new Inflater(true); // Enable no wrap option - decompressor.setInput(src); - - try { - while (!decompressor.finished()) { - int count = decompressor.inflate(buffer); - if (count == 0) { - break; - } - result.writeBytes(buffer, result.readerIndex(), count); - } - decompressor.end(); - - return ByteBufUtil.toBytes(result); - } catch (DataFormatException e) { - e.printStackTrace(); - return new byte[0]; - } - - } - -} diff --git a/src/main/java/icu/samnyan/aqua/sega/util/Compression.java b/src/main/java/icu/samnyan/aqua/sega/util/Compression.java index 016e0ade..35d5f193 100644 --- a/src/main/java/icu/samnyan/aqua/sega/util/Compression.java +++ b/src/main/java/icu/samnyan/aqua/sega/util/Compression.java @@ -12,10 +12,10 @@ import java.util.zip.Inflater; */ public class Compression { - public static byte[] decompress(byte[] src) { + public static byte[] decompress(byte[] src, boolean nowrap) { ByteBuf result = Unpooled.buffer(); byte[] buffer = new byte[100]; - Inflater decompressor = new Inflater(); + Inflater decompressor = new Inflater(nowrap); decompressor.setInput(src); try { @@ -36,6 +36,10 @@ public class Compression { } + public static byte[] decompress(byte[] src) { + return decompress(src, false); + } + public static byte[] compress(byte[] src) { ByteBuf result = Unpooled.buffer(); byte[] buffer = new byte[100]; diff --git a/src/main/java/icu/samnyan/aqua/sega/util/Decoder.kt b/src/main/java/icu/samnyan/aqua/sega/util/Decoder.kt new file mode 100644 index 00000000..1c0f2328 --- /dev/null +++ b/src/main/java/icu/samnyan/aqua/sega/util/Decoder.kt @@ -0,0 +1,33 @@ +package icu.samnyan.aqua.sega.util + +import java.nio.charset.StandardCharsets +import java.util.* + +object Decoder { + /** + * Decode the input byte array from Base64 MIME encoding and decompress the decoded byte array + */ + fun decode(src: ByteArray, base64: Boolean, nowrap: Boolean): Map { + // Decode the input byte array from Base64 MIME encoding + var bytes = src + if (base64) bytes = Base64.getMimeDecoder().decode(bytes) + + // Decompress the decoded byte array + val output = Compression.decompress(bytes, nowrap) + + // Convert the decompressed byte array to a UTF-8 encoded string and trim any trailing spaces + val str = String(output, StandardCharsets.UTF_8).trim() + + // Split the string by '&' symbol to separate key-value pairs + return str.split("&").associate { + val (key, value) = it.split("=") + key to value + } + } + + @JvmStatic + fun decodeAllNet(src: ByteArray) = decode(src, base64 = true, nowrap = false) + + @JvmStatic + fun decodeBilling(src: ByteArray) = decode(src, base64 = false, nowrap = true) +}