Skip to content

Commit 283c353

Browse files
david-livefrontSaintPatrck
authored andcommitted
PM-14433: Null domain data
1 parent 8dd0cee commit 283c353

File tree

10 files changed

+275
-19
lines changed

10 files changed

+275
-19
lines changed

app/schemas/com.x8bit.bitwarden.data.vault.datasource.disk.database.VaultDatabase/4.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -253,4 +253,4 @@
253253
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f7906c69e0a2c065d4d3be140fc721b6')"
254254
]
255255
}
256-
}
256+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
{
2+
"formatVersion": 1,
3+
"database": {
4+
"version": 5,
5+
"identityHash": "ee697e71290c92fe5b607d0b7665481b",
6+
"entities": [
7+
{
8+
"tableName": "ciphers",
9+
"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, PRIMARY KEY(`id`))",
10+
"fields": [
11+
{
12+
"fieldPath": "id",
13+
"columnName": "id",
14+
"affinity": "TEXT",
15+
"notNull": true
16+
},
17+
{
18+
"fieldPath": "userId",
19+
"columnName": "user_id",
20+
"affinity": "TEXT",
21+
"notNull": true
22+
},
23+
{
24+
"fieldPath": "cipherType",
25+
"columnName": "cipher_type",
26+
"affinity": "TEXT",
27+
"notNull": true
28+
},
29+
{
30+
"fieldPath": "cipherJson",
31+
"columnName": "cipher_json",
32+
"affinity": "TEXT",
33+
"notNull": true
34+
}
35+
],
36+
"primaryKey": {
37+
"autoGenerate": false,
38+
"columnNames": [
39+
"id"
40+
]
41+
},
42+
"indices": [
43+
{
44+
"name": "index_ciphers_user_id",
45+
"unique": false,
46+
"columnNames": [
47+
"user_id"
48+
],
49+
"orders": [],
50+
"createSql": "CREATE INDEX IF NOT EXISTS `index_ciphers_user_id` ON `${TABLE_NAME}` (`user_id`)"
51+
}
52+
],
53+
"foreignKeys": []
54+
},
55+
{
56+
"tableName": "collections",
57+
"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 NOT NULL, PRIMARY KEY(`id`))",
58+
"fields": [
59+
{
60+
"fieldPath": "id",
61+
"columnName": "id",
62+
"affinity": "TEXT",
63+
"notNull": true
64+
},
65+
{
66+
"fieldPath": "userId",
67+
"columnName": "user_id",
68+
"affinity": "TEXT",
69+
"notNull": true
70+
},
71+
{
72+
"fieldPath": "organizationId",
73+
"columnName": "organization_id",
74+
"affinity": "TEXT",
75+
"notNull": true
76+
},
77+
{
78+
"fieldPath": "shouldHidePasswords",
79+
"columnName": "should_hide_passwords",
80+
"affinity": "INTEGER",
81+
"notNull": true
82+
},
83+
{
84+
"fieldPath": "name",
85+
"columnName": "name",
86+
"affinity": "TEXT",
87+
"notNull": true
88+
},
89+
{
90+
"fieldPath": "externalId",
91+
"columnName": "external_id",
92+
"affinity": "TEXT",
93+
"notNull": false
94+
},
95+
{
96+
"fieldPath": "isReadOnly",
97+
"columnName": "read_only",
98+
"affinity": "INTEGER",
99+
"notNull": true
100+
},
101+
{
102+
"fieldPath": "canManage",
103+
"columnName": "manage",
104+
"affinity": "INTEGER",
105+
"notNull": true
106+
}
107+
],
108+
"primaryKey": {
109+
"autoGenerate": false,
110+
"columnNames": [
111+
"id"
112+
]
113+
},
114+
"indices": [
115+
{
116+
"name": "index_collections_user_id",
117+
"unique": false,
118+
"columnNames": [
119+
"user_id"
120+
],
121+
"orders": [],
122+
"createSql": "CREATE INDEX IF NOT EXISTS `index_collections_user_id` ON `${TABLE_NAME}` (`user_id`)"
123+
}
124+
],
125+
"foreignKeys": []
126+
},
127+
{
128+
"tableName": "domains",
129+
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`user_id` TEXT NOT NULL, `domains_json` TEXT, PRIMARY KEY(`user_id`))",
130+
"fields": [
131+
{
132+
"fieldPath": "userId",
133+
"columnName": "user_id",
134+
"affinity": "TEXT",
135+
"notNull": true
136+
},
137+
{
138+
"fieldPath": "domainsJson",
139+
"columnName": "domains_json",
140+
"affinity": "TEXT",
141+
"notNull": false
142+
}
143+
],
144+
"primaryKey": {
145+
"autoGenerate": false,
146+
"columnNames": [
147+
"user_id"
148+
]
149+
},
150+
"indices": [],
151+
"foreignKeys": []
152+
},
153+
{
154+
"tableName": "folders",
155+
"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`))",
156+
"fields": [
157+
{
158+
"fieldPath": "id",
159+
"columnName": "id",
160+
"affinity": "TEXT",
161+
"notNull": true
162+
},
163+
{
164+
"fieldPath": "userId",
165+
"columnName": "user_id",
166+
"affinity": "TEXT",
167+
"notNull": true
168+
},
169+
{
170+
"fieldPath": "name",
171+
"columnName": "name",
172+
"affinity": "TEXT",
173+
"notNull": false
174+
},
175+
{
176+
"fieldPath": "revisionDate",
177+
"columnName": "revision_date",
178+
"affinity": "INTEGER",
179+
"notNull": true
180+
}
181+
],
182+
"primaryKey": {
183+
"autoGenerate": false,
184+
"columnNames": [
185+
"id"
186+
]
187+
},
188+
"indices": [
189+
{
190+
"name": "index_folders_user_id",
191+
"unique": false,
192+
"columnNames": [
193+
"user_id"
194+
],
195+
"orders": [],
196+
"createSql": "CREATE INDEX IF NOT EXISTS `index_folders_user_id` ON `${TABLE_NAME}` (`user_id`)"
197+
}
198+
],
199+
"foreignKeys": []
200+
},
201+
{
202+
"tableName": "sends",
203+
"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`))",
204+
"fields": [
205+
{
206+
"fieldPath": "id",
207+
"columnName": "id",
208+
"affinity": "TEXT",
209+
"notNull": true
210+
},
211+
{
212+
"fieldPath": "userId",
213+
"columnName": "user_id",
214+
"affinity": "TEXT",
215+
"notNull": true
216+
},
217+
{
218+
"fieldPath": "sendType",
219+
"columnName": "send_type",
220+
"affinity": "TEXT",
221+
"notNull": true
222+
},
223+
{
224+
"fieldPath": "sendJson",
225+
"columnName": "send_json",
226+
"affinity": "TEXT",
227+
"notNull": true
228+
}
229+
],
230+
"primaryKey": {
231+
"autoGenerate": false,
232+
"columnNames": [
233+
"id"
234+
]
235+
},
236+
"indices": [
237+
{
238+
"name": "index_sends_user_id",
239+
"unique": false,
240+
"columnNames": [
241+
"user_id"
242+
],
243+
"orders": [],
244+
"createSql": "CREATE INDEX IF NOT EXISTS `index_sends_user_id` ON `${TABLE_NAME}` (`user_id`)"
245+
}
246+
],
247+
"foreignKeys": []
248+
}
249+
],
250+
"views": [],
251+
"setupQueries": [
252+
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
253+
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ee697e71290c92fe5b607d0b7665481b')"
254+
]
255+
}
256+
}

