From 243a9b2ddce3add619e92254832a860053e6fd02 Mon Sep 17 00:00:00 2001 From: Raymond <101374892+raymonable@users.noreply.github.com> Date: Sat, 16 May 2026 00:30:42 -0400 Subject: [PATCH] =?UTF-8?q?fix:=20=F0=9F=9B=A1=EF=B8=8F=20don't=20leak=20e?= =?UTF-8?q?xtid=20&=20token=20in=20mai=20photos?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AquaNet/src/pages/MaiPhoto.svelte | 4 +--- .../samnyan/aqua/net/games/mai2/Maimai2.kt | 24 ++++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/AquaNet/src/pages/MaiPhoto.svelte b/AquaNet/src/pages/MaiPhoto.svelte index 355143c1..70770b6b 100644 --- a/AquaNet/src/pages/MaiPhoto.svelte +++ b/AquaNet/src/pages/MaiPhoto.svelte @@ -18,13 +18,11 @@ {:then photos} {#if photos.length === 0}
{t('maiphoto.none')}
- {:else} -
{t('maiphoto.url_warning')}
{/if}
{#each photos as photo}
- Memorial + Mai Photo
{/each}
diff --git a/src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt b/src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt index 1a7fbc47..7129e8c0 100644 --- a/src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt +++ b/src/main/java/icu/samnyan/aqua/net/games/mai2/Maimai2.kt @@ -17,6 +17,8 @@ import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserOption import org.springframework.http.MediaType import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RestController +import java.security.MessageDigest +import kotlin.text.Charsets.UTF_8 import kotlin.jvm.optionals.getOrNull import kotlin.reflect.KMutableProperty1 import kotlin.reflect.full.memberProperties @@ -207,7 +209,11 @@ class Maimai2( } val photoDir = UploadUserPhotoHandler.uploadDir.toFile().canonicalFile + val photoHashMap: MutableMap = emptyMap().toMutableMap() + // creating a ton of MD5 hashes every launch *probably* isn't ideal but it's better than exposing token AND extid... + + @OptIn(ExperimentalStdlibApi::class) @API("my-photo") suspend fun myPhoto(@RP token: Str) = us.jwt.auth(token) { u -> val find = "${u.ghostCard.extId}-" @@ -215,15 +221,21 @@ class Maimai2( ?.map { it.name } ?.filter { it.startsWith(find) } ?.sorted() + ?.map { + // generate MD5 hash of photo as to not expose details + if (!photoHashMap.containsKey(it)) + photoHashMap[it] = MessageDigest.getInstance("MD5") + .digest(it.toByteArray(UTF_8)).toHexString() + photoHashMap[it] + } ?: emptyList() } @API("my-photo/{fileName}", produces = [MediaType.IMAGE_JPEG_VALUE]) - suspend fun myPhoto(@RP token: Str, @PV fileName: Str) = us.jwt.auth(token) { u -> - val f = (photoDir / fileName) - if (!f.canonicalFile.startsWith(photoDir)) (403 - "Never gonna give you up") - if (!f.name.startsWith("${u.ghostCard.extId}-")) (403 - "Not your photo") - if (!f.exists()) (404 - "Photo not found") - f.readBytes() + suspend fun accessMyPhoto(@PV fileName: Str): ByteArray { + val trueFileName = photoHashMap.entries.firstOrNull { it.value == fileName }?.key + if (trueFileName.isNullOrEmpty()) 404 - "Photo does not exist" + val file = (photoDir / trueFileName) + return file.readBytes() } }