mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 07:05:35 +03:00
BIT-2438: Update push notification processing logic to be more lenient (#3393)
This commit is contained in:
parent
f5039d72b9
commit
b181d0d026
2 changed files with 114 additions and 93 deletions
|
@ -120,7 +120,7 @@ class PushManagerImpl @Inject constructor(
|
|||
onMessageReceived(notification)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod", "ReturnCount")
|
||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||
private fun onMessageReceived(notification: BitwardenNotification) {
|
||||
if (authDiskSource.uniqueAppId == notification.contextId) return
|
||||
|
||||
|
@ -130,62 +130,67 @@ class PushManagerImpl @Inject constructor(
|
|||
NotificationType.AUTH_REQUEST,
|
||||
NotificationType.AUTH_REQUEST_RESPONSE,
|
||||
-> {
|
||||
val payload: NotificationPayload.PasswordlessRequestNotification =
|
||||
json.decodeFromString(string = notification.payload)
|
||||
mutablePasswordlessRequestSharedFlow.tryEmit(
|
||||
PasswordlessRequestData(
|
||||
loginRequestId = payload.id,
|
||||
userId = payload.userId,
|
||||
),
|
||||
)
|
||||
json
|
||||
.decodeFromString<NotificationPayload.PasswordlessRequestNotification>(
|
||||
string = notification.payload,
|
||||
)
|
||||
.takeIf { it.loginRequestId != null && it.userId != null }
|
||||
?.let {
|
||||
mutablePasswordlessRequestSharedFlow.tryEmit(
|
||||
PasswordlessRequestData(
|
||||
loginRequestId = requireNotNull(it.loginRequestId),
|
||||
userId = requireNotNull(it.userId),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
NotificationType.LOG_OUT -> {
|
||||
val payload: NotificationPayload.UserNotification =
|
||||
json.decodeFromString(notification.payload)
|
||||
mutableLogoutSharedFlow.tryEmit(
|
||||
NotificationLogoutData(payload.userId),
|
||||
)
|
||||
json
|
||||
.decodeFromString<NotificationPayload.UserNotification>(
|
||||
string = notification.payload,
|
||||
)
|
||||
.userId
|
||||
?.let { mutableLogoutSharedFlow.tryEmit(NotificationLogoutData(it)) }
|
||||
}
|
||||
|
||||
NotificationType.SYNC_CIPHER_CREATE,
|
||||
NotificationType.SYNC_CIPHER_UPDATE,
|
||||
-> {
|
||||
val payload: NotificationPayload.SyncCipherNotification =
|
||||
json.decodeFromString(notification.payload)
|
||||
@Suppress("ComplexCondition")
|
||||
if (payload.id == null ||
|
||||
payload.revisionDate == null ||
|
||||
!isLoggedIn(userId) ||
|
||||
!payload.userMatchesNotification(userId)
|
||||
) {
|
||||
return
|
||||
}
|
||||
mutableSyncCipherUpsertSharedFlow.tryEmit(
|
||||
SyncCipherUpsertData(
|
||||
cipherId = payload.id,
|
||||
revisionDate = payload.revisionDate,
|
||||
organizationId = payload.organizationId,
|
||||
collectionIds = payload.collectionIds,
|
||||
isUpdate = type == NotificationType.SYNC_CIPHER_UPDATE,
|
||||
),
|
||||
)
|
||||
json
|
||||
.decodeFromString<NotificationPayload.SyncCipherNotification>(
|
||||
string = notification.payload,
|
||||
)
|
||||
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||
?.takeIf {
|
||||
it.cipherId != null &&
|
||||
it.revisionDate != null &&
|
||||
it.organizationId != null &&
|
||||
it.collectionIds != null
|
||||
}
|
||||
?.let {
|
||||
mutableSyncCipherUpsertSharedFlow.tryEmit(
|
||||
SyncCipherUpsertData(
|
||||
cipherId = requireNotNull(it.cipherId),
|
||||
revisionDate = requireNotNull(it.revisionDate),
|
||||
organizationId = requireNotNull(it.organizationId),
|
||||
collectionIds = requireNotNull(it.collectionIds),
|
||||
isUpdate = type == NotificationType.SYNC_CIPHER_UPDATE,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
NotificationType.SYNC_CIPHER_DELETE,
|
||||
NotificationType.SYNC_LOGIN_DELETE,
|
||||
-> {
|
||||
val payload: NotificationPayload.SyncCipherNotification =
|
||||
json.decodeFromString(notification.payload)
|
||||
if (payload.id == null ||
|
||||
!isLoggedIn(userId) ||
|
||||
!payload.userMatchesNotification(userId)
|
||||
) {
|
||||
return
|
||||
}
|
||||
mutableSyncCipherDeleteSharedFlow.tryEmit(
|
||||
SyncCipherDeleteData(payload.id),
|
||||
)
|
||||
json
|
||||
.decodeFromString<NotificationPayload.SyncCipherNotification>(
|
||||
string = notification.payload,
|
||||
)
|
||||
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||
?.cipherId
|
||||
?.let { mutableSyncCipherDeleteSharedFlow.tryEmit(SyncCipherDeleteData(it)) }
|
||||
}
|
||||
|
||||
NotificationType.SYNC_CIPHERS,
|
||||
|
@ -198,55 +203,67 @@ class PushManagerImpl @Inject constructor(
|
|||
NotificationType.SYNC_FOLDER_CREATE,
|
||||
NotificationType.SYNC_FOLDER_UPDATE,
|
||||
-> {
|
||||
val payload: NotificationPayload.SyncFolderNotification =
|
||||
json.decodeFromString(notification.payload)
|
||||
if (!isLoggedIn(userId) || !payload.userMatchesNotification(userId)) return
|
||||
mutableSyncFolderUpsertSharedFlow.tryEmit(
|
||||
SyncFolderUpsertData(
|
||||
folderId = payload.id,
|
||||
revisionDate = payload.revisionDate,
|
||||
isUpdate = type == NotificationType.SYNC_FOLDER_UPDATE,
|
||||
),
|
||||
)
|
||||
json
|
||||
.decodeFromString<NotificationPayload.SyncFolderNotification>(
|
||||
string = notification.payload,
|
||||
)
|
||||
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||
?.takeIf { it.folderId != null && it.revisionDate != null }
|
||||
?.let {
|
||||
mutableSyncFolderUpsertSharedFlow.tryEmit(
|
||||
SyncFolderUpsertData(
|
||||
folderId = requireNotNull(it.folderId),
|
||||
revisionDate = requireNotNull(it.revisionDate),
|
||||
isUpdate = type == NotificationType.SYNC_FOLDER_UPDATE,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
NotificationType.SYNC_FOLDER_DELETE -> {
|
||||
val payload: NotificationPayload.SyncFolderNotification =
|
||||
json.decodeFromString(notification.payload)
|
||||
if (!isLoggedIn(userId) || !payload.userMatchesNotification(userId)) return
|
||||
|
||||
mutableSyncFolderDeleteSharedFlow.tryEmit(
|
||||
SyncFolderDeleteData(payload.id),
|
||||
)
|
||||
json
|
||||
.decodeFromString<NotificationPayload.SyncFolderNotification>(
|
||||
string = notification.payload,
|
||||
)
|
||||
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||
?.folderId
|
||||
?.let { mutableSyncFolderDeleteSharedFlow.tryEmit(SyncFolderDeleteData(it)) }
|
||||
}
|
||||
|
||||
NotificationType.SYNC_ORG_KEYS -> {
|
||||
if (!isLoggedIn(userId)) return
|
||||
mutableSyncOrgKeysSharedFlow.tryEmit(Unit)
|
||||
if (isLoggedIn(userId)) {
|
||||
mutableSyncOrgKeysSharedFlow.tryEmit(Unit)
|
||||
}
|
||||
}
|
||||
|
||||
NotificationType.SYNC_SEND_CREATE,
|
||||
NotificationType.SYNC_SEND_UPDATE,
|
||||
-> {
|
||||
val payload: NotificationPayload.SyncSendNotification =
|
||||
json.decodeFromString(notification.payload)
|
||||
if (!isLoggedIn(userId) || !payload.userMatchesNotification(userId)) return
|
||||
mutableSyncSendUpsertSharedFlow.tryEmit(
|
||||
SyncSendUpsertData(
|
||||
sendId = payload.id,
|
||||
revisionDate = payload.revisionDate,
|
||||
isUpdate = type == NotificationType.SYNC_SEND_UPDATE,
|
||||
),
|
||||
)
|
||||
json
|
||||
.decodeFromString<NotificationPayload.SyncSendNotification>(
|
||||
string = notification.payload,
|
||||
)
|
||||
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||
?.takeIf { it.sendId != null && it.revisionDate != null }
|
||||
?.let {
|
||||
mutableSyncSendUpsertSharedFlow.tryEmit(
|
||||
SyncSendUpsertData(
|
||||
sendId = requireNotNull(it.sendId),
|
||||
revisionDate = requireNotNull(it.revisionDate),
|
||||
isUpdate = type == NotificationType.SYNC_SEND_UPDATE,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
NotificationType.SYNC_SEND_DELETE -> {
|
||||
val payload: NotificationPayload.SyncSendNotification =
|
||||
json.decodeFromString(notification.payload)
|
||||
if (!isLoggedIn(userId) || !payload.userMatchesNotification(userId)) return
|
||||
mutableSyncSendDeleteSharedFlow.tryEmit(
|
||||
SyncSendDeleteData(payload.id),
|
||||
)
|
||||
json
|
||||
.decodeFromString<NotificationPayload.SyncSendNotification>(
|
||||
string = notification.payload,
|
||||
)
|
||||
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||
?.sendId
|
||||
?.let { mutableSyncSendDeleteSharedFlow.tryEmit(SyncSendDeleteData(it)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -290,15 +307,15 @@ class PushManagerImpl @Inject constructor(
|
|||
if (token == currentToken) {
|
||||
// Our token is up-to-date, so just update the last registration date
|
||||
pushDiskSource.storeLastPushTokenRegistrationDate(
|
||||
userId,
|
||||
ZonedDateTime.ofInstant(clock.instant(), ZoneOffset.UTC),
|
||||
userId = userId,
|
||||
registrationDate = ZonedDateTime.ofInstant(clock.instant(), ZoneOffset.UTC),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
pushService
|
||||
.putDeviceToken(
|
||||
PushTokenRequest(token),
|
||||
body = PushTokenRequest(token),
|
||||
)
|
||||
.fold(
|
||||
onSuccess = {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager.model
|
||||
|
||||
import com.x8bit.bitwarden.data.platform.manager.PushManager
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
@ -7,6 +8,9 @@ import java.time.ZonedDateTime
|
|||
|
||||
/**
|
||||
* The payload of a push notification.
|
||||
*
|
||||
* Note: The data we receive is not always reliable, so everything is nullable and we validate the
|
||||
* data in the [PushManager] as necessary.
|
||||
*/
|
||||
@Serializable
|
||||
sealed class NotificationPayload {
|
||||
|
@ -20,7 +24,7 @@ sealed class NotificationPayload {
|
|||
*/
|
||||
@Serializable
|
||||
data class SyncCipherNotification(
|
||||
@SerialName("Id") val id: String?,
|
||||
@SerialName("Id") val cipherId: String?,
|
||||
@SerialName("UserId") override val userId: String?,
|
||||
@SerialName("OrganizationId") val organizationId: String?,
|
||||
@SerialName("CollectionIds") val collectionIds: List<String>?,
|
||||
|
@ -33,10 +37,10 @@ sealed class NotificationPayload {
|
|||
*/
|
||||
@Serializable
|
||||
data class SyncFolderNotification(
|
||||
@SerialName("Id") val id: String,
|
||||
@SerialName("UserId") override val userId: String,
|
||||
@SerialName("Id") val folderId: String?,
|
||||
@SerialName("UserId") override val userId: String?,
|
||||
@Contextual
|
||||
@SerialName("RevisionDate") val revisionDate: ZonedDateTime,
|
||||
@SerialName("RevisionDate") val revisionDate: ZonedDateTime?,
|
||||
) : NotificationPayload()
|
||||
|
||||
/**
|
||||
|
@ -44,9 +48,9 @@ sealed class NotificationPayload {
|
|||
*/
|
||||
@Serializable
|
||||
data class UserNotification(
|
||||
@SerialName("UserId") override val userId: String,
|
||||
@SerialName("UserId") override val userId: String?,
|
||||
@Contextual
|
||||
@SerialName("Date") val date: ZonedDateTime,
|
||||
@SerialName("Date") val date: ZonedDateTime?,
|
||||
) : NotificationPayload()
|
||||
|
||||
/**
|
||||
|
@ -54,10 +58,10 @@ sealed class NotificationPayload {
|
|||
*/
|
||||
@Serializable
|
||||
data class SyncSendNotification(
|
||||
@SerialName("Id") val id: String,
|
||||
@SerialName("UserId") override val userId: String,
|
||||
@SerialName("Id") val sendId: String?,
|
||||
@SerialName("UserId") override val userId: String?,
|
||||
@Contextual
|
||||
@SerialName("RevisionDate") val revisionDate: ZonedDateTime,
|
||||
@SerialName("RevisionDate") val revisionDate: ZonedDateTime?,
|
||||
) : NotificationPayload()
|
||||
|
||||
/**
|
||||
|
@ -65,7 +69,7 @@ sealed class NotificationPayload {
|
|||
*/
|
||||
@Serializable
|
||||
data class PasswordlessRequestNotification(
|
||||
@SerialName("UserId") override val userId: String,
|
||||
@SerialName("Id") val id: String,
|
||||
@SerialName("UserId") override val userId: String?,
|
||||
@SerialName("Id") val loginRequestId: String?,
|
||||
) : NotificationPayload()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue