From 6d2b7b02fc71de2a7b310806724ed27e7cecc262 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 16:31:45 +0000 Subject: [PATCH 01/27] SDK Update - com.bitwarden:sdk-android 1.0.0-3966-a09e691a --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 886b24636f0..152984a2229 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-3958-7f09fd2f" +bitwardenSdk = "1.0.0-3966-a09e691a" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From cdcd411823a6c93dc1b3ae9505a7e17be7293aef Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 16:37:58 +0000 Subject: [PATCH 02/27] SDK Update - com.bitwarden:sdk-android 1.0.0-3967-069d7829 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 152984a2229..1767aae37c5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-3966-a09e691a" +bitwardenSdk = "1.0.0-3967-069d7829" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 0319173b947b37f8c59710cf1d871e0b0e2da7e9 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 21:50:28 +0000 Subject: [PATCH 03/27] SDK Update - com.bitwarden:sdk-android 1.0.0-3972-7e4b2cc6 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1767aae37c5..988ac7a3342 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-3967-069d7829" +bitwardenSdk = "1.0.0-3972-7e4b2cc6" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 9feb7e75b898c484ae187f66382f1fb8036a35e8 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 11:25:47 +0000 Subject: [PATCH 04/27] SDK Update - com.bitwarden:sdk-android 1.0.0-3973-ab7ae369 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 988ac7a3342..67f9cce7f0f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-3972-7e4b2cc6" +bitwardenSdk = "1.0.0-3973-ab7ae369" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From d7fec88e265eab54d68fd2c5ae0a4b11b4e59e76 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 14:32:27 +0000 Subject: [PATCH 05/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4001-5c178bed --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 67f9cce7f0f..72448e9108a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-3973-ab7ae369" +bitwardenSdk = "1.0.0-4001-5c178bed" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 32c4790744ed06fbbdb447e217a4d894fca8cc95 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 16:38:33 +0000 Subject: [PATCH 06/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4005-7840f554 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 72448e9108a..76a84d6d657 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4001-5c178bed" +bitwardenSdk = "1.0.0-4005-7840f554" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From e255f41905a81e1309fa8394546324d60ccfbddd Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 16:39:09 +0000 Subject: [PATCH 07/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4006-0d52f617 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 76a84d6d657..8f81a24a7ec 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4005-7840f554" +bitwardenSdk = "1.0.0-4006-0d52f617" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From f954ff7ceabc0be246512b84aef16ce91a30bc9a Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:18:27 +0000 Subject: [PATCH 08/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4016-a8a19d3f --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8f81a24a7ec..d6258ab109b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4006-0d52f617" +bitwardenSdk = "1.0.0-4016-a8a19d3f" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From b157b8e67d24b69984310e9b63e2e0cb6dc5814c Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 18:45:36 +0000 Subject: [PATCH 09/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4033-1cc3a8d0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d6258ab109b..04eec2816fd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4016-a8a19d3f" +bitwardenSdk = "1.0.0-4033-1cc3a8d0" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 60e548e0160431bc179a856899c7153460075ba3 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Tue, 9 Dec 2025 22:32:19 +0000 Subject: [PATCH 10/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4036-becb420b --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 04eec2816fd..6990cb0a37a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4033-1cc3a8d0" +bitwardenSdk = "1.0.0-4036-becb420b" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 5458dba28b286598560b0477ff536578985d4031 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 09:49:53 +0000 Subject: [PATCH 11/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4044-14a6450a --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6990cb0a37a..92d9cebd3f7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4036-becb420b" +bitwardenSdk = "1.0.0-4044-14a6450a" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From bab53e7bb9a05810915ae2b58531df4a8c8d7c13 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 10:12:52 +0000 Subject: [PATCH 12/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4046-b86e0206 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 92d9cebd3f7..976308fa179 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4044-14a6450a" +bitwardenSdk = "1.0.0-4046-b86e0206" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 656e0620767c805ae27ba57a389726f4139d1db9 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 10:14:49 +0000 Subject: [PATCH 13/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4047-26dffec3 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 976308fa179..4772516e428 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4046-b86e0206" +bitwardenSdk = "1.0.0-4047-26dffec3" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From f26bf67507b6062c5bdac494a1e12865fee6231a Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 10:21:10 +0000 Subject: [PATCH 14/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4049-f0d4b0e7 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4772516e428..0fae9c96349 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4047-26dffec3" +bitwardenSdk = "1.0.0-4049-f0d4b0e7" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 1268bf2bbf1459fa74b2666cb6ba299d5e2e0ff1 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 13:12:49 +0000 Subject: [PATCH 15/27] SDK Update - com.bitwarden:sdk-android 1.0.0-4063-ec0231c0 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0fae9c96349..6410ebb6337 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4049-f0d4b0e7" +bitwardenSdk = "1.0.0-4063-ec0231c0" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 03d4366347ce8f02d085f87020860c9fd255cec6 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 19:52:16 +0000 Subject: [PATCH 16/27] SDK Update - com.bitwarden:sdk-android 2.0.0-4076-26df6719 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6410ebb6337..40adce78308 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "1.0.0-4063-ec0231c0" +bitwardenSdk = "2.0.0-4076-26df6719" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 345212babf96c91a72ff631ab3edbb50e89a5aa3 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 20:18:27 +0000 Subject: [PATCH 17/27] SDK Update - com.bitwarden:sdk-android 2.0.0-4078-a004d825 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 40adce78308..2b8090297d2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "2.0.0-4076-26df6719" +bitwardenSdk = "2.0.0-4078-a004d825" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 93f9e7d678b231ba8174c53ad7238fc2ba756d39 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 14:30:44 +0000 Subject: [PATCH 18/27] SDK Update - com.bitwarden:sdk-android 2.0.0-4088-30879c14 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2b8090297d2..ea16d392c58 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "2.0.0-4078-a004d825" +bitwardenSdk = "2.0.0-4088-30879c14" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From f0e05c24bfbd37ff23ee8fceffa0d773b92ea584 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Thu, 11 Dec 2025 18:46:19 +0000 Subject: [PATCH 19/27] SDK Update - com.bitwarden:sdk-android 2.0.0-4101-fc6d3170 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ea16d392c58..4aa3858d887 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "2.0.0-4088-30879c14" +bitwardenSdk = "2.0.0-4101-fc6d3170" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From edb1a936306257e447d6b28d5034450a68959f86 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 12:26:42 +0000 Subject: [PATCH 20/27] SDK Update - com.bitwarden:sdk-android 2.0.0-4109-fd11c49b --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4aa3858d887..1442869dd8d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "2.0.0-4101-fc6d3170" +bitwardenSdk = "2.0.0-4109-fd11c49b" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From e88b750ed9288b8c21b6078e9a7318c9b0aaa980 Mon Sep 17 00:00:00 2001 From: "bw-ghapp[bot]" <178206702+bw-ghapp[bot]@users.noreply.github.com> Date: Fri, 12 Dec 2025 15:08:46 +0000 Subject: [PATCH 21/27] SDK Update - com.bitwarden:sdk-android 2.0.0-4110-bd636a4f --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1442869dd8d..73b7b7ef889 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.3" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "2.0.0-4109-fd11c49b" +bitwardenSdk = "2.0.0-4110-bd636a4f" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 29cbcaf68bb354437fee52e9eb37a34d92b14c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonc=CC=A7alves?= Date: Mon, 15 Dec 2025 17:40:40 +0000 Subject: [PATCH 22/27] pm-29777 Fix breaking changes --- .../auth/repository/AuthRepositoryImpl.kt | 84 +- .../manager/BitwardenCredentialManagerImpl.kt | 1 + .../AuthenticatorBridgeRepositoryImpl.kt | 11 +- .../vault/datasource/sdk/VaultSdkSource.kt | 1 + .../datasource/sdk/VaultSdkSourceImpl.kt | 3 +- ...edentialAuthenticationUserInterfaceImpl.kt | 2 +- ...CredentialRegistrationUserInterfaceImpl.kt | 2 +- .../Fido2CredentialSearchUserInterfaceImpl.kt | 2 +- .../sdk/model/Fido2CredentialStoreImpl.kt | 6 +- .../data/vault/manager/VaultLockManager.kt | 5 +- .../vault/manager/VaultLockManagerImpl.kt | 20 +- .../data/vault/repository/VaultRepository.kt | 1 + .../vault/repository/VaultRepositoryImpl.kt | 13 +- ...ppedAccountCryptographicStateExtensions.kt | 35 + .../auth/repository/AuthRepositoryTest.kt | 716 +++++++++++------- .../manager/BitwardenCredentialManagerTest.kt | 3 + .../AuthenticatorBridgeRepositoryTest.kt | 73 +- .../datasource/sdk/VaultSdkSourceTest.kt | 18 +- ...icKeyAuthenticatorAssertionResponseUtil.kt | 1 - ...KeyAuthenticatorAttestationResponseUtil.kt | 1 - ...nticatorAssertionResponseExtensionsTest.kt | 2 - ...icatorAttestationResponseExtensionsTest.kt | 1 - .../vault/manager/VaultLockManagerTest.kt | 307 +++++--- .../vault/repository/VaultRepositoryTest.kt | 185 +++-- 24 files changed, 976 insertions(+), 517 deletions(-) create mode 100644 app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensions.kt diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt index 26af426919d..3693d9af140 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt @@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.auth.repository import com.bitwarden.core.AuthRequestMethod import com.bitwarden.core.InitUserCryptoMethod +import com.bitwarden.core.WrappedAccountCryptographicState import com.bitwarden.core.data.manager.dispatcher.DispatcherManager import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow import com.bitwarden.core.data.util.asFailure @@ -112,6 +113,7 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource import com.x8bit.bitwarden.data.vault.repository.VaultRepository import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockError import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult +import com.x8bit.bitwarden.data.vault.repository.util.createWrappedAccountCryptographicState import com.x8bit.bitwarden.data.vault.repository.util.toSdkMasterPasswordUnlock import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -514,6 +516,7 @@ class AuthRepositoryImpl( ) val signingKey = accountKeys?.signatureKeyPair?.wrappedSigningKey val securityState = accountKeys?.securityState?.securityState + val signedPublicKey = accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey checkForVaultUnlockError( onVaultUnlockError = { error -> @@ -521,10 +524,13 @@ class AuthRepositoryImpl( }, ) { unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = securityState, + signingKey = signingKey, + signedPublicKey = signedPublicKey, + ), accountProfile = profile, - privateKey = privateKey, - signingKey = signingKey, - securityState = securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricalKey), @@ -1805,15 +1811,20 @@ class AuthRepositoryImpl( accessToken = loginResponse.accessToken, ) .map { + val accountKeys = loginResponse.accountKeys unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = accountKeys?.securityState?.securityState, + signingKey = accountKeys?.signatureKeyPair?.wrappedSigningKey, + signedPublicKey = + accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey, + ), accountProfile = profile, - privateKey = privateKey, initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( masterKey = it.masterKey, userKey = key, ), - securityState = loginResponse.accountKeys?.securityState?.securityState, - signingKey = loginResponse.accountKeys?.signatureKeyPair?.wrappedSigningKey, ) } .fold( @@ -1834,11 +1845,16 @@ class AuthRepositoryImpl( organizationIdentifier = orgIdentifier, ) .map { keyConnectorResponse -> + val accountKeys = loginResponse.accountKeys val result = unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = keyConnectorResponse.keys.private, + securityState = accountKeys?.securityState?.securityState, + signingKey = accountKeys?.signatureKeyPair?.wrappedSigningKey, + signedPublicKey = + accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey, + ), accountProfile = profile, - privateKey = keyConnectorResponse.keys.private, - securityState = loginResponse.accountKeys?.securityState?.securityState, - signingKey = loginResponse.accountKeys?.signatureKeyPair?.wrappedSigningKey, initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( masterKey = keyConnectorResponse.masterKey, userKey = keyConnectorResponse.encryptedUserKey, @@ -1900,10 +1916,14 @@ class AuthRepositoryImpl( ) return unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = loginResponse.accountKeys?.securityState?.securityState, + signingKey = loginResponse.accountKeys?.signatureKeyPair?.wrappedSigningKey, + signedPublicKey = + loginResponse.accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey, + ), accountProfile = profile, - privateKey = privateKey, - securityState = loginResponse.accountKeys?.securityState?.securityState, - signingKey = loginResponse.accountKeys?.signatureKeyPair?.wrappedSigningKey, initUserCryptoMethod = initUserCryptoMethod, ) } @@ -1923,10 +1943,14 @@ class AuthRepositoryImpl( if (privateKey != null && key != null) { deviceData?.let { model -> return unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = loginResponse.accountKeys?.securityState?.securityState, + signingKey = loginResponse.accountKeys?.signatureKeyPair?.wrappedSigningKey, + signedPublicKey = + loginResponse.accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey, + ), accountProfile = profile, - privateKey = privateKey, - securityState = loginResponse.accountKeys?.securityState?.securityState, - signingKey = loginResponse.accountKeys?.signatureKeyPair?.wrappedSigningKey, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = model.privateKey, method = model @@ -1958,6 +1982,8 @@ class AuthRepositoryImpl( profile = profile, privateKey = accountKeys.publicKeyEncryptionKeyPair.wrappedPrivateKey, securityState = accountKeys.securityState?.securityState, + signedPublicKey = + accountKeys.publicKeyEncryptionKeyPair.signedPublicKey, signingKey = accountKeys.signatureKeyPair?.wrappedSigningKey, ) } @@ -1968,6 +1994,7 @@ class AuthRepositoryImpl( profile = profile, privateKey = privateKey, securityState = null, + signedPublicKey = null, signingKey = null, ) } @@ -1983,6 +2010,7 @@ class AuthRepositoryImpl( profile: AccountJson.Profile, privateKey: String, securityState: String?, + signedPublicKey: String?, signingKey: String?, ): VaultUnlockResult? { var vaultUnlockResult: VaultUnlockResult? = null @@ -2000,10 +2028,13 @@ class AuthRepositoryImpl( // For approved requests the key will always be present. val userKey = requireNotNull(request.key) vaultUnlockResult = unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = securityState, + signingKey = signingKey, + signedPublicKey = signedPublicKey, + ), accountProfile = profile, - privateKey = privateKey, - signingKey = signingKey, - securityState = securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = pendingRequest.requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = userKey), @@ -2029,10 +2060,13 @@ class AuthRepositoryImpl( } vaultUnlockResult = unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = securityState, + signingKey = signingKey, + signedPublicKey = signedPublicKey, + ), accountProfile = profile, - privateKey = privateKey, - securityState = securityState, - signingKey = signingKey, initUserCryptoMethod = InitUserCryptoMethod.DeviceKey( deviceKey = deviceKey, protectedDevicePrivateKey = encryptedPrivateKey, @@ -2050,20 +2084,16 @@ class AuthRepositoryImpl( * A helper function to unlock the vault for the user associated with the [accountProfile]. */ private suspend fun unlockVault( + accountCryptographicState: WrappedAccountCryptographicState, accountProfile: AccountJson.Profile, - privateKey: String, - securityState: String?, - signingKey: String?, initUserCryptoMethod: InitUserCryptoMethod, ): VaultUnlockResult { val userId = accountProfile.userId return vaultRepository.unlockVault( + accountCryptographicState = accountCryptographicState, userId = userId, email = accountProfile.email, kdf = accountProfile.toSdkParams(), - privateKey = privateKey, - signingKey = signingKey, - securityState = securityState, initUserCryptoMethod = initUserCryptoMethod, // The value for the organization keys here will typically be null. We can separately // unlock the vault for organization data after receiving the sync response if this diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/credentials/manager/BitwardenCredentialManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/credentials/manager/BitwardenCredentialManagerImpl.kt index 9ee8c56eea7..31e82a1892d 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/credentials/manager/BitwardenCredentialManagerImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/credentials/manager/BitwardenCredentialManagerImpl.kt @@ -258,6 +258,7 @@ class BitwardenCredentialManagerImpl( userId = userId, fido2CredentialStore = fido2CredentialStore, relyingPartyId = relyingPartyId, + userHandle = null, ) .fold( onSuccess = { it }, 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 344fc03bfb2..ce9f492eacc 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 @@ -16,6 +16,7 @@ import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource import com.x8bit.bitwarden.data.vault.datasource.sdk.ScopedVaultSdkSource import com.x8bit.bitwarden.data.vault.datasource.sdk.model.InitializeCryptoResult import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult +import com.x8bit.bitwarden.data.vault.repository.util.createWrappedAccountCryptographicState import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCipher import com.x8bit.bitwarden.data.vault.repository.util.toVaultUnlockResult @@ -137,17 +138,21 @@ class AuthenticatorBridgeRepositoryImpl( ?.securityState ?.securityState val signingKey = accountKeys?.signatureKeyPair?.wrappedSigningKey + val signedPublicKey = accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey return scopedVaultSdkSource .initializeCrypto( userId = userId, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = securityState, + signingKey = signingKey, + signedPublicKey = signedPublicKey, + ), userId = userId, kdfParams = account.profile.toSdkParams(), email = account.profile.email, - privateKey = privateKey, - securityState = securityState, - signingKey = signingKey, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = decryptedUserKey, ), diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSource.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSource.kt index d061d7e71a5..c2c2cd10b8f 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSource.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSource.kt @@ -487,6 +487,7 @@ interface VaultSdkSource { userId: String, fido2CredentialStore: Fido2CredentialStore, relyingPartyId: String, + userHandle: String?, ): Result> /** diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceImpl.kt index 131d1844427..2f18c9e91c7 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceImpl.kt @@ -599,6 +599,7 @@ class VaultSdkSourceImpl( userId: String, fido2CredentialStore: Fido2CredentialStore, relyingPartyId: String, + userHandle: String?, ): Result> = runCatchingWithLogs { getClient(userId) .platform() @@ -607,7 +608,7 @@ class VaultSdkSourceImpl( userInterface = Fido2CredentialSearchUserInterfaceImpl(), credentialStore = fido2CredentialStore, ) - .silentlyDiscoverCredentials(relyingPartyId) + .silentlyDiscoverCredentials(relyingPartyId, userHandle?.toByteArray()) } override suspend fun makeUpdateKdf( diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialAuthenticationUserInterfaceImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialAuthenticationUserInterfaceImpl.kt index 1836dc26e36..c38b1bfaf26 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialAuthenticationUserInterfaceImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialAuthenticationUserInterfaceImpl.kt @@ -28,7 +28,7 @@ class Fido2CredentialAuthenticationUserInterfaceImpl( newCredential: Fido2CredentialNewView, ): CheckUserAndPickCredentialForCreationResult = throw IllegalStateException() - override suspend fun isVerificationEnabled(): Boolean = isVerificationSupported + override fun isVerificationEnabled(): Boolean = isVerificationSupported override suspend fun pickCredentialForAuthentication( availableCredentials: List, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialRegistrationUserInterfaceImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialRegistrationUserInterfaceImpl.kt index 0afab79b1e4..9be84bd30ce 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialRegistrationUserInterfaceImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialRegistrationUserInterfaceImpl.kt @@ -32,7 +32,7 @@ class Fido2CredentialRegistrationUserInterfaceImpl( checkUserResult = CheckUserResult(userPresent = true, userVerified = true), ) - override suspend fun isVerificationEnabled(): Boolean = isVerificationSupported + override fun isVerificationEnabled(): Boolean = isVerificationSupported override suspend fun pickCredentialForAuthentication( availableCredentials: List, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialSearchUserInterfaceImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialSearchUserInterfaceImpl.kt index ff1614901af..0501f6709c0 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialSearchUserInterfaceImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialSearchUserInterfaceImpl.kt @@ -29,7 +29,7 @@ class Fido2CredentialSearchUserInterfaceImpl : Fido2UserInterface { // Always return true for this property because any problems with verification should // be handled downstream where the app can actually offer verification methods. - override suspend fun isVerificationEnabled(): Boolean = true + override fun isVerificationEnabled(): Boolean = true override suspend fun pickCredentialForAuthentication( availableCredentials: List, diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialStoreImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialStoreImpl.kt index 8f0f596be20..793cb1675cf 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialStoreImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/Fido2CredentialStoreImpl.kt @@ -42,7 +42,11 @@ class Fido2CredentialStoreImpl( * @param ids Optional list of FIDO 2 credential ID's to find. * @param ripId Relying Party ID to find. */ - override suspend fun findCredentials(ids: List?, ripId: String): List = + override suspend fun findCredentials( + ids: List?, + ripId: String, + userHandle: ByteArray?, + ): List = vaultRepository .decryptCipherListResultStateFlow .value diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManager.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManager.kt index 53fc1f91538..2718cabc391 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManager.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManager.kt @@ -1,6 +1,7 @@ package com.x8bit.bitwarden.data.vault.manager import com.bitwarden.core.InitUserCryptoMethod +import com.bitwarden.core.WrappedAccountCryptographicState import com.bitwarden.crypto.Kdf import com.bitwarden.sdk.AuthClient import com.x8bit.bitwarden.data.vault.manager.model.VaultStateEvent @@ -61,12 +62,10 @@ interface VaultLockManager { */ @Suppress("LongParameterList") suspend fun unlockVault( + accountCryptographicState: WrappedAccountCryptographicState, userId: String, email: String, kdf: Kdf, - privateKey: String, - signingKey: String?, - securityState: String?, initUserCryptoMethod: InitUserCryptoMethod, organizationKeys: Map?, ): VaultUnlockResult diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt index c3a7a362173..7d18788fa7b 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerImpl.kt @@ -7,6 +7,7 @@ import android.content.IntentFilter import com.bitwarden.core.InitOrgCryptoRequest import com.bitwarden.core.InitUserCryptoMethod import com.bitwarden.core.InitUserCryptoRequest +import com.bitwarden.core.WrappedAccountCryptographicState import com.bitwarden.core.data.manager.dispatcher.DispatcherManager import com.bitwarden.core.data.manager.realtime.RealtimeManager import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow @@ -39,6 +40,7 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.model.InitializeCryptoResul import com.x8bit.bitwarden.data.vault.manager.model.VaultStateEvent import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult +import com.x8bit.bitwarden.data.vault.repository.util.createWrappedAccountCryptographicState import com.x8bit.bitwarden.data.vault.repository.util.logTag import com.x8bit.bitwarden.data.vault.repository.util.statusFor import com.x8bit.bitwarden.data.vault.repository.util.toVaultUnlockResult @@ -171,12 +173,10 @@ class VaultLockManagerImpl( @Suppress("LongMethod") override suspend fun unlockVault( + accountCryptographicState: WrappedAccountCryptographicState, userId: String, email: String, kdf: Kdf, - privateKey: String, - signingKey: String?, - securityState: String?, initUserCryptoMethod: InitUserCryptoMethod, organizationKeys: Map?, ): VaultUnlockResult = withContext(context = NonCancellable) { @@ -187,13 +187,11 @@ class VaultLockManagerImpl( .initializeCrypto( userId = userId, request = InitUserCryptoRequest( + accountCryptographicState = accountCryptographicState, kdfParams = kdf, email = email, - privateKey = privateKey, method = initUserCryptoMethod, userId = userId, - signingKey = signingKey, - securityState = securityState, ), ) .flatMap { result -> @@ -693,14 +691,18 @@ class VaultLockManagerImpl( ) val signingKey = accountKeys?.signatureKeyPair?.wrappedSigningKey val securityState = accountKeys?.securityState?.securityState + val signedPublicKey = accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey val organizationKeys = authDiskSource.getOrganizationKeys(userId = userId) return unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = securityState, + signingKey = signingKey, + signedPublicKey = signedPublicKey, + ), userId = userId, email = account.profile.email, kdf = account.profile.toSdkParams(), - privateKey = privateKey, - signingKey = signingKey, - securityState = securityState, initUserCryptoMethod = initUserCryptoMethod, organizationKeys = organizationKeys, ) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepository.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepository.kt index bef061f6c0a..7f725ebbaef 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepository.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepository.kt @@ -92,6 +92,7 @@ interface VaultRepository : userId: String, fido2CredentialStore: Fido2CredentialStore, relyingPartyId: String, + userHandle: String?, ): Result> /** diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt index 69d1b1d991a..29bfa649bf2 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryImpl.kt @@ -41,6 +41,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.GenerateTotpResult import com.x8bit.bitwarden.data.vault.repository.model.ImportCredentialsResult import com.x8bit.bitwarden.data.vault.repository.model.TotpCodeResult import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult +import com.x8bit.bitwarden.data.vault.repository.util.createWrappedAccountCryptographicState import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCipher import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkFolder import com.x8bit.bitwarden.data.vault.repository.util.toSdkAccount @@ -253,12 +254,14 @@ class VaultRepositoryImpl( userId: String, fido2CredentialStore: Fido2CredentialStore, relyingPartyId: String, + userHandle: String?, ): Result> = vaultSdkSource .silentlyDiscoverCredentials( userId = userId, fido2CredentialStore = fido2CredentialStore, relyingPartyId = relyingPartyId, + userHandle = userHandle, ) override fun emitTotpCodeResult(totpCodeResult: TotpCodeResult) { @@ -543,15 +546,19 @@ class VaultRepositoryImpl( ) val signingKey = accountKeys?.signatureKeyPair?.wrappedSigningKey val securityState = accountKeys?.securityState?.securityState + val signedPublicKey = accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey val organizationKeys = authDiskSource .getOrganizationKeys(userId = userId) return vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = securityState, + signingKey = signingKey, + signedPublicKey = signedPublicKey, + ), userId = userId, email = account.profile.email, kdf = account.profile.toSdkParams(), - privateKey = privateKey, - signingKey = signingKey, - securityState = securityState, initUserCryptoMethod = initUserCryptoMethod, organizationKeys = organizationKeys, ) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensions.kt new file mode 100644 index 00000000000..ba518919a59 --- /dev/null +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensions.kt @@ -0,0 +1,35 @@ +package com.x8bit.bitwarden.data.vault.repository.util + +import com.bitwarden.core.WrappedAccountCryptographicState + +/** + * Creates a [WrappedAccountCryptographicState] based on the available cryptographic parameters. + * + * Returns [WrappedAccountCryptographicState.V2] if signing key, signed public key, and security + * state are present, otherwise returns [WrappedAccountCryptographicState.V1]. + * + * @param privateKey The user's wrapped private key. + * @param signingKey The user's wrapped signing key (V2 only). + * @param signedPublicKey The user's signed public key (V2 only). + * @param securityState The user's signed security state (V2 only). + */ +fun createWrappedAccountCryptographicState( + privateKey: String, + securityState: String?, + signingKey: String?, + signedPublicKey: String?, +): WrappedAccountCryptographicState { + return if (signingKey != null && signedPublicKey != null && securityState != null) { + WrappedAccountCryptographicState.V2( + privateKey = privateKey, + securityState = securityState, + signingKey = signingKey, + signedPublicKey = signedPublicKey, + ) + } else { + // V1 user: only private key + WrappedAccountCryptographicState.V1( + privateKey = privateKey, + ) + } +} diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt index 9f925aae9a0..60765dfe4b7 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt @@ -132,6 +132,7 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.VaultSdkSource import com.x8bit.bitwarden.data.vault.repository.VaultRepository import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult +import com.x8bit.bitwarden.data.vault.repository.util.createWrappedAccountCryptographicState import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every @@ -403,18 +404,23 @@ class AuthRepositoryTest { } returns successResponse.asSuccess() coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -478,18 +484,23 @@ class AuthRepositoryTest { uniqueAppId = UNIQUE_APP_ID, ) vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -1410,12 +1421,15 @@ class AuthRepositoryTest { fakeAuthDiskSource.storeAccountKeys(userId = USER_ID_1, accountKeys = null) coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricalKey), @@ -1431,12 +1445,15 @@ class AuthRepositoryTest { ) coVerify(exactly = 1) { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricalKey), @@ -1464,12 +1481,15 @@ class AuthRepositoryTest { fakeAuthDiskSource.storeOrganizationKeys(userId = USER_ID_1, organizationKeys = orgKeys) coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = accountKeys.publicKeyEncryptionKeyPair.wrappedPrivateKey, + securityState = accountKeys.securityState?.securityState, + signedPublicKey = accountKeys.publicKeyEncryptionKeyPair.signedPublicKey, + signingKey = accountKeys.signatureKeyPair?.wrappedSigningKey, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = accountKeys.publicKeyEncryptionKeyPair.wrappedPrivateKey, - signingKey = accountKeys.signatureKeyPair?.wrappedSigningKey, - securityState = accountKeys.securityState?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricKey), @@ -1486,12 +1506,15 @@ class AuthRepositoryTest { coVerify(exactly = 1) { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = accountKeys.publicKeyEncryptionKeyPair.wrappedPrivateKey, + securityState = accountKeys.securityState?.securityState, + signedPublicKey = accountKeys.publicKeyEncryptionKeyPair.signedPublicKey, + signingKey = accountKeys.signatureKeyPair?.wrappedSigningKey, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = accountKeys.publicKeyEncryptionKeyPair.wrappedPrivateKey, - signingKey = accountKeys.signatureKeyPair?.wrappedSigningKey, - securityState = accountKeys.securityState?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricKey), @@ -1517,12 +1540,15 @@ class AuthRepositoryTest { fakeAuthDiskSource.storeOrganizationKeys(userId = USER_ID_1, organizationKeys = orgKeys) coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricalKey), @@ -1539,12 +1565,15 @@ class AuthRepositoryTest { coVerify(exactly = 1) { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricalKey), @@ -1569,12 +1598,15 @@ class AuthRepositoryTest { val error = Throwable("Fail") coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricalKey), @@ -1591,12 +1623,15 @@ class AuthRepositoryTest { coVerify(exactly = 1) { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricalKey), @@ -1806,18 +1841,23 @@ class AuthRepositoryTest { } returns successResponse.asSuccess() coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -1862,18 +1902,23 @@ class AuthRepositoryTest { uniqueAppId = UNIQUE_APP_ID, ) vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -1915,18 +1960,23 @@ class AuthRepositoryTest { val error = Throwable("Fail") coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -1978,18 +2028,23 @@ class AuthRepositoryTest { ) vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -2077,18 +2132,23 @@ class AuthRepositoryTest { } coVerify(exactly = 0) { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = any(), organizationKeys = null, ) @@ -2120,18 +2180,23 @@ class AuthRepositoryTest { } returns successResponse.asSuccess() coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -2186,18 +2251,23 @@ class AuthRepositoryTest { uniqueAppId = UNIQUE_APP_ID, ) vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -2314,18 +2384,23 @@ class AuthRepositoryTest { } returns successResponse.asSuccess() coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -2416,18 +2491,23 @@ class AuthRepositoryTest { val error = Throwable("Fail") coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -2485,18 +2565,23 @@ class AuthRepositoryTest { } returns successResponse.asSuccess() coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -2538,18 +2623,23 @@ class AuthRepositoryTest { twoFactorData = rememberedTwoFactorData, ) vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -2734,18 +2824,23 @@ class AuthRepositoryTest { } returns SINGLE_USER_STATE_1 coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = DEVICE_REQUEST_PRIVATE_KEY, method = AuthRequestMethod.MasterKey( @@ -2790,18 +2885,23 @@ class AuthRepositoryTest { ) vaultRepository.syncIfNecessary() vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = DEVICE_REQUEST_PRIVATE_KEY, method = AuthRequestMethod.MasterKey( @@ -2848,18 +2948,23 @@ class AuthRepositoryTest { } returns SINGLE_USER_STATE_1 coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = DEVICE_REQUEST_PRIVATE_KEY, method = AuthRequestMethod.MasterKey( @@ -2904,18 +3009,23 @@ class AuthRepositoryTest { ) vaultRepository.syncIfNecessary() vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = DEVICE_REQUEST_PRIVATE_KEY, method = AuthRequestMethod.MasterKey( @@ -3054,18 +3164,23 @@ class AuthRepositoryTest { } returns SINGLE_USER_STATE_1 coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = SINGLE_USER_STATE_1.activeUserId, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = DEVICE_REQUEST_PRIVATE_KEY, method = AuthRequestMethod.MasterKey( @@ -3400,12 +3515,15 @@ class AuthRepositoryTest { } returns keyConnectorMasterKeyResponseJson.asSuccess() coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "privateKey", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = "privateKey", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( masterKey = masterKey, userKey = "key", @@ -3447,12 +3565,15 @@ class AuthRepositoryTest { accessToken = ACCESS_TOKEN, ) vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "privateKey", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = "privateKey", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( masterKey = masterKey, userKey = "key", @@ -3597,12 +3718,15 @@ class AuthRepositoryTest { } returns keyConnectorResponse.asSuccess() coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = PRIVATE_KEY, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( masterKey = masterKey, userKey = ENCRYPTED_USER_KEY, @@ -3653,12 +3777,15 @@ class AuthRepositoryTest { organizationIdentifier = ORGANIZATION_IDENTIFIER, ) vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "privateKey", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = "privateKey", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( masterKey = masterKey, userKey = ENCRYPTED_USER_KEY, @@ -3773,12 +3900,15 @@ class AuthRepositoryTest { coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = PRIVATE_KEY, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( masterKey = masterKey, userKey = ENCRYPTED_USER_KEY, @@ -3847,18 +3977,23 @@ class AuthRepositoryTest { } returns SINGLE_USER_STATE_1 coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = DEVICE_REQUEST_PRIVATE_KEY, method = AuthRequestMethod.UserKey( @@ -3902,18 +4037,23 @@ class AuthRepositoryTest { ) vaultRepository.syncIfNecessary() vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = DEVICE_REQUEST_PRIVATE_KEY, method = AuthRequestMethod.UserKey( @@ -4014,18 +4154,23 @@ class AuthRepositoryTest { ) coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.DeviceKey( deviceKey = deviceKey, protectedDevicePrivateKey = encryptedPrivateKey, @@ -4079,18 +4224,23 @@ class AuthRepositoryTest { uniqueAppId = UNIQUE_APP_ID, ) vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.DeviceKey( deviceKey = deviceKey, protectedDevicePrivateKey = encryptedPrivateKey, @@ -4130,18 +4280,23 @@ class AuthRepositoryTest { fakeAuthDiskSource.storePendingAuthRequest(USER_ID_1, pendingAuthRequest) coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = pendingAuthRequest.requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = authRequestKey), @@ -4193,18 +4348,23 @@ class AuthRepositoryTest { uniqueAppId = UNIQUE_APP_ID, ) vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = SINGLE_USER_STATE_1.activeAccount.profile.email, kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( requestPrivateKey = pendingAuthRequest.requestPrivateKey, method = AuthRequestMethod.UserKey(protectedUserKey = authRequestKey), @@ -6812,18 +6972,23 @@ class AuthRepositoryTest { } returns successResponse.asSuccess() coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, @@ -6885,18 +7050,23 @@ class AuthRepositoryTest { } returns successResponse.asSuccess() coEvery { vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = successResponse.accountKeys + ?.securityState + ?.securityState, + signedPublicKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = successResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + ), userId = USER_ID_1, email = EMAIL, kdf = ACCOUNT_1.profile.toSdkParams(), - privateKey = successResponse.accountKeys!! - .publicKeyEncryptionKeyPair - .wrappedPrivateKey, - signingKey = successResponse.accountKeys - ?.signatureKeyPair - ?.wrappedSigningKey, - securityState = successResponse.accountKeys - ?.securityState - ?.securityState, initUserCryptoMethod = InitUserCryptoMethod.Password( password = PASSWORD, userKey = successResponse.key!!, diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/credentials/manager/BitwardenCredentialManagerTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/credentials/manager/BitwardenCredentialManagerTest.kt index caa355225cd..94060f0db96 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/credentials/manager/BitwardenCredentialManagerTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/credentials/manager/BitwardenCredentialManagerTest.kt @@ -1165,6 +1165,7 @@ class BitwardenCredentialManagerTest { userId = "mockUserId", fido2CredentialStore = any(), relyingPartyId = "mockRpId-1", + userHandle = null, ) } returns fido2CredentialAutofillViews.asSuccess() every { @@ -1304,6 +1305,7 @@ class BitwardenCredentialManagerTest { userId = "mockUserId", fido2CredentialStore = any(), relyingPartyId = "mockRpId-1", + userHandle = null, ) } returns fido2CredentialAutofillViews.asSuccess() every { @@ -1425,6 +1427,7 @@ class BitwardenCredentialManagerTest { userId = "mockUserId", fido2CredentialStore = any(), relyingPartyId = "mockRpId-1", + userHandle = null, ) } returns fido2CredentialAutofillViews.asSuccess() every { 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 99a0ff2a343..ef03d491019 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 @@ -23,6 +23,7 @@ import com.x8bit.bitwarden.data.platform.repository.util.sanitizeTotpUri import com.x8bit.bitwarden.data.vault.datasource.disk.VaultDiskSource import com.x8bit.bitwarden.data.vault.datasource.sdk.ScopedVaultSdkSource import com.x8bit.bitwarden.data.vault.datasource.sdk.model.InitializeCryptoResult +import com.x8bit.bitwarden.data.vault.repository.util.createWrappedAccountCryptographicState import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCipher import io.mockk.coEvery import io.mockk.coVerify @@ -86,15 +87,18 @@ class AuthenticatorBridgeRepositoryTest { scopedVaultSdkSource.initializeCrypto( userId = USER_1_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = USER_1_PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_1_ID, kdfParams = Kdf.Argon2id(iterations = 0U, memory = 0U, parallelism = 0U), email = USER_1_EMAIL, - privateKey = USER_1_PRIVATE_KEY, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = USER_1_UNLOCK_KEY, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -102,15 +106,18 @@ class AuthenticatorBridgeRepositoryTest { scopedVaultSdkSource.initializeCrypto( userId = USER_2_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = USER_2_PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_2_ID, kdfParams = Kdf.Argon2id(iterations = 0U, memory = 0U, parallelism = 0U), email = USER_2_EMAIL, - privateKey = USER_2_PRIVATE_KEY, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = USER_2_UNLOCK_KEY, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -200,15 +207,18 @@ class AuthenticatorBridgeRepositoryTest { scopedVaultSdkSource.initializeCrypto( userId = USER_2_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = USER_2_PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_2_ID, kdfParams = Kdf.Argon2id(iterations = 0U, memory = 0U, parallelism = 0U), email = USER_2_EMAIL, - privateKey = USER_2_PRIVATE_KEY, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = USER_2_UNLOCK_KEY, ), - signingKey = null, - securityState = null, ), ) scopedVaultSdkSource.initializeOrganizationCrypto( @@ -239,15 +249,18 @@ class AuthenticatorBridgeRepositoryTest { scopedVaultSdkSource.initializeCrypto( userId = USER_1_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = USER_1_PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_1_ID, kdfParams = Kdf.Argon2id(iterations = 0U, memory = 0U, parallelism = 0U), email = USER_1_EMAIL, - privateKey = USER_1_PRIVATE_KEY, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = USER_1_UNLOCK_KEY, ), - signingKey = null, - securityState = null, ), ) scopedVaultSdkSource.initializeOrganizationCrypto( @@ -262,15 +275,18 @@ class AuthenticatorBridgeRepositoryTest { scopedVaultSdkSource.initializeCrypto( userId = USER_2_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = USER_2_PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_2_ID, kdfParams = Kdf.Argon2id(iterations = 0U, memory = 0U, parallelism = 0U), email = USER_2_EMAIL, - privateKey = USER_2_PRIVATE_KEY, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = USER_2_UNLOCK_KEY, ), - signingKey = null, - securityState = null, ), ) scopedVaultSdkSource.initializeOrganizationCrypto( @@ -297,15 +313,18 @@ class AuthenticatorBridgeRepositoryTest { scopedVaultSdkSource.initializeCrypto( userId = USER_1_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = USER_1_PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_1_ID, kdfParams = Kdf.Argon2id(iterations = 0U, memory = 0U, parallelism = 0U), email = USER_1_EMAIL, - privateKey = USER_1_PRIVATE_KEY, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = USER_1_UNLOCK_KEY, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.AuthenticationError(error = Throwable()).asSuccess() @@ -319,29 +338,35 @@ class AuthenticatorBridgeRepositoryTest { scopedVaultSdkSource.initializeCrypto( userId = USER_1_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = USER_1_PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_1_ID, kdfParams = Kdf.Argon2id(iterations = 0U, memory = 0U, parallelism = 0U), email = USER_1_EMAIL, - privateKey = USER_1_PRIVATE_KEY, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = USER_1_UNLOCK_KEY, ), - signingKey = null, - securityState = null, ), ) scopedVaultSdkSource.initializeCrypto( userId = USER_2_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = USER_2_PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_2_ID, kdfParams = Kdf.Argon2id(iterations = 0U, memory = 0U, parallelism = 0U), email = USER_2_EMAIL, - privateKey = USER_2_PRIVATE_KEY, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = USER_2_UNLOCK_KEY, ), - signingKey = null, - securityState = null, ), ) scopedVaultSdkSource.initializeOrganizationCrypto( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceTest.kt index 30fbf90a386..3925d97cd8f 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/VaultSdkSourceTest.kt @@ -1394,18 +1394,24 @@ class VaultSdkSourceTest { val userId = "userId" val fido2CredentialStore: Fido2CredentialStore = mockk() val relyingPartyId = "relyingPartyId" + val userHandle = "mockUserHandle" val mockAutofillView = Fido2CredentialAutofillView( credentialId = byteArrayOf(0), cipherId = "mockCipherId", rpId = "mockRpId", userNameForUi = "mockUserNameForUi", - userHandle = "mockUserHandle".toByteArray(), + userHandle = userHandle.toByteArray(), hasCounter = false, ) val autofillViews = listOf(mockAutofillView) val authenticator: ClientFido2Authenticator = mockk { - coEvery { silentlyDiscoverCredentials(relyingPartyId) } returns autofillViews + coEvery { + silentlyDiscoverCredentials( + relyingPartyId, + userHandle.toByteArray(), + ) + } returns autofillViews } every { clientFido2.authenticator( @@ -1418,6 +1424,7 @@ class VaultSdkSourceTest { userId = userId, fido2CredentialStore = fido2CredentialStore, relyingPartyId = relyingPartyId, + userHandle = userHandle, ) assertEquals( @@ -1432,6 +1439,7 @@ class VaultSdkSourceTest { val userId = "userId" val fido2CredentialStore: Fido2CredentialStore = mockk() val relyingPartyId = "relyingPartyId" + val userHandle = "mockUserHandle" coEvery { clientFido2 @@ -1439,7 +1447,10 @@ class VaultSdkSourceTest { userInterface = Fido2CredentialSearchUserInterfaceImpl(), credentialStore = fido2CredentialStore, ) - .silentlyDiscoverCredentials(relyingPartyId) + .silentlyDiscoverCredentials( + relyingPartyId, + userHandle.toByteArray(), + ) } throws BitwardenException.SilentlyDiscoverCredentials( mockk("mockException"), ) @@ -1448,6 +1459,7 @@ class VaultSdkSourceTest { userId = userId, fido2CredentialStore = fido2CredentialStore, relyingPartyId = relyingPartyId, + userHandle = userHandle, ) assertTrue(result.isFailure) diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/PublicKeyAuthenticatorAssertionResponseUtil.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/PublicKeyAuthenticatorAssertionResponseUtil.kt index 8f0cbbcdd96..2bc413f5703 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/PublicKeyAuthenticatorAssertionResponseUtil.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/PublicKeyAuthenticatorAssertionResponseUtil.kt @@ -18,7 +18,6 @@ fun createMockPublicKeyAssertionResponse(number: Int) = clientExtensionResults = ClientExtensionResults( credProps = CredPropsResult( rk = true, - authenticatorDisplayName = "mockAuthenticatorDisplayName-$number", ), ), response = AuthenticatorAssertionResponse( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/PublicKeyAuthenticatorAttestationResponseUtil.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/PublicKeyAuthenticatorAttestationResponseUtil.kt index 934117a4628..e7821bd5368 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/PublicKeyAuthenticatorAttestationResponseUtil.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/model/PublicKeyAuthenticatorAttestationResponseUtil.kt @@ -18,7 +18,6 @@ fun createMockPublicKeyAttestationResponse(number: Int) = clientExtensionResults = ClientExtensionResults( credProps = CredPropsResult( rk = true, - authenticatorDisplayName = "mockDisplayName", ), ), response = AuthenticatorAttestationResponse( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/util/PublicKeyCredentialAuthenticatorAssertionResponseExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/util/PublicKeyCredentialAuthenticatorAssertionResponseExtensionsTest.kt index d9ff79f66d6..113ab008043 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/util/PublicKeyCredentialAuthenticatorAssertionResponseExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/util/PublicKeyCredentialAuthenticatorAssertionResponseExtensionsTest.kt @@ -61,7 +61,6 @@ class PublicKeyCredentialAuthenticatorAssertionResponseExtensionsTest { number = 1, credProps = CredPropsResult( rk = true, - authenticatorDisplayName = null, ), ) val result = mockSdkResponse.toAndroidFido2PublicKeyCredential() @@ -74,7 +73,6 @@ class PublicKeyCredentialAuthenticatorAssertionResponseExtensionsTest { number = 1, credProps = CredPropsResult( rk = null, - authenticatorDisplayName = null, ), ) val result = mockSdkResponse.toAndroidFido2PublicKeyCredential() diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/util/PublicKeyCredentialAuthenticatorAttestationResponseExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/util/PublicKeyCredentialAuthenticatorAttestationResponseExtensionsTest.kt index 82f4861fec1..f0f06962e83 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/util/PublicKeyCredentialAuthenticatorAttestationResponseExtensionsTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/datasource/sdk/util/PublicKeyCredentialAuthenticatorAttestationResponseExtensionsTest.kt @@ -60,7 +60,6 @@ class PublicKeyCredentialAuthenticatorAttestationResponseExtensionsTest { number = 1, credProps = CredPropsResult( rk = true, - authenticatorDisplayName = null, ), ) val result = mockSdkResponse.toAndroidAttestationResponse(callingPackageName = "") diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerTest.kt index 355ae034f07..ac61dc26e2e 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/manager/VaultLockManagerTest.kt @@ -39,6 +39,7 @@ import com.x8bit.bitwarden.data.vault.datasource.sdk.model.InitializeCryptoResul import com.x8bit.bitwarden.data.vault.manager.model.VaultStateEvent import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockData import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult +import com.x8bit.bitwarden.data.vault.repository.util.createWrappedAccountCryptographicState import io.mockk.clearMocks import io.mockk.coEvery import io.mockk.coVerify @@ -762,15 +763,18 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = MOCK_PROFILE.toSdkParams(), email = MOCK_PROFILE.email, - privateKey = privateKey, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = userAutoUnlockKey, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -788,15 +792,18 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = MOCK_PROFILE.toSdkParams(), email = MOCK_PROFILE.email, - privateKey = privateKey, method = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = userAutoUnlockKey, ), - signingKey = null, - securityState = null, ), ) trustedDeviceManager.trustThisDeviceIfNecessary(userId = USER_ID) @@ -921,16 +928,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -954,12 +964,15 @@ class VaultLockManagerTest { ) val result = vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -990,16 +1003,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) vaultSdkSource.initializeOrganizationCrypto( @@ -1026,16 +1042,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -1068,12 +1087,15 @@ class VaultLockManagerTest { } val result = vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -1106,16 +1128,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) vaultSdkSource.initializeOrganizationCrypto( @@ -1142,16 +1167,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.AuthenticationError(error = error).asSuccess() @@ -1166,12 +1194,15 @@ class VaultLockManagerTest { ) val result = vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -1192,16 +1223,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } @@ -1221,16 +1255,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -1252,12 +1289,15 @@ class VaultLockManagerTest { ) val result = vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -1278,16 +1318,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } @@ -1314,16 +1357,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } returns error.asFailure() @@ -1337,12 +1383,15 @@ class VaultLockManagerTest { ) val result = vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -1363,16 +1412,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } @@ -1392,16 +1444,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -1422,12 +1477,15 @@ class VaultLockManagerTest { ) val result = vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -1448,16 +1506,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } @@ -1483,16 +1544,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -1513,12 +1577,15 @@ class VaultLockManagerTest { ) val result = vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -1546,16 +1613,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } @@ -1663,16 +1733,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -1692,12 +1765,15 @@ class VaultLockManagerTest { mutableVaultTimeoutStateFlow.value = VaultTimeout.ThirtyMinutes val result = vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -1720,16 +1796,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) vaultSdkSource.initializeOrganizationCrypto( @@ -1762,13 +1841,16 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = initUserCryptoMethod, - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -1792,12 +1874,15 @@ class VaultLockManagerTest { ) val result = vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = initUserCryptoMethod, organizationKeys = organizationKeys, ) @@ -1825,13 +1910,16 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = USER_ID, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = USER_ID, kdfParams = kdf, email = email, - privateKey = privateKey, method = initUserCryptoMethod, - signingKey = null, - securityState = null, ), ) vaultSdkSource.initializeOrganizationCrypto( @@ -1873,16 +1961,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = userId, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } coAnswers { @@ -1891,12 +1982,15 @@ class VaultLockManagerTest { } vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -1923,16 +2017,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = userId, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } returns InitializeCryptoResult.Success.asSuccess() @@ -1944,12 +2041,15 @@ class VaultLockManagerTest { } returns true.asSuccess() val result = vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = email, kdf = kdf, - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -1962,16 +2062,19 @@ class VaultLockManagerTest { vaultSdkSource.initializeCrypto( userId = userId, request = InitUserCryptoRequest( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, kdfParams = kdf, email = email, - privateKey = privateKey, method = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, ), - signingKey = null, - securityState = null, ), ) } diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt index c7271852db1..bab7175711f 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/VaultRepositoryTest.kt @@ -55,6 +55,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.ImportCredentialsResult import com.x8bit.bitwarden.data.vault.repository.model.SendData import com.x8bit.bitwarden.data.vault.repository.model.VaultData import com.x8bit.bitwarden.data.vault.repository.model.VaultUnlockResult +import com.x8bit.bitwarden.data.vault.repository.util.createWrappedAccountCryptographicState import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCipher import com.x8bit.bitwarden.data.vault.repository.util.toSdkMasterPasswordUnlock import com.x8bit.bitwarden.ui.vault.feature.verificationcode.util.createVerificationCodeItem @@ -257,12 +258,15 @@ class VaultRepositoryTest { } coEvery { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = encryptedBytes.toString(Charsets.ISO_8859_1), ), @@ -280,12 +284,15 @@ class VaultRepositoryTest { assertEquals(VaultUnlockResult.Success, result) coVerify(exactly = 1) { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = encryptedBytes.toString(Charsets.ISO_8859_1), ), @@ -310,12 +317,15 @@ class VaultRepositoryTest { } coEvery { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = biometricsKey, ), @@ -333,12 +343,15 @@ class VaultRepositoryTest { assertEquals(VaultUnlockResult.Success, result) coVerify { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = biometricsKey, ), @@ -367,12 +380,15 @@ class VaultRepositoryTest { fakeAuthDiskSource.userState = MOCK_USER_STATE coEvery { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = authenticatorSyncUnlockKey, ), @@ -394,12 +410,15 @@ class VaultRepositoryTest { assertEquals(VaultUnlockResult.Success, result) coVerify { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = authenticatorSyncUnlockKey, ), @@ -419,12 +438,15 @@ class VaultRepositoryTest { val error = Throwable("Fail") coEvery { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = privateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = privateKey, - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = authenticatorSyncUnlockKey, ), @@ -446,12 +468,15 @@ class VaultRepositoryTest { assertEquals(VaultUnlockResult.InvalidStateError(error = error), result) coVerify { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.DecryptedKey( decryptedUserKey = authenticatorSyncUnlockKey, ), @@ -530,12 +555,15 @@ class VaultRepositoryTest { ) coVerify { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = "mockPassword-1", userKey = "mockKey-1", @@ -580,12 +608,15 @@ class VaultRepositoryTest { coEvery { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.MasterPasswordUnlock( password = masterPassword, masterPasswordUnlock = masterPasswordUnlockData, @@ -601,12 +632,15 @@ class VaultRepositoryTest { assertEquals(VaultUnlockResult.Success, result) coVerify { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.MasterPasswordUnlock( password = masterPassword, masterPasswordUnlock = masterPasswordUnlockData, @@ -638,12 +672,15 @@ class VaultRepositoryTest { coEvery { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -659,12 +696,15 @@ class VaultRepositoryTest { assertEquals(VaultUnlockResult.Success, result) coVerify { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = masterPassword, userKey = userKey, @@ -692,12 +732,15 @@ class VaultRepositoryTest { ) coVerify { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = "mockPassword-1", userKey = "mockKey-1", @@ -781,12 +824,15 @@ class VaultRepositoryTest { ) coVerify { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.PinEnvelope( pin = "1234", pinProtectedUserKeyEnvelope = "mockKey-1", @@ -816,12 +862,15 @@ class VaultRepositoryTest { ) coVerify { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Pin( pin = "1234", pinProtectedUserKey = "mockKey-1", @@ -847,12 +896,15 @@ class VaultRepositoryTest { ) coVerify { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.PinEnvelope( pin = "1234", pinProtectedUserKeyEnvelope = "mockKey-1", @@ -1383,12 +1435,14 @@ class VaultRepositoryTest { val userId = "userId" val fido2CredentialStore: Fido2CredentialStore = mockk() val relyingPartyId = "relyingPartyId" + val userHandle = "mockUserHandle" val expected: List = mockk() coEvery { vaultSdkSource.silentlyDiscoverCredentials( userId = userId, fido2CredentialStore = fido2CredentialStore, relyingPartyId = relyingPartyId, + userHandle = userHandle, ) } returns expected.asSuccess() @@ -1396,6 +1450,7 @@ class VaultRepositoryTest { userId = userId, fido2CredentialStore = fido2CredentialStore, relyingPartyId = relyingPartyId, + userHandle = userHandle, ) assertEquals(expected.asSuccess(), result) @@ -1405,6 +1460,7 @@ class VaultRepositoryTest { userId = userId, fido2CredentialStore = fido2CredentialStore, relyingPartyId = relyingPartyId, + userHandle = userHandle, ) } } @@ -1454,12 +1510,15 @@ class VaultRepositoryTest { // Master password unlock coEvery { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Password( password = mockMasterPassword, userKey = "mockKey-1", @@ -1471,12 +1530,15 @@ class VaultRepositoryTest { // PIN unlock coEvery { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.Pin( pin = mockPin, pinProtectedUserKey = "mockKey-1", @@ -1488,12 +1550,15 @@ class VaultRepositoryTest { // PIN ENVELOPE unlock coEvery { vaultLockManager.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "mockPrivateKey-1", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), userId = userId, email = "email", kdf = MOCK_PROFILE.toSdkParams(), - privateKey = "mockPrivateKey-1", - signingKey = null, - securityState = null, initUserCryptoMethod = InitUserCryptoMethod.PinEnvelope( pin = mockPin, pinProtectedUserKeyEnvelope = "mockKey-1", From 207a3f12b65b429aaed26c25223eed89ee0794a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonc=CC=A7alves?= Date: Wed, 17 Dec 2025 18:29:57 +0000 Subject: [PATCH 23/27] pm-29777 Update sdk to 2.0.0-4151-b444e590 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b2a6340125f..395fdb24710 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.4" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "2.0.0-4110-bd636a4f" +bitwardenSdk = "2.0.0-4151-b444e590" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 58535b0e7e944fce535e1f6b2fbcc151c1a0f3a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonc=CC=A7alves?= Date: Thu, 18 Dec 2025 11:21:28 +0000 Subject: [PATCH 24/27] pm-29777 Add tests for new extension --- ...ppedAccountCryptographicStateExtensions.kt | 8 +- ...AccountCryptographicStateExtensionsTest.kt | 111 ++++++++++++++++++ 2 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensionsTest.kt diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensions.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensions.kt index 46ef03948c8..b1c948e877a 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensions.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensions.kt @@ -5,13 +5,13 @@ import com.bitwarden.core.WrappedAccountCryptographicState /** * Creates a [WrappedAccountCryptographicState] based on the available cryptographic parameters. * - * Returns [WrappedAccountCryptographicState.V2] if signing key and security - * state are present, otherwise returns [WrappedAccountCryptographicState.V1]. + * Returns [WrappedAccountCryptographicState.V2] if signing key, signed public key, and security + * state are all present, otherwise returns [WrappedAccountCryptographicState.V1]. * * @param privateKey The user's wrapped private key. + * @param securityState The user's signed security state (V2 only). * @param signingKey The user's wrapped signing key (V2 only). * @param signedPublicKey The user's signed public key (V2 only). - * @param securityState The user's signed security state (V2 only). */ fun createWrappedAccountCryptographicState( privateKey: String, @@ -19,7 +19,7 @@ fun createWrappedAccountCryptographicState( signingKey: String?, signedPublicKey: String?, ): WrappedAccountCryptographicState { - return if (signingKey != null && securityState != null) { + return if (signingKey != null && securityState != null && signedPublicKey != null) { WrappedAccountCryptographicState.V2( privateKey = privateKey, securityState = securityState, diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensionsTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensionsTest.kt new file mode 100644 index 00000000000..75a4b07cf52 --- /dev/null +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/vault/repository/util/WrappedAccountCryptographicStateExtensionsTest.kt @@ -0,0 +1,111 @@ +package com.x8bit.bitwarden.data.vault.repository.util + +import com.bitwarden.core.WrappedAccountCryptographicState +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test + +private const val PRIVATE_KEY = "test-private-key" +private const val SECURITY_STATE = "test-security-state" +private const val SIGNING_KEY = "test-signing-key" +private const val SIGNED_PUBLIC_KEY = "test-signed-public-key" + +class WrappedAccountCryptographicStateExtensionsTest { + + @Suppress("MaxLineLength") + @Test + fun `createWrappedAccountCryptographicState returns V2 when securityState, signedPublicKey and signingKey are non-null`() { + val result = createWrappedAccountCryptographicState( + privateKey = PRIVATE_KEY, + securityState = SECURITY_STATE, + signedPublicKey = SIGNED_PUBLIC_KEY, + signingKey = SIGNING_KEY, + ) + + val v2State = result as WrappedAccountCryptographicState.V2 + assertEquals(PRIVATE_KEY, v2State.privateKey) + assertEquals(SECURITY_STATE, v2State.securityState) + assertEquals(SIGNED_PUBLIC_KEY, v2State.signedPublicKey) + assertEquals(SIGNING_KEY, v2State.signingKey) + } + + @Test + fun `createWrappedAccountCryptographicState returns V1 when securityState is null`() { + val result = createWrappedAccountCryptographicState( + privateKey = PRIVATE_KEY, + securityState = null, + signedPublicKey = SIGNED_PUBLIC_KEY, + signingKey = SIGNING_KEY, + ) + + val v1State = result as WrappedAccountCryptographicState.V1 + assertEquals(PRIVATE_KEY, v1State.privateKey) + } + + @Test + fun `createWrappedAccountCryptographicState returns V1 when signedPublicKey is null`() { + val result = createWrappedAccountCryptographicState( + privateKey = PRIVATE_KEY, + securityState = SECURITY_STATE, + signedPublicKey = null, + signingKey = SIGNING_KEY, + ) + + val v1State = result as WrappedAccountCryptographicState.V1 + assertEquals(PRIVATE_KEY, v1State.privateKey) + } + + @Test + fun `createWrappedAccountCryptographicState returns V1 when signingKey is null`() { + val result = createWrappedAccountCryptographicState( + privateKey = PRIVATE_KEY, + securityState = SECURITY_STATE, + signedPublicKey = SIGNED_PUBLIC_KEY, + signingKey = null, + ) + + val v1State = result as WrappedAccountCryptographicState.V1 + assertEquals(PRIVATE_KEY, v1State.privateKey) + } + + @Suppress("MaxLineLength") + @Test + fun `createWrappedAccountCryptographicState returns V1 when both securityState and signedPublicKey are null`() { + val result = createWrappedAccountCryptographicState( + privateKey = PRIVATE_KEY, + securityState = null, + signedPublicKey = null, + signingKey = SIGNING_KEY, + ) + + val v1State = result as WrappedAccountCryptographicState.V1 + assertEquals(PRIVATE_KEY, v1State.privateKey) + } + + @Suppress("MaxLineLength") + @Test + fun `createWrappedAccountCryptographicState returns V1 when both securityState and signingKey are null`() { + val result = createWrappedAccountCryptographicState( + privateKey = PRIVATE_KEY, + securityState = null, + signedPublicKey = SIGNED_PUBLIC_KEY, + signingKey = null, + ) + + val v1State = result as WrappedAccountCryptographicState.V1 + assertEquals(PRIVATE_KEY, v1State.privateKey) + } + + @Suppress("MaxLineLength") + @Test + fun `createWrappedAccountCryptographicState returns V1 when both signedPublicKey and signingKey are null`() { + val result = createWrappedAccountCryptographicState( + privateKey = PRIVATE_KEY, + securityState = SECURITY_STATE, + signedPublicKey = null, + signingKey = null, + ) + + val v1State = result as WrappedAccountCryptographicState.V1 + assertEquals(PRIVATE_KEY, v1State.privateKey) + } +} From 1b5ff1c31cd28e71e9a142f5fc433f18e93c253d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonc=CC=A7alves?= Date: Thu, 18 Dec 2025 16:04:09 +0000 Subject: [PATCH 25/27] pm-29777 Added tests --- .../auth/repository/AuthRepositoryImpl.kt | 71 +++-- .../auth/repository/AuthRepositoryTest.kt | 279 ++++++++++++++++++ .../network/model/AccountKeysJsonUtil.kt | 17 +- 3 files changed, 344 insertions(+), 23 deletions(-) diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt index f63ffe5748d..e9ce261edce 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryImpl.kt @@ -1814,14 +1814,18 @@ class AuthRepositoryImpl( accessToken = loginResponse.accessToken, ) .map { - val accountKeys = loginResponse.accountKeys unlockVault( accountCryptographicState = createWrappedAccountCryptographicState( privateKey = privateKey, - securityState = accountKeys?.securityState?.securityState, - signingKey = accountKeys?.signatureKeyPair?.wrappedSigningKey, - signedPublicKey = - accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey, + securityState = loginResponse.accountKeys + ?.securityState + ?.securityState, + signingKey = loginResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + signedPublicKey = loginResponse.accountKeys + ?.publicKeyEncryptionKeyPair + ?.signedPublicKey, ), accountProfile = profile, initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( @@ -1852,10 +1856,15 @@ class AuthRepositoryImpl( val result = unlockVault( accountCryptographicState = createWrappedAccountCryptographicState( privateKey = keyConnectorResponse.keys.private, - securityState = accountKeys?.securityState?.securityState, - signingKey = accountKeys?.signatureKeyPair?.wrappedSigningKey, - signedPublicKey = - accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey, + securityState = accountKeys + ?.securityState + ?.securityState, + signingKey = accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + signedPublicKey = accountKeys + ?.publicKeyEncryptionKeyPair + ?.signedPublicKey, ), accountProfile = profile, initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( @@ -1915,10 +1924,15 @@ class AuthRepositoryImpl( return unlockVault( accountCryptographicState = createWrappedAccountCryptographicState( privateKey = privateKey, - securityState = loginResponse.accountKeys?.securityState?.securityState, - signingKey = loginResponse.accountKeys?.signatureKeyPair?.wrappedSigningKey, - signedPublicKey = - loginResponse.accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey, + securityState = loginResponse.accountKeys + ?.securityState + ?.securityState, + signingKey = loginResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + signedPublicKey = loginResponse.accountKeys + ?.publicKeyEncryptionKeyPair + ?.signedPublicKey, ), accountProfile = profile, initUserCryptoMethod = initUserCryptoMethod, @@ -1928,6 +1942,7 @@ class AuthRepositoryImpl( /** * Attempt to unlock the current user's vault with trusted device specific data. */ + @Suppress("LongMethod") private suspend fun unlockVaultWithTdeOnLoginSuccess( loginResponse: GetTokenResponseJson.Success, profile: AccountJson.Profile, @@ -1942,10 +1957,15 @@ class AuthRepositoryImpl( return unlockVault( accountCryptographicState = createWrappedAccountCryptographicState( privateKey = privateKey, - securityState = loginResponse.accountKeys?.securityState?.securityState, - signingKey = loginResponse.accountKeys?.signatureKeyPair?.wrappedSigningKey, - signedPublicKey = - loginResponse.accountKeys?.publicKeyEncryptionKeyPair?.signedPublicKey, + securityState = loginResponse.accountKeys + ?.securityState + ?.securityState, + signingKey = loginResponse.accountKeys + ?.signatureKeyPair + ?.wrappedSigningKey, + signedPublicKey = loginResponse.accountKeys + ?.publicKeyEncryptionKeyPair + ?.signedPublicKey, ), accountProfile = profile, initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( @@ -1977,11 +1997,18 @@ class AuthRepositoryImpl( unlockVaultWithTrustedDeviceUserDecryptionOptionsAndStoreKeys( options = options, profile = profile, - privateKey = accountKeys.publicKeyEncryptionKeyPair.wrappedPrivateKey, - securityState = accountKeys.securityState?.securityState, - signedPublicKey = - accountKeys.publicKeyEncryptionKeyPair.signedPublicKey, - signingKey = accountKeys.signatureKeyPair?.wrappedSigningKey, + privateKey = accountKeys + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = accountKeys + .securityState + ?.securityState, + signedPublicKey = accountKeys + .publicKeyEncryptionKeyPair + .signedPublicKey, + signingKey = accountKeys + .signatureKeyPair + ?.wrappedSigningKey, ) } ?: loginResponse.privateKey diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt index 6252a587912..8383a7f00ba 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/auth/repository/AuthRepositoryTest.kt @@ -59,6 +59,7 @@ import com.bitwarden.network.model.VerifiedOrganizationDomainSsoDetailsResponse import com.bitwarden.network.model.VerifyEmailTokenRequestJson import com.bitwarden.network.model.VerifyEmailTokenResponseJson import com.bitwarden.network.model.createMockAccountKeysJson +import com.bitwarden.network.model.createMockAccountKeysJsonWithNullFields import com.bitwarden.network.model.createMockOrganization import com.bitwarden.network.model.createMockPolicy import com.bitwarden.network.service.AccountsService @@ -1649,6 +1650,65 @@ class AuthRepositoryTest { assertEquals(LoginResult.Error(errorMessage = null, error = error), result) } + @Suppress("MaxLineLength") + @Test + fun `completeTdeLogin with accountKeys with null nested fields should unlock vault with null properties`() = + runTest { + val requestPrivateKey = "requestPrivateKey" + val asymmetricalKey = "asymmetricalKey" + val accountKeys = ACCOUNT_KEYS_WITH_NULL_FIELDS + val orgKeys = mapOf("orgId" to "orgKey") + fakeAuthDiskSource.userState = SINGLE_USER_STATE_1 + fakeAuthDiskSource.storeAccountKeys(userId = USER_ID_1, accountKeys = accountKeys) + fakeAuthDiskSource.storeOrganizationKeys(userId = USER_ID_1, organizationKeys = orgKeys) + coEvery { + vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = accountKeys.publicKeyEncryptionKeyPair.wrappedPrivateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), + userId = USER_ID_1, + email = SINGLE_USER_STATE_1.activeAccount.profile.email, + kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), + initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( + requestPrivateKey = requestPrivateKey, + method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricalKey), + ), + organizationKeys = orgKeys, + ) + } returns VaultUnlockResult.Success + coEvery { vaultRepository.syncIfNecessary() } just runs + + val result = repository.completeTdeLogin( + requestPrivateKey = requestPrivateKey, + asymmetricalKey = asymmetricalKey, + ) + + coVerify(exactly = 1) { + vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = accountKeys.publicKeyEncryptionKeyPair.wrappedPrivateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), + userId = USER_ID_1, + email = SINGLE_USER_STATE_1.activeAccount.profile.email, + kdf = SINGLE_USER_STATE_1.activeAccount.profile.toSdkParams(), + initUserCryptoMethod = InitUserCryptoMethod.AuthRequest( + requestPrivateKey = requestPrivateKey, + method = AuthRequestMethod.UserKey(protectedUserKey = asymmetricalKey), + ), + organizationKeys = orgKeys, + ) + vaultRepository.syncIfNecessary() + settingsRepository.storeUserHasLoggedInValue(userId = USER_ID_1) + } + assertEquals(LoginResult.Success, result) + } + @Test fun `login when pre login fails should return Error with no message`() = runTest { val error = RuntimeException() @@ -1941,6 +2001,113 @@ class AuthRepositoryTest { } } + @Test + @Suppress("MaxLineLength") + fun `login get token succeeds with accountKeys with null nested fields should unlock vault with null properties`() = + runTest { + val successResponse = GET_TOKEN_WITH_ACCOUNT_KEYS_RESPONSE_SUCCESS.copy( + accountKeys = ACCOUNT_KEYS_WITH_NULL_FIELDS, + ) + coEvery { + identityService.preLogin(email = EMAIL) + } returns PRE_LOGIN_SUCCESS.asSuccess() + coEvery { + identityService.getToken( + email = EMAIL, + authModel = IdentityTokenAuthModel.MasterPassword( + username = EMAIL, + password = PASSWORD_HASH, + ), + uniqueAppId = UNIQUE_APP_ID, + ) + } returns successResponse.asSuccess() + coEvery { + vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), + userId = USER_ID_1, + email = EMAIL, + kdf = ACCOUNT_1.profile.toSdkParams(), + initUserCryptoMethod = InitUserCryptoMethod.MasterPasswordUnlock( + password = PASSWORD, + masterPasswordUnlock = MOCK_MASTER_PASSWORD_UNLOCK, + ), + organizationKeys = null, + ) + } returns VaultUnlockResult.Success + coEvery { vaultRepository.syncIfNecessary() } just runs + every { + successResponse.toUserState( + previousUserState = null, + environmentUrlData = EnvironmentUrlDataJson.DEFAULT_US, + ) + } returns SINGLE_USER_STATE_1 + val result = repository.login(email = EMAIL, password = PASSWORD) + assertEquals(LoginResult.Success, result) + assertEquals(AuthState.Authenticated(ACCESS_TOKEN), repository.authStateFlow.value) + coVerify { identityService.preLogin(email = EMAIL) } + fakeAuthDiskSource.assertPrivateKey( + userId = USER_ID_1, + privateKey = "privateKey", + ) + fakeAuthDiskSource.assertAccountKeys( + userId = USER_ID_1, + accountKeys = ACCOUNT_KEYS_WITH_NULL_FIELDS, + ) + fakeAuthDiskSource.assertUserKey( + userId = USER_ID_1, + userKey = "key", + ) + fakeAuthDiskSource.assertMasterPasswordHash( + userId = USER_ID_1, + passwordHash = PASSWORD_HASH, + ) + coVerify { + identityService.getToken( + email = EMAIL, + authModel = IdentityTokenAuthModel.MasterPassword( + username = EMAIL, + password = PASSWORD_HASH, + ), + uniqueAppId = UNIQUE_APP_ID, + ) + vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = successResponse.accountKeys!! + .publicKeyEncryptionKeyPair + .wrappedPrivateKey, + securityState = null, + signedPublicKey = null, + signingKey = null, + ), + userId = USER_ID_1, + email = EMAIL, + kdf = ACCOUNT_1.profile.toSdkParams(), + initUserCryptoMethod = InitUserCryptoMethod.MasterPasswordUnlock( + password = PASSWORD, + masterPasswordUnlock = MOCK_MASTER_PASSWORD_UNLOCK, + ), + organizationKeys = null, + ) + vaultRepository.syncIfNecessary() + settingsRepository.storeUserHasLoggedInValue(userId = USER_ID_1) + } + assertEquals( + SINGLE_USER_STATE_1, + fakeAuthDiskSource.userState, + ) + verify(exactly = 1) { + userStateManager.hasPendingAccountAddition = false + settingsRepository.setDefaultsIfNecessary(userId = USER_ID_1) + } + } + @Test fun `login should return Error result when get token succeeds but unlock vault fails`() = runTest { @@ -3592,6 +3759,116 @@ class AuthRepositoryTest { } } + @Test + @Suppress("MaxLineLength") + fun `SSO login get token succeeds with key connector and accountKeys with null nested fields should unlock vault`() = + runTest { + val keyConnectorUrl = "www.example.com" + val successResponse = GET_TOKEN_RESPONSE_SUCCESS.copy( + keyConnectorUrl = keyConnectorUrl, + accountKeys = ACCOUNT_KEYS_WITH_NULL_FIELDS, + userDecryptionOptions = USER_DECRYPTION_OPTIONS.copy( + hasMasterPassword = false, + trustedDeviceUserDecryptionOptions = null, + ), + ) + val masterKey = "masterKey" + val keyConnectorMasterKeyResponseJson = mockk { + every { this@mockk.masterKey } returns masterKey + } + coEvery { + identityService.getToken( + email = EMAIL, + authModel = IdentityTokenAuthModel.SingleSignOn( + ssoCode = SSO_CODE, + ssoCodeVerifier = SSO_CODE_VERIFIER, + ssoRedirectUri = SSO_REDIRECT_URI, + ), + uniqueAppId = UNIQUE_APP_ID, + ) + } returns successResponse.asSuccess() + coEvery { + keyConnectorManager.getMasterKeyFromKeyConnector( + url = keyConnectorUrl, + accessToken = ACCESS_TOKEN, + ) + } returns keyConnectorMasterKeyResponseJson.asSuccess() + coEvery { + vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "privateKey", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), + userId = USER_ID_1, + email = EMAIL, + kdf = ACCOUNT_1.profile.toSdkParams(), + initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( + masterKey = masterKey, + userKey = "key", + ), + organizationKeys = null, + ) + } returns VaultUnlockResult.Success + coEvery { vaultRepository.syncIfNecessary() } just runs + every { + successResponse.toUserState( + previousUserState = null, + environmentUrlData = EnvironmentUrlDataJson.DEFAULT_US, + ) + } returns SINGLE_USER_STATE_1 + val result = repository.login( + email = EMAIL, + ssoCode = SSO_CODE, + ssoCodeVerifier = SSO_CODE_VERIFIER, + ssoRedirectUri = SSO_REDIRECT_URI, + organizationIdentifier = ORGANIZATION_IDENTIFIER, + ) + + assertEquals(LoginResult.Success, result) + assertEquals(AuthState.Authenticated(ACCESS_TOKEN), repository.authStateFlow.value) + fakeAuthDiskSource.assertPrivateKey(userId = USER_ID_1, privateKey = "privateKey") + fakeAuthDiskSource.assertUserKey(userId = USER_ID_1, userKey = "key") + coVerify(exactly = 1) { + identityService.getToken( + email = EMAIL, + authModel = IdentityTokenAuthModel.SingleSignOn( + ssoCode = SSO_CODE, + ssoCodeVerifier = SSO_CODE_VERIFIER, + ssoRedirectUri = SSO_REDIRECT_URI, + ), + uniqueAppId = UNIQUE_APP_ID, + ) + keyConnectorManager.getMasterKeyFromKeyConnector( + url = keyConnectorUrl, + accessToken = ACCESS_TOKEN, + ) + vaultRepository.unlockVault( + accountCryptographicState = createWrappedAccountCryptographicState( + privateKey = "privateKey", + securityState = null, + signedPublicKey = null, + signingKey = null, + ), + userId = USER_ID_1, + email = EMAIL, + kdf = ACCOUNT_1.profile.toSdkParams(), + initUserCryptoMethod = InitUserCryptoMethod.KeyConnector( + masterKey = masterKey, + userKey = "key", + ), + organizationKeys = null, + ) + vaultRepository.syncIfNecessary() + } + assertEquals(SINGLE_USER_STATE_1, fakeAuthDiskSource.userState) + verify(exactly = 1) { + userStateManager.hasPendingAccountAddition = false + settingsRepository.setDefaultsIfNecessary(userId = USER_ID_1) + } + } + @Test @Suppress("MaxLineLength") fun `SSO login get token succeeds with key connector, no master password, no key and no private key should return failure`() = @@ -7208,6 +7485,8 @@ class AuthRepositoryTest { private const val ORGANIZATION_IDENTIFIER = "organizationIdentifier" private val ORGANIZATIONS = listOf(createMockOrganization(number = 0)) private val ACCOUNT_KEYS = createMockAccountKeysJson(number = 1) + private val ACCOUNT_KEYS_WITH_NULL_FIELDS = + createMockAccountKeysJsonWithNullFields(number = 1) private val TWO_FACTOR_AUTH_METHODS_DATA = mapOf( TwoFactorAuthMethod.EMAIL to JsonObject( mapOf("Email" to JsonPrimitive("ex***@email.com")), diff --git a/network/src/testFixtures/kotlin/com/bitwarden/network/model/AccountKeysJsonUtil.kt b/network/src/testFixtures/kotlin/com/bitwarden/network/model/AccountKeysJsonUtil.kt index 11b9c23762d..03e697fe60d 100644 --- a/network/src/testFixtures/kotlin/com/bitwarden/network/model/AccountKeysJsonUtil.kt +++ b/network/src/testFixtures/kotlin/com/bitwarden/network/model/AccountKeysJsonUtil.kt @@ -7,9 +7,9 @@ fun createMockAccountKeysJson( number: Int, ): AccountKeysJson = AccountKeysJson( - signatureKeyPair = createMockSignatureKeyPair(number = number), publicKeyEncryptionKeyPair = createMockPublicKeyEncryptionKeyPair(number = number), securityState = createMockSecurityState(number = number), + signatureKeyPair = createMockSignatureKeyPair(number = number), ) /** @@ -53,3 +53,18 @@ fun createMockSignatureKeyPair( wrappedSigningKey = wrappedSigningKey, verifyingKey = verifyingKey, ) + +/** + * Create a mock set of account keys with null nested fields for testing null-safety. + */ +fun createMockAccountKeysJsonWithNullFields( + number: Int, +): AccountKeysJson = + AccountKeysJson( + publicKeyEncryptionKeyPair = createMockPublicKeyEncryptionKeyPair( + number = number, + signedPublicKey = null, + ), + securityState = null, + signatureKeyPair = null, + ) From 90af0a37a75b2b63f38f482b338b59914f7d879f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonc=CC=A7alves?= Date: Tue, 23 Dec 2025 13:09:52 +0000 Subject: [PATCH 26/27] pm-29777 Update sdk to 2.0.0-4208-b9cf7b78 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 395fdb24710..2973fa9e174 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.4" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "2.0.0-4151-b444e590" +bitwardenSdk = "2.0.0-4208-b9cf7b78" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0" From 3786d791a0fcdb40eb8cd79c34d152614a6826bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonc=CC=A7alves?= Date: Tue, 23 Dec 2025 15:48:43 +0000 Subject: [PATCH 27/27] pm-29777 Update sdk to 2.0.0-4254-6c954013 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2973fa9e174..05663d581a4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ androidxRoom = "2.8.4" androidxSecurityCrypto = "1.1.0" androidxSplash = "1.2.0" androidxWork = "2.11.0" -bitwardenSdk = "2.0.0-4208-b9cf7b78" +bitwardenSdk = "2.0.0-4254-6c954013" crashlytics = "3.0.6" detekt = "1.23.8" firebaseBom = "34.5.0"