Update SDK to 1.0.0-2681-1a956d45 (#5756)

Co-authored-by: bw-ghapp[bot] <178206702+bw-ghapp[bot]@users.noreply.github.com>
Co-authored-by: Carlos Gonçalves <cgoncalves@bitwarden.com>
This commit is contained in:
bw-ghapp[bot] 2025-08-22 19:57:39 +01:00 committed by GitHub
parent bc7e682941
commit 99ab2245f6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 375 additions and 3 deletions

View File

@ -0,0 +1,264 @@
{
"formatVersion": 1,
"database": {
"version": 8,
"identityHash": "11387825dab701f9d2dd2e940ffbd794",
"entities": [
{
"tableName": "ciphers",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `user_id` TEXT NOT NULL, `has_totp` INTEGER NOT NULL DEFAULT 1, `cipher_type` TEXT NOT NULL, `cipher_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": "hasTotp",
"columnName": "has_totp",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "1"
},
{
"fieldPath": "cipherType",
"columnName": "cipher_type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "cipherJson",
"columnName": "cipher_json",
"affinity": "TEXT",
"notNull": true
}
],
"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`)"
}
]
},
{
"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, '11387825dab701f9d2dd2e940ffbd794')"
]
}
}

View File

@ -146,6 +146,8 @@ class VaultDiskSourceImpl(
externalId = collection.externalId, externalId = collection.externalId,
isReadOnly = collection.isReadOnly, isReadOnly = collection.isReadOnly,
canManage = collection.canManage, canManage = collection.canManage,
defaultUserCollectionEmail = collection.defaultUserCollectionEmail,
type = collection.type,
), ),
) )
} }
@ -167,6 +169,8 @@ class VaultDiskSourceImpl(
externalId = entity.externalId, externalId = entity.externalId,
isReadOnly = entity.isReadOnly, isReadOnly = entity.isReadOnly,
canManage = entity.canManage, canManage = entity.canManage,
defaultUserCollectionEmail = entity.defaultUserCollectionEmail,
type = entity.type,
) )
} }
}, },
@ -290,6 +294,8 @@ class VaultDiskSourceImpl(
externalId = collection.externalId, externalId = collection.externalId,
isReadOnly = collection.isReadOnly, isReadOnly = collection.isReadOnly,
canManage = collection.canManage, canManage = collection.canManage,
defaultUserCollectionEmail = collection.defaultUserCollectionEmail,
type = collection.type,
) )
}, },
) )

View File

@ -27,10 +27,11 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.entity.SendEntity
FolderEntity::class, FolderEntity::class,
SendEntity::class, SendEntity::class,
], ],
version = 7, version = 8,
exportSchema = true, exportSchema = true,
autoMigrations = [ autoMigrations = [
AutoMigration(from = 6, to = 7), AutoMigration(from = 6, to = 7),
AutoMigration(from = 7, to = 8),
], ],
) )
@TypeConverters(ZonedDateTimeTypeConverter::class) @TypeConverters(ZonedDateTimeTypeConverter::class)

View File

