Skip to content

Commit

Permalink
feat(POM-327): Token is optional when parsing 3DS and APM return deep…
Browse files Browse the repository at this point in the history
… link (#156)
  • Loading branch information
vitalii-vanziak-cko authored Jan 15, 2024
1 parent 72cb75e commit 4f96574
Show file tree
Hide file tree
Showing 14 changed files with 76 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,18 @@ internal class DefaultAlternativePaymentMethodsService(
}

override fun alternativePaymentMethodResponse(uri: Uri): ProcessOutResult<POAlternativePaymentMethodResponse> {
val errorMessage = "Invalid or malformed Alternative Payment Method URL: $uri"
if (uri.isOpaque)
return ProcessOutResult.Failure(code = Internal(), message = errorMessage)
if (uri.isOpaque) {
return ProcessOutResult.Failure(
code = Internal(),
message = "Invalid or malformed alternative payment method URI: $uri"
)
}

uri.getQueryParameter("error_code")?.let { errorCode ->
return ProcessOutResult.Failure(failureCode(errorCode))
}

val gatewayToken = uri.getQueryParameter("token")
?: return ProcessOutResult.Failure(code = Internal(), message = errorMessage)
val gatewayToken = uri.getQueryParameter("token") ?: String()

val customerId = uri.getQueryParameter("customer_id")
val tokenId = uri.getQueryParameter("token_id")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class POAlternativePaymentMethodCustomTabLauncher private constructor(
customTabLauncher.launch(
CustomTabConfiguration(
uri = uri,
returnUri = Uri.parse(returnUrl),
timeoutSeconds = null
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class PO3DSRedirectCustomTabLauncher private constructor(
customTabLauncher.launch(
CustomTabConfiguration(
uri = delegate.uri,
returnUri = Uri.parse(returnUrl),
timeoutSeconds = redirect.timeoutSeconds
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@ internal class ThreeDSRedirectWebAuthorizationDelegate(
}

override fun complete(uri: Uri) {
uri.getQueryParameter(TOKEN_QUERY_KEY)?.let { token ->
callback(ProcessOutResult.Success(token))
} ?: callback(
ProcessOutResult.Failure(
POFailure.Code.Internal(),
"Token not found in URI: $uri"
if (uri.isHierarchical) {
callback(
ProcessOutResult.Success(
value = uri.getQueryParameter(TOKEN_QUERY_KEY) ?: String()
)
)
)
} else {
callback(
ProcessOutResult.Failure(
code = POFailure.Code.Internal(),
message = "Invalid or malformed 3DS redirect URI: $uri"
)
)
}
}

override fun complete(failure: ProcessOutResult.Failure) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.processout.sdk.ui.web.customtab

import android.net.Uri
import android.os.Parcelable
import com.processout.sdk.core.ProcessOutActivityResult
import kotlinx.parcelize.Parcelize

internal sealed class CustomTabAuthorizationUiState : Parcelable {
Expand All @@ -17,6 +18,9 @@ internal sealed class CustomTabAuthorizationUiState : Parcelable {
@Parcelize
data class Success(val returnUri: Uri) : CustomTabAuthorizationUiState()

@Parcelize
data class Failure(val failure: ProcessOutActivityResult.Failure) : CustomTabAuthorizationUiState()

@Parcelize
data object Cancelled : CustomTabAuthorizationUiState()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import androidx.lifecycle.AbstractSavedStateViewModelFactory
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.savedstate.SavedStateRegistryOwner
import com.processout.sdk.core.POFailure
import com.processout.sdk.core.ProcessOutActivityResult
import com.processout.sdk.core.logger.POLogger
import com.processout.sdk.ui.web.customtab.CustomTabAuthorizationActivityContract.Companion.EXTRA_TIMEOUT_FINISH
import com.processout.sdk.ui.web.customtab.CustomTabAuthorizationUiState.*
Expand Down Expand Up @@ -59,8 +61,22 @@ internal class CustomTabAuthorizationViewModel(
val returnUri = intent.data
if (returnUri != null) {
timeoutHandler.removeCallbacks(cancellationRunnable)
POLogger.info("Custom Chrome Tabs has been redirected to return URL: %s", returnUri)
savedState[KEY_SAVED_STATE] = Success(returnUri)
if (returnUri.scheme == configuration.returnUri.scheme &&
returnUri.host == configuration.returnUri.host &&
returnUri.path == configuration.returnUri.path
) {
POLogger.info("Custom Chrome Tabs has been redirected to return URI: %s", returnUri)
savedState[KEY_SAVED_STATE] = Success(returnUri)
} else {
val errorMessage = "Unexpected Custom Chrome Tabs redirect to URI: $returnUri"
POLogger.error(errorMessage)
savedState[KEY_SAVED_STATE] = Failure(
ProcessOutActivityResult.Failure(
code = POFailure.Code.Internal(),
message = errorMessage
)
)
}
return
}
when (uiState) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ import kotlinx.parcelize.Parcelize
@Parcelize
internal data class CustomTabConfiguration(
val uri: Uri,
val returnUri: Uri,
val timeoutSeconds: Int? = null
) : Parcelable
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class POCustomTabAuthorizationActivity : AppCompatActivity() {
is Success -> finishWithActivityResult(
ProcessOutActivityResult.Success(uiState.returnUri)
)
is Failure -> finishWithActivityResult(uiState.failure)
Cancelled -> finishWithActivityResult(
ProcessOutActivityResult.Failure(
POFailure.Code.Cancelled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,11 @@ internal class ProcessOutWebView(
super.onPageStarted(view, url, favicon)
url?.let {
val uri = Uri.parse(it)
if (uri.isHierarchical && uri.path != null) {
if (uri.isHierarchical) {
configuration.returnUris.find { returnUri ->
val returnUrl = returnUri.toString()
if (returnUrl.isNotBlank()) {
uri.toString().startsWith(returnUrl, ignoreCase = false)
} else false
uri.scheme == returnUri.scheme &&
uri.host == returnUri.host &&
uri.path == returnUri.path
}?.let { complete(uri) }
}
}
Expand Down Expand Up @@ -136,7 +135,7 @@ internal class ProcessOutWebView(
}
} ?: complete(
ProcessOutResult.Failure(
POFailure.Code.Internal(),
POFailure.Code.Generic(),
"$description | Failed to load URL: $failingUrl"
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,19 @@ class AlternativePaymentMethodsServiceTests {
}
}

@Test
fun alternativePaymentMethodResponseWithoutGatewayToken() {
val returnUrl = "https://processout.return"

apmService.alternativePaymentMethodResponse(Uri.parse(returnUrl)).let { result ->
result.assertFailure()
result.onSuccess { response ->
assert(response.gatewayToken.isEmpty())
assert(response.returnType == POAlternativePaymentMethodResponse.APMReturnType.AUTHORIZATION)
}
}
}

@Test
fun alternativePaymentMethodResponseWithCustomerToken() {
val returnUrl = "https://processout.return?token=gway_req_test" +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ package com.processout.sdk.ui.card.tokenization

import android.os.Parcelable
import androidx.annotation.ColorRes
import com.processout.sdk.core.annotation.ProcessOutInternalApi
import com.processout.sdk.ui.core.style.POActionsContainerStyle
import com.processout.sdk.ui.core.style.POFieldStyle
import com.processout.sdk.ui.core.style.POTextStyle
import com.processout.sdk.ui.shared.configuration.POCancellationConfiguration
import kotlinx.parcelize.Parcelize

/** @suppress */
@ProcessOutInternalApi
@Parcelize
data class POCardTokenizationConfiguration(
val title: String? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.processout.sdk.ui.card.tokenization

import android.os.Parcelable
import com.processout.sdk.core.annotation.ProcessOutInternalApi
import kotlinx.parcelize.Parcelize

/** @suppress */
@ProcessOutInternalApi
@Parcelize
data class POCardTokenizationFormData(
internal val cardInformation: CardInformation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import androidx.fragment.app.Fragment
import com.processout.sdk.core.ProcessOutActivityResult
import com.processout.sdk.core.annotation.ProcessOutInternalApi

/**
* Launcher that starts [CardTokenizationActivity] and provides the result.
*/
/** @suppress */
@ProcessOutInternalApi
class POCardTokenizationLauncher private constructor() {

private lateinit var launcher: ActivityResultLauncher<POCardTokenizationConfiguration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package com.processout.sdk.ui.card.tokenization

import android.os.Parcelable
import com.processout.sdk.api.model.response.POCard
import com.processout.sdk.core.annotation.ProcessOutInternalApi
import kotlinx.parcelize.Parcelize

/** @suppress */
@ProcessOutInternalApi
@Parcelize
data class POCardTokenizationResponse(
val card: POCard,
Expand Down

0 comments on commit 4f96574

Please sign in to comment.