mirror of
https://github.com/bitwarden/android.git
synced 2025-12-10 09:56:45 -06:00
[PM-24258] Building a specific Fido2AttestationResponse to work with Binance (#5986)
This commit is contained in:
parent
2d2b740ae1
commit
a7bbb81b31
@ -323,6 +323,7 @@ class BitwardenCredentialManagerImpl(
|
||||
createPublicKeyCredentialRequest = createPublicKeyCredentialRequest,
|
||||
selectedCipherView = selectedCipherView,
|
||||
clientData = clientData,
|
||||
callingPackageName = callingAppInfo.packageName,
|
||||
)
|
||||
}
|
||||
|
||||
@ -347,6 +348,7 @@ class BitwardenCredentialManagerImpl(
|
||||
createPublicKeyCredentialRequest = createPublicKeyCredentialRequest,
|
||||
selectedCipherView = selectedCipherView,
|
||||
clientData = clientData,
|
||||
callingPackageName = callingAppInfo.packageName,
|
||||
)
|
||||
}
|
||||
|
||||
@ -356,6 +358,7 @@ class BitwardenCredentialManagerImpl(
|
||||
createPublicKeyCredentialRequest: CreatePublicKeyCredentialRequest,
|
||||
selectedCipherView: CipherView,
|
||||
clientData: ClientData,
|
||||
callingPackageName: String,
|
||||
): Fido2RegisterCredentialResult = vaultSdkSource
|
||||
.registerFido2Credential(
|
||||
request = RegisterFido2CredentialRequest(
|
||||
@ -370,7 +373,9 @@ class BitwardenCredentialManagerImpl(
|
||||
),
|
||||
fido2CredentialStore = this,
|
||||
)
|
||||
.map { it.toAndroidAttestationResponse() }
|
||||
.map {
|
||||
it.toAndroidAttestationResponse(callingPackageName = callingPackageName)
|
||||
}
|
||||
.mapCatching { json.encodeToString(it) }
|
||||
.fold(
|
||||
onSuccess = { Fido2RegisterCredentialResult.Success(it) },
|
||||
|
||||
@ -4,24 +4,33 @@ import android.util.Base64
|
||||
import com.bitwarden.fido.PublicKeyCredentialAuthenticatorAttestationResponse
|
||||
import com.x8bit.bitwarden.data.credentials.model.Fido2AttestationResponse
|
||||
|
||||
private const val BINANCE_PACKAGE_NAME = "com.binance.dev"
|
||||
|
||||
/**
|
||||
* Converts the SDK attestation response to a [Fido2AttestationResponse] that can be serialized into
|
||||
* the expected system JSON.
|
||||
*/
|
||||
@Suppress("MaxLineLength")
|
||||
fun PublicKeyCredentialAuthenticatorAttestationResponse.toAndroidAttestationResponse(): Fido2AttestationResponse =
|
||||
Fido2AttestationResponse(
|
||||
fun PublicKeyCredentialAuthenticatorAttestationResponse.toAndroidAttestationResponse(
|
||||
callingPackageName: String?,
|
||||
): Fido2AttestationResponse {
|
||||
val registrationResponse = Fido2AttestationResponse.RegistrationResponse(
|
||||
clientDataJson = response.clientDataJson.base64EncodeForFido2Response(),
|
||||
attestationObject = response.attestationObject.base64EncodeForFido2Response(),
|
||||
transports = response.transports.takeUnless {
|
||||
// Setting transports as null, otherwise Binance labels the passkey broken
|
||||
// PM-26734 remove this flow if not necessary anymore
|
||||
callingPackageName == BINANCE_PACKAGE_NAME
|
||||
},
|
||||
publicKeyAlgorithm = response.publicKeyAlgorithm,
|
||||
publicKey = response.publicKey?.base64EncodeForFido2Response(),
|
||||
authenticatorData = response.authenticatorData.base64EncodeForFido2Response(),
|
||||
)
|
||||
|
||||
return Fido2AttestationResponse(
|
||||
id = id,
|
||||
type = ty,
|
||||
rawId = rawId.base64EncodeForFido2Response(),
|
||||
response = Fido2AttestationResponse.RegistrationResponse(
|
||||
clientDataJson = response.clientDataJson.base64EncodeForFido2Response(),
|
||||
attestationObject = response.attestationObject.base64EncodeForFido2Response(),
|
||||
transports = response.transports,
|
||||
publicKeyAlgorithm = response.publicKeyAlgorithm,
|
||||
publicKey = response.publicKey?.base64EncodeForFido2Response(),
|
||||
authenticatorData = response.authenticatorData.base64EncodeForFido2Response(),
|
||||
),
|
||||
response = registrationResponse,
|
||||
clientExtensionResults = clientExtensionResults
|
||||
.credProps
|
||||
?.rk
|
||||
@ -34,6 +43,7 @@ fun PublicKeyCredentialAuthenticatorAttestationResponse.toAndroidAttestationResp
|
||||
} ?: Fido2AttestationResponse.ClientExtensionResults(),
|
||||
authenticatorAttachment = authenticatorAttachment,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Attestation response fields of type [ByteArray] must be base 64 encoded in a url safe format
|
||||
|
||||
@ -33,7 +33,7 @@ class PublicKeyCredentialAuthenticatorAttestationResponseExtensionsTest {
|
||||
@Test
|
||||
fun `authenticatorAttachment should be null when SDK value is null`() {
|
||||
val mockSdkResponse = createMockSdkAttestationResponse(number = 1)
|
||||
val result = mockSdkResponse.toAndroidAttestationResponse()
|
||||
val result = mockSdkResponse.toAndroidAttestationResponse(callingPackageName = "")
|
||||
assertNull(result.authenticatorAttachment)
|
||||
}
|
||||
|
||||
@ -43,14 +43,14 @@ class PublicKeyCredentialAuthenticatorAttestationResponseExtensionsTest {
|
||||
number = 1,
|
||||
authenticatorAttachment = "mockAuthenticatorAttachment",
|
||||
)
|
||||
val result = mockSdkResponse.toAndroidAttestationResponse()
|
||||
val result = mockSdkResponse.toAndroidAttestationResponse(callingPackageName = "")
|
||||
assertNotNull(result.authenticatorAttachment)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clientExtensionResults should be populated when SDK value is null`() {
|
||||
val mockSdkResponse = createMockSdkAttestationResponse(number = 1)
|
||||
val result = mockSdkResponse.toAndroidAttestationResponse()
|
||||
val result = mockSdkResponse.toAndroidAttestationResponse(callingPackageName = "")
|
||||
assertNotNull(result.clientExtensionResults)
|
||||
}
|
||||
|
||||
@ -63,9 +63,41 @@ class PublicKeyCredentialAuthenticatorAttestationResponseExtensionsTest {
|
||||
authenticatorDisplayName = null,
|
||||
),
|
||||
)
|
||||
val result = mockSdkResponse.toAndroidAttestationResponse()
|
||||
val result = mockSdkResponse.toAndroidAttestationResponse(callingPackageName = "")
|
||||
assert(result.clientExtensionResults.credentialProperties?.residentKey ?: false)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `toAndroidAttestationResponse should build specific response when package name is Binance`() {
|
||||
val binancePackageName = "com.binance.dev"
|
||||
val mockSdkResponse = createMockSdkAttestationResponse(number = 1)
|
||||
|
||||
val result = mockSdkResponse.toAndroidAttestationResponse(callingPackageName = binancePackageName)
|
||||
|
||||
assertNull(result.response.transports)
|
||||
assertNotNull(result.response.publicKey)
|
||||
assertNotNull(result.response.publicKeyAlgorithm)
|
||||
assertNotNull(result.response.authenticatorData)
|
||||
assertNotNull(result.response.clientDataJson)
|
||||
assertNotNull(result.response.attestationObject)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `toAndroidAttestationResponse should build full response for any package name other than Binance`() {
|
||||
val otherPackageName = "com.any.app"
|
||||
val mockSdkResponse = createMockSdkAttestationResponse(number = 1)
|
||||
|
||||
val result = mockSdkResponse.toAndroidAttestationResponse(callingPackageName = otherPackageName)
|
||||
|
||||
assertNotNull(result.response.transports)
|
||||
assertNotNull(result.response.publicKey)
|
||||
assertNotNull(result.response.publicKeyAlgorithm)
|
||||
assertNotNull(result.response.authenticatorData)
|
||||
assertNotNull(result.response.clientDataJson)
|
||||
assertNotNull(result.response.attestationObject)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createMockSdkAttestationResponse(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user