From 4726cb743a87abc134ae9e9b3636dd08de091e6a Mon Sep 17 00:00:00 2001 From: David Perez Date: Thu, 15 Aug 2024 13:53:48 -0500 Subject: [PATCH] PM-10936: Add account apis for key connectors (#3748) --- .../network/api/AuthenticatedAccountsApi.kt | 14 ++++++++ .../model/KeyConnectorKeyRequestJson.kt | 33 +++++++++++++++++++ .../network/service/AccountsService.kt | 11 +++++++ .../network/service/AccountsServiceImpl.kt | 11 +++++++ .../network/service/AccountsServiceTest.kt | 33 +++++++++++++++++++ 5 files changed, 102 insertions(+) create mode 100644 app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/model/KeyConnectorKeyRequestJson.kt diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/api/AuthenticatedAccountsApi.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/api/AuthenticatedAccountsApi.kt index 72d86d0c6..e1175c2b7 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/api/AuthenticatedAccountsApi.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/api/AuthenticatedAccountsApi.kt @@ -2,6 +2,7 @@ package com.x8bit.bitwarden.data.auth.datasource.network.api import com.x8bit.bitwarden.data.auth.datasource.network.model.CreateAccountKeysRequest import com.x8bit.bitwarden.data.auth.datasource.network.model.DeleteAccountRequestJson +import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorKeyRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.SetPasswordRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.VerifyOtpRequestJson @@ -13,6 +14,13 @@ import retrofit2.http.POST * Defines raw calls under the /accounts API with authentication applied. */ interface AuthenticatedAccountsApi { + + /** + * Converts the currently active account to a key-connector account. + */ + @POST("/accounts/convert-to-key-connector") + suspend fun convertToKeyConnector(): Result + /** * Creates the keys for the current account. */ @@ -45,6 +53,12 @@ interface AuthenticatedAccountsApi { @HTTP(method = "POST", path = "/accounts/password", hasBody = true) suspend fun resetPassword(@Body body: ResetPasswordRequestJson): Result + /** + * Sets the key connector key. + */ + @POST("/accounts/set-key-connector-key") + suspend fun setKeyConnectorKey(@Body body: KeyConnectorKeyRequestJson): Result + /** * Sets the password. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/model/KeyConnectorKeyRequestJson.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/model/KeyConnectorKeyRequestJson.kt new file mode 100644 index 000000000..4946d1eeb --- /dev/null +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/model/KeyConnectorKeyRequestJson.kt @@ -0,0 +1,33 @@ +package com.x8bit.bitwarden.data.auth.datasource.network.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * Represents the request body used to create the key connector keys for an account. + */ +@Serializable +data class KeyConnectorKeyRequestJson( + @SerialName("key") val userKey: String, + @SerialName("keys") val keys: Keys, + @SerialName("kdf") val kdfType: KdfTypeJson, + @SerialName("kdfIterations") val kdfIterations: Int?, + @SerialName("kdfMemory") val kdfMemory: Int?, + @SerialName("kdfParallelism") val kdfParallelism: Int?, + @SerialName("orgIdentifier") val organizationIdentifier: String, +) { + /** + * A keys object containing public and private keys. + * + * @param publicKey the public key (encrypted). + * @param encryptedPrivateKey the private key (encrypted). + */ + @Serializable + data class Keys( + @SerialName("publicKey") + val publicKey: String, + + @SerialName("encryptedPrivateKey") + val encryptedPrivateKey: String, + ) +} diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsService.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsService.kt index 7ac269a3d..25a9c2c76 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsService.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsService.kt @@ -1,6 +1,7 @@ package com.x8bit.bitwarden.data.auth.datasource.network.service import com.x8bit.bitwarden.data.auth.datasource.network.model.DeleteAccountResponseJson +import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorKeyRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson @@ -11,6 +12,11 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.SetPasswordRequest */ interface AccountsService { + /** + * Converts the currently active account to a key-connector account. + */ + suspend fun convertToKeyConnector(): Result + /** * Creates a new account's keys. */ @@ -49,6 +55,11 @@ interface AccountsService { */ suspend fun resetPassword(body: ResetPasswordRequestJson): Result + /** + * Set the key connector key. + */ + suspend fun setKeyConnectorKey(body: KeyConnectorKeyRequestJson): Result + /** * Set the password. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsServiceImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsServiceImpl.kt index 8686fe877..e6110dcad 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsServiceImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsServiceImpl.kt @@ -5,6 +5,7 @@ import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedAccount import com.x8bit.bitwarden.data.auth.datasource.network.model.CreateAccountKeysRequest import com.x8bit.bitwarden.data.auth.datasource.network.model.DeleteAccountRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.DeleteAccountResponseJson +import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorKeyRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson @@ -21,6 +22,12 @@ class AccountsServiceImpl( private val json: Json, ) : AccountsService { + /** + * Converts the currently active account to a key-connector account. + */ + override suspend fun convertToKeyConnector(): Result = + authenticatedAccountsApi.convertToKeyConnector() + override suspend fun createAccountKeys( publicKey: String, encryptedPrivateKey: String, @@ -93,6 +100,10 @@ class AccountsServiceImpl( } } + override suspend fun setKeyConnectorKey( + body: KeyConnectorKeyRequestJson, + ): Result = authenticatedAccountsApi.setKeyConnectorKey(body) + override suspend fun setPassword( body: SetPasswordRequestJson, ): Result = authenticatedAccountsApi.setPassword(body) diff --git a/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsServiceTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsServiceTest.kt index d19f4681c..10d2965ca 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsServiceTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/auth/datasource/network/service/AccountsServiceTest.kt @@ -2,6 +2,8 @@ package com.x8bit.bitwarden.data.auth.datasource.network.service import com.x8bit.bitwarden.data.auth.datasource.network.api.AccountsApi import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedAccountsApi +import com.x8bit.bitwarden.data.auth.datasource.network.model.KdfTypeJson +import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorKeyRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson import com.x8bit.bitwarden.data.auth.datasource.network.model.RegisterRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson @@ -28,6 +30,16 @@ class AccountsServiceTest : BaseServiceTest() { }, ) + @Test + fun `convertToKeyConnector with empty response is success`() = runTest { + val response = MockResponse().setBody("") + server.enqueue(response) + + val result = service.convertToKeyConnector() + + assertTrue(result.isSuccess) + } + @Test fun `createAccountKeys with empty response is success`() = runTest { val publicKey = "publicKey" @@ -173,4 +185,25 @@ class AccountsServiceTest : BaseServiceTest() { ) assertTrue(result.isSuccess) } + + @Test + fun `setKeyConnectorKey with empty response is success`() = runTest { + val response = MockResponse().setBody("") + server.enqueue(response) + val result = service.setKeyConnectorKey( + body = KeyConnectorKeyRequestJson( + organizationIdentifier = "organizationId", + kdfIterations = 7, + kdfMemory = 1, + kdfParallelism = 2, + kdfType = KdfTypeJson.ARGON2_ID, + userKey = "encryptedUserKey", + keys = KeyConnectorKeyRequestJson.Keys( + publicKey = "public", + encryptedPrivateKey = "private", + ), + ), + ) + assertTrue(result.isSuccess) + } }