upgrade(docker)

This commit is contained in:
stefan 2025-08-29 12:03:00 +02:00
parent 20788bde91
commit e77c2561dc
3 changed files with 78 additions and 3 deletions

View File

@ -26,6 +26,17 @@ subprojects {
// Removed byte-buddy-agent configuration to fix Gradle 9.0.0 deprecation warning // Removed byte-buddy-agent configuration to fix Gradle 9.0.0 deprecation warning
// The agent configuration was causing Task.project access at execution time // 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<org.gradle.api.tasks.Exec>().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 // 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<org.gradle.api.tasks.Exec>().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 { tasks.wrapper {
gradleVersion = "9.0.0" gradleVersion = "9.0.0"
distributionType = Wrapper.DistributionType.BIN distributionType = Wrapper.DistributionType.BIN

View File

@ -52,5 +52,18 @@ kotlin {
// Using core testing dependencies for now // 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<org.jetbrains.kotlin.gradle.targets.js.ir.DefaultIncrementalSyncTask>("jsTestTestDevelopmentExecutableCompileSync").configure {
// Skip copying duplicates that already exist in destination
duplicatesStrategy = org.gradle.api.file.DuplicatesStrategy.EXCLUDE
}

View File

@ -5,7 +5,10 @@ import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.exceptions.JWTVerificationException import com.auth0.jwt.exceptions.JWTVerificationException
import io.github.oshai.kotlinlogging.KotlinLogging import io.github.oshai.kotlinlogging.KotlinLogging
import java.nio.charset.StandardCharsets
import java.util.* import java.util.*
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.Duration.Companion.minutes import kotlin.time.Duration.Companion.minutes
@ -49,14 +52,18 @@ class JwtService(
*/ */
fun validateToken(token: String): Result<Boolean> { fun validateToken(token: String): Result<Boolean> {
return try { 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) verifier.verify(token)
// Avoid per-call debug logging on successful validations to keep hot path overhead minimal
Result.success(true) Result.success(true)
} catch (e: JWTVerificationException) { } 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) Result.failure(e)
} catch (e: Exception) { } catch (e: Exception) {
logger.error(e) { "Unexpected error during JWT token validation" } logger.debug { "Unexpected error during JWT token validation" }
Result.failure(e) Result.failure(e)
} }
} }
@ -148,4 +155,39 @@ class JwtService(
fun getPermissions(token: String): List<BerechtigungE> { fun getPermissions(token: String): List<BerechtigungE> {
return getPermissionsFromToken(token).getOrElse { emptyList() } 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
}
} }