mirror of
https://github.com/bitwarden/android.git
synced 2026-06-02 02:36:58 -05:00
Add AuthSdkSource (#118)
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
package com.x8bit.bitwarden.data.auth.datasource.sdk
|
||||
|
||||
import com.bitwarden.core.Kdf
|
||||
import com.bitwarden.core.MasterPasswordPolicyOptions
|
||||
import com.bitwarden.core.RegisterKeyResponse
|
||||
import com.bitwarden.sdk.ClientAuth
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.model.PasswordStrength
|
||||
import com.x8bit.bitwarden.data.platform.util.asSuccess
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class AuthSdkSourceTest {
|
||||
private val clientAuth = mockk<ClientAuth>()
|
||||
|
||||
private val authSkdSource: AuthSdkSource = AuthSdkSourceImpl(
|
||||
clientAuth = clientAuth,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `hashPassword should call SDK and return a Result with the correct data`() = runBlocking {
|
||||
val email = "email"
|
||||
val password = "password"
|
||||
val kdf = mockk<Kdf>()
|
||||
val expectedResult = "hashedPassword"
|
||||
coEvery {
|
||||
clientAuth.hashPassword(
|
||||
email = email,
|
||||
password = password,
|
||||
kdfParams = kdf,
|
||||
)
|
||||
} returns expectedResult
|
||||
|
||||
val result = authSkdSource.hashPassword(
|
||||
email = email,
|
||||
password = password,
|
||||
kdf = kdf,
|
||||
)
|
||||
assertEquals(
|
||||
expectedResult.asSuccess(),
|
||||
result,
|
||||
)
|
||||
coVerify {
|
||||
clientAuth.hashPassword(
|
||||
email = email,
|
||||
password = password,
|
||||
kdfParams = kdf,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `makeRegisterKeys should call SDK and return a Result with the correct data`() =
|
||||
runBlocking {
|
||||
val email = "email"
|
||||
val password = "password"
|
||||
val kdf = mockk<Kdf>()
|
||||
val expectedResult = mockk<RegisterKeyResponse>()
|
||||
coEvery {
|
||||
clientAuth.makeRegisterKeys(
|
||||
email = email,
|
||||
password = password,
|
||||
kdf = kdf,
|
||||
)
|
||||
} returns expectedResult
|
||||
|
||||
val result = authSkdSource.makeRegisterKeys(
|
||||
email = email,
|
||||
password = password,
|
||||
kdf = kdf,
|
||||
)
|
||||
assertEquals(
|
||||
expectedResult.asSuccess(),
|
||||
result,
|
||||
)
|
||||
coVerify {
|
||||
clientAuth.makeRegisterKeys(
|
||||
email = email,
|
||||
password = password,
|
||||
kdf = kdf,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: This test is disabled due to issue here with mocking UByte (BIT-877).
|
||||
// See: https://github.com/mockk/mockk/issues/544
|
||||
@Disabled
|
||||
@Test
|
||||
fun `passwordStrength should call SDK and return a Result with the correct data`() =
|
||||
runBlocking {
|
||||
val email = "email"
|
||||
val password = "password"
|
||||
val additionalInputs = listOf("test1", "test2")
|
||||
val sdkResult = 3.toUByte()
|
||||
val expectedResult = PasswordStrength.LEVEL_3
|
||||
coEvery {
|
||||
clientAuth.passwordStrength(
|
||||
email = email,
|
||||
password = password,
|
||||
additionalInputs = additionalInputs,
|
||||
)
|
||||
} returns sdkResult
|
||||
|
||||
val result = authSkdSource.passwordStrength(
|
||||
email = email,
|
||||
password = password,
|
||||
additionalInputs = additionalInputs,
|
||||
)
|
||||
assertEquals(
|
||||
expectedResult.asSuccess(),
|
||||
result,
|
||||
)
|
||||
coVerify {
|
||||
clientAuth.passwordStrength(
|
||||
email = email,
|
||||
password = password,
|
||||
additionalInputs = additionalInputs,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `satisfiesPolicy should call SDK and return a Result with the correct data`() =
|
||||
runBlocking {
|
||||
val password = "password"
|
||||
val passwordStrength = PasswordStrength.LEVEL_3
|
||||
val rawStrength = 3.toUByte()
|
||||
val policy = mockk<MasterPasswordPolicyOptions>()
|
||||
val expectedResult = true
|
||||
coEvery {
|
||||
clientAuth.satisfiesPolicy(
|
||||
password = password,
|
||||
strength = rawStrength,
|
||||
policy = policy,
|
||||
)
|
||||
} returns expectedResult
|
||||
|
||||
val result = authSkdSource.satisfiesPolicy(
|
||||
password = password,
|
||||
passwordStrength = passwordStrength,
|
||||
policy = policy,
|
||||
)
|
||||
assertEquals(
|
||||
expectedResult.asSuccess(),
|
||||
result,
|
||||
)
|
||||
coVerify {
|
||||
clientAuth.satisfiesPolicy(
|
||||
password = password,
|
||||
strength = rawStrength,
|
||||
policy = policy,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.x8bit.bitwarden.data.auth.repository
|
||||
|
||||
import app.cash.turbine.test
|
||||
import com.bitwarden.sdk.Client
|
||||
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.model.AuthState
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.model.GetTokenResponseJson
|
||||
@@ -10,6 +9,7 @@ import com.x8bit.bitwarden.data.auth.datasource.network.model.PreLoginResponseJs
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.AccountsService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.service.IdentityService
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.util.CaptchaCallbackTokenResult
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.AuthSdkSource
|
||||
import com.x8bit.bitwarden.data.auth.util.toSdkParams
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.interceptor.AuthTokenInterceptor
|
||||
import io.mockk.clearMocks
|
||||
@@ -30,20 +30,20 @@ class AuthRepositoryTest {
|
||||
private val identityService: IdentityService = mockk()
|
||||
private val authInterceptor = mockk<AuthTokenInterceptor>()
|
||||
private val fakeAuthDiskSource = FakeAuthDiskSource()
|
||||
private val mockBitwardenSdk = mockk<Client> {
|
||||
private val authSdkSource = mockk<AuthSdkSource> {
|
||||
coEvery {
|
||||
auth().hashPassword(
|
||||
hashPassword(
|
||||
email = EMAIL,
|
||||
password = PASSWORD,
|
||||
kdfParams = PRE_LOGIN_SUCCESS.kdfParams.toSdkParams(),
|
||||
kdf = PRE_LOGIN_SUCCESS.kdfParams.toSdkParams(),
|
||||
)
|
||||
} returns PASSWORD_HASH
|
||||
} returns Result.success(PASSWORD_HASH)
|
||||
}
|
||||
|
||||
private val repository = AuthRepositoryImpl(
|
||||
accountsService = accountsService,
|
||||
identityService = identityService,
|
||||
bitwardenSdkClient = mockBitwardenSdk,
|
||||
authSdkSource = authSdkSource,
|
||||
authDiskSource = fakeAuthDiskSource,
|
||||
authTokenInterceptor = authInterceptor,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.x8bit.bitwarden.data.platform.datasource.sdk.util
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.model.PasswordStrength
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.util.toInt
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.util.toPasswordStrengthOrNull
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.util.toUByte
|
||||
import com.x8bit.bitwarden.data.auth.datasource.sdk.util.toUInt
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNull
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class PasswordStrengthExtensionsTest {
|
||||
@Nested
|
||||
inner class IntegerType {
|
||||
@Test
|
||||
fun `toPasswordStrengthOrNull returns the correct values in 0 to 4 range`() {
|
||||
mapOf(
|
||||
0 to PasswordStrength.LEVEL_0,
|
||||
1 to PasswordStrength.LEVEL_1,
|
||||
2 to PasswordStrength.LEVEL_2,
|
||||
3 to PasswordStrength.LEVEL_3,
|
||||
4 to PasswordStrength.LEVEL_4,
|
||||
)
|
||||
.forEach { (intValue, level) ->
|
||||
assertEquals(
|
||||
level,
|
||||
intValue.toPasswordStrengthOrNull(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toPasswordStrengthOrNull returns null outside the 0 to 4 range`() {
|
||||
listOf(-2, -1, 5, 6).forEach { intValue ->
|
||||
assertNull(
|
||||
intValue.toPasswordStrengthOrNull(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toInt returns the correct Int for each level`() {
|
||||
mapOf(
|
||||
PasswordStrength.LEVEL_0 to 0,
|
||||
PasswordStrength.LEVEL_1 to 1,
|
||||
PasswordStrength.LEVEL_2 to 2,
|
||||
PasswordStrength.LEVEL_3 to 3,
|
||||
PasswordStrength.LEVEL_4 to 4,
|
||||
)
|
||||
.forEach { (level, intValue) ->
|
||||
assertEquals(
|
||||
intValue,
|
||||
level.toInt(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class UByteType {
|
||||
@Test
|
||||
fun `toPasswordStrengthOrNull returns the correct values in 0 to 4 range`() {
|
||||
mapOf(
|
||||
0.toUByte() to PasswordStrength.LEVEL_0,
|
||||
1.toUByte() to PasswordStrength.LEVEL_1,
|
||||
2.toUByte() to PasswordStrength.LEVEL_2,
|
||||
3.toUByte() to PasswordStrength.LEVEL_3,
|
||||
4.toUByte() to PasswordStrength.LEVEL_4,
|
||||
)
|
||||
.forEach { (uByteValue, level) ->
|
||||
assertEquals(
|
||||
level,
|
||||
uByteValue.toPasswordStrengthOrNull(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toPasswordStrengthOrNull returns null outside the 0 to 4 range`() {
|
||||
listOf(5.toUByte(), 6.toUByte()).forEach { uByteValue ->
|
||||
assertNull(
|
||||
uByteValue.toPasswordStrengthOrNull(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toUByte returns the correct UByte for each level`() {
|
||||
mapOf(
|
||||
PasswordStrength.LEVEL_0 to 0.toUByte(),
|
||||
PasswordStrength.LEVEL_1 to 1.toUByte(),
|
||||
PasswordStrength.LEVEL_2 to 2.toUByte(),
|
||||
PasswordStrength.LEVEL_3 to 3.toUByte(),
|
||||
PasswordStrength.LEVEL_4 to 4.toUByte(),
|
||||
)
|
||||
.forEach { (level, uByteValue) ->
|
||||
assertEquals(
|
||||
uByteValue,
|
||||
level.toUByte(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
inner class UIntType {
|
||||
@Test
|
||||
fun `toPasswordStrengthOrNull returns the correct values in 0 to 4 range`() {
|
||||
mapOf(
|
||||
0u to PasswordStrength.LEVEL_0,
|
||||
1u to PasswordStrength.LEVEL_1,
|
||||
2u to PasswordStrength.LEVEL_2,
|
||||
3u to PasswordStrength.LEVEL_3,
|
||||
4u to PasswordStrength.LEVEL_4,
|
||||
)
|
||||
.forEach { (uIntValue, level) ->
|
||||
assertEquals(
|
||||
level,
|
||||
uIntValue.toPasswordStrengthOrNull(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toPasswordStrengthOrNull returns null outside the 0 to 4 range`() {
|
||||
listOf(5u, 6u).forEach { uIntValue ->
|
||||
assertNull(
|
||||
uIntValue.toPasswordStrengthOrNull(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `toUInt returns the correct UInt for each level`() {
|
||||
mapOf(
|
||||
PasswordStrength.LEVEL_0 to 0u,
|
||||
PasswordStrength.LEVEL_1 to 1u,
|
||||
PasswordStrength.LEVEL_2 to 2u,
|
||||
PasswordStrength.LEVEL_3 to 3u,
|
||||
PasswordStrength.LEVEL_4 to 4u,
|
||||
)
|
||||
.forEach { (level, uIntValue) ->
|
||||
assertEquals(
|
||||
uIntValue,
|
||||
level.toUInt(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,4 +49,21 @@ class ResultTest {
|
||||
assertTrue(stringResult.isFailure)
|
||||
assertEquals(expectedException, stringResult.exceptionOrNull())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `asSuccess returns a success Result with the correct content`() {
|
||||
assertEquals(
|
||||
Result.success("Test"),
|
||||
"Test".asSuccess(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `asFailure returns a failure Result with the correct content`() {
|
||||
val throwable = IllegalStateException("Test")
|
||||
assertEquals(
|
||||
Result.failure<Nothing>(throwable),
|
||||
throwable.asFailure(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user