upgrade(docker)
This commit is contained in:
parent
20788bde91
commit
e77c2561dc
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user