fixes for jwt token (now 30 days) screentime sync and redis

This commit is contained in:
Oliver Wallisch 2026-09-09 23:23:23 +02:00
parent 49c472f748
commit 17f04d71a4
3 changed files with 29 additions and 16 deletions

View file

@ -78,7 +78,7 @@ class ExposedKidioRepository : KidioRepository {
val dbSeconds = DatabaseFactory.dbQuery { val dbSeconds = DatabaseFactory.dbQuery {
ScreentimeTable.selectAll() ScreentimeTable.selectAll()
.where { ScreentimeTable.userId eq userId } .where { ScreentimeTable.userId eq userId }
.map { it[ScreentimeTable.remainingSeconds] } // Korrigiert: Abfrage der Sekunden! .map { it[ScreentimeTable.remainingSeconds] }
.singleOrNull() ?: 1800 .singleOrNull() ?: 1800
} }
@ -93,15 +93,26 @@ class ExposedKidioRepository : KidioRepository {
return dbSeconds return dbSeconds
} }
override suspend fun updateScreentime(userId: String, seconds: Int) = DatabaseFactory.dbQuery { override suspend fun updateScreentime(userId: String, seconds: Int) {
val rowsUpdated = ScreentimeTable.update({ ScreentimeTable.userId eq userId }) { DatabaseFactory.dbQuery {
it[remainingSeconds] = seconds val rowsUpdated = ScreentimeTable.update({ ScreentimeTable.userId eq userId }) {
} it[remainingSeconds] = seconds
if (rowsUpdated == 0) {
ScreentimeTable.insert {
it[ScreentimeTable.userId] = userId
it[ScreentimeTable.remainingSeconds] = seconds // Korrigiert: Wert wird wieder mitgegeben!
} }
if (rowsUpdated == 0) {
ScreentimeTable.insert {
it[ScreentimeTable.userId] = userId
it[ScreentimeTable.remainingSeconds] = seconds
}
}
}
val redisKey = "screentime:$userId"
try {
RedisFactory.getResource().use { jedis ->
jedis.setex(redisKey, 3600, seconds.toString())
println("DEBUG: Bildschirmzeit für $userId in REDIS aktualisiert auf $seconds Sek")
}
} catch (e: Exception) {
println("WARNUNG: Konnte Redis nicht aktualisieren: ${e.message}")
} }
} }

View file

@ -6,7 +6,6 @@ import com.oliver.kidio.backend.security.JwtService
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.server.application.* import io.ktor.server.application.*
import io.ktor.server.auth.authenticate import io.ktor.server.auth.authenticate
import io.ktor.server.auth.jwt.JWTPrincipal
import io.ktor.server.auth.principal import io.ktor.server.auth.principal
import io.ktor.server.request.* import io.ktor.server.request.*
import io.ktor.server.response.* import io.ktor.server.response.*
@ -91,9 +90,8 @@ fun Application.configureRouting(repository: KidioRepository, jwtService : JwtSe
// 2. Antwort auf eine Aufgabe überprüfen // 2. Antwort auf eine Aufgabe überprüfen
post("/api/v1/tasks/verify") { post("/api/v1/tasks/verify") {
val request = call.receive<TaskVerifyRequest>() val request = call.receive<TaskVerifyRequest>()
val principal = call.principal<JWTPrincipal>() val principal = call.principal<UserPrincipal>()
val userId = principal?.payload?.getClaim("userId")?.asString() val userId = principal?.userId
if (userId == null){ if (userId == null){
call.respond(HttpStatusCode.Unauthorized, mapOf("error" to "Ungültiges oder abgelaufenes Token")) call.respond(HttpStatusCode.Unauthorized, mapOf("error" to "Ungültiges oder abgelaufenes Token"))
return@post return@post
@ -140,11 +138,15 @@ fun Application.configureRouting(repository: KidioRepository, jwtService : JwtSe
post("/api/v1/screentime/sync") { post("/api/v1/screentime/sync") {
val request = call.receive<SyncRequest>() val request = call.receive<SyncRequest>()
val currentSeconds = repository.getScreentime(request.userId) // Wir holen die echte, fälschungssichere userId aus dem Login-Token:
val principal = call.principal<UserPrincipal>()
val userId = principal?.userId ?: request.userId // Fallback auf request.userId, falls token noch fehlt
val currentSeconds = repository.getScreentime(userId)
var newSeconds = currentSeconds - request.usedSecondsSinceLastSync var newSeconds = currentSeconds - request.usedSecondsSinceLastSync
if (newSeconds < 0) newSeconds = 0 if (newSeconds < 0) newSeconds = 0
repository.updateScreentime(request.userId, newSeconds) repository.updateScreentime(userId, newSeconds)
call.respond( call.respond(
SyncResponse( SyncResponse(

View file

@ -9,7 +9,7 @@ class JwtService(
private val secret: String = System.getenv("JWT_SECRET") ?: "super-geheimes-secret-fuer-dev", private val secret: String = System.getenv("JWT_SECRET") ?: "super-geheimes-secret-fuer-dev",
private val issuer: String = "https://kidio.oliver.com/", private val issuer: String = "https://kidio.oliver.com/",
private val audience: String = "kidio-users", private val audience: String = "kidio-users",
private val expirationInMs: Long = 36_000_000 // 10 Stunden private val expirationInMs: Long = java.util.concurrent.TimeUnit.DAYS.toMillis(30) // 30 Tage
) { ) {
val verifier: JWTVerifier = JWT val verifier: JWTVerifier = JWT