@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.vault.datasource.disk.entity
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.bitwarden.network.model.CollectionTypeJson
/** /**
* Entity representing a collection in the database. * Entity representing a collection in the database.
@ -33,4 +34,10 @@ data class CollectionEntity(
@ColumnInfo(name = "manage") @ColumnInfo(name = "manage")
val canManage: Boolean?, val canManage: Boolean?,
@ColumnInfo(name = "default_user_collection_email")
val defaultUserCollectionEmail: String?,
@ColumnInfo(name = "type", defaultValue = "0")
val type: CollectionTypeJson,
) )

View File

@ -1,8 +1,10 @@
package com.x8bit.bitwarden.data.vault.repository.util package com.x8bit.bitwarden.data.vault.repository.util
import com.bitwarden.collections.Collection import com.bitwarden.collections.Collection
import com.bitwarden.collections.CollectionType
import com.bitwarden.collections.CollectionView import com.bitwarden.collections.CollectionView
import com.bitwarden.core.data.repository.util.SpecialCharWithPrecedenceComparator import com.bitwarden.core.data.repository.util.SpecialCharWithPrecedenceComparator
import com.bitwarden.network.model.CollectionTypeJson
import com.bitwarden.network.model.SyncResponseJson import com.bitwarden.network.model.SyncResponseJson
/** /**
@ -18,6 +20,8 @@ fun SyncResponseJson.Collection.toEncryptedSdkCollection(): Collection =
hidePasswords = this.shouldHidePasswords, hidePasswords = this.shouldHidePasswords,
readOnly = this.isReadOnly, readOnly = this.isReadOnly,
manage = this.canManage ?: !this.isReadOnly, manage = this.canManage ?: !this.isReadOnly,
defaultUserCollectionEmail = this.defaultUserCollectionEmail,
type = this.type.toCollectionType(),
) )
/** /**
@ -38,3 +42,13 @@ fun List<CollectionView>.sortAlphabetically(): List<CollectionView> {
}, },
) )
} }
/**
* Converts a [CollectionType] object to a corresponding
* Bitwarden SDK [CollectionTypeJson] object.
*/
fun CollectionTypeJson.toCollectionType(): CollectionType =
when (this) {
CollectionTypeJson.SHARED_COLLECTION -> CollectionType.SHARED_COLLECTION
CollectionTypeJson.DEFAULT_USER_COLLECTION -> CollectionType.DEFAULT_USER_COLLECTION
}

View File

@ -3,6 +3,7 @@ package com.x8bit.bitwarden.data.vault.datasource.disk
import app.cash.turbine.test import app.cash.turbine.test
import com.bitwarden.core.di.CoreModule import com.bitwarden.core.di.CoreModule
import com.bitwarden.data.datasource.disk.base.FakeDispatcherManager import com.bitwarden.data.datasource.disk.base.FakeDispatcherManager
import com.bitwarden.network.model.CollectionTypeJson
import com.bitwarden.network.model.SyncResponseJson import com.bitwarden.network.model.SyncResponseJson
import com.bitwarden.network.model.createMockCipher import com.bitwarden.network.model.createMockCipher
import com.bitwarden.network.model.createMockCollection import com.bitwarden.network.model.createMockCollection
@ -479,6 +480,8 @@ private val COLLECTION_ENTITY = CollectionEntity(
externalId = "mockExternalId-3", externalId = "mockExternalId-3",
isReadOnly = false, isReadOnly = false,
canManage = true, canManage = true,
defaultUserCollectionEmail = "mockOffboardedUserEmail-3",
type = CollectionTypeJson.SHARED_COLLECTION,
) )
private const val DOMAINS_JSON = """ private const val DOMAINS_JSON = """

View File

