diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt index d4804c580..d5b5b74ff 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/security/SecurityConfiguration.kt @@ -55,9 +55,11 @@ class SecurityConfiguration( // authorize frames for H2 console .and() - .headers().frameOptions().sameOrigin() + .headers { + it.frameOptions().sameOrigin() + it.cacheControl().disable() //headers are set in WebMvcConfiguration + } - .and() .httpBasic() .and() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/Utils.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/Utils.kt index e38a10113..dbe271e54 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/Utils.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/Utils.kt @@ -13,7 +13,10 @@ fun filePathToUrl(filePath: String): URL = Paths.get(filePath).toUri().toURL() fun ResponseEntity.BodyBuilder.setCachePrivate() = - this.cacheControl(CacheControl.maxAge(0, TimeUnit.SECONDS) - .cachePrivate() - .mustRevalidate() - ) + this.cacheControl(cachePrivate) + +val cachePrivate = CacheControl + .maxAge(0, TimeUnit.SECONDS) + .noTransform() + .cachePrivate() + .mustRevalidate() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/StaticResourceConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/WebMvcConfiguration.kt similarity index 81% rename from komga/src/main/kotlin/org/gotson/komga/infrastructure/web/StaticResourceConfiguration.kt rename to komga/src/main/kotlin/org/gotson/komga/infrastructure/web/WebMvcConfiguration.kt index 56fd53a57..6e774ea59 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/StaticResourceConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/web/WebMvcConfiguration.kt @@ -6,13 +6,15 @@ import org.springframework.stereotype.Component import org.springframework.web.bind.annotation.ControllerAdvice import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.servlet.NoHandlerFoundException +import org.springframework.web.servlet.config.annotation.InterceptorRegistry import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry import org.springframework.web.servlet.config.annotation.WebMvcConfigurer +import org.springframework.web.servlet.mvc.WebContentInterceptor import java.util.concurrent.TimeUnit @Configuration -class StaticResourceConfiguration : WebMvcConfigurer { +class WebMvcConfiguration : WebMvcConfigurer { override fun addResourceHandlers(registry: ResourceHandlerRegistry) { if (!registry.hasMappingForPattern("/webjars/**")) { registry.addResourceHandler("/webjars/**") @@ -51,6 +53,17 @@ class StaticResourceConfiguration : WebMvcConfigurer { ) .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS).cachePublic()) } + + override fun addInterceptors(registry: InterceptorRegistry) { + registry.addInterceptor( + WebContentInterceptor().apply { + addCacheMapping( + cachePrivate, + "/api/**", "/opds/**" + ) + } + ) + } } @Component diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/BookController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/BookController.kt index eb5cb5495..de0cfb330 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/BookController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/BookController.kt @@ -191,16 +191,12 @@ class BookController( fun getBookThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable bookId: String - ): ResponseEntity { + ): ByteArray { bookRepository.getLibraryId(bookId)?.let { if (!principal.user.canAccessLibrary(it)) throw ResponseStatusException(HttpStatus.FORBIDDEN) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) - return bookLifecycle.getThumbnailBytes(bookId)?.let { - ResponseEntity.ok() - .setCachePrivate() - .body(it) - } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + return bookLifecycle.getThumbnailBytes(bookId) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } @Operation(description = "Download the book file.") diff --git a/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/SeriesController.kt b/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/SeriesController.kt index 5b7386616..bda6c4b9f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/SeriesController.kt +++ b/komga/src/main/kotlin/org/gotson/komga/interfaces/rest/SeriesController.kt @@ -23,7 +23,6 @@ import org.gotson.komga.infrastructure.jooq.UnpagedSorted import org.gotson.komga.infrastructure.security.KomgaPrincipal import org.gotson.komga.infrastructure.swagger.PageableAsQueryParam import org.gotson.komga.infrastructure.swagger.PageableWithoutSortAsQueryParam -import org.gotson.komga.infrastructure.web.setCachePrivate import org.gotson.komga.interfaces.rest.dto.BookDto import org.gotson.komga.interfaces.rest.dto.CollectionDto import org.gotson.komga.interfaces.rest.dto.SeriesDto @@ -38,7 +37,6 @@ import org.springframework.data.domain.Pageable import org.springframework.data.domain.Sort import org.springframework.http.HttpStatus import org.springframework.http.MediaType -import org.springframework.http.ResponseEntity import org.springframework.security.access.prepost.PreAuthorize import org.springframework.security.core.annotation.AuthenticationPrincipal import org.springframework.web.bind.annotation.DeleteMapping @@ -196,16 +194,12 @@ class SeriesController( fun getSeriesThumbnail( @AuthenticationPrincipal principal: KomgaPrincipal, @PathVariable(name = "seriesId") seriesId: String - ): ResponseEntity { + ): ByteArray { seriesRepository.getLibraryId(seriesId)?.let { if (!principal.user.canAccessLibrary(it)) throw ResponseStatusException(HttpStatus.FORBIDDEN) } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) - return seriesLifecycle.getThumbnailBytes(seriesId)?.let { - ResponseEntity.ok() - .setCachePrivate() - .body(it) - } ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) + return seriesLifecycle.getThumbnailBytes(seriesId) ?: throw ResponseStatusException(HttpStatus.NOT_FOUND) } @PageableAsQueryParam