Establish device trust directly with a TrustDeviceResponse (#1246)

This commit is contained in:
David Perez 2024-04-09 11:06:31 -05:00 committed by Álison Fernandes
parent 05d1607024
commit 2ae8a76103
3 changed files with 90 additions and 19 deletions

View file

@ -1,5 +1,7 @@
package com.x8bit.bitwarden.data.auth.manager package com.x8bit.bitwarden.data.auth.manager
import com.bitwarden.crypto.TrustDeviceResponse
/** /**
* Manager used to establish trust with this device. * Manager used to establish trust with this device.
*/ */
@ -8,4 +10,12 @@ interface TrustedDeviceManager {
* Establishes trust with this device if necessary. * Establishes trust with this device if necessary.
*/ */
suspend fun trustThisDeviceIfNecessary(userId: String): Result<Boolean> suspend fun trustThisDeviceIfNecessary(userId: String): Result<Boolean>
/**
* Establishes trust with this device based on the provided [TrustDeviceResponse].
*/
suspend fun trustThisDevice(
userId: String,
trustDeviceResponse: TrustDeviceResponse,
): Result<Unit>
} }

View file

@ -1,5 +1,6 @@
package com.x8bit.bitwarden.data.auth.manager package com.x8bit.bitwarden.data.auth.manager
import com.bitwarden.crypto.TrustDeviceResponse
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.auth.datasource.network.service.DevicesService import com.x8bit.bitwarden.data.auth.datasource.network.service.DevicesService
import com.x8bit.bitwarden.data.auth.manager.util.toUserStateJson import com.x8bit.bitwarden.data.auth.manager.util.toUserStateJson
@ -32,26 +33,31 @@ class TrustedDeviceManagerImpl(
} else { } else {
vaultSdkSource vaultSdkSource
.getTrustDevice(userId = userId) .getTrustDevice(userId = userId)
.flatMap { trustedDevice -> .flatMap { trustThisDevice(userId = userId, trustDeviceResponse = it) }
devicesService
.trustDevice(
appId = authDiskSource.uniqueAppId,
encryptedDevicePrivateKey = trustedDevice.protectedDevicePrivateKey,
encryptedDevicePublicKey = trustedDevice.protectedDevicePublicKey,
encryptedUserKey = trustedDevice.protectedUserKey,
)
.onSuccess {
authDiskSource.storeDeviceKey(
userId = userId,
deviceKey = trustedDevice.deviceKey,
)
authDiskSource.userState = trustedDevice.toUserStateJson(
userId = userId,
previousUserState = requireNotNull(authDiskSource.userState),
)
}
}
.also { authDiskSource.shouldTrustDevice = false } .also { authDiskSource.shouldTrustDevice = false }
.map { true } .map { true }
} }
override suspend fun trustThisDevice(
userId: String,
trustDeviceResponse: TrustDeviceResponse,
): Result<Unit> = devicesService
.trustDevice(
appId = authDiskSource.uniqueAppId,
encryptedDevicePrivateKey = trustDeviceResponse.protectedDevicePrivateKey,
encryptedDevicePublicKey = trustDeviceResponse.protectedDevicePublicKey,
encryptedUserKey = trustDeviceResponse.protectedUserKey,
)
.onSuccess {
authDiskSource.storeDeviceKey(
userId = userId,
deviceKey = trustDeviceResponse.deviceKey,
)
authDiskSource.userState = trustDeviceResponse.toUserStateJson(
userId = userId,
previousUserState = requireNotNull(authDiskSource.userState),
)
}
.also { authDiskSource.shouldTrustDevice = false }
.map { Unit }
} }

View file

@ -207,6 +207,61 @@ class TrustedDeviceManagerTests {
) )
} }
} }
@Test
fun `trustThisDevice when success should return success with true`() = runTest {
val deviceKey = "deviceKey"
val protectedUserKey = "protectedUserKey"
val protectedDevicePrivateKey = "protectedDevicePrivateKey"
val protectedDevicePublicKey = "protectedDevicePublicKey"
val trustDeviceResponse = TrustDeviceResponse(
deviceKey = deviceKey,
protectedUserKey = protectedUserKey,
protectedDevicePrivateKey = protectedDevicePrivateKey,
protectedDevicePublicKey = protectedDevicePublicKey,
)
val trustedDeviceKeysResponseJson = TrustedDeviceKeysResponseJson(
id = "id",
name = "name",
identifier = "identifier",
type = 0,
creationDate = ZonedDateTime.parse("2024-09-13T01:00:00.00Z"),
)
fakeAuthDiskSource.userState = DEFAULT_USER_STATE
fakeAuthDiskSource.shouldTrustDevice = true
coEvery {
devicesService.trustDevice(
appId = "testUniqueAppId",
encryptedUserKey = protectedUserKey,
encryptedDevicePublicKey = protectedDevicePublicKey,
encryptedDevicePrivateKey = protectedDevicePrivateKey,
)
} returns trustedDeviceKeysResponseJson.asSuccess()
every {
trustDeviceResponse.toUserStateJson(
userId = USER_ID,
previousUserState = DEFAULT_USER_STATE,
)
} returns UPDATED_USER_STATE
val result = manager.trustThisDevice(
userId = USER_ID,
trustDeviceResponse = trustDeviceResponse,
)
assertEquals(Unit.asSuccess(), result)
fakeAuthDiskSource.assertDeviceKey(userId = USER_ID, deviceKey = deviceKey)
assertFalse(fakeAuthDiskSource.shouldTrustDevice)
fakeAuthDiskSource.assertUserState(UPDATED_USER_STATE)
coVerify(exactly = 1) {
devicesService.trustDevice(
appId = "testUniqueAppId",
encryptedUserKey = protectedUserKey,
encryptedDevicePublicKey = protectedDevicePublicKey,
encryptedDevicePrivateKey = protectedDevicePrivateKey,
)
}
}
} }
private const val USER_ID: String = "userId" private const val USER_ID: String = "userId"