From e77c2561dcdcd918daf75e4e0c77a06f32de5500 Mon Sep 17 00:00:00 2001 From: stefan Date: Fri, 29 Aug 2025 12:03:00 +0200 Subject: [PATCH] upgrade(docker) --- build.gradle.kts | 20 ++++++++ client/common-ui/build.gradle.kts | 13 +++++ .../infrastructure/auth/client/JwtService.kt | 48 +++++++++++++++++-- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 658c9102..aef0b67f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -26,6 +26,17 @@ subprojects { // Removed byte-buddy-agent configuration to fix Gradle 9.0.0 deprecation warning // The agent configuration was causing Task.project access at execution time } + + // Suppress Node.js deprecation warnings (e.g., DEP0040 punycode) during Kotlin/JS npm/yarn tasks + // Applies to all Exec-based tasks (covers Yarn/NPM invocations used by Kotlin JS plugin) + tasks.withType().configureEach { + // Merge existing NODE_OPTIONS with --no-deprecation + val current = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS") + val merged = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation" + environment("NODE_OPTIONS", merged) + // Also set the legacy switch to silence warnings entirely + environment("NODE_NO_WARNINGS", "1") + } } // ################################################################## @@ -110,6 +121,15 @@ tasks.register("generateAllDocs") { } // Wrapper-Konfiguration +// Apply Node warning suppression on root project Exec tasks as well +// Ensures aggregated Kotlin/JS tasks created at root (e.g., kotlinNpmInstall) inherit the env +tasks.withType().configureEach { + val current = (environment["NODE_OPTIONS"] as String?) ?: System.getenv("NODE_OPTIONS") + val merged = if (current.isNullOrBlank()) "--no-deprecation" else "$current --no-deprecation" + environment("NODE_OPTIONS", merged) + environment("NODE_NO_WARNINGS", "1") +} + tasks.wrapper { gradleVersion = "9.0.0" distributionType = Wrapper.DistributionType.BIN diff --git a/client/common-ui/build.gradle.kts b/client/common-ui/build.gradle.kts index 590fc4c2..9b3f5eef 100644 --- a/client/common-ui/build.gradle.kts +++ b/client/common-ui/build.gradle.kts @@ -52,5 +52,18 @@ kotlin { // Using core testing dependencies for now } } + val jsTest by getting { + // Avoid duplicate Skiko runtime files in test processedResources + resources.exclude("**/skiko.*") + resources.exclude("**/skikod8.mjs") + } } } + +// Avoid overwrite warnings when syncing JS test executable: keep first occurrence of duplicate resources +// Configure the Kotlin JS incremental sync task directly using fully-qualified types (no imports in the middle of the file) + +tasks.named("jsTestTestDevelopmentExecutableCompileSync").configure { + // Skip copying duplicates that already exist in destination + duplicatesStrategy = org.gradle.api.file.DuplicatesStrategy.EXCLUDE +} diff --git a/infrastructure/auth/auth-client/src/main/kotlin/at/mocode/infrastructure/auth/client/JwtService.kt b/infrastructure/auth/auth-client/src/main/kotlin/at/mocode/infrastructure/auth/client/JwtService.kt index 50b1a154..5b3367f1 100644 --- a/infrastructure/auth/auth-client/src/main/kotlin/at/mocode/infrastructure/auth/client/JwtService.kt +++ b/infrastructure/auth/auth-client/src/main/kotlin/at/mocode/infrastructure/auth/client/JwtService.kt @@ -5,7 +5,10 @@ import com.auth0.jwt.JWT import com.auth0.jwt.algorithms.Algorithm import com.auth0.jwt.exceptions.JWTVerificationException import io.github.oshai.kotlinlogging.KotlinLogging +import java.nio.charset.StandardCharsets import java.util.* +import javax.crypto.Mac +import javax.crypto.spec.SecretKeySpec import kotlin.time.Duration import kotlin.time.Duration.Companion.minutes @@ -49,14 +52,18 @@ class JwtService( */ fun validateToken(token: String): Result { return try { + // Perform a strict, constant-time signature pre-check before invoking the library verifier + if (!hasValidSignature(token)) { + throw JWTVerificationException("Invalid token signature") + } verifier.verify(token) - // Avoid per-call debug logging on successful validations to keep hot path overhead minimal Result.success(true) } catch (e: JWTVerificationException) { - logger.warn { "JWT token validation failed: ${e.message}" } + // Keep logging minimal to avoid timing variations under high frequency invalid inputs + logger.debug { "JWT token validation failed" } Result.failure(e) } catch (e: Exception) { - logger.error(e) { "Unexpected error during JWT token validation" } + logger.debug { "Unexpected error during JWT token validation" } Result.failure(e) } } @@ -148,4 +155,39 @@ class JwtService( fun getPermissions(token: String): List { return getPermissionsFromToken(token).getOrElse { emptyList() } } + + // ====== Internal helpers for strict signature validation ====== + private fun hasValidSignature(token: String): Boolean { + return try { + val parts = token.split('.') + if (parts.size != 3) return false + val header = parts[0] + val payload = parts[1] + val signature = parts[2] + if (header.isBlank() || payload.isBlank() || signature.isBlank()) return false + + val mac = Mac.getInstance("HmacSHA512") + mac.init(SecretKeySpec(secret.toByteArray(StandardCharsets.UTF_8), "HmacSHA512")) + val signingInput = "$header.$payload".toByteArray(StandardCharsets.UTF_8) + val expected = mac.doFinal(signingInput) + val expectedB64 = Base64.getUrlEncoder().withoutPadding().encodeToString(expected) + + constantTimeEquals(expectedB64, signature) + } catch (_: Exception) { + false + } + } + + private fun constantTimeEquals(a: String, b: String): Boolean { + val aBytes = a.toByteArray(StandardCharsets.UTF_8) + val bBytes = b.toByteArray(StandardCharsets.UTF_8) + var diff = aBytes.size xor bBytes.size + val minLen = if (aBytes.size < bBytes.size) aBytes.size else bBytes.size + var i = 0 + while (i < minLen) { + diff = diff or (aBytes[i].toInt() xor bBytes[i].toInt()) + i++ + } + return diff == 0 + } }