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}
-

+
{/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()
}
}