feat(security): add internal secret handling and Redis integration for bot events

This commit is contained in:
2026-04-28 09:29:05 +02:00
parent c10a4d7e64
commit 1ab6532b0a
50 changed files with 951 additions and 214 deletions
@@ -0,0 +1,57 @@
package de.nowchess.ws.resource
import de.nowchess.ws.config.RedisConfig
import io.quarkus.websockets.next.*
import io.smallrye.jwt.auth.principal.JWTParser
import jakarta.inject.Inject
import org.redisson.api.listener.MessageListener
import org.redisson.api.RedissonClient
import scala.compiletime.uninitialized
import scala.util.Try
import java.util.concurrent.ConcurrentHashMap
@WebSocket(path = "/api/user/ws")
class UserWebSocketResource:
// scalafix:off DisableSyntax.var
@Inject
var redisson: RedissonClient = uninitialized
@Inject
var redisConfig: RedisConfig = uninitialized
@Inject
var jwtParser: JWTParser = uninitialized
// scalafix:on DisableSyntax.var
private val connections = new ConcurrentHashMap[String, (String, Int)]()
private def userTopic(userId: String): String =
s"${redisConfig.prefix}:user:$userId:events"
@OnOpen
def onOpen(connection: WebSocketConnection, handshake: HandshakeRequest): Unit =
val userIdOpt = Option(handshake.header("Authorization"))
.filter(_.nonEmpty)
.flatMap(token => Try(jwtParser.parse(token)).toOption)
.map(_.getSubject)
userIdOpt match
case None => connection.close().subscribe().`with`(_ => (), _ => ())
case Some(userId) =>
val listenerId = redisson.getTopic(userTopic(userId)).addListener(
classOf[String],
new MessageListener[String]:
def onMessage(channel: CharSequence, msg: String): Unit =
connection.sendText(msg).subscribe().`with`(_ => (), _ => ()),
)
connections.put(connection.id(), (userId, listenerId))
val connectedMsg = s"""{"type":"CONNECTED","userId":"$userId"}"""
connection.sendText(connectedMsg).subscribe().`with`(_ => (), _ => ())
@OnClose
def onClose(connection: WebSocketConnection): Unit =
Option(connections.remove(connection.id())).foreach { (userId, listenerId) =>
redisson.getTopic(userTopic(userId)).removeListener(listenerId)
}