mirror of
https://github.com/bitwarden/android.git
synced 2024-11-22 17:36:01 +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)
|
onMessageReceived(notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("LongMethod", "CyclomaticComplexMethod", "ReturnCount")
|
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||||
private fun onMessageReceived(notification: BitwardenNotification) {
|
private fun onMessageReceived(notification: BitwardenNotification) {
|
||||||
if (authDiskSource.uniqueAppId == notification.contextId) return
|
if (authDiskSource.uniqueAppId == notification.contextId) return
|
||||||
|
|
||||||
|
@ -130,62 +130,67 @@ class PushManagerImpl @Inject constructor(
|
||||||
NotificationType.AUTH_REQUEST,
|
NotificationType.AUTH_REQUEST,
|
||||||
NotificationType.AUTH_REQUEST_RESPONSE,
|
NotificationType.AUTH_REQUEST_RESPONSE,
|
||||||
-> {
|
-> {
|
||||||
val payload: NotificationPayload.PasswordlessRequestNotification =
|
json
|
||||||
json.decodeFromString(string = notification.payload)
|
.decodeFromString<NotificationPayload.PasswordlessRequestNotification>(
|
||||||
|
string = notification.payload,
|
||||||
|
)
|
||||||
|
.takeIf { it.loginRequestId != null && it.userId != null }
|
||||||
|
?.let {
|
||||||
mutablePasswordlessRequestSharedFlow.tryEmit(
|
mutablePasswordlessRequestSharedFlow.tryEmit(
|
||||||
PasswordlessRequestData(
|
PasswordlessRequestData(
|
||||||
loginRequestId = payload.id,
|
loginRequestId = requireNotNull(it.loginRequestId),
|
||||||
userId = payload.userId,
|
userId = requireNotNull(it.userId),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NotificationType.LOG_OUT -> {
|
NotificationType.LOG_OUT -> {
|
||||||
val payload: NotificationPayload.UserNotification =
|
json
|
||||||
json.decodeFromString(notification.payload)
|
.decodeFromString<NotificationPayload.UserNotification>(
|
||||||
mutableLogoutSharedFlow.tryEmit(
|
string = notification.payload,
|
||||||
NotificationLogoutData(payload.userId),
|
|
||||||
)
|
)
|
||||||
|
.userId
|
||||||
|
?.let { mutableLogoutSharedFlow.tryEmit(NotificationLogoutData(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationType.SYNC_CIPHER_CREATE,
|
NotificationType.SYNC_CIPHER_CREATE,
|
||||||
NotificationType.SYNC_CIPHER_UPDATE,
|
NotificationType.SYNC_CIPHER_UPDATE,
|
||||||
-> {
|
-> {
|
||||||
val payload: NotificationPayload.SyncCipherNotification =
|
json
|
||||||
json.decodeFromString(notification.payload)
|
.decodeFromString<NotificationPayload.SyncCipherNotification>(
|
||||||
@Suppress("ComplexCondition")
|
string = notification.payload,
|
||||||
if (payload.id == null ||
|
)
|
||||||
payload.revisionDate == null ||
|
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||||
!isLoggedIn(userId) ||
|
?.takeIf {
|
||||||
!payload.userMatchesNotification(userId)
|
it.cipherId != null &&
|
||||||
) {
|
it.revisionDate != null &&
|
||||||
return
|
it.organizationId != null &&
|
||||||
|
it.collectionIds != null
|
||||||
}
|
}
|
||||||
|
?.let {
|
||||||
mutableSyncCipherUpsertSharedFlow.tryEmit(
|
mutableSyncCipherUpsertSharedFlow.tryEmit(
|
||||||
SyncCipherUpsertData(
|
SyncCipherUpsertData(
|
||||||
cipherId = payload.id,
|
cipherId = requireNotNull(it.cipherId),
|
||||||
revisionDate = payload.revisionDate,
|
revisionDate = requireNotNull(it.revisionDate),
|
||||||
organizationId = payload.organizationId,
|
organizationId = requireNotNull(it.organizationId),
|
||||||
collectionIds = payload.collectionIds,
|
collectionIds = requireNotNull(it.collectionIds),
|
||||||
isUpdate = type == NotificationType.SYNC_CIPHER_UPDATE,
|
isUpdate = type == NotificationType.SYNC_CIPHER_UPDATE,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NotificationType.SYNC_CIPHER_DELETE,
|
NotificationType.SYNC_CIPHER_DELETE,
|
||||||
NotificationType.SYNC_LOGIN_DELETE,
|
NotificationType.SYNC_LOGIN_DELETE,
|
||||||
-> {
|
-> {
|
||||||
val payload: NotificationPayload.SyncCipherNotification =
|
json
|
||||||
json.decodeFromString(notification.payload)
|
.decodeFromString<NotificationPayload.SyncCipherNotification>(
|
||||||
if (payload.id == null ||
|
string = notification.payload,
|
||||||
!isLoggedIn(userId) ||
|
|
||||||
!payload.userMatchesNotification(userId)
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mutableSyncCipherDeleteSharedFlow.tryEmit(
|
|
||||||
SyncCipherDeleteData(payload.id),
|
|
||||||
)
|
)
|
||||||
|
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||||
|
?.cipherId
|
||||||
|
?.let { mutableSyncCipherDeleteSharedFlow.tryEmit(SyncCipherDeleteData(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationType.SYNC_CIPHERS,
|
NotificationType.SYNC_CIPHERS,
|
||||||
|
@ -198,55 +203,67 @@ class PushManagerImpl @Inject constructor(
|
||||||
NotificationType.SYNC_FOLDER_CREATE,
|
NotificationType.SYNC_FOLDER_CREATE,
|
||||||
NotificationType.SYNC_FOLDER_UPDATE,
|
NotificationType.SYNC_FOLDER_UPDATE,
|
||||||
-> {
|
-> {
|
||||||
val payload: NotificationPayload.SyncFolderNotification =
|
json
|
||||||
json.decodeFromString(notification.payload)
|
.decodeFromString<NotificationPayload.SyncFolderNotification>(
|
||||||
if (!isLoggedIn(userId) || !payload.userMatchesNotification(userId)) return
|
string = notification.payload,
|
||||||
|
)
|
||||||
|
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||||
|
?.takeIf { it.folderId != null && it.revisionDate != null }
|
||||||
|
?.let {
|
||||||
mutableSyncFolderUpsertSharedFlow.tryEmit(
|
mutableSyncFolderUpsertSharedFlow.tryEmit(
|
||||||
SyncFolderUpsertData(
|
SyncFolderUpsertData(
|
||||||
folderId = payload.id,
|
folderId = requireNotNull(it.folderId),
|
||||||
revisionDate = payload.revisionDate,
|
revisionDate = requireNotNull(it.revisionDate),
|
||||||
isUpdate = type == NotificationType.SYNC_FOLDER_UPDATE,
|
isUpdate = type == NotificationType.SYNC_FOLDER_UPDATE,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NotificationType.SYNC_FOLDER_DELETE -> {
|
NotificationType.SYNC_FOLDER_DELETE -> {
|
||||||
val payload: NotificationPayload.SyncFolderNotification =
|
json
|
||||||
json.decodeFromString(notification.payload)
|
.decodeFromString<NotificationPayload.SyncFolderNotification>(
|
||||||
if (!isLoggedIn(userId) || !payload.userMatchesNotification(userId)) return
|
string = notification.payload,
|
||||||
|
|
||||||
mutableSyncFolderDeleteSharedFlow.tryEmit(
|
|
||||||
SyncFolderDeleteData(payload.id),
|
|
||||||
)
|
)
|
||||||
|
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||||
|
?.folderId
|
||||||
|
?.let { mutableSyncFolderDeleteSharedFlow.tryEmit(SyncFolderDeleteData(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
NotificationType.SYNC_ORG_KEYS -> {
|
NotificationType.SYNC_ORG_KEYS -> {
|
||||||
if (!isLoggedIn(userId)) return
|
if (isLoggedIn(userId)) {
|
||||||
mutableSyncOrgKeysSharedFlow.tryEmit(Unit)
|
mutableSyncOrgKeysSharedFlow.tryEmit(Unit)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NotificationType.SYNC_SEND_CREATE,
|
NotificationType.SYNC_SEND_CREATE,
|
||||||
NotificationType.SYNC_SEND_UPDATE,
|
NotificationType.SYNC_SEND_UPDATE,
|
||||||
-> {
|
-> {
|
||||||
val payload: NotificationPayload.SyncSendNotification =
|
json
|
||||||
json.decodeFromString(notification.payload)
|
.decodeFromString<NotificationPayload.SyncSendNotification>(
|
||||||
if (!isLoggedIn(userId) || !payload.userMatchesNotification(userId)) return
|
string = notification.payload,
|
||||||
|
)
|
||||||
|
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||||
|
?.takeIf { it.sendId != null && it.revisionDate != null }
|
||||||
|
?.let {
|
||||||
mutableSyncSendUpsertSharedFlow.tryEmit(
|
mutableSyncSendUpsertSharedFlow.tryEmit(
|
||||||
SyncSendUpsertData(
|
SyncSendUpsertData(
|
||||||
sendId = payload.id,
|
sendId = requireNotNull(it.sendId),
|
||||||
revisionDate = payload.revisionDate,
|
revisionDate = requireNotNull(it.revisionDate),
|
||||||
isUpdate = type == NotificationType.SYNC_SEND_UPDATE,
|
isUpdate = type == NotificationType.SYNC_SEND_UPDATE,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NotificationType.SYNC_SEND_DELETE -> {
|
NotificationType.SYNC_SEND_DELETE -> {
|
||||||
val payload: NotificationPayload.SyncSendNotification =
|
json
|
||||||
json.decodeFromString(notification.payload)
|
.decodeFromString<NotificationPayload.SyncSendNotification>(
|
||||||
if (!isLoggedIn(userId) || !payload.userMatchesNotification(userId)) return
|
string = notification.payload,
|
||||||
mutableSyncSendDeleteSharedFlow.tryEmit(
|
|
||||||
SyncSendDeleteData(payload.id),
|
|
||||||
)
|
)
|
||||||
|
.takeIf { isLoggedIn(userId) && it.userMatchesNotification(userId) }
|
||||||
|
?.sendId
|
||||||
|
?.let { mutableSyncSendDeleteSharedFlow.tryEmit(SyncSendDeleteData(it)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,15 +307,15 @@ class PushManagerImpl @Inject constructor(
|
||||||
if (token == currentToken) {
|
if (token == currentToken) {
|
||||||
// Our token is up-to-date, so just update the last registration date
|
// Our token is up-to-date, so just update the last registration date
|
||||||
pushDiskSource.storeLastPushTokenRegistrationDate(
|
pushDiskSource.storeLastPushTokenRegistrationDate(
|
||||||
userId,
|
userId = userId,
|
||||||
ZonedDateTime.ofInstant(clock.instant(), ZoneOffset.UTC),
|
registrationDate = ZonedDateTime.ofInstant(clock.instant(), ZoneOffset.UTC),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pushService
|
pushService
|
||||||
.putDeviceToken(
|
.putDeviceToken(
|
||||||
PushTokenRequest(token),
|
body = PushTokenRequest(token),
|
||||||
)
|
)
|
||||||
.fold(
|
.fold(
|
||||||
onSuccess = {
|
onSuccess = {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.x8bit.bitwarden.data.platform.manager.model
|
package com.x8bit.bitwarden.data.platform.manager.model
|
||||||
|
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.PushManager
|
||||||
import kotlinx.serialization.Contextual
|
import kotlinx.serialization.Contextual
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
@ -7,6 +8,9 @@ import java.time.ZonedDateTime
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The payload of a push notification.
|
* 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
|
@Serializable
|
||||||
sealed class NotificationPayload {
|
sealed class NotificationPayload {
|
||||||
|
@ -20,7 +24,7 @@ sealed class NotificationPayload {
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SyncCipherNotification(
|
data class SyncCipherNotification(
|
||||||
@SerialName("Id") val id: String?,
|
@SerialName("Id") val cipherId: String?,
|
||||||
@SerialName("UserId") override val userId: String?,
|
@SerialName("UserId") override val userId: String?,
|
||||||
@SerialName("OrganizationId") val organizationId: String?,
|
@SerialName("OrganizationId") val organizationId: String?,
|
||||||
@SerialName("CollectionIds") val collectionIds: List<String>?,
|
@SerialName("CollectionIds") val collectionIds: List<String>?,
|
||||||
|
@ -33,10 +37,10 @@ sealed class NotificationPayload {
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SyncFolderNotification(
|
data class SyncFolderNotification(
|
||||||
@SerialName("Id") val id: String,
|
@SerialName("Id") val folderId: String?,
|
||||||
@SerialName("UserId") override val userId: String,
|
@SerialName("UserId") override val userId: String?,
|
||||||
@Contextual
|
@Contextual
|
||||||
@SerialName("RevisionDate") val revisionDate: ZonedDateTime,
|
@SerialName("RevisionDate") val revisionDate: ZonedDateTime?,
|
||||||
) : NotificationPayload()
|
) : NotificationPayload()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,9 +48,9 @@ sealed class NotificationPayload {
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class UserNotification(
|
data class UserNotification(
|
||||||
@SerialName("UserId") override val userId: String,
|
@SerialName("UserId") override val userId: String?,
|
||||||
@Contextual
|
@Contextual
|
||||||
@SerialName("Date") val date: ZonedDateTime,
|
@SerialName("Date") val date: ZonedDateTime?,
|
||||||
) : NotificationPayload()
|
) : NotificationPayload()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,10 +58,10 @@ sealed class NotificationPayload {
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SyncSendNotification(
|
data class SyncSendNotification(
|
||||||
@SerialName("Id") val id: String,
|
@SerialName("Id") val sendId: String?,
|
||||||
@SerialName("UserId") override val userId: String,
|
@SerialName("UserId") override val userId: String?,
|
||||||
@Contextual
|
@Contextual
|
||||||
@SerialName("RevisionDate") val revisionDate: ZonedDateTime,
|
@SerialName("RevisionDate") val revisionDate: ZonedDateTime?,
|
||||||
) : NotificationPayload()
|
) : NotificationPayload()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,7 +69,7 @@ sealed class NotificationPayload {
|
||||||
*/
|
*/
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PasswordlessRequestNotification(
|
data class PasswordlessRequestNotification(
|
||||||
@SerialName("UserId") override val userId: String,
|
@SerialName("UserId") override val userId: String?,
|
||||||
@SerialName("Id") val id: String,
|
@SerialName("Id") val loginRequestId: String?,
|
||||||
) : NotificationPayload()
|
) : NotificationPayload()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue