diff --git a/app/schemas/com.x8bit.bitwarden.data.vault.datasource.disk.database.VaultDatabase/10.json b/app/schemas/com.x8bit.bitwarden.data.vault.datasource.disk.database.VaultDatabase/10.json new file mode 100644 index 00000000000..5c1b4b16c73 --- /dev/null +++ b/app/schemas/com.x8bit.bitwarden.data.vault.datasource.disk.database.VaultDatabase/10.json @@ -0,0 +1,272 @@ +{ + "formatVersion": 1, + "database": { + "version": 10, + "identityHash": "67e32a70f154b819751a225259e8222b", + "entities": [ + { + "tableName": "ciphers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `cipher_type` TEXT NOT NULL, `cipher_json` TEXT NOT NULL, `organization_id` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "cipherType", + "columnName": "cipher_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "cipherJson", + "columnName": "cipher_json", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "organizationId", + "columnName": "organization_id", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_ciphers_user_id", + "unique": false, + "columnNames": [ + "user_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_ciphers_user_id` ON `${TABLE_NAME}` (`user_id`)" + }, + { + "name": "index_ciphers_user_id_organization_id", + "unique": false, + "columnNames": [ + "user_id", + "organization_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_ciphers_user_id_organization_id` ON `${TABLE_NAME}` (`user_id`, `organization_id`)" + } + ] + }, + { + "tableName": "collections", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `organization_id` TEXT NOT NULL, `should_hide_passwords` INTEGER NOT NULL, `name` TEXT NOT NULL, `external_id` TEXT, `read_only` INTEGER NOT NULL, `manage` INTEGER, `default_user_collection_email` TEXT, `type` TEXT NOT NULL DEFAULT '0', PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "organizationId", + "columnName": "organization_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "shouldHidePasswords", + "columnName": "should_hide_passwords", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "externalId", + "columnName": "external_id", + "affinity": "TEXT" + }, + { + "fieldPath": "isReadOnly", + "columnName": "read_only", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "canManage", + "columnName": "manage", + "affinity": "INTEGER" + }, + { + "fieldPath": "defaultUserCollectionEmail", + "columnName": "default_user_collection_email", + "affinity": "TEXT" + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true, + "defaultValue": "'0'" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_collections_user_id", + "unique": false, + "columnNames": [ + "user_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_collections_user_id` ON `${TABLE_NAME}` (`user_id`)" + } + ] + }, + { + "tableName": "domains", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_id` TEXT NOT NULL, `domains_json` TEXT, PRIMARY KEY(`user_id`))", + "fields": [ + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "domainsJson", + "columnName": "domains_json", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "user_id" + ] + } + }, + { + "tableName": "folders", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `name` TEXT, `revision_date` INTEGER NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT" + }, + { + "fieldPath": "revisionDate", + "columnName": "revision_date", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_folders_user_id", + "unique": false, + "columnNames": [ + "user_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_folders_user_id` ON `${TABLE_NAME}` (`user_id`)" + } + ] + }, + { + "tableName": "sends", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `send_type` TEXT NOT NULL, `send_json` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "user_id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sendType", + "columnName": "send_type", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sendJson", + "columnName": "send_json", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [ + { + "name": "index_sends_user_id", + "unique": false, + "columnNames": [ + "user_id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_sends_user_id` ON `${TABLE_NAME}` (`user_id`)" + } + ] + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '67e32a70f154b819751a225259e8222b')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/repository/AuthenticatorBridgeRepositoryImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/repository/AuthenticatorBridgeRepositoryImpl.kt index 522c4c506de..0b45b35f47f 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/repository/AuthenticatorBridgeRepositoryImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/platform/repository/AuthenticatorBridgeRepositoryImpl.kt @@ -88,7 +88,7 @@ class AuthenticatorBridgeRepositoryImpl( // Vault is unlocked, query vault disk source for totp logins: val cipherData = vaultDiskSource - .getTotpCiphers(userId = userId) + .getLoginCiphers(userId = userId) // Filter out any deleted and archived ciphers. .filter { it.deletedDate == null && it.archivedDate == null } .mapNotNull { diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSource.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSource.kt index e46db66e096..87765532b41 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSource.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSource.kt @@ -43,9 +43,9 @@ interface VaultDiskSource { ): List /** - * Retrieves all ciphers from the data source for a given [userId] that contain TOTP codes. + * Retrieves all login ciphers from the data source for a given [userId]. */ - suspend fun getTotpCiphers(userId: String): List + suspend fun getLoginCiphers(userId: String): List /** * Retrieves a cipher from the data source for a given [userId] and [cipherId]. diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSourceImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSourceImpl.kt index 1bb6c02ec04..6e1e5cc1d7f 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSourceImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSourceImpl.kt @@ -4,7 +4,6 @@ import com.bitwarden.core.data.manager.dispatcher.DispatcherManager import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow import com.bitwarden.core.data.util.decodeFromStringWithErrorCallback import com.bitwarden.network.model.SyncResponseJson -import com.bitwarden.ui.platform.base.util.orNullIfBlank import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CiphersDao import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CollectionsDao import com.x8bit.bitwarden.data.vault.datasource.disk.dao.DomainsDao @@ -53,7 +52,6 @@ class VaultDiskSourceImpl( CipherEntity( id = cipher.id, userId = userId, - hasTotp = cipher.login?.totp != null, cipherType = json.encodeToString(cipher.type), cipherJson = json.encodeToString(cipher), organizationId = cipher.organizationId, @@ -120,8 +118,8 @@ class VaultDiskSourceImpl( } } - override suspend fun getTotpCiphers(userId: String): List { - val entities = ciphersDao.getAllTotpCiphers(userId = userId) + override suspend fun getLoginCiphers(userId: String): List { + val entities = ciphersDao.getAllLoginCiphers(userId = userId) return withContext(context = dispatcherManager.default) { entities .map { entity -> @@ -132,11 +130,6 @@ class VaultDiskSourceImpl( } } .awaitAll() - .filter { - // A safety-check since after the DB migration, we will temporarily think - // all ciphers contain a totp code - it.login?.totp.orNullIfBlank() != null - } } } @@ -167,7 +160,6 @@ class VaultDiskSourceImpl( CipherEntity( id = cipher.id, userId = userId, - hasTotp = cipher.login?.totp.orNullIfBlank() != null, cipherType = json.encodeToString(cipher.type), cipherJson = json.encodeToString(cipher), organizationId = cipher.organizationId, @@ -369,7 +361,6 @@ class VaultDiskSourceImpl( CipherEntity( id = cipher.id, userId = userId, - hasTotp = cipher.login?.totp != null, cipherType = json.encodeToString(cipher.type), cipherJson = json.encodeToString(cipher), organizationId = cipher.organizationId, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/dao/CiphersDao.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/dao/CiphersDao.kt index 9bb9b5d5527..832ea367bc3 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/dao/CiphersDao.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/dao/CiphersDao.kt @@ -48,10 +48,10 @@ interface CiphersDao { ): List /** - * Retrieves all ciphers from the database for a given [userId]. + * Retrieves all login type ciphers from the database for a given [userId]. */ - @Query("SELECT * FROM ciphers WHERE user_id = :userId AND has_totp = 1") - suspend fun getAllTotpCiphers( + @Query("SELECT * FROM ciphers WHERE user_id = :userId AND cipher_type = 1") + suspend fun getAllLoginCiphers( userId: String, ): List diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/database/VaultDatabase.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/database/VaultDatabase.kt index e471bdead07..0dbbf2d1f48 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/database/VaultDatabase.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/database/VaultDatabase.kt @@ -2,8 +2,10 @@ package com.x8bit.bitwarden.data.vault.datasource.disk.database import androidx.room.AutoMigration import androidx.room.Database +import androidx.room.DeleteColumn import androidx.room.RoomDatabase import androidx.room.TypeConverters +import androidx.room.migration.AutoMigrationSpec import com.x8bit.bitwarden.data.vault.datasource.disk.convertor.InstantTypeConverter import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CiphersDao import com.x8bit.bitwarden.data.vault.datasource.disk.dao.CollectionsDao @@ -27,11 +29,13 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.entity.SendEntity FolderEntity::class, SendEntity::class, ], - version = 9, + version = 10, exportSchema = true, autoMigrations = [ AutoMigration(from = 6, to = 7), AutoMigration(from = 7, to = 8), + AutoMigration(from = 8, to = 9), + AutoMigration(from = 9, to = 10, RemoveTotpAutoMigration::class), ], ) @TypeConverters(InstantTypeConverter::class) @@ -62,3 +66,9 @@ abstract class VaultDatabase : RoomDatabase() { */ abstract fun sendsDao(): SendsDao } + +/** + * A defined migration to remove the `has_totp` field from the `cipher` table. + */ +@DeleteColumn.Entries(DeleteColumn(tableName = "ciphers", columnName = "has_totp")) +class RemoveTotpAutoMigration : AutoMigrationSpec diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/entity/CipherEntity.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/entity/CipherEntity.kt index 87cbbc511ae..5e47e5ec5aa 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/entity/CipherEntity.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/entity/CipherEntity.kt @@ -23,11 +23,6 @@ data class CipherEntity( @ColumnInfo(name = "user_id") val userId: String, - // Default to true for initial migration. - // Subsequent syncs will populate with correct values for optimizations. - @ColumnInfo(name = "has_totp", defaultValue = "1") - val hasTotp: Boolean, - @ColumnInfo(name = "cipher_type") val cipherType: String, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCipherExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCipherExtensions.kt index 226fa90e00c..0646a4d3ad3 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCipherExtensions.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/VaultSdkCipherExtensions.kt @@ -117,6 +117,7 @@ fun Cipher.toEncryptedNetworkCipherResponse( key = key, encryptedFor = encryptedFor, archivedDate = archivedDate, + data = data, ) /** @@ -490,7 +491,7 @@ fun SyncResponseJson.Cipher.toEncryptedSdkCipher(): Cipher = deletedDate = deletedDate, revisionDate = revisionDate, archivedDate = archivedDate, - data = null, + data = data, ) /** diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/repository/AuthenticatorBridgeRepositoryTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/repository/AuthenticatorBridgeRepositoryTest.kt index e40a672e2a4..29b09a5451a 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/repository/AuthenticatorBridgeRepositoryTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/platform/repository/AuthenticatorBridgeRepositoryTest.kt @@ -143,8 +143,8 @@ class AuthenticatorBridgeRepositoryTest { // Add some ciphers to vaultDiskSource for each user, // and setup mock decryption for them: - coEvery { vaultDiskSource.getTotpCiphers(USER_1_ID) } returns USER_1_CIPHERS - coEvery { vaultDiskSource.getTotpCiphers(USER_2_ID) } returns USER_2_CIPHERS + coEvery { vaultDiskSource.getLoginCiphers(USER_1_ID) } returns USER_1_CIPHERS + coEvery { vaultDiskSource.getLoginCiphers(USER_2_ID) } returns USER_2_CIPHERS mockkStatic( SyncResponseJson.Cipher::toEncryptedSdkCipher, EnvironmentUrlDataJson::toEnvironmentUrlsOrDefault, @@ -213,7 +213,7 @@ class AuthenticatorBridgeRepositoryTest { userId = USER_2_ID, request = InitOrgCryptoRequest(organizationKeys = USER_2_ORG_KEYS), ) - vaultDiskSource.getTotpCiphers(userId = USER_2_ID) + vaultDiskSource.getLoginCiphers(userId = USER_2_ID) scopedVaultSdkSource.decryptCipher( userId = USER_2_ID, cipher = USER_2_ENCRYPTED_SDK_TOTP_CIPHER, @@ -251,7 +251,7 @@ class AuthenticatorBridgeRepositoryTest { userId = USER_1_ID, request = InitOrgCryptoRequest(organizationKeys = USER_1_ORG_KEYS), ) - vaultDiskSource.getTotpCiphers(userId = USER_1_ID) + vaultDiskSource.getLoginCiphers(userId = USER_1_ID) scopedVaultSdkSource.decryptCipher( userId = USER_1_ID, cipher = USER_1_ENCRYPTED_SDK_TOTP_CIPHER, @@ -273,7 +273,7 @@ class AuthenticatorBridgeRepositoryTest { userId = USER_2_ID, request = InitOrgCryptoRequest(organizationKeys = USER_2_ORG_KEYS), ) - vaultDiskSource.getTotpCiphers(userId = USER_2_ID) + vaultDiskSource.getLoginCiphers(userId = USER_2_ID) scopedVaultSdkSource.decryptCipher( userId = USER_2_ID, cipher = USER_2_ENCRYPTED_SDK_TOTP_CIPHER, @@ -341,7 +341,7 @@ class AuthenticatorBridgeRepositoryTest { userId = USER_2_ID, request = InitOrgCryptoRequest(organizationKeys = USER_2_ORG_KEYS), ) - vaultDiskSource.getTotpCiphers(userId = USER_2_ID) + vaultDiskSource.getLoginCiphers(userId = USER_2_ID) scopedVaultSdkSource.decryptCipher( userId = USER_2_ID, cipher = USER_2_ENCRYPTED_SDK_TOTP_CIPHER, diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSourceTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSourceTest.kt index 7dad4d6e847..5081dd150fd 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSourceTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSourceTest.kt @@ -123,17 +123,17 @@ class VaultDiskSourceTest { } @Test - fun `getTotpCiphers should return all CiphersDao totp ciphers`() = runTest { + fun `getLoginCiphers should return all CiphersDao login ciphers`() = runTest { val cipherEntities = listOf( CIPHER_ENTITY, - CIPHER_ENTITY.copy(id = "otherCipherId", hasTotp = false), + CIPHER_ENTITY.copy(id = "otherCipherId", cipherType = "2"), ) val ciphers = listOf(CIPHER_1) - val result1 = vaultDiskSource.getTotpCiphers(USER_ID) + val result1 = vaultDiskSource.getLoginCiphers(USER_ID) assertEquals(emptyList(), result1) ciphersDao.insertCiphers(cipherEntities) - val result2 = vaultDiskSource.getTotpCiphers(USER_ID) + val result2 = vaultDiskSource.getLoginCiphers(USER_ID) assertEquals(ciphers, result2) } @@ -638,7 +638,6 @@ private const val CIPHER_JSON = """ private val CIPHER_ENTITY = CipherEntity( id = "mockId-1", userId = USER_ID, - hasTotp = true, cipherType = "1", cipherJson = CIPHER_JSON, organizationId = "mockOrganizationId-1", diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/dao/FakeCiphersDao.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/dao/FakeCiphersDao.kt index e5e2b3671be..924cc0d520a 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/dao/FakeCiphersDao.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/disk/dao/FakeCiphersDao.kt @@ -56,8 +56,8 @@ class FakeCiphersDao : CiphersDao { ): List = storedCiphers.filter { it.userId == userId && it.id in cipherIds } - override suspend fun getAllTotpCiphers(userId: String): List = - storedCiphers.filter { it.userId == userId && it.hasTotp } + override suspend fun getAllLoginCiphers(userId: String): List = + storedCiphers.filter { it.userId == userId && it.cipherType == "1" } override suspend fun getCipher(userId: String, cipherId: String): CipherEntity? = storedCiphers.find { it.userId == userId && it.id == cipherId } diff --git a/network/src/main/kotlin/com/bitwarden/network/model/SyncResponseJson.kt b/network/src/main/kotlin/com/bitwarden/network/model/SyncResponseJson.kt index f83ca1a8f0c..2ca6a4fc27d 100644 --- a/network/src/main/kotlin/com/bitwarden/network/model/SyncResponseJson.kt +++ b/network/src/main/kotlin/com/bitwarden/network/model/SyncResponseJson.kt @@ -774,6 +774,9 @@ data class SyncResponseJson( @SerialName("archivedDate") @Contextual val archivedDate: Instant?, + + @SerialName("data") + val data: String?, ) { /** * Represents an attachment in the vault response. diff --git a/network/src/testFixtures/kotlin/com/bitwarden/network/model/SyncResponseCipherUtil.kt b/network/src/testFixtures/kotlin/com/bitwarden/network/model/SyncResponseCipherUtil.kt index 77658828883..e398cb39980 100644 --- a/network/src/testFixtures/kotlin/com/bitwarden/network/model/SyncResponseCipherUtil.kt +++ b/network/src/testFixtures/kotlin/com/bitwarden/network/model/SyncResponseCipherUtil.kt @@ -50,6 +50,7 @@ fun createMockCipher( shouldViewPassword: Boolean = false, key: String? = "mockKey-$number", encryptedFor: String? = "mockEncryptedFor-$number", + data: String? = null, ): SyncResponseJson.Cipher = SyncResponseJson.Cipher( id = id, @@ -82,6 +83,7 @@ fun createMockCipher( shouldViewPassword = shouldViewPassword, key = key, encryptedFor = encryptedFor, + data = data, ) /**