From 4a7d9a6510f4b1e84fdec315208fbddaae5f9eef Mon Sep 17 00:00:00 2001 From: Gauthier Roebroeck Date: Fri, 17 Apr 2026 10:39:40 +0800 Subject: [PATCH] fix(kobo): proxy raw request body to kobo store Closes: #2289 --- .../komga/infrastructure/kobo/KoboProxy.kt | 2 +- .../komga/interfaces/api/kobo/KoboController.kt | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KoboProxy.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KoboProxy.kt index 2df061ec..dd93877e 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KoboProxy.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/kobo/KoboProxy.kt @@ -74,7 +74,7 @@ class KoboProxy( * raw Kobo sync token returned, and added to the response headers. */ fun proxyCurrentRequest( - body: Any? = null, + body: ByteArray? = null, includeSyncToken: Boolean = false, ): ResponseEntity { if (!komgaSettingsProvider.koboProxy) throw IllegalStateException("kobo proxying is disabled") diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt index 53eb11a6..455e6d72 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/api/kobo/KoboController.kt @@ -3,6 +3,7 @@ package org.gotson.komga.interfaces.api.kobo import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.node.ObjectNode +import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.treeToValue import com.github.benmanes.caffeine.cache.Caffeine import io.github.oshai.kotlinlogging.KotlinLogging @@ -174,6 +175,7 @@ class KoboController( private val imageConverter: ImageConverter, private val mediaRepository: MediaRepository, private val contentRestrictionChecker: ContentRestrictionChecker, + private val objectMapper: ObjectMapper, ) { private val cachedKepub = Caffeine @@ -230,14 +232,16 @@ class KoboController( */ @PostMapping("v1/auth/device") fun authDevice( - @RequestBody body: JsonNode, + @RequestBody rawBody: ByteArray, ): Any { try { - return koboProxy.proxyCurrentRequest(body) + return koboProxy.proxyCurrentRequest(rawBody) } catch (_: Exception) { logger.warn { "Failed to get response from Kobo /v1/auth/device, fallback to noproxy" } } + val body = objectMapper.readTree(rawBody) + /** * Komga does not use the /v1/auth/device API call for authentication/authorization. * Return dummy data to keep the device happy. @@ -546,13 +550,15 @@ class KoboController( fun updateState( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String, - @RequestBody body: ReadingStateStateUpdateDto, + @RequestBody rawBody: ByteArray, @RequestHeader(name = X_KOBO_DEVICEID, required = false) koboDeviceId: String = "unknown", ): ResponseEntity<*> { + val body = objectMapper.readValue(rawBody) + val book = bookRepository.findByIdOrNull(bookId) ?: if (koboProxy.isEnabled()) - return koboProxy.proxyCurrentRequest(body) + return koboProxy.proxyCurrentRequest(rawBody) else throw ResponseStatusException(HttpStatus.NOT_FOUND) @@ -733,7 +739,7 @@ class KoboController( method = [RequestMethod.GET, RequestMethod.PUT, RequestMethod.POST, RequestMethod.DELETE, RequestMethod.PATCH], ) fun catchAll( - @RequestBody body: Any?, + @RequestBody body: ByteArray?, ): ResponseEntity = if (koboProxy.isEnabled()) koboProxy.proxyCurrentRequest(body)