From fddff499e5b679e779b684483d48f2106f155614 Mon Sep 17 00:00:00 2001 From: MrPowerGamerBR Date: Tue, 15 Oct 2024 16:00:24 -0300 Subject: [PATCH] Make every auth token store to a specific folder, return where the file was saved, filter path traversal (even tho we are the only one using it...) and allow checking if a file already exists --- .../backend/routes/api/v1/PostUploadFileRoute.kt | 15 +++++++++++++-- .../backend/utils/EtherealGambiConfig.kt | 9 ++------- build.gradle.kts | 5 +---- .../etherealgambi/client/EtherealGambiClient.kt | 7 ++++--- .../etherealgambi/data/api/UploadFile.kt | 11 +++++++++-- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/backend/src/main/kotlin/net/perfectdreams/etherealgambi/backend/routes/api/v1/PostUploadFileRoute.kt b/backend/src/main/kotlin/net/perfectdreams/etherealgambi/backend/routes/api/v1/PostUploadFileRoute.kt index 1a1f714..a892850 100644 --- a/backend/src/main/kotlin/net/perfectdreams/etherealgambi/backend/routes/api/v1/PostUploadFileRoute.kt +++ b/backend/src/main/kotlin/net/perfectdreams/etherealgambi/backend/routes/api/v1/PostUploadFileRoute.kt @@ -35,11 +35,22 @@ class PostUploadFileRoute(val m: EtherealGambi) : BaseRoute("/api/v1/upload") { val fileData = Base64.getDecoder().decode(request.dataBase64) - val file = File(m.files, request.path) + if (request.path.contains("..")) { + call.respondText(Json.encodeToString(UploadFileResponse.PathTraversalDisallowed)) + return + } + + val writeToPath = "/${authorizationToken.folder}/${request.path}" + val file = File(m.files, writeToPath) + if (request.failIfFileAlreadyExists && file.exists()) { + call.respondText(Json.encodeToString(UploadFileResponse.FileAlreadyExists)) + return + } + val folder = file.parentFile folder.mkdirs() file.writeBytes(fileData) - call.respondText(Json.encodeToString(UploadFileResponse.Success)) + call.respondText(Json.encodeToString(UploadFileResponse.Success(writeToPath))) } } \ No newline at end of file diff --git a/backend/src/main/kotlin/net/perfectdreams/etherealgambi/backend/utils/EtherealGambiConfig.kt b/backend/src/main/kotlin/net/perfectdreams/etherealgambi/backend/utils/EtherealGambiConfig.kt index b20b40f..44b788f 100644 --- a/backend/src/main/kotlin/net/perfectdreams/etherealgambi/backend/utils/EtherealGambiConfig.kt +++ b/backend/src/main/kotlin/net/perfectdreams/etherealgambi/backend/utils/EtherealGambiConfig.kt @@ -9,12 +9,7 @@ data class EtherealGambiConfig( @Serializable data class AuthorizationToken( val name: String, - val token: String - ) - - @Serializable - data class OptimizationSettings( - val path: String, - val useOptiPNG: Boolean + val folder: String, + val token: String, ) } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index a3d8e7b..7336a46 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,12 +3,9 @@ plugins { kotlin("plugin.serialization") version libs.versions.kotlin apply false } -group = "net.perfectdreams.etherealgambi" -version = "1.0.1-SNAPSHOT" - allprojects { group = "net.perfectdreams.etherealgambi" - version = "1.0.1" + version = "1.0.2" repositories { mavenCentral() diff --git a/client/src/main/kotlin/net/perfectdreams/etherealgambi/client/EtherealGambiClient.kt b/client/src/main/kotlin/net/perfectdreams/etherealgambi/client/EtherealGambiClient.kt index 5f90dd9..21ddecf 100644 --- a/client/src/main/kotlin/net/perfectdreams/etherealgambi/client/EtherealGambiClient.kt +++ b/client/src/main/kotlin/net/perfectdreams/etherealgambi/client/EtherealGambiClient.kt @@ -10,6 +10,7 @@ import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import net.perfectdreams.etherealgambi.data.api.UploadFileRequest +import net.perfectdreams.etherealgambi.data.api.UploadFileResponse import net.perfectdreams.etherealgambi.data.api.requests.ImageVariantsRequest import net.perfectdreams.etherealgambi.data.api.responses.ImageVariantsResponse import java.io.Closeable @@ -32,14 +33,14 @@ class EtherealGambiClient(baseUrl: String) : Closeable { ) } - suspend fun uploadFile(token: String, path: String, data: ByteArray) { - return Json.decodeFromString( + suspend fun uploadFile(token: String, path: String, failIfFileAlreadyExists: Boolean, data: ByteArray): UploadFileResponse { + return Json.decodeFromString( http.post("$baseUrl/api/v1/upload") { header(HttpHeaders.Authorization, token) setBody( TextContent( - Json.encodeToString(UploadFileRequest(path, Base64.getEncoder().encodeToString(data))), + Json.encodeToString(UploadFileRequest(path, failIfFileAlreadyExists, Base64.getEncoder().encodeToString(data))), ContentType.Application.Json ) ) diff --git a/common/src/main/kotlin/net/perfectdreams/etherealgambi/data/api/UploadFile.kt b/common/src/main/kotlin/net/perfectdreams/etherealgambi/data/api/UploadFile.kt index d93ac7b..406e442 100644 --- a/common/src/main/kotlin/net/perfectdreams/etherealgambi/data/api/UploadFile.kt +++ b/common/src/main/kotlin/net/perfectdreams/etherealgambi/data/api/UploadFile.kt @@ -5,13 +5,20 @@ import kotlinx.serialization.Serializable @Serializable data class UploadFileRequest( val path: String, - val dataBase64: String + val failIfFileAlreadyExists: Boolean, + val dataBase64: String, ) @Serializable sealed class UploadFileResponse { @Serializable - data object Success : UploadFileResponse() + data class Success(val path: String) : UploadFileResponse() + + @Serializable + data object FileAlreadyExists : UploadFileResponse() + + @Serializable + data object PathTraversalDisallowed : UploadFileResponse() @Serializable data object Unauthorized : UploadFileResponse()