@ -1,16 +1,19 @@
package com.x8bit.bitwarden.data.vault.datasource.sdk.model package com.x8bit.bitwarden.data.vault.datasource.sdk.model
import com.bitwarden.collections.CollectionType
import com.bitwarden.collections.CollectionView import com.bitwarden.collections.CollectionView
/** /**
* Create a mock [CollectionView] with a given [number]. * Create a mock [CollectionView] with a given [number].
*/ */
@Suppress("LongParameterList")
fun createMockCollectionView( fun createMockCollectionView(
number: Int, number: Int,
name: String? = null, name: String? = null,
readOnly: Boolean = false, readOnly: Boolean = false,
manage: Boolean = true, manage: Boolean = true,
hidePasswords: Boolean = false, hidePasswords: Boolean = false,
type: CollectionType = CollectionType.SHARED_COLLECTION,
): CollectionView = ): CollectionView =
CollectionView( CollectionView(
id = "mockId-$number", id = "mockId-$number",
@ -20,6 +23,7 @@ fun createMockCollectionView(
externalId = "mockExternalId-$number", externalId = "mockExternalId-$number",
readOnly = readOnly, readOnly = readOnly,
manage = manage, manage = manage,
type = type,
) )
/** /**

View File

@ -1,6 +1,7 @@
package com.x8bit.bitwarden.data.vault.datasource.sdk.model package com.x8bit.bitwarden.data.vault.datasource.sdk.model
import com.bitwarden.collections.Collection import com.bitwarden.collections.Collection
import com.bitwarden.collections.CollectionType
/** /**
* Create a mock [Collection] with a given [number]. * Create a mock [Collection] with a given [number].
@ -14,4 +15,6 @@ fun createMockSdkCollection(number: Int): Collection =
externalId = "mockExternalId-$number", externalId = "mockExternalId-$number",
readOnly = false, readOnly = false,
manage = true, manage = true,
defaultUserCollectionEmail = "mockOffboardedUserEmail-$number",
type = CollectionType.SHARED_COLLECTION,
) )

View File

@ -1,6 +1,8 @@
package com.x8bit.bitwarden.data.vault.repository.util package com.x8bit.bitwarden.data.vault.repository.util
import com.bitwarden.collections.Collection import com.bitwarden.collections.Collection
import com.bitwarden.collections.CollectionType
import com.bitwarden.network.model.CollectionTypeJson
import com.bitwarden.network.model.SyncResponseJson import com.bitwarden.network.model.SyncResponseJson
import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView import com.x8bit.bitwarden.data.vault.datasource.sdk.model.createMockCollectionView
import org.junit.Test import org.junit.Test
@ -18,6 +20,8 @@ class VaultSdkCollectionExtensionsTest {
readOnly = true, readOnly = true,
id = "id", id = "id",
manage = true, manage = true,
defaultUserCollectionEmail = null,
type = CollectionType.SHARED_COLLECTION,
), ),
SyncResponseJson.Collection( SyncResponseJson.Collection(
organizationId = "organizationId", organizationId = "organizationId",
@ -27,6 +31,8 @@ class VaultSdkCollectionExtensionsTest {
isReadOnly = true, isReadOnly = true,
id = "id", id = "id",
canManage = true, canManage = true,
defaultUserCollectionEmail = null,
type = CollectionTypeJson.SHARED_COLLECTION,
) )
.toEncryptedSdkCollection(), .toEncryptedSdkCollection(),
) )
@ -43,6 +49,8 @@ class VaultSdkCollectionExtensionsTest {
readOnly = false, readOnly = false,
id = "id", id = "id",
manage = true, manage = true,
defaultUserCollectionEmail = null,
type = CollectionType.SHARED_COLLECTION,
), ),
SyncResponseJson.Collection( SyncResponseJson.Collection(
organizationId = "organizationId", organizationId = "organizationId",
@ -52,6 +60,8 @@ class VaultSdkCollectionExtensionsTest {
isReadOnly = false, isReadOnly = false,
id = "id", id = "id",
canManage = null, canManage = null,
defaultUserCollectionEmail = null,
type = CollectionTypeJson.SHARED_COLLECTION,
) )
.toEncryptedSdkCollection(), .toEncryptedSdkCollection(),
) )
@ -70,6 +80,8 @@ class VaultSdkCollectionExtensionsTest {
readOnly = true, readOnly = true,
id = "id", id = "id",
manage = true, manage = true,
defaultUserCollectionEmail = null,
type = CollectionType.SHARED_COLLECTION,
), ),
), ),
listOf( listOf(
@ -81,6 +93,8 @@ class VaultSdkCollectionExtensionsTest {
isReadOnly = true, isReadOnly = true,
id = "id", id = "id",
canManage = true, canManage = true,
defaultUserCollectionEmail = null,
type = CollectionTypeJson.SHARED_COLLECTION,
) )
.toEncryptedSdkCollection(), .toEncryptedSdkCollection(),
), ),
@ -115,4 +129,14 @@ class VaultSdkCollectionExtensionsTest {
list.sortAlphabetically(), list.sortAlphabetically(),
) )
} }
@Test
fun `toCollectionType should convert CollectionTypeJson to CollectionType`() {
val collectionType = CollectionTypeJson.SHARED_COLLECTION
val sdkCollectionType = collectionType.toCollectionType()
assertEquals(
CollectionType.SHARED_COLLECTION,
sdkCollectionType,
)
}
} }

View File

@ -29,7 +29,7 @@ androidxRoom = "2.7.2"
androidxSecurityCrypto = "1.1.0" androidxSecurityCrypto = "1.1.0"
androidxSplash = "1.1.0-rc01" androidxSplash = "1.1.0-rc01"
androidxWork = "2.10.3" androidxWork = "2.10.3"
bitwardenSdk = "1.0.0-2450-9fe3aeda" bitwardenSdk = "1.0.0-2681-1a956d45"
crashlytics = "3.0.6" crashlytics = "3.0.6"
detekt = "1.23.8" detekt = "1.23.8"
firebaseBom = "34.1.0" firebaseBom = "34.1.0"

View File

@ -0,0 +1,31 @@
package com.bitwarden.network.model
import androidx.annotation.Keep
import com.bitwarden.core.data.serializer.BaseEnumeratedIntSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents the type of collection assigned to user(s) or group(s).
*/
@Serializable(CollectionTypeSerializer::class)
enum class CollectionTypeJson {
/**
* Default collection type. Can be assigned by an organization to user(s) or group(s).
*/
@SerialName("0")
SHARED_COLLECTION,
/**
* Default collection assigned to a user for an organization that has
* OrganizationDataOwnership (formerly PersonalOwnership) policy enabled.
*/
@SerialName("1")
DEFAULT_USER_COLLECTION,
}
@Keep
private class CollectionTypeSerializer : BaseEnumeratedIntSerializer<CollectionTypeJson>(
className = "CollectionTypeJson",
values = CollectionTypeJson.entries.toTypedArray(),
)

View File

@ -998,6 +998,9 @@ data class SyncResponseJson(
* @property externalId The external ID of the collection (nullable). * @property externalId The external ID of the collection (nullable).
* @property isReadOnly If the collection is marked as read only. * @property isReadOnly If the collection is marked as read only.
* @property id The ID of the collection. * @property id The ID of the collection.
* @property defaultUserCollectionEmail The offboarded user's email address to be used as name
* for the collection.
* @property type The collection's type.
*/ */
@Serializable @Serializable
data class Collection( data class Collection(
@ -1021,5 +1024,11 @@ data class SyncResponseJson(
@SerialName("manage") @SerialName("manage")
val canManage: Boolean?, val canManage: Boolean?,
@SerialName("defaultUserCollectionEmail")
val defaultUserCollectionEmail: String?,
@SerialName("type")
val type: CollectionTypeJson = CollectionTypeJson.SHARED_COLLECTION,
) )
} }

View File

@ -214,7 +214,9 @@ private const val SYNC_SUCCESS_JSON = """
"externalId": "mockExternalId-1", "externalId": "mockExternalId-1",
"readOnly": false, "readOnly": false,
"id": "mockId-1", "id": "mockId-1",
"manage": true "manage": true,
"defaultUserCollectionEmail": "mockOffboardedUserEmail-1",
"type": 0
} }
], ],
"ciphers": [ "ciphers": [

View File

@ -13,6 +13,8 @@ fun createMockCollection(
isReadOnly: Boolean = false, isReadOnly: Boolean = false,
id: String = "mockId-$number", id: String = "mockId-$number",
canManage: Boolean? = true, canManage: Boolean? = true,
defaultUserCollectionEmail: String? = "mockOffboardedUserEmail-$number",
type: CollectionTypeJson = CollectionTypeJson.SHARED_COLLECTION,
): SyncResponseJson.Collection = ): SyncResponseJson.Collection =
SyncResponseJson.Collection( SyncResponseJson.Collection(
organizationId = organizationId, organizationId = organizationId,
@ -22,4 +24,6 @@ fun createMockCollection(
isReadOnly = isReadOnly, isReadOnly = isReadOnly,
id = id, id = id,
canManage = canManage, canManage = canManage,
defaultUserCollectionEmail = defaultUserCollectionEmail,
type = type,
) )