diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManager.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManager.kt index b13bff9113..d7345429c1 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManager.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManager.kt @@ -1,5 +1,7 @@ package com.x8bit.bitwarden.data.auth.manager +import com.bitwarden.crypto.TrustDeviceResponse + /** * Manager used to establish trust with this device. */ @@ -8,4 +10,12 @@ interface TrustedDeviceManager { * Establishes trust with this device if necessary. */ suspend fun trustThisDeviceIfNecessary(userId: String): Result + + /** + * Establishes trust with this device based on the provided [TrustDeviceResponse]. + */ + suspend fun trustThisDevice( + userId: String, + trustDeviceResponse: TrustDeviceResponse, + ): Result } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManagerImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManagerImpl.kt index 44daee84d9..68b43aebca 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManagerImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManagerImpl.kt @@ -1,5 +1,6 @@ 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.network.service.DevicesService import com.x8bit.bitwarden.data.auth.manager.util.toUserStateJson @@ -32,26 +33,31 @@ class TrustedDeviceManagerImpl( } else { vaultSdkSource .getTrustDevice(userId = userId) - .flatMap { trustedDevice -> - 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), - ) - } - } + .flatMap { trustThisDevice(userId = userId, trustDeviceResponse = it) } .also { authDiskSource.shouldTrustDevice = false } .map { true } } + + override suspend fun trustThisDevice( + userId: String, + trustDeviceResponse: TrustDeviceResponse, + ): Result = 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 } } diff --git a/app/src/test/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManagerTests.kt b/app/src/test/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManagerTests.kt index add0bc439c..d792e20e8e 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManagerTests.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/auth/manager/TrustedDeviceManagerTests.kt @@ -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"