Skip to content

Commit

Permalink
fix(threedsmethod): changed Three DS method API call to hidden Form P…
Browse files Browse the repository at this point in the history
…ost (#302)

Co-authored-by: Praful Koppalkar <126236898+prafulkoppalkar@users.noreply.github.com>
Co-authored-by: Vrishab Srivatsa <vrishab.srivatsa@juspay.in>
  • Loading branch information
3 people committed Apr 18, 2024
1 parent b13a369 commit e42a5a3
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 163 deletions.
122 changes: 62 additions & 60 deletions src/ThreeDSMethod.res
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,25 @@ open Utils
let make = () => {
let logger = OrcaLogger.make()

let mountToInnerHTML = innerHTML => {
let ele = Window.querySelector("#threeDsInvisibleIframe")
switch ele->Nullable.toOption {
| Some(elem) => elem->Window.innerHTML(innerHTML)
| None =>
Console.warn(
"INTEGRATION ERROR: Div does not seem to exist on which threeDSMethod is to be mounted",
)
}
let (stateMetadata, setStateMetadata) = React.useState(_ => Dict.make()->JSON.Encode.object)

let handleLoaded = _ev => {
stateMetadata->Utils.getDictFromJson->Dict.set("3dsMethodComp", "Y"->JSON.Encode.string)
let metadataDict = stateMetadata->JSON.Decode.object->Option.getOr(Dict.make())
let iframeId = metadataDict->getString("iframeId", "")
LoggerUtils.handleLogging(
~optLogger=Some(logger),
~eventName=THREE_DS_METHOD_RESULT,
~value="Y",
~paymentMethod="CARD",
(),
)
handlePostMessage([
("fullscreen", true->JSON.Encode.bool),
("param", `3dsAuth`->JSON.Encode.string),
("iframeId", iframeId->JSON.Encode.string),
("metadata", stateMetadata),
])
}

React.useEffect0(() => {
Expand All @@ -21,6 +31,7 @@ let make = () => {
let dict = json->Utils.getDictFromJson
if dict->Dict.get("fullScreenIframeMounted")->Option.isSome {
let metadata = dict->getJsonObjectFromDict("metadata")
setStateMetadata(_ => metadata)
let metaDataDict = metadata->JSON.Decode.object->Option.getOr(Dict.make())
let threeDsDataDict =
metaDataDict
Expand All @@ -42,74 +53,65 @@ let make = () => {
->Option.getOr(Dict.make()->JSON.Encode.object)
let paymentIntentId = metaDataDict->Utils.getString("paymentIntentId", "")
let publishableKey = metaDataDict->Utils.getString("publishableKey", "")
let iframeId = metaDataDict->getString("iframeId", "")

logger.setClientSecret(paymentIntentId)
logger.setMerchantId(publishableKey)

open Promise
PaymentHelpers.threeDsMethod(threeDsUrl, threeDsMethodData, ~optLogger=Some(logger))
->then(res => {
if res == "" {
Exn.raiseError("Empty response from threeDsMethod")->reject
} else {
LoggerUtils.handleLogging(
~optLogger=Some(logger),
~eventName=THREE_DS_METHOD_RESULT,
~value="Y",
~paymentMethod="CARD",
(),
)
mountToInnerHTML(res)
metadata->Utils.getDictFromJson->Dict.set("3dsMethodComp", "Y"->JSON.Encode.string)
handlePostMessage([
("fullscreen", true->JSON.Encode.bool),
("param", `3dsAuth`->JSON.Encode.string),
("iframeId", iframeId->JSON.Encode.string),
("metadata", metadata),
])
resolve(res)
}
})
->catch(err => {
let exceptionMessage = err->Utils.formatException
metadata->Utils.getDictFromJson->Dict.set("3dsMethodComp", "N"->JSON.Encode.string)
handlePostMessage([
("fullscreen", true->JSON.Encode.bool),
("param", `3dsAuth`->JSON.Encode.string),
("iframeId", iframeId->JSON.Encode.string),
("metadata", metadata),
])
let iframeId = metaDataDict->getString("iframeId", "")

let handleFailureScenarios = value => {
LoggerUtils.handleLogging(
~optLogger=Some(logger),
~eventName=THREE_DS_METHOD_RESULT,
~value=exceptionMessage->JSON.stringify,
~value,
~paymentMethod="CARD",
~logType=ERROR,
(),
)
reject(err)
})
->ignore
metadata->Utils.getDictFromJson->Dict.set("3dsMethodComp", "N"->JSON.Encode.string)
handlePostMessage([
("fullscreen", true->JSON.Encode.bool),
("param", `3dsAuth`->JSON.Encode.string),
("iframeId", iframeId->JSON.Encode.string),
("metadata", stateMetadata),
])
}

let headersDict =
metaDataDict
->getJsonObjectFromDict("headers")
->JSON.Decode.object
->Option.getOr(Dict.make())
let headers = Dict.make()
let ele = Window.querySelector("#threeDsInvisibleDiv")

headersDict
->Dict.toArray
->Array.forEach(entries => {
let (x, val) = entries
Dict.set(headers, x, val->JSON.Decode.string->Option.getOr(""))
})
switch ele->Nullable.toOption {
| Some(elem) => {
let form = elem->makeForm(threeDsUrl, "threeDsHiddenPostMethod")
let input = Types.createElement("input")
input.name = encodeURIComponent("threeDSMethodData")
let threeDsMethodStr = threeDsMethodData->JSON.Decode.string->Option.getOr("")
input.value = encodeURIComponent(threeDsMethodStr)
form.target = "threeDsInvisibleIframe"
form.appendChild(input)
try {
form.submit()
} catch {
| err => {
let exceptionMessage = err->Utils.formatException->JSON.stringify
handleFailureScenarios(exceptionMessage)
}
}
}
| None => handleFailureScenarios("Unable to Locate threeDsInvisibleDiv")
}
}
}
Window.addEventListener("message", handle)
Some(() => {Window.removeEventListener("message", handle)})
})

<div id="threeDsInvisibleIframe" className="bg-black-100 h-96" />
<>
<div id="threeDsInvisibleDiv" className="hidden" />
<iframe
id="threeDsInvisibleIframe"
name="threeDsInvisibleIframe"
className="h-96 invisible"
onLoad=handleLoaded
/>
</>
}
63 changes: 0 additions & 63 deletions src/Utilities/PaymentHelpers.res
Original file line number Diff line number Diff line change
Expand Up @@ -79,69 +79,6 @@ let retrievePaymentIntent = (
})
}

let threeDsMethod = (url, threeDsMethodData, ~optLogger) => {
open Promise
logApi(
~optLogger,
~url,
~apiLogType=Request,
~eventName=THREE_DS_METHOD_CALL_INIT,
~logType=INFO,
~logCategory=API,
(),
)
let threeDsMethodStr = threeDsMethodData->JSON.Decode.string->Option.getOr("")
let body = `${encodeURIComponent("threeDSMethodData")}=${encodeURIComponent(threeDsMethodStr)}`

fetchApiWithNoCors(url, ~method=#POST, ~bodyStr=body, ())
->then(res => {
let statusCode = res->Fetch.Response.status->Int.toString
if statusCode->String.charAt(0) !== "2" {
res
->Fetch.Response.text
->then(text => {
logApi(
~optLogger,
~url,
~data=text->JSON.Encode.string,
~statusCode,
~apiLogType=Err,
~eventName=THREE_DS_METHOD_CALL,
~logType=ERROR,
~logCategory=API,
(),
)
""->resolve
})
} else {
logApi(
~optLogger,
~url,
~statusCode,
~apiLogType=Response,
~eventName=THREE_DS_METHOD_CALL,
(),
)
res->Fetch.Response.text
}
})
->catch(err => {
let exceptionMessage = err->formatException
Console.log2("Unable to call 3ds method ", exceptionMessage)
logApi(
~optLogger,
~url,
~eventName=THREE_DS_METHOD_CALL,
~apiLogType=NoResponse,
~data=exceptionMessage,
~logType=ERROR,
~logCategory=API,
(),
)
reject(err)
})
}

let threeDsAuth = (~clientSecret, ~optLogger, ~threeDsMethodComp, ~headers) => {
let endpoint = ApiEndpoint.getApiEndPoint()
let paymentIntentID = String.split(clientSecret, "_secret_")[0]->Option.getOr("")
Expand Down
33 changes: 1 addition & 32 deletions src/Utilities/Utils.res
Original file line number Diff line number Diff line change
Expand Up @@ -835,37 +835,6 @@ let fetchApi = (uri, ~bodyStr: string="", ~headers=Dict.make(), ~method: Fetch.m
})
}

let fetchApiWithNoCors = (
uri,
~bodyStr: string="",
~headers=Dict.make(),
~method: Fetch.method,
(),
) => {
open Promise
let body = switch method {
| #GET => resolve(None)
| _ => resolve(Some(Fetch.Body.string(bodyStr)))
}
body->then(body => {
Fetch.fetch(
uri,
{
method,
mode: #"no-cors",
?body,
headers: getHeaders(~headers, ~uri, ()),
},
)
->catch(err => {
reject(err)
})
->then(resp => {
resolve(resp)
})
})
}

let arrayJsonToCamelCase = arr => {
arr->Array.map(item => {
item->transformKeys(CamelCase)
Expand Down Expand Up @@ -1192,7 +1161,7 @@ let makeForm = (element, url, id) => {
form.action = url
form.method = "POST"
form.enctype = "application/x-www-form-urlencoded;charset=UTF-8"
form.style = "display: hidden; "
form.style = "display: hidden;"
element->appendChild(form)
form
}
Expand Down
4 changes: 2 additions & 2 deletions src/orca-loader/Types.res
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,8 @@ type rec ele = {
mutable target: string,
mutable enctype: string,
mutable value: string,
submit: (. unit) => unit,
appendChild: (. ele) => unit,
submit: unit => unit,
appendChild: ele => unit,
}
@scope("document") @val external createElement: string => ele = "createElement"

Expand Down
8 changes: 2 additions & 6 deletions src/orca-log-catcher/OrcaLogger.res
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ type eventName =
| RETRIEVE_CALL
| AUTHENTICATION_CALL_INIT
| AUTHENTICATION_CALL
| THREE_DS_METHOD_CALL_INIT
| THREE_DS_METHOD_CALL
| CONFIRM_CALL_INIT
| CONFIRM_CALL
| SESSIONS_CALL_INIT
Expand Down Expand Up @@ -79,8 +77,6 @@ let eventNameToStrMapper = eventName => {
| RETRIEVE_CALL => "RETRIEVE_CALL"
| AUTHENTICATION_CALL_INIT => "AUTHENTICATION_CALL_INIT"
| AUTHENTICATION_CALL => "AUTHENTICATION_CALL"
| THREE_DS_METHOD_CALL_INIT => "THREE_DS_METHOD_CALL_INIT"
| THREE_DS_METHOD_CALL => "THREE_DS_METHOD_CALL"
| CONFIRM_CALL_INIT => "CONFIRM_CALL_INIT"
| CONFIRM_CALL => "CONFIRM_CALL"
| SESSIONS_CALL_INIT => "SESSIONS_CALL_INIT"
Expand Down Expand Up @@ -499,7 +495,7 @@ let make = (
PAYMENT_ATTEMPT,
CONFIRM_CALL,
AUTHENTICATION_CALL,
THREE_DS_METHOD_CALL,
THREE_DS_METHOD_RESULT,
SDK_CRASH,
REDIRECTING_USER,
DISPLAY_BANK_TRANSFER_INFO_PAGE,
Expand All @@ -508,6 +504,7 @@ let make = (
LOADER_CHANGED,
SESSIONS_CALL,
RETRIEVE_CALL,
DISPLAY_THREE_DS_SDK,
]
arrayOfLogs
->Array.find(log => {
Expand Down Expand Up @@ -542,7 +539,6 @@ let make = (
}
}
| AUTHENTICATION_CALL
| THREE_DS_METHOD_CALL
| RETRIEVE_CALL
| CONFIRM_CALL
| SESSIONS_CALL
Expand Down

0 comments on commit e42a5a3

Please sign in to comment.