feat: add plaintext admin message endpoint for testing
- New POST /api/admin/send-message endpoint (admin-only) - Messages prefixed with [PLAINTEXT] bypass E2EE decryption - App recognizes [PLAINTEXT] marker and strips it before display - Allows easy chat testing without E2EE key management
This commit is contained in:
parent
30e86bb7e0
commit
ca6cfbfad9
2 changed files with 64 additions and 5 deletions
|
|
@ -70,11 +70,20 @@ internal class MessageRepositoryImpl @Inject constructor(
|
||||||
when (event) {
|
when (event) {
|
||||||
is WebSocketEvent.NewMessage -> {
|
is WebSocketEvent.NewMessage -> {
|
||||||
val msg = event.message
|
val msg = event.message
|
||||||
val decryptedBody = try {
|
val decryptedBody = when {
|
||||||
e2eeKeyManager.decryptMessage(msg.body)
|
msg.body.startsWith("[PLAINTEXT] ") -> {
|
||||||
} catch (e: Exception) {
|
// Admin test messages – remove prefix
|
||||||
Log.e(TAG, "E2EE: Failed to decrypt message ${msg.id}", e)
|
msg.body.removePrefix("[PLAINTEXT] ")
|
||||||
"[Entschlüsselung fehlgeschlagen]"
|
}
|
||||||
|
else -> {
|
||||||
|
// E2EE messages – decrypt
|
||||||
|
try {
|
||||||
|
e2eeKeyManager.decryptMessage(msg.body)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(TAG, "E2EE: Failed to decrypt message ${msg.id}", e)
|
||||||
|
"[Entschlüsselung fehlgeschlagen]"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dao.upsert(
|
dao.upsert(
|
||||||
MessageEntity(
|
MessageEntity(
|
||||||
|
|
|
||||||
|
|
@ -95,4 +95,54 @@ internal fun Route.messageRoutes(
|
||||||
call.respond(HttpStatusCode.OK, messages)
|
call.respond(HttpStatusCode.OK, messages)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
route("/api/admin/send-message") {
|
||||||
|
post {
|
||||||
|
val principal = call.principal<UserPrincipal>()
|
||||||
|
?: return@post call.respond(
|
||||||
|
HttpStatusCode.Unauthorized,
|
||||||
|
ErrorResponse(status = 401, message = "Unauthorized")
|
||||||
|
)
|
||||||
|
// Only admins can send test messages
|
||||||
|
if (!principal.isAdmin) {
|
||||||
|
return@post call.respond(
|
||||||
|
HttpStatusCode.Forbidden,
|
||||||
|
ErrorResponse(status = 403, message = "Admin access required")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val request = call.receive<SendMessageRequest>()
|
||||||
|
if (request.body.isBlank()) {
|
||||||
|
call.respond(
|
||||||
|
HttpStatusCode.BadRequest,
|
||||||
|
ErrorResponse(status = 400, message = "Body must not be empty")
|
||||||
|
)
|
||||||
|
return@post
|
||||||
|
}
|
||||||
|
if (userRepository.findById(request.receiverId) == null) {
|
||||||
|
call.respond(
|
||||||
|
HttpStatusCode.NotFound,
|
||||||
|
ErrorResponse(status = 404, message = "Receiver not found")
|
||||||
|
)
|
||||||
|
return@post
|
||||||
|
}
|
||||||
|
|
||||||
|
val msgId = request.id ?: UUID.randomUUID().toString()
|
||||||
|
// Wrap body with [PLAINTEXT] marker so app doesn't try to decrypt
|
||||||
|
val plaintext = "[PLAINTEXT] ${request.body}"
|
||||||
|
val message = messageRepository.save(
|
||||||
|
id = msgId,
|
||||||
|
senderId = principal.userId,
|
||||||
|
senderUsername = principal.username,
|
||||||
|
receiverId = request.receiverId,
|
||||||
|
body = plaintext,
|
||||||
|
sentAt = request.sentAt
|
||||||
|
)
|
||||||
|
wsManager.notifyNewMessage(request.receiverId, message)
|
||||||
|
if (wsManager.isOnline(request.receiverId)) {
|
||||||
|
messageRepository.markDelivered(msgId)
|
||||||
|
}
|
||||||
|
call.respond(HttpStatusCode.Created, SendMessageResponse(message = message))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue