diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/tooling/deviceFingerprinting/DeviceFingerprinting.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/tooling/deviceFingerprinting/DeviceFingerprinting.java new file mode 100644 index 0000000..73d1fde --- /dev/null +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/tooling/deviceFingerprinting/DeviceFingerprinting.java @@ -0,0 +1,218 @@ +package eu.mhsl.craftattack.spawn.common.appliances.tooling.deviceFingerprinting; + +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import eu.mhsl.craftattack.spawn.core.Main; +import eu.mhsl.craftattack.spawn.core.api.server.HttpServer; +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import net.kyori.adventure.resource.ResourcePackInfo; +import net.kyori.adventure.resource.ResourcePackRequest; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerResourcePackStatusEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import spark.Response; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Type; +import java.net.URI; +import java.util.*; + +public class DeviceFingerprinting extends Appliance { + public record PackInfo(String url, UUID uuid, String hash) { + private static final String failingUrl = "http://127.0.0.1:0"; + public PackInfo asFailing() { + return new PackInfo(failingUrl, this.uuid, this.hash); + } + } + + public enum PackStatus { + ERROR, + SUCCESS; + + public static PackStatus fromBukkitStatus(PlayerResourcePackStatusEvent.Status status) { + return switch(status) { + case DISCARDED -> SUCCESS; + case FAILED_DOWNLOAD -> ERROR; + default -> throw new IllegalStateException("Unexpected value: " + status); + }; + } + } + + public enum PlayerStatus { + PREPARATION, + TESTING, + FINISHED; + } + + public record FingerprintData( + Player player, + PlayerStatus status, + @Nullable Long fingerPrint, + @Nullable List pendingPacks + ) { + public FingerprintData(Player player) { + this(player, PlayerStatus.PREPARATION, null, null); + } + } + + private List packs; + private final Map> pendingPacks = new WeakHashMap<>(); + + @Override + public void onEnable() { + this.packs = this.readPacksFromConfig(); + + } + + public void testAllPacks(Player player) { + this.pendingPacks.put(player, Arrays.asList(new PackStatus[this.packs.size()])); + System.out.println("Sending packs..."); + this.packs.forEach(pack -> this.sendPack(player, pack.asFailing())); + } + + public void onPackReceive(Player player, UUID packId, PlayerResourcePackStatusEvent.Status status) { + if(!this.pendingPacks.containsKey(player)) return; + + PackInfo pack = this.packs.stream() + .filter(packInfo -> packInfo.uuid.equals(packId)) + .findFirst() + .orElse(null); + if(pack == null) return; + int packIndex = this.packs.indexOf(pack); + + List currentPendingStatus = this.pendingPacks.get(player); + try { + currentPendingStatus.set(packIndex, PackStatus.fromBukkitStatus(status)); + System.out.println(packIndex + " > " + PackStatus.fromBukkitStatus(status)); + } catch(IllegalStateException ignored) { + return; + } + + long fingerPrint = this.calculateFingerprintId(currentPendingStatus); + if(fingerPrint == -1) return; + + if(fingerPrint == 0) { + // new Player + long newFingerprintId = this.generateNewFingerprintId(); + System.out.println("New Fingerprint: " + newFingerprintId); + this.sendMarkedPacks(player, newFingerprintId); + } else { + System.out.println("Fingerprint: " + fingerPrint); + } + + this.pendingPacks.remove(player); + } + + private long calculateFingerprintId(List packStatus) { + long fingerprintId = 0; + for (int i = 0; i < packStatus.size(); i++) { + var status = packStatus.get(i); + if(status == null) return -1; + switch (status) { + case SUCCESS: + fingerprintId |= 1L << i; + break; + case ERROR: + break; + default: + return -1; + } + } + return fingerprintId; + } + + private long generateNewFingerprintId() { + long id = 0; + Random random = new Random(); + for (int i = 0; i < this.packs.size() / 2; i++) { + while (true) { + int bitIndex = random.nextInt(this.packs.size()); + if ((id & (1L << bitIndex)) == 0) { + id |= 1L << bitIndex; + break; + } + } + } + return id; + } + + private void sendMarkedPacks(Player player, long fingerprintId) { + for (int i = 0; i < this.packs.size(); i++) { + if ((fingerprintId & (1L << i)) != 0) { + PackInfo pack = this.packs.get(i); + this.sendPack(player, pack); + } + } + } + + public void sendPack(Player player, PackInfo pack) { + System.out.println("Sending pack: " + pack.url); + player.sendResourcePacks( + ResourcePackRequest.resourcePackRequest() + .required(true) + .packs(ResourcePackInfo.resourcePackInfo(pack.uuid, URI.create(pack.url), pack.hash)) + ); + } + + private List readPacksFromConfig() { + try (InputStreamReader reader = new InputStreamReader(Objects.requireNonNull(Main.class.getResourceAsStream("/deviceFingerprinting/packs.json")))) { + Type packListType = new TypeToken>(){}.getType(); + List packs = new Gson().fromJson(reader, packListType); + + if (packs.isEmpty()) + throw new IllegalStateException("No resource packs found in packs.json."); + + return packs; + } catch (Exception e) { + throw new IllegalStateException("Failed to parse packs.json.", e); + } + } + + @Override + public void httpApi(HttpServer.ApiBuilder apiBuilder) { + apiBuilder.rawGet( + "base.zip", + (request, response) -> this.servePack("base.zip", response) + ); + + for(int i = 0; i < this.packs.size(); i++) { + int packIndex = i; + apiBuilder.rawGet( + String.format("packs/%d", i), + (request, response) -> this.servePack(String.valueOf(packIndex), response) + ); + } + } + + private Object servePack(String name, Response response) { + try { + String resourcePath = String.format("/deviceFingerprinting/packs/%s", name); + var inputStream = Main.class.getResourceAsStream(resourcePath); + + if (inputStream == null) { + throw new IllegalStateException("Pack file not found: " + resourcePath); + } + + response.header("Content-Type", "application/zip"); + response.header("Content-Disposition", String.format("attachment; filename=\"pack-%s.zip\"", name)); + + var outputStream = response.raw().getOutputStream(); + inputStream.transferTo(outputStream); + outputStream.close(); + + return HttpServer.nothing; + } catch (IOException e) { + throw new RuntimeException(String.format("Failed to serve pack '%s'", name), e); + } + } + + @Override + protected @NotNull List listeners() { + return List.of( + new PlayerJoinListener() + ); + } +} diff --git a/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/tooling/deviceFingerprinting/PlayerJoinListener.java b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/tooling/deviceFingerprinting/PlayerJoinListener.java new file mode 100644 index 0000000..2d92e04 --- /dev/null +++ b/common/src/main/java/eu/mhsl/craftattack/spawn/common/appliances/tooling/deviceFingerprinting/PlayerJoinListener.java @@ -0,0 +1,27 @@ +package eu.mhsl.craftattack.spawn.common.appliances.tooling.deviceFingerprinting; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerResourcePackStatusEvent; + +class PlayerJoinListener extends ApplianceListener { + @EventHandler + public void onJoin(PlayerJoinEvent event) { +// if(Bukkit.getServer().getServerResourcePack() != null && !event.getPlayer().hasResourcePack()) { +// System.out.println("NO RESSOURCEPACK"); +// return; +// } + + this.getAppliance().testAllPacks(event.getPlayer()); + } + + @EventHandler + public void onResourcePackEvent(PlayerResourcePackStatusEvent event) { + this.getAppliance().onPackReceive( + event.getPlayer(), + event.getID(), + event.getStatus() + ); + } +} diff --git a/common/src/main/resources/deviceFingerprinting/README.md b/common/src/main/resources/deviceFingerprinting/README.md new file mode 100644 index 0000000..b40a304 --- /dev/null +++ b/common/src/main/resources/deviceFingerprinting/README.md @@ -0,0 +1,5 @@ +## Files originally from "TrackPack" +https://github.com/ALaggyDev/TrackPack/blob/main/README.md + + +Discovered by: [Laggy](https://github.com/ALaggyDev/) and [NikOverflow](https://github.com/NikOverflow) \ No newline at end of file diff --git a/common/src/main/resources/deviceFingerprinting/gen_packs.py b/common/src/main/resources/deviceFingerprinting/gen_packs.py new file mode 100644 index 0000000..2e7b1df --- /dev/null +++ b/common/src/main/resources/deviceFingerprinting/gen_packs.py @@ -0,0 +1,33 @@ +import zipfile +import hashlib +import uuid +import json + +SERVER_URL = "http://localhost:8080/api/devicefingerprinting" +packs = [] + +def file_sha1(path): + h = hashlib.sha1() + with open(path, "rb") as f: + for chunk in iter(lambda: f.read(8192), b""): + h.update(chunk) + return h.hexdigest() + +for i in range(0, 24): + path = f"packs/{i}" + + with zipfile.ZipFile(path, mode="w") as zf: + zf.writestr( + "pack.mcmeta", + '{"pack":{"pack_format":22,"supported_formats":[22,1000],"description":"pack ' + str(i) + '"}}', + ) + + hash = file_sha1(path) + packs.append({ + "url": f"{SERVER_URL}/packs/{i}", + "uuid": str(uuid.uuid4()), + "hash": hash + }) + +with open("packs.json", "w") as f: + json.dump(packs, f, indent=4) diff --git a/common/src/main/resources/deviceFingerprinting/packs.json b/common/src/main/resources/deviceFingerprinting/packs.json new file mode 100644 index 0000000..59cbad1 --- /dev/null +++ b/common/src/main/resources/deviceFingerprinting/packs.json @@ -0,0 +1,122 @@ +[ + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/0", + "uuid": "b35f6e2f-1b50-4493-85be-fb18bd90f9bb", + "hash": "7a39af839ea6484431f7b707759546bea991d435" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/1", + "uuid": "71095b62-d5ef-4ab2-ba3b-3c1b403f5e34", + "hash": "a9192ee73df1c5cff2c188fac6e9e638a1e7b6ce" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/2", + "uuid": "a4dba0a2-f8f2-4a81-bbb2-a9a818820330", + "hash": "6b85b0eb54865dae70bbda89746d83717dc2a214" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/3", + "uuid": "79fa2dc4-8c84-45fc-a09f-d89906f0d900", + "hash": "c7abf7a316f7e8c98985e8317a8b649e824e9f79" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/4", + "uuid": "15702c9b-a22b-426d-b48a-3d65b0368e9a", + "hash": "10cd0e2c46f192deb87ac75c149827d44a713017" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/5", + "uuid": "3d702d41-8e2f-4920-8dd0-1fd2146da9fb", + "hash": "8ad517d259e800b88a38ff00ee6721d5656822f2" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/6", + "uuid": "c20a2e47-ef43-49da-a80d-adf238df3695", + "hash": "798677405a4fd678892e1cf55585c8c91f82e1e2" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/7", + "uuid": "7ce51b81-1263-4919-9f4e-bb749ffe6e2e", + "hash": "af473b8eb7572f35d307bede5f2e20f263c0d804" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/8", + "uuid": "0c70d586-fe48-4ffc-86b0-6b9ec3bfe045", + "hash": "2fb698ff88f2436637641f3b2e6792201feb5144" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/9", + "uuid": "c7af75a8-0b72-495d-a0ff-c1c40e229c13", + "hash": "cf660460798eecf451d639873cc1fedc4661db1b" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/10", + "uuid": "248dbce6-4b2a-44b5-b038-8d718b0ced99", + "hash": "a8ebe708d0f3747c76e4e5e68db5dcb561922706" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/11", + "uuid": "10979174-cb02-40eb-a754-275551ad608d", + "hash": "54961b48db1582a1a0981c8cc9be5ae0f3122cf3" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/12", + "uuid": "a361cfa7-674c-4493-a4cf-4baff851f276", + "hash": "013719dc8da79c96b45a1c5319c20bffe1a56cc9" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/13", + "uuid": "24b39bdb-ada9-40ec-9e3a-132c74b81dc6", + "hash": "206898c6b6600d2648b2d79c61fc6255b19587d9" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/14", + "uuid": "158fc5b4-be2c-4f7a-98cb-af5993adcc90", + "hash": "061b266a7c526fb3a3152a4ea70ca5592e0b503c" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/15", + "uuid": "4f9097a7-be02-48ad-919c-f292307f8490", + "hash": "45a667a0fe06246defabca14ef1271fb6db5a1ac" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/16", + "uuid": "3ce31e60-7e8a-4fb1-8c6d-da9065bea798", + "hash": "75bb12e46203d49e89aa9a826d267552372758bc" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/17", + "uuid": "cd978e5c-3de0-4ada-8ec5-3a88a305eec6", + "hash": "5b20261f7be03e83e9c52307f1408b0c5e58358c" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/18", + "uuid": "75001e58-3999-4779-a1d1-43ab161770ce", + "hash": "544420cffb6c17113c06fb49eeba892c208719d3" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/19", + "uuid": "6a7005a9-c2ca-476d-9a12-07d120ee121a", + "hash": "fcc066a4d3193b60b102e3d906ad8dc0b0fcf65b" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/20", + "uuid": "521c0d84-d82e-49ef-b096-d9b90f15aa19", + "hash": "4545835983ec7f07d02675a69181a80dc396f038" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/21", + "uuid": "c1b590c5-43fc-41e3-83c0-47f35b14f845", + "hash": "8d4c670eaefc0482734e839b72758226dde13bc3" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/22", + "uuid": "43958a18-c087-4f2b-a6ea-066231606eb1", + "hash": "004282602f7bdbb7cd7724f23aae23876f224092" + }, + { + "url": "http://localhost:8080/api/devicefingerprinting/packs/23", + "uuid": "4b91ac81-9de4-4c2b-a876-47e621496d10", + "hash": "dae68eae109e08ea4c4c943905502eb331939f64" + } +] \ No newline at end of file diff --git a/common/src/main/resources/deviceFingerprinting/packs/.gitignore b/common/src/main/resources/deviceFingerprinting/packs/.gitignore new file mode 100644 index 0000000..073c2a0 --- /dev/null +++ b/common/src/main/resources/deviceFingerprinting/packs/.gitignore @@ -0,0 +1 @@ +!base.zip \ No newline at end of file diff --git a/common/src/main/resources/deviceFingerprinting/packs/0 b/common/src/main/resources/deviceFingerprinting/packs/0 new file mode 100644 index 0000000..9ed3503 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/0 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/1 b/common/src/main/resources/deviceFingerprinting/packs/1 new file mode 100644 index 0000000..5303a21 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/1 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/10 b/common/src/main/resources/deviceFingerprinting/packs/10 new file mode 100644 index 0000000..4a784b8 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/10 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/11 b/common/src/main/resources/deviceFingerprinting/packs/11 new file mode 100644 index 0000000..0f82518 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/11 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/12 b/common/src/main/resources/deviceFingerprinting/packs/12 new file mode 100644 index 0000000..4104d6d Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/12 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/13 b/common/src/main/resources/deviceFingerprinting/packs/13 new file mode 100644 index 0000000..e2785e3 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/13 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/14 b/common/src/main/resources/deviceFingerprinting/packs/14 new file mode 100644 index 0000000..c2cca34 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/14 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/15 b/common/src/main/resources/deviceFingerprinting/packs/15 new file mode 100644 index 0000000..cac2af0 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/15 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/16 b/common/src/main/resources/deviceFingerprinting/packs/16 new file mode 100644 index 0000000..5aaf529 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/16 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/17 b/common/src/main/resources/deviceFingerprinting/packs/17 new file mode 100644 index 0000000..3fbd817 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/17 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/18 b/common/src/main/resources/deviceFingerprinting/packs/18 new file mode 100644 index 0000000..b14a577 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/18 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/19 b/common/src/main/resources/deviceFingerprinting/packs/19 new file mode 100644 index 0000000..6f3e95d Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/19 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/2 b/common/src/main/resources/deviceFingerprinting/packs/2 new file mode 100644 index 0000000..b659f26 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/2 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/20 b/common/src/main/resources/deviceFingerprinting/packs/20 new file mode 100644 index 0000000..f89bf32 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/20 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/21 b/common/src/main/resources/deviceFingerprinting/packs/21 new file mode 100644 index 0000000..f21f8e5 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/21 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/22 b/common/src/main/resources/deviceFingerprinting/packs/22 new file mode 100644 index 0000000..7aa7565 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/22 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/23 b/common/src/main/resources/deviceFingerprinting/packs/23 new file mode 100644 index 0000000..be0b732 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/23 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/3 b/common/src/main/resources/deviceFingerprinting/packs/3 new file mode 100644 index 0000000..830d172 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/3 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/4 b/common/src/main/resources/deviceFingerprinting/packs/4 new file mode 100644 index 0000000..c0ae942 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/4 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/5 b/common/src/main/resources/deviceFingerprinting/packs/5 new file mode 100644 index 0000000..b82f92a Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/5 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/6 b/common/src/main/resources/deviceFingerprinting/packs/6 new file mode 100644 index 0000000..8bc5b39 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/6 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/7 b/common/src/main/resources/deviceFingerprinting/packs/7 new file mode 100644 index 0000000..79f630d Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/7 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/8 b/common/src/main/resources/deviceFingerprinting/packs/8 new file mode 100644 index 0000000..96903ec Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/8 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/9 b/common/src/main/resources/deviceFingerprinting/packs/9 new file mode 100644 index 0000000..3c90e43 Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/9 differ diff --git a/common/src/main/resources/deviceFingerprinting/packs/base.zip b/common/src/main/resources/deviceFingerprinting/packs/base.zip new file mode 100644 index 0000000..bdfb24c Binary files /dev/null and b/common/src/main/resources/deviceFingerprinting/packs/base.zip differ diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/server/HttpServer.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/server/HttpServer.java index 6c2ba8b..b6f2128 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/server/HttpServer.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/api/server/HttpServer.java @@ -7,6 +7,7 @@ import org.bukkit.configuration.ConfigurationSection; import spark.Request; import spark.Spark; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @@ -43,12 +44,16 @@ public class HttpServer { this.applianceName = appliance.getClass().getSimpleName().toLowerCase(); } + public void rawGet(String path, BiFunction onCall) { + Spark.get(this.buildRoute(path), (req, resp) -> this.process(() -> onCall.apply(req, resp))); + } + public void get(String path, Function onCall) { Spark.get(this.buildRoute(path), (req, resp) -> this.process(() -> onCall.apply(req))); } - public void rawPost(String path, Function onCall) { - Spark.post(this.buildRoute(path), (req, resp) -> this.process(() -> onCall.apply(req))); + public void rawPost(String path, BiFunction onCall) { + Spark.post(this.buildRoute(path), (req, resp) -> this.process(() -> onCall.apply(req, resp))); } public void post(String path, Class clazz, RequestProvider onCall) {