PM-10954: Add network APIs for key-connector (#3752)

This commit is contained in:
David Perez 2024-08-16 08:36:42 -05:00 committed by GitHub
parent bd55b9ce72
commit 8094b3fd22
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 116 additions and 4 deletions

View file

@ -0,0 +1,24 @@
package com.x8bit.bitwarden.data.auth.datasource.network.api
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyResponseJson
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Url
/**
* Defines raw calls specific for key connectors that use custom urls.
*/
interface AuthenticatedKeyConnectorApi {
@POST
suspend fun storeMasterKeyToKeyConnector(
@Url url: String,
@Body body: KeyConnectorMasterKeyRequestJson,
): Result<Unit>
@GET
suspend fun getMasterKeyFromKeyConnector(
@Url url: String,
): Result<KeyConnectorMasterKeyResponseJson>
}

View file

@ -38,6 +38,9 @@ object AuthNetworkModule {
): AccountsService = AccountsServiceImpl( ): AccountsService = AccountsServiceImpl(
accountsApi = retrofits.unauthenticatedApiRetrofit.create(), accountsApi = retrofits.unauthenticatedApiRetrofit.create(),
authenticatedAccountsApi = retrofits.authenticatedApiRetrofit.create(), authenticatedAccountsApi = retrofits.authenticatedApiRetrofit.create(),
authenticatedKeyConnectorApi = retrofits
.createStaticRetrofit(isAuthenticated = true)
.create(),
json = json, json = json,
) )

View file

@ -0,0 +1,12 @@
package com.x8bit.bitwarden.data.auth.datasource.network.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents the request body used to store the master key in the cloud.
*/
@Serializable
data class KeyConnectorMasterKeyRequestJson(
@SerialName("Key") val masterKey: String,
)

View file

@ -0,0 +1,12 @@
package com.x8bit.bitwarden.data.auth.datasource.network.model
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
/**
* Represents the response body used to retrieve the master key from the cloud.
*/
@Serializable
data class KeyConnectorMasterKeyResponseJson(
@SerialName("Key") val masterKey: String,
)

View file

@ -2,6 +2,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.DeleteAccountResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorKeyRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorKeyRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson 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.ResendEmailRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson
@ -10,6 +11,7 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.SetPasswordRequest
/** /**
* Provides an API for querying accounts endpoints. * Provides an API for querying accounts endpoints.
*/ */
@Suppress("TooManyFunctions")
interface AccountsService { interface AccountsService {
/** /**
@ -64,4 +66,16 @@ interface AccountsService {
* Set the password. * Set the password.
*/ */
suspend fun setPassword(body: SetPasswordRequestJson): Result<Unit> suspend fun setPassword(body: SetPasswordRequestJson): Result<Unit>
/**
* Retrieves the master key from the key connector.
*/
suspend fun getMasterKeyFromKeyConnector(
url: String,
): Result<KeyConnectorMasterKeyResponseJson>
/**
* Stores the master key to the key connector.
*/
suspend fun storeMasterKeyToKeyConnector(url: String, masterKey: String): Result<Unit>
} }

View file

