fix: 401 token refresh in MessageRepositoryImpl

fetchUsers() and attemptSendToServer() had no retry logic on 401.
SyncServiceImpl already had this pattern (auto-refresh on 401).

Add private refreshAccessToken(serverUrl) and retry once on 401
in both methods.
This commit is contained in:
Jens Reinemann 2026-05-18 00:44:58 +02:00
parent ea02029dbe
commit a14c40d756

View file

@ -4,6 +4,8 @@ import android.util.Log
import de.bollwerk.app.data.db.dao.MessageDao
import de.bollwerk.app.data.db.entity.MessageEntity
import de.bollwerk.app.data.security.E2EEKeyManager
import de.bollwerk.app.data.sync.LoginResponse
import de.bollwerk.app.data.sync.RefreshRequest
import de.bollwerk.app.data.sync.WebSocketClient
import de.bollwerk.app.data.sync.WebSocketEvent
import de.bollwerk.app.di.ApplicationScope
@ -129,12 +131,19 @@ internal class MessageRepositoryImpl @Inject constructor(
withContext(Dispatchers.IO) {
val serverUrl = settingsRepository.getStringOrNull(StringKey.ServerUrl)
?: return@withContext Result.failure(SyncError.NotConfigured("Server-URL nicht gesetzt"))
val token = settingsRepository.getStringOrNull(StringKey.AuthAccessToken)
var token = settingsRepository.getStringOrNull(StringKey.AuthAccessToken)
?: return@withContext Result.failure(SyncError.NotConfigured("Nicht angemeldet"))
try {
val response = httpClient.get("${serverUrl.trimEnd('/')}/api/users") {
var response = httpClient.get("${serverUrl.trimEnd('/')}/api/users") {
header("Authorization", "Bearer $token")
}
if (response.status == HttpStatusCode.Unauthorized && refreshAccessToken(serverUrl)) {
token = settingsRepository.getStringOrNull(StringKey.AuthAccessToken)
?: return@withContext Result.failure(SyncError.NotConfigured("Nicht angemeldet"))
response = httpClient.get("${serverUrl.trimEnd('/')}/api/users") {
header("Authorization", "Bearer $token")
}
}
if (response.status == HttpStatusCode.OK) {
Result.success(response.body<List<UserListItemDto>>())
} else {
@ -199,6 +208,27 @@ internal class MessageRepositoryImpl @Inject constructor(
}
}
private suspend fun refreshAccessToken(serverUrl: String): Boolean {
val refreshToken = settingsRepository.getStringOrNull(StringKey.AuthRefreshToken)
?.takeIf { it.isNotBlank() } ?: return false
return try {
val response = httpClient.post("${serverUrl.trimEnd('/')}/api/auth/refresh") {
contentType(ContentType.Application.Json)
setBody(RefreshRequest(refreshToken))
}
if (response.status == HttpStatusCode.OK) {
val loginResponse: LoginResponse = response.body()
settingsRepository.setString(StringKey.AuthAccessToken, loginResponse.accessToken)
settingsRepository.setString(StringKey.AuthRefreshToken, loginResponse.refreshToken)
true
} else {
false
}
} catch (_: Exception) {
false
}
}
private suspend fun attemptSendToServer(
id: String,
recipientId: String,
@ -207,14 +237,23 @@ internal class MessageRepositoryImpl @Inject constructor(
): Result<Unit> = withContext(Dispatchers.IO) {
val serverUrl = settingsRepository.getStringOrNull(StringKey.ServerUrl)
?: return@withContext Result.failure(SyncError.NotConfigured("Server-URL nicht gesetzt"))
val token = settingsRepository.getStringOrNull(StringKey.AuthAccessToken)
var token = settingsRepository.getStringOrNull(StringKey.AuthAccessToken)
?: return@withContext Result.failure(SyncError.NotConfigured("Nicht angemeldet"))
try {
val response = httpClient.post("${serverUrl.trimEnd('/')}/api/messages") {
var response = httpClient.post("${serverUrl.trimEnd('/')}/api/messages") {
header("Authorization", "Bearer $token")
contentType(ContentType.Application.Json)
setBody(SendMessageRequest(id = id, receiverId = recipientId, body = body, sentAt = sentAt))
}
if (response.status == HttpStatusCode.Unauthorized && refreshAccessToken(serverUrl)) {
token = settingsRepository.getStringOrNull(StringKey.AuthAccessToken)
?: return@withContext Result.failure(SyncError.NotConfigured("Nicht angemeldet"))
response = httpClient.post("${serverUrl.trimEnd('/')}/api/messages") {
header("Authorization", "Bearer $token")
contentType(ContentType.Application.Json)
setBody(SendMessageRequest(id = id, receiverId = recipientId, body = body, sentAt = sentAt))
}
}
if (response.status == HttpStatusCode.Created || response.status == HttpStatusCode.OK) {
Result.success(Unit)
} else {