From 928ec4830e2e00d66c3e5cbe4eabdae121bdb672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bispo?= Date: Fri, 23 Oct 2026 13:53:35 +0000 Subject: [PATCH] [PM-44810] fix: Ignore "Vault Items" send type parsing [bug-factory poc] (#7488) Co-authored-by: bug-factory --- .../repository/model/PolicyInformation.kt | 5 +- .../util/SyncResponseJsonExtensions.kt | 5 ++ .../util/SyncResponseJsonExtensionsTest.kt | 58 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/model/PolicyInformation.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/model/PolicyInformation.kt index dd2802e231..fdeb1d53de 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/model/PolicyInformation.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/model/PolicyInformation.kt @@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.auth.repository.model import com.bitwarden.network.model.SendAccessTypeJson import com.bitwarden.network.model.SendTypeJson import com.bitwarden.network.model.SyncResponseJson +import kotlinx.serialization.Contextual import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -128,7 +129,8 @@ sealed class PolicyInformation { * when [whoCanAccess] is [SendAccessTypeJson.SPECIFIC_PEOPLE]. * @property deletionHours The number of hours until a Send is deleted, if enforced. * @property allowedSendTypes The types of Sends that are allowed to be created, if - * restricted. + * restricted. Send types unknown to this client are dropped rather than failing the decode of + * the whole policy. */ @Serializable data class SendControls( @@ -147,6 +149,7 @@ sealed class PolicyInformation { @SerialName("deletionHours") val deletionHours: Int?, + @Contextual @SerialName("allowedSendTypes") val allowedSendTypes: List?, ) : PolicyInformation() diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensions.kt index cb5cea0422..9de1c098a0 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensions.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensions.kt @@ -1,5 +1,6 @@ package com.x8bit.bitwarden.data.auth.repository.util +import com.bitwarden.core.data.serializer.SafeListSerializer import com.bitwarden.core.data.util.decodeFromStringOrNull import com.bitwarden.network.model.MemberDecryptionType import com.bitwarden.network.model.OrganizationStatusType @@ -23,6 +24,7 @@ import com.bitwarden.policies.PolicyType import com.x8bit.bitwarden.data.auth.repository.model.Organization import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation import kotlinx.serialization.json.Json +import kotlinx.serialization.modules.SerializersModule import com.bitwarden.organizations.MemberDecryptionType as SdkMemberDecryptionType import com.bitwarden.organizations.ProductTierType as SdkProductTierType import com.bitwarden.organizations.ProviderType as SdkProviderType @@ -30,6 +32,9 @@ import com.bitwarden.organizations.ProviderType as SdkProviderType private val JSON = Json { ignoreUnknownKeys = true explicitNulls = false + serializersModule = SerializersModule { + contextual(List::class) { args -> SafeListSerializer(args.first()) } + } } /** diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensionsTest.kt index 311c9edb84..7df0e5ef99 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/util/SyncResponseJsonExtensionsTest.kt @@ -207,6 +207,64 @@ class SyncResponseJsonExtensionsTest { ) } + @Test + fun `policyInformation drops unknown allowedSendTypes and keeps the SendControls policy`() { + val policy = createMockSdkPolicy( + type = PolicyType.SEND_CONTROLS, + data = """ + { + "disableSend": false, + "disableHideEmail": true, + "whoCanAccess": 2, + "allowedDomains": "bitwarden.com", + "deletionHours": 168, + "allowedSendTypes": [0, 2] + } + """.trimIndent(), + ) + + assertEquals( + PolicyInformation.SendControls( + disableSend = false, + disableHideEmail = true, + whoCanAccess = SendAccessTypeJson.SPECIFIC_PEOPLE, + allowedDomains = "bitwarden.com", + deletionHours = 168, + allowedSendTypes = listOf(SendTypeJson.TEXT), + ), + policy.policyInformation, + ) + } + + @Test + fun `policyInformation maps allowedSendTypes with only unknown types to an empty list`() { + val policy = createMockSdkPolicy( + type = PolicyType.SEND_CONTROLS, + data = """ + { + "disableSend": false, + "disableHideEmail": true, + "whoCanAccess": 2, + "allowedDomains": "bitwarden.com", + "deletionHours": 168, + "allowedSendTypes": [2] + } + """.trimIndent(), + ) + + assertEquals( + PolicyInformation.SendControls( + disableSend = false, + disableHideEmail = true, + whoCanAccess = SendAccessTypeJson.SPECIFIC_PEOPLE, + allowedDomains = "bitwarden.com", + deletionHours = 168, + allowedSendTypes = emptyList(), + ), + policy.policyInformation, + ) + } + @Test @Suppress("MaxLineLength") fun `policyInformation converts the OrganizationUserNotification Json data to policy information`() {