@ -2,10 +2,13 @@ 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.AccountsApi
import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedAccountsApi import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedAccountsApi
import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedKeyConnectorApi
import com.x8bit.bitwarden.data.auth.datasource.network.model.CreateAccountKeysRequest 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.DeleteAccountRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.DeleteAccountResponseJson 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.KeyConnectorKeyRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintRequestJson 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.PasswordHintResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson
@ -16,9 +19,14 @@ import com.x8bit.bitwarden.data.platform.datasource.network.model.toBitwardenErr
import com.x8bit.bitwarden.data.platform.datasource.network.util.parseErrorBodyOrNull import com.x8bit.bitwarden.data.platform.datasource.network.util.parseErrorBodyOrNull
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
/**
* The default implementation of the [AccountsService].
*/
@Suppress("TooManyFunctions")
class AccountsServiceImpl( class AccountsServiceImpl(
private val accountsApi: AccountsApi, private val accountsApi: AccountsApi,
private val authenticatedAccountsApi: AuthenticatedAccountsApi, private val authenticatedAccountsApi: AuthenticatedAccountsApi,
private val authenticatedKeyConnectorApi: AuthenticatedKeyConnectorApi,
private val json: Json, private val json: Json,
) : AccountsService { ) : AccountsService {
@ -107,4 +115,18 @@ class AccountsServiceImpl(
override suspend fun setPassword( override suspend fun setPassword(
body: SetPasswordRequestJson, body: SetPasswordRequestJson,
): Result<Unit> = authenticatedAccountsApi.setPassword(body) ): Result<Unit> = authenticatedAccountsApi.setPassword(body)
override suspend fun getMasterKeyFromKeyConnector(
url: String,
): Result<KeyConnectorMasterKeyResponseJson> =
authenticatedKeyConnectorApi.getMasterKeyFromKeyConnector(url = url)
override suspend fun storeMasterKeyToKeyConnector(
url: String,
masterKey: String,
): Result<Unit> =
authenticatedKeyConnectorApi.storeMasterKeyToKeyConnector(
url = url,
body = KeyConnectorMasterKeyRequestJson(masterKey = masterKey),
)
} }

View file

@ -2,16 +2,18 @@ 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.AccountsApi
import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedAccountsApi import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedAccountsApi
import com.x8bit.bitwarden.data.auth.datasource.network.api.AuthenticatedKeyConnectorApi
import com.x8bit.bitwarden.data.auth.datasource.network.model.KdfTypeJson 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.KeyConnectorKeyRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.KeyConnectorMasterKeyResponseJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.PasswordHintResponseJson 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.RegisterRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson import com.x8bit.bitwarden.data.auth.datasource.network.model.ResendEmailRequestJson
import com.x8bit.bitwarden.data.auth.datasource.network.model.ResetPasswordRequestJson 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.SetPasswordRequestJson
import com.x8bit.bitwarden.data.platform.base.BaseServiceTest import com.x8bit.bitwarden.data.platform.base.BaseServiceTest
import com.x8bit.bitwarden.data.platform.util.asSuccess
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockResponse
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Assertions.assertTrue
@ -22,12 +24,12 @@ class AccountsServiceTest : BaseServiceTest() {
private val accountsApi: AccountsApi = retrofit.create() private val accountsApi: AccountsApi = retrofit.create()
private val authenticatedAccountsApi: AuthenticatedAccountsApi = retrofit.create() private val authenticatedAccountsApi: AuthenticatedAccountsApi = retrofit.create()
private val authenticatedKeyConnectorApi: AuthenticatedKeyConnectorApi = retrofit.create()
private val service = AccountsServiceImpl( private val service = AccountsServiceImpl(
accountsApi = accountsApi, accountsApi = accountsApi,
authenticatedAccountsApi = authenticatedAccountsApi, authenticatedAccountsApi = authenticatedAccountsApi,
json = Json { authenticatedKeyConnectorApi = authenticatedKeyConnectorApi,
ignoreUnknownKeys = true json = json,
},
) )
@Test @Test
@ -206,4 +208,27 @@ class AccountsServiceTest : BaseServiceTest() {
) )
assertTrue(result.isSuccess) assertTrue(result.isSuccess)
} }
@Test
fun `getMasterKeyFromKeyConnector with empty response is success`() = runTest {
val masterKey = "masterKey"
val response = MockResponse().setBody("""{ "Key": "$masterKey" }""")
server.enqueue(response)
val result = service.getMasterKeyFromKeyConnector(url = "$url/test")
assertEquals(
KeyConnectorMasterKeyResponseJson(masterKey = masterKey).asSuccess(),
result,
)
}
@Test
fun `storeMasterKeyToKeyConnector success should return Success`() = runTest {
val response = MockResponse()
server.enqueue(response)
val result = service.storeMasterKeyToKeyConnector(
url = "$url/test",
masterKey = "masterKey",
)
assertEquals(Unit.asSuccess(), result)
}
} }