app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSource.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ interface VaultDiskSource {
3737
/**
3838
* Retrieves all domains from the data source for a given [userId].
3939
*/
40-
fun getDomains(userId: String): Flow<SyncResponseJson.Domains>
40+
fun getDomains(userId: String): Flow<SyncResponseJson.Domains?>
4141

4242
/**
4343
* Deletes a folder from the data source for the given [userId] and [folderId].

app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSourceImpl.kt

+3-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import kotlinx.coroutines.async
1717
import kotlinx.coroutines.awaitAll
1818
import kotlinx.coroutines.coroutineScope
1919
import kotlinx.coroutines.flow.Flow
20-
import kotlinx.coroutines.flow.filterNotNull
2120
import kotlinx.coroutines.flow.first
2221
import kotlinx.coroutines.flow.map
2322
import kotlinx.coroutines.flow.merge
@@ -122,13 +121,12 @@ class VaultDiskSourceImpl(
122121
},
123122
)
124123

125-
override fun getDomains(userId: String): Flow<SyncResponseJson.Domains> =
124+
override fun getDomains(userId: String): Flow<SyncResponseJson.Domains?> =
126125
domainsDao
127126
.getDomains(userId)
128-
.filterNotNull()
129127
.map { entity ->
130128
withContext(dispatcherManager.default) {
131-
json.decodeFromString<SyncResponseJson.Domains>(entity.domainsJson)
129+
entity?.domainsJson?.let { json.decodeFromString<SyncResponseJson.Domains>(it) }
132130
}
133131
}
134132

@@ -242,7 +240,7 @@ class VaultDiskSourceImpl(
242240
domainsDao.insertDomains(
243241
domains = DomainsEntity(
244242
userId = userId,
245-
domainsJson = json.encodeToString(vault.domains),
243+
domainsJson = vault.domains?.let { json.encodeToString(it) },
246244
),
247245
)
248246
}

app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/disk/database/VaultDatabase.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.entity.SendEntity
2626
FolderEntity::class,
2727
SendEntity::class,
2828
],
29-
version = 4,
29+
version = 5,
3030
exportSchema = true,
3131
)
3232
@TypeConverters(ZonedDateTimeTypeConverter::class)

app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/disk/entity/DomainsEntity.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ data class DomainsEntity(
1414
val userId: String,
1515

1616
@ColumnInfo(name = "domains_json")
17-
val domainsJson: String,
17+
val domainsJson: String?,
1818
)

app/src/main/java/com/x8bit/bitwarden/data/vault/datasource/network/model/SyncResponseJson.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ data class SyncResponseJson(
3939
val policies: List<Policy>?,
4040

4141
@SerialName("domains")
42-
val domains: Domains,
42+
val domains: Domains?,
4343

4444
@SerialName("sends")
4545
val sends: List<Send>?,

app/src/main/java/com/x8bit/bitwarden/data/vault/repository/util/DomainsExtensions.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import com.x8bit.bitwarden.data.vault.repository.model.DomainsData
66
/**
77
* Map the API [Domains] model to the internal [DomainsData] model.
88
*/
9-
fun Domains.toDomainsData(): DomainsData {
9+
fun Domains?.toDomainsData(): DomainsData {
1010
val globalEquivalentDomains = this
11-
.globalEquivalentDomains
11+
?.globalEquivalentDomains
1212
?.map { it.toInternalModel() }
1313
.orEmpty()
1414

1515
return DomainsData(
16-
equivalentDomains = this.equivalentDomains.orEmpty(),
16+
equivalentDomains = this?.equivalentDomains.orEmpty(),
1717
globalEquivalentDomains = globalEquivalentDomains,
1818
)
1919
}

app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/disk/VaultDiskSourceTest.kt

+6-3
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,13 @@ class VaultDiskSourceTest {
248248
// We cannot compare the JSON strings directly because of formatting differences
249249
// So we split that off into its own assertion.
250250
assertEquals(
251-
DOMAINS_ENTITY.copy(domainsJson = ""),
252-
storedDomainsEntity.copy(domainsJson = ""),
251+
DOMAINS_ENTITY.copy(domainsJson = null),
252+
storedDomainsEntity.copy(domainsJson = null),
253+
)
254+
assertJsonEquals(
255+
requireNotNull(DOMAINS_ENTITY.domainsJson),
256+
requireNotNull(storedDomainsEntity.domainsJson),
253257
)
254-
assertJsonEquals(DOMAINS_ENTITY.domainsJson, storedDomainsEntity.domainsJson)
255258

256259
// Verify the folders dao is updated
257260
assertEquals(listOf(FOLDER_ENTITY), foldersDao.storedFolders)

app/src/test/java/com/x8bit/bitwarden/data/vault/datasource/disk/dao/FakeDomainsDao.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package com.x8bit.bitwarden.data.vault.datasource.disk.dao
33
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
44
import com.x8bit.bitwarden.data.vault.datasource.disk.entity.DomainsEntity
55
import kotlinx.coroutines.flow.Flow
6-
import kotlinx.coroutines.flow.filterNotNull
76

87
class FakeDomainsDao : DomainsDao {
98
var storedDomains: DomainsEntity? = null
@@ -18,9 +17,9 @@ class FakeDomainsDao : DomainsDao {
1817
deleteDomainsCalled = true
1918
}
2019

21-
override fun getDomains(userId: String): Flow<DomainsEntity> {
20+
override fun getDomains(userId: String): Flow<DomainsEntity?> {
2221
getDomainsCalled = true
23-
return mutableDomainsFlow.filterNotNull()
22+
return mutableDomainsFlow
2423
}
2524

2625
override suspend fun insertDomains(domains: DomainsEntity) {

0 commit comments

Comments
 (0)