Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix formatting of maxTimeout value in Stripe3ds2AuthParams #2483

Merged
merged 1 commit into from
May 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions stripe/src/main/java/com/stripe/android/Stripe3ds2AuthParams.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.stripe.android

import android.os.Parcelable
import androidx.annotation.VisibleForTesting
import com.stripe.android.model.StripeParamsModel
import java.text.DecimalFormat
import kotlinx.android.parcel.Parcelize
import org.json.JSONArray
import org.json.JSONObject
Expand All @@ -23,35 +23,35 @@ internal data class Stripe3ds2AuthParams(
override fun toParamMap(): Map<String, Any> {
return mapOf(
FIELD_SOURCE to sourceId,
FIELD_APP to createAppParams().toString()
FIELD_APP to appParams.toString()
).plus(
returnUrl?.let {
mapOf(FIELD_FALLBACK_RETURN_URL to it)
}.orEmpty()
)
}

private fun createAppParams(): JSONObject {
return runCatching {
internal val appParams: JSONObject
@JvmSynthetic
@VisibleForTesting
get() = runCatching {
JSONObject()
.put(FIELD_SDK_APP_ID, sdkAppId)
.put(FIELD_SDK_TRANS_ID, sdkTransactionId)
.put(FIELD_SDK_ENC_DATA, deviceData)
.put(FIELD_SDK_EPHEM_PUB_KEY, JSONObject(sdkEphemeralPublicKey))
.put(FIELD_SDK_MAX_TIMEOUT, MAX_TIMEOUT_FORMATTER.format(maxTimeout.toLong()))
.put(FIELD_SDK_MAX_TIMEOUT, maxTimeout.toString().padStart(2, '0'))
.put(FIELD_SDK_REFERENCE_NUMBER, sdkReferenceNumber)
.put(FIELD_MESSAGE_VERSION, messageVersion)
.put(FIELD_DEVICE_RENDER_OPTIONS, createDeviceRenderOptions())
.put(FIELD_DEVICE_RENDER_OPTIONS, deviceRenderOptions)
}.getOrDefault(JSONObject())
}

private fun createDeviceRenderOptions(): JSONObject {
return runCatching {
private val deviceRenderOptions: JSONObject
get() = runCatching {
JSONObject()
.put(FIELD_SDK_INTERFACE, "03")
.put(FIELD_SDK_UI_TYPE, JSONArray(listOf("01", "02", "03", "04", "05")))
}.getOrDefault(JSONObject())
}

internal companion object {
internal const val FIELD_APP = "app"
Expand All @@ -69,7 +69,5 @@ internal data class Stripe3ds2AuthParams(

private const val FIELD_SDK_INTERFACE = "sdkInterface"
private const val FIELD_SDK_UI_TYPE = "sdkUiType"

private val MAX_TIMEOUT_FORMATTER = DecimalFormat("00")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,10 @@ class Stripe3ds2AuthParamsTest {

@Test
fun toParamMap_shouldReturnCorrectObject() {
val sourceId = "src_12345"
val appId = "1.0.0"
val sdkReferenceNumber = "3DS_LOA_SDK_STIN_12345"
val sdkTransactionId = "26a3ef80-f09c-4954-94f4-66c7fe9409ba"
val deviceData = "eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.nid2Q-Ii21cSPHBaszR5KSXz866yX9I7AthLKpfWZoc7RIfz11UJ1EHuvIRDIyqqJ8txNUKKoL4keqMTqK5Yc5TqsxMn0nML8pZaPn40nXsJm_HFv3zMeOtRR7UTewsDWIgf5J-A6bhowIOmvKPCJRxspn_Cmja-YpgFWTp08uoJvqgntgg1lHmI1kh1UV6DuseYFUfuQlICTqC3TspAzah2CALWZORF_QtSeHc_RuqK02wOQMs-7079jRuSdBXvI6dQnL5ESH25wHHosfjHMZ9vtdUFNJo9J35UI1sdWFDzzj8k7bt0BupZhyeU0PSM9EHP-yv01-MQ9eslPTVNbFJ9YOHtq8WamvlKDr1sKxz6Ac_gUM8NgEcPP9SafPVxDd4H1Fwb5-4NYu2AD4xoAgMWE-YtzvfIFXZcU46NDoi6Xum3cHJqTH0UaOhBoqJJft9XZXYW80fjts-v28TkA76-QPF7CTDM6KbupvBkSoRq218eJLEywySXgCwf-Q95fsBtnnyhKcvfRaByq5kT7PH3DYD1rCQLexJ76A79kurre9pDjTKAv85G9DNkOFuVUYnNB3QGFReCcF9wzkGnZXdfkgN2BkB6n94bbkEyjbRb5r37XH6oRagx2fWLVj7kC5baeIwUPVb5kV_x4Kle7C-FPY1Obz4U7s6SVRnLGXY.IP9OcQx5uZxBRluOpn1m6Q.w-Ko5Qg6r-KCmKnprXEbKA7wV-SdLNDAKqjtuku6hda_0crOPRCPU4nn26Yxj7EG.p01pl8CKukuXzjLeY3a_Ew"
val sdkEphemeralPublicKey = JSONObject(
"""
{
"kty": "EC",
"use": "sig",
"crv": "P-256",
"kid": "b23da28b-d611-46a8-93af-44ad57ce9c9d",
"x": "hSwyaaAp3ppSGkpt7d9G8wnp3aIXelsZVo05EPpqetg",
"y": "OUVOv9xPh5RYWapla0oz3vCJWRRXlDmppy5BGNeSl-A"
}
""".trimIndent()
).toString()
val messageVersion = "2.1.0"
val timeout = 5

val params = Stripe3ds2AuthParams(
sourceId, appId,
sdkReferenceNumber,
sdkTransactionId,
deviceData,
sdkEphemeralPublicKey,
messageVersion,
timeout,
RETURN_URL
).toParamMap()
val params = createParams().toParamMap()

assertThat(params[Stripe3ds2AuthParams.FIELD_SOURCE])
.isEqualTo(sourceId)
.isEqualTo(SOURCE_ID)

assertThat(params[Stripe3ds2AuthParams.FIELD_APP])
.isEqualTo(
Expand All @@ -52,8 +23,8 @@ class Stripe3ds2AuthParamsTest {
{
"sdkAppID": "1.0.0",
"sdkTransID": "26a3ef80-f09c-4954-94f4-66c7fe9409ba",
"sdkEncData": "$deviceData",
"sdkEphemPubKey": $sdkEphemeralPublicKey,
"sdkEncData": "$DEVICE_DATA",
"sdkEphemPubKey": $SDK_EPHEMERAL_PUBLIC_KEY,
"sdkMaxTimeout": "05",
"sdkReferenceNumber": "3DS_LOA_SDK_STIN_12345",
"messageVersion": "2.1.0",
Expand All @@ -70,7 +41,57 @@ class Stripe3ds2AuthParamsTest {
.isEqualTo(RETURN_URL)
}

@Test
fun appParams_correctlyFormatsSdkTimeout() {
listOf(
5 to "05",
10 to "10",
19 to "19",
99 to "99"
).forEach { (first, second) ->
assertThat(
createParams(timeout = first)
.appParams
.getString("sdkMaxTimeout")
).isEqualTo(second)
}
}

private fun createParams(timeout: Int = 5): Stripe3ds2AuthParams {
val appId = "1.0.0"
val sdkReferenceNumber = "3DS_LOA_SDK_STIN_12345"
val sdkTransactionId = "26a3ef80-f09c-4954-94f4-66c7fe9409ba"
val messageVersion = "2.1.0"

return Stripe3ds2AuthParams(
SOURCE_ID,
appId,
sdkReferenceNumber,
sdkTransactionId,
DEVICE_DATA,
SDK_EPHEMERAL_PUBLIC_KEY,
messageVersion,
timeout,
RETURN_URL
)
}

private companion object {
private const val SOURCE_ID = "src_12345"
private const val RETURN_URL = "stripe://payment-auth-return"
private const val DEVICE_DATA = "eyJlbmMiOiJBMTI4Q0JDLUhTMjU2IiwiYWxnIjoiUlNBLU9BRVAtMjU2In0.nid2Q-Ii21cSPHBaszR5KSXz866yX9I7AthLKpfWZoc7RIfz11UJ1EHuvIRDIyqqJ8txNUKKoL4keqMTqK5Yc5TqsxMn0nML8pZaPn40nXsJm_HFv3zMeOtRR7UTewsDWIgf5J-A6bhowIOmvKPCJRxspn_Cmja-YpgFWTp08uoJvqgntgg1lHmI1kh1UV6DuseYFUfuQlICTqC3TspAzah2CALWZORF_QtSeHc_RuqK02wOQMs-7079jRuSdBXvI6dQnL5ESH25wHHosfjHMZ9vtdUFNJo9J35UI1sdWFDzzj8k7bt0BupZhyeU0PSM9EHP-yv01-MQ9eslPTVNbFJ9YOHtq8WamvlKDr1sKxz6Ac_gUM8NgEcPP9SafPVxDd4H1Fwb5-4NYu2AD4xoAgMWE-YtzvfIFXZcU46NDoi6Xum3cHJqTH0UaOhBoqJJft9XZXYW80fjts-v28TkA76-QPF7CTDM6KbupvBkSoRq218eJLEywySXgCwf-Q95fsBtnnyhKcvfRaByq5kT7PH3DYD1rCQLexJ76A79kurre9pDjTKAv85G9DNkOFuVUYnNB3QGFReCcF9wzkGnZXdfkgN2BkB6n94bbkEyjbRb5r37XH6oRagx2fWLVj7kC5baeIwUPVb5kV_x4Kle7C-FPY1Obz4U7s6SVRnLGXY.IP9OcQx5uZxBRluOpn1m6Q.w-Ko5Qg6r-KCmKnprXEbKA7wV-SdLNDAKqjtuku6hda_0crOPRCPU4nn26Yxj7EG.p01pl8CKukuXzjLeY3a_Ew"

private val SDK_EPHEMERAL_PUBLIC_KEY = JSONObject(
"""
{
"kty": "EC",
"use": "sig",
"crv": "P-256",
"kid": "b23da28b-d611-46a8-93af-44ad57ce9c9d",
"x": "hSwyaaAp3ppSGkpt7d9G8wnp3aIXelsZVo05EPpqetg",
"y": "OUVOv9xPh5RYWapla0oz3vCJWRRXlDmppy5BGNeSl-A"
}
""".trimIndent()
).toString()
}
}