@fat-zebra/sdk 2.0.1-beta.1 → 2.0.1-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hpp/hpp.d.ts +10 -3
- package/dist/hpp/hpp.js +67 -50
- package/dist/logging/instrument.d.ts +8 -4
- package/dist/logging/instrument.js +14 -5
- package/dist/logging/logMethod.d.ts +4 -4
- package/dist/logging/logMethod.js +1 -0
- package/dist/main.d.ts +11 -2
- package/dist/main.js +246 -47
- package/dist/react/useFatZebra.js +9 -2
- package/dist/react/useMessage.js +4 -3
- package/dist/sca/index.js +1 -0
- package/dist/shared/envs/local.d.ts +2 -2
- package/dist/shared/envs/local.js +2 -2
- package/dist/three_d_secure/index.d.ts +6 -2
- package/dist/three_d_secure/index.js +20 -10
- package/dist/three_d_secure/utility/device-data-collection.d.ts +1 -1
- package/dist/three_d_secure/utility/device-data-collection.js +20 -6
- package/dist/three_d_secure/utility/three_d_secure_challenge_window.js +0 -5
- package/package.json +2 -2
package/dist/hpp/hpp.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Sca from '../sca';
|
|
2
2
|
import { ChallengeWindowSize } from '../sca/types';
|
|
3
3
|
import { Customer, PaymentIntent } from '../shared/types';
|
|
4
|
+
import ThreeDSecure from "../three_d_secure";
|
|
4
5
|
declare const HPP_DEFAULT_OPTIONS: {
|
|
5
6
|
[key: string]: boolean | string;
|
|
6
7
|
};
|
|
@@ -11,6 +12,8 @@ interface HppModuleConfig {
|
|
|
11
12
|
customer: Customer;
|
|
12
13
|
username: string;
|
|
13
14
|
sca: Sca;
|
|
15
|
+
threeDSecure: ThreeDSecure;
|
|
16
|
+
requestThreeDSEnabled: () => Promise<boolean>;
|
|
14
17
|
test?: boolean;
|
|
15
18
|
}
|
|
16
19
|
interface HppLoadParams {
|
|
@@ -42,7 +45,7 @@ declare class Hpp {
|
|
|
42
45
|
private customer;
|
|
43
46
|
private username;
|
|
44
47
|
private sca;
|
|
45
|
-
private
|
|
48
|
+
private threeDSecure;
|
|
46
49
|
private cardToken;
|
|
47
50
|
private postMessageClient;
|
|
48
51
|
private test;
|
|
@@ -50,11 +53,14 @@ declare class Hpp {
|
|
|
50
53
|
private headlessLoaded;
|
|
51
54
|
private headlessPreviouslyLoaded;
|
|
52
55
|
private iframeLoaded;
|
|
53
|
-
private
|
|
56
|
+
private isThreeDSecureEnabled;
|
|
57
|
+
private requestThreeDSEnabled;
|
|
54
58
|
private challengeWindowSize;
|
|
55
59
|
private scaHandler;
|
|
60
|
+
private crossFrameListenersBound;
|
|
61
|
+
private publicEventListenersBound;
|
|
56
62
|
constructor(config: HppModuleConfig);
|
|
57
|
-
setListenersAndEmitReady(): void
|
|
63
|
+
setListenersAndEmitReady(): Promise<void>;
|
|
58
64
|
load(config: HppLoadParams): void;
|
|
59
65
|
purchase(): void;
|
|
60
66
|
getPayNowUrl(options?: {
|
|
@@ -62,6 +68,7 @@ declare class Hpp {
|
|
|
62
68
|
}): string;
|
|
63
69
|
setCrossFramesEventListeners(): void;
|
|
64
70
|
setPublicEventListeners(): void;
|
|
71
|
+
destroy(): void;
|
|
65
72
|
createPurchase(extra?: {
|
|
66
73
|
[key: string]: boolean | string;
|
|
67
74
|
}): void;
|
package/dist/hpp/hpp.js
CHANGED
|
@@ -4,6 +4,15 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
8
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
9
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
10
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
11
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
12
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
13
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
14
|
+
});
|
|
15
|
+
};
|
|
7
16
|
import * as bridge from '../shared/bridge-client';
|
|
8
17
|
import { LocalStorageAccessTokenKey } from '../shared/constants';
|
|
9
18
|
import { emit, off, on } from '../shared/event-manager';
|
|
@@ -12,7 +21,8 @@ import { BridgeEvent, PublicEvent, } from '../shared/types';
|
|
|
12
21
|
import * as util from '../shared/util';
|
|
13
22
|
import { setTransactionReference } from "../logging/logger-context";
|
|
14
23
|
import { logMethod } from "../logging/logMethod";
|
|
15
|
-
import
|
|
24
|
+
import env from "../shared/env";
|
|
25
|
+
import { configureLogger } from "../logging/instrument";
|
|
16
26
|
const HPP_DEFAULT_OPTIONS = {
|
|
17
27
|
enableSca: false,
|
|
18
28
|
hideButton: false,
|
|
@@ -20,7 +30,7 @@ const HPP_DEFAULT_OPTIONS = {
|
|
|
20
30
|
};
|
|
21
31
|
class Hpp {
|
|
22
32
|
constructor(config) {
|
|
23
|
-
this.
|
|
33
|
+
this.isThreeDSecureEnabled = false;
|
|
24
34
|
this.paymentIntent = config.paymentIntent;
|
|
25
35
|
this.customer = config.customer;
|
|
26
36
|
this.username = config.username;
|
|
@@ -30,58 +40,66 @@ class Hpp {
|
|
|
30
40
|
this.headlessLoaded = false;
|
|
31
41
|
this.headlessPreviouslyLoaded = false;
|
|
32
42
|
this.iframeLoaded = false;
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
this.threeDSecure = config.threeDSecure;
|
|
44
|
+
this.requestThreeDSEnabled = config.requestThreeDSEnabled;
|
|
45
|
+
this.crossFrameListenersBound = false;
|
|
46
|
+
this.publicEventListenersBound = false;
|
|
47
|
+
configureLogger({
|
|
48
|
+
baseUrl: env[process.env.API_ENV].payNowUrl
|
|
36
49
|
});
|
|
37
50
|
}
|
|
38
51
|
setListenersAndEmitReady() {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// subsequent iframe loads after headless has been previously loaded
|
|
64
|
-
// this caters for the SPA scenario
|
|
65
|
-
emit(PublicEvent.HPP_READY);
|
|
66
|
-
}
|
|
52
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
if (!this.crossFrameListenersBound) {
|
|
54
|
+
this.setCrossFramesEventListeners();
|
|
55
|
+
this.crossFrameListenersBound = true;
|
|
56
|
+
}
|
|
57
|
+
if (this.headlessLoaded && this.iframeLoaded) {
|
|
58
|
+
this.isThreeDSecureEnabled = yield this.requestThreeDSEnabled();
|
|
59
|
+
if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled) {
|
|
60
|
+
this.setPublicEventListeners();
|
|
61
|
+
this.publicEventListenersBound = true;
|
|
62
|
+
}
|
|
63
|
+
emit(PublicEvent.HPP_READY);
|
|
64
|
+
}
|
|
65
|
+
else if (this.headlessPreviouslyLoaded && this.iframeLoaded) {
|
|
66
|
+
this.isThreeDSecureEnabled = yield this.requestThreeDSEnabled();
|
|
67
|
+
// subsequent iframe loads after headless has been previously loaded
|
|
68
|
+
// this caters for the SPA scenario
|
|
69
|
+
if (!this.publicEventListenersBound && !this.isThreeDSecureEnabled) {
|
|
70
|
+
this.setPublicEventListeners();
|
|
71
|
+
this.publicEventListenersBound = true;
|
|
72
|
+
}
|
|
73
|
+
emit(PublicEvent.HPP_READY);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
67
76
|
}
|
|
68
77
|
load(config) {
|
|
69
|
-
|
|
78
|
+
var _a;
|
|
79
|
+
this.challengeWindowSize = (_a = config.options) === null || _a === void 0 ? void 0 : _a.challengeWindowSize;
|
|
70
80
|
setTransactionReference(config.paymentIntent.payment.reference);
|
|
71
|
-
this.hppOptions = config.options;
|
|
81
|
+
this.hppOptions = config.options || {};
|
|
72
82
|
const { el, isExisting } = bridge.load2(process.env.PAYNOW_BRIDGE_URL);
|
|
73
83
|
this.headless = el;
|
|
74
84
|
this.headlessPreviouslyLoaded = isExisting;
|
|
75
85
|
this.iframe = document.createElement('iframe');
|
|
76
86
|
document.getElementById(config.containerId).appendChild(this.iframe);
|
|
77
|
-
this.
|
|
87
|
+
this.postMessageClient = new PostMessageClient({
|
|
88
|
+
channel: 'sca',
|
|
89
|
+
target: this.iframe
|
|
90
|
+
});
|
|
91
|
+
this.headless.addEventListener('load', () => {
|
|
78
92
|
this.headlessLoaded = true;
|
|
79
93
|
this.setListenersAndEmitReady();
|
|
80
|
-
};
|
|
94
|
+
});
|
|
81
95
|
this.iframe.onload = () => {
|
|
82
96
|
this.iframeLoaded = true;
|
|
83
97
|
this.setListenersAndEmitReady();
|
|
84
98
|
};
|
|
99
|
+
if (this.headlessPreviouslyLoaded) {
|
|
100
|
+
this.headlessLoaded = true;
|
|
101
|
+
this.setListenersAndEmitReady();
|
|
102
|
+
}
|
|
85
103
|
const payNowUrl = this.getPayNowUrl(config.options);
|
|
86
104
|
this.iframe.setAttribute("src", payNowUrl);
|
|
87
105
|
this.iframe.setAttribute('allow', 'payment');
|
|
@@ -141,13 +159,15 @@ class Hpp {
|
|
|
141
159
|
if (this.hppOptions.tokenizeOnly)
|
|
142
160
|
return;
|
|
143
161
|
if (this.hppOptions.enableSca) {
|
|
144
|
-
if (this.
|
|
145
|
-
this.
|
|
162
|
+
if (this.isThreeDSecureEnabled) {
|
|
163
|
+
this.threeDSecure.run({
|
|
146
164
|
paymentIntent: this.paymentIntent,
|
|
147
165
|
merchantUsername: this.username,
|
|
148
166
|
cardToken: this.cardToken,
|
|
149
167
|
test: this.test,
|
|
150
|
-
challengeWindowSize: this.challengeWindowSize
|
|
168
|
+
challengeWindowSize: this.challengeWindowSize,
|
|
169
|
+
iframe: this.iframe,
|
|
170
|
+
tokenizeOnly: false
|
|
151
171
|
});
|
|
152
172
|
return; // do not continue execution to old 3DS
|
|
153
173
|
}
|
|
@@ -210,16 +230,7 @@ class Hpp {
|
|
|
210
230
|
data: data,
|
|
211
231
|
});
|
|
212
232
|
};
|
|
213
|
-
|
|
214
|
-
this.threeDSecureEnabled = typeof data === "boolean" ? data : false;
|
|
215
|
-
if (this.threeDSecureEnabled) {
|
|
216
|
-
// setPublicEventListeners is set before this feature flag is returned.
|
|
217
|
-
// we need to therefore unset the scaHandler (for the old implementation or we will get two purchase requests
|
|
218
|
-
off(PublicEvent.SCA_SUCCESS, this.scaHandler);
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
const handlersIncludingThreeDSecure = Object.assign(Object.assign({}, handlers), this.ThreeDSecure.messageHandlers());
|
|
222
|
-
this.postMessageClient.setEventListeners(handlersIncludingThreeDSecure);
|
|
233
|
+
this.postMessageClient.setEventListeners(handlers);
|
|
223
234
|
}
|
|
224
235
|
setPublicEventListeners() {
|
|
225
236
|
this.scaHandler = (event) => {
|
|
@@ -231,6 +242,12 @@ class Hpp {
|
|
|
231
242
|
};
|
|
232
243
|
on(PublicEvent.SCA_SUCCESS, this.scaHandler);
|
|
233
244
|
}
|
|
245
|
+
destroy() {
|
|
246
|
+
if (this.publicEventListenersBound && this.scaHandler) {
|
|
247
|
+
off(PublicEvent.SCA_SUCCESS, this.scaHandler);
|
|
248
|
+
this.publicEventListenersBound = false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
234
251
|
createPurchase(extra = null) {
|
|
235
252
|
const message = {
|
|
236
253
|
channel: 'sca',
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
type LogOptions = {
|
|
2
|
-
endpoint?: string;
|
|
3
|
-
mapArgs?: (args:
|
|
1
|
+
export type LogOptions<A extends unknown[]> = {
|
|
2
|
+
endpoint?: string | ((...args: A) => string);
|
|
3
|
+
mapArgs?: (args: A) => unknown;
|
|
4
4
|
enabled?: () => boolean;
|
|
5
5
|
};
|
|
6
|
-
|
|
6
|
+
type LoggerConfig = {
|
|
7
|
+
baseUrl?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function configureLogger(config: LoggerConfig): void;
|
|
10
|
+
export declare function instrumentFunction<A extends unknown[], R>(methodName: string, fn: (...args: A) => R, opts?: LogOptions<A>): (...args: A) => R;
|
|
7
11
|
export {};
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
import { getLoggerUsername, getTransactionReference } from "./logger-context";
|
|
3
|
+
let loggerConfig = {};
|
|
4
|
+
export function configureLogger(config) {
|
|
5
|
+
loggerConfig = config;
|
|
6
|
+
}
|
|
3
7
|
function defaultEndpoint() {
|
|
4
|
-
return
|
|
8
|
+
return loggerConfig.baseUrl
|
|
9
|
+
? `${loggerConfig.baseUrl}/log_sdk`
|
|
10
|
+
: `${process.env.PAYNOW_BASE_URL}/log_sdk`;
|
|
5
11
|
}
|
|
6
12
|
function sendLog(endpoint, payload) {
|
|
7
13
|
try {
|
|
@@ -20,12 +26,15 @@ function sendLog(endpoint, payload) {
|
|
|
20
26
|
}
|
|
21
27
|
}
|
|
22
28
|
export function instrumentFunction(methodName, fn, opts = {}) {
|
|
23
|
-
var _a, _b
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
const mapArgs = (_c = opts.mapArgs) !== null && _c !== void 0 ? _c : ((a) => a);
|
|
29
|
+
var _a, _b;
|
|
30
|
+
const enabled = (_a = opts.enabled) !== null && _a !== void 0 ? _a : (() => true);
|
|
31
|
+
const mapArgs = (_b = opts.mapArgs) !== null && _b !== void 0 ? _b : ((a) => a);
|
|
27
32
|
return function instrumented(...args) {
|
|
33
|
+
var _a;
|
|
28
34
|
if (enabled()) {
|
|
35
|
+
const endpoint = typeof opts.endpoint === "function"
|
|
36
|
+
? opts.endpoint(...args)
|
|
37
|
+
: (_a = opts.endpoint) !== null && _a !== void 0 ? _a : defaultEndpoint();
|
|
29
38
|
const payload = {
|
|
30
39
|
username: getLoggerUsername(),
|
|
31
40
|
reference: getTransactionReference(),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
type LogOptions = {
|
|
2
|
-
endpoint?: string;
|
|
3
|
-
mapArgs?: (args:
|
|
1
|
+
type LogOptions<A extends unknown[]> = {
|
|
2
|
+
endpoint?: string | ((args: A) => string);
|
|
3
|
+
mapArgs?: (args: A) => unknown;
|
|
4
4
|
enabled?: () => boolean;
|
|
5
5
|
};
|
|
6
|
-
export declare function logMethod(opts?: LogOptions): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
6
|
+
export declare function logMethod(opts?: LogOptions<unknown[]>): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
7
7
|
export {};
|
|
@@ -35,6 +35,7 @@ export function logMethod(opts = {}) {
|
|
|
35
35
|
const original = descriptor.value;
|
|
36
36
|
if (typeof original !== "function") {
|
|
37
37
|
console.error(`@logMethod can only decorate methods (${propertyKey})`);
|
|
38
|
+
return descriptor;
|
|
38
39
|
}
|
|
39
40
|
descriptor.value = instrumentFunction(propertyKey, original, Object.assign(Object.assign({}, opts), { mapArgs: (_a = opts.mapArgs) !== null && _a !== void 0 ? _a : ((args) => args.map((a) => {
|
|
40
41
|
if (!a || typeof a !== "object")
|
package/dist/main.d.ts
CHANGED
|
@@ -27,13 +27,22 @@ export default class FatZebra {
|
|
|
27
27
|
private sca;
|
|
28
28
|
private fzConfig;
|
|
29
29
|
private gatewayClient;
|
|
30
|
+
private headless;
|
|
31
|
+
private threeDSecure;
|
|
32
|
+
private threeDSecureListenersBound;
|
|
33
|
+
private bridgeReady;
|
|
30
34
|
constructor(config: FZConfig);
|
|
31
|
-
tokenizeCard(card: Card
|
|
32
|
-
cardDidTokenize(
|
|
35
|
+
tokenizeCard(card: Card): void;
|
|
36
|
+
cardDidTokenize(callback: (data: any) => void): void;
|
|
37
|
+
private requestThreeDSEnabled;
|
|
33
38
|
verifyCard(params: VerifyCardParams): Promise<void>;
|
|
39
|
+
setThreeDSecureListeners(): void;
|
|
34
40
|
renderPaymentsPage(params: HppLoadParams): void;
|
|
35
41
|
renderApplePayButton(params: ApplePayParams): void;
|
|
36
42
|
renderClickToPay(params: HppClickToPayParams): void;
|
|
43
|
+
reportThreeDSecureFetchedOnInit(data: any): void;
|
|
44
|
+
reportThreeDSecureFetched(data: any, paymentIntent?: PaymentIntent): void;
|
|
45
|
+
reportRequestThreedsEnabledTimeout(paymentIntent?: PaymentIntent): void;
|
|
37
46
|
checkout(): void;
|
|
38
47
|
on(event: PublicEvent, callback: (e: any) => void): void;
|
|
39
48
|
off(event: PublicEvent, callback: (e: any) => void): void;
|
package/dist/main.js
CHANGED
|
@@ -23,12 +23,14 @@ import { toHumanizedErrors, validateClickToPayLoadParams, validateHppLoadParams,
|
|
|
23
23
|
import GatewayClient from './shared/api-gateway-client';
|
|
24
24
|
import { Hpp } from './hpp';
|
|
25
25
|
import ClickToPay from './click_to_pay';
|
|
26
|
-
import { validateApplePayLoadParams } from
|
|
27
|
-
import { ApplePay } from
|
|
28
|
-
import { setLoggerUsername } from
|
|
29
|
-
import { logMethod } from
|
|
26
|
+
import { validateApplePayLoadParams } from './validation/validators/apple-pay-load-params-button-validator';
|
|
27
|
+
import { ApplePay } from './applepay';
|
|
28
|
+
import { setLoggerUsername } from './logging/logger-context';
|
|
29
|
+
import { logMethod } from './logging/logMethod';
|
|
30
|
+
import ThreeDSecure from './three_d_secure';
|
|
30
31
|
export default class FatZebra {
|
|
31
32
|
constructor(config) {
|
|
33
|
+
this.threeDSecureListenersBound = false;
|
|
32
34
|
setLoggerUsername(config.username);
|
|
33
35
|
this.fzConfig = config;
|
|
34
36
|
window.MerchantUsername = config.username;
|
|
@@ -40,29 +42,57 @@ export default class FatZebra {
|
|
|
40
42
|
gatewayClient: this.gatewayClient,
|
|
41
43
|
});
|
|
42
44
|
this.sca.loadScript();
|
|
45
|
+
const { el, isExisting } = bridge.load2(process.env.PAYNOW_BRIDGE_URL);
|
|
46
|
+
this.headless = el;
|
|
47
|
+
this.threeDSecure = new ThreeDSecure({
|
|
48
|
+
bridge: this.headless,
|
|
49
|
+
environment: process.env.API_ENV,
|
|
50
|
+
});
|
|
51
|
+
// bridgeReady is a single promise created once.
|
|
52
|
+
// After it resolves (bridge loaded), every subsequent "await this.bridgeReady"
|
|
53
|
+
// returns instantly — there's no re-evaluation.
|
|
54
|
+
// So for a SPA where the bridge is already loaded, there's zero overhead.
|
|
55
|
+
if (isExisting) {
|
|
56
|
+
console.log('headless exists');
|
|
57
|
+
this.bridgeReady = Promise.resolve();
|
|
58
|
+
this.setThreeDSecureListeners();
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
this.bridgeReady = new Promise((resolve) => {
|
|
62
|
+
this.headless.addEventListener('load', () => {
|
|
63
|
+
console.log('headless loaded');
|
|
64
|
+
this.setThreeDSecureListeners();
|
|
65
|
+
resolve();
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const message = {
|
|
70
|
+
channel: 'sca',
|
|
71
|
+
subject: BridgeEvent.READY,
|
|
72
|
+
data: {},
|
|
73
|
+
};
|
|
74
|
+
window.top.postMessage(message, '*');
|
|
43
75
|
}
|
|
44
|
-
tokenizeCard(card
|
|
76
|
+
tokenizeCard(card) {
|
|
45
77
|
const channel = 'sca';
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
headless.contentWindow.postMessage(message, '*');
|
|
78
|
+
const message = {
|
|
79
|
+
channel,
|
|
80
|
+
subject: BridgeEvent.TOKENIZE_CARD_REQUEST,
|
|
81
|
+
data: {
|
|
82
|
+
access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
|
|
83
|
+
card_holder: card.holder,
|
|
84
|
+
card_number: card.number,
|
|
85
|
+
card_expiry: `${card.expiryMonth}/${card.expiryYear}`,
|
|
86
|
+
cvv: card.cvv,
|
|
87
|
+
},
|
|
59
88
|
};
|
|
89
|
+
this.headless.contentWindow.postMessage(message, '*');
|
|
60
90
|
}
|
|
61
|
-
cardDidTokenize(
|
|
91
|
+
cardDidTokenize(callback) {
|
|
62
92
|
const channel = 'sca';
|
|
63
93
|
const postMessageClient = new PostMessageClient({
|
|
64
94
|
channel,
|
|
65
|
-
target: headless
|
|
95
|
+
target: this.headless,
|
|
66
96
|
});
|
|
67
97
|
const handlers = {};
|
|
68
98
|
handlers[BridgeEvent.TOKENIZE_CARD_RESPONSE] = (data) => {
|
|
@@ -70,57 +100,154 @@ export default class FatZebra {
|
|
|
70
100
|
};
|
|
71
101
|
postMessageClient.setEventListeners(handlers);
|
|
72
102
|
}
|
|
103
|
+
requestThreeDSEnabled(timeout, paymentIntent) {
|
|
104
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
105
|
+
console.log('requestThreeDSEnabled');
|
|
106
|
+
// If the bridge loads in time, bridgeReady wins and we can continue requesting the flag.
|
|
107
|
+
// If not, the timeout resolves the race and we fall through
|
|
108
|
+
// — the postMessage is sent to an unready bridge, the response never arrives,
|
|
109
|
+
// and the existing window.setTimeout at the bottom fires and resolves false.
|
|
110
|
+
// The total worst-case wait is still bounded by timeout.
|
|
111
|
+
yield Promise.race([
|
|
112
|
+
this.bridgeReady,
|
|
113
|
+
new Promise((resolve) => window.setTimeout(resolve, timeout)),
|
|
114
|
+
]);
|
|
115
|
+
return new Promise((resolve) => {
|
|
116
|
+
const channel = 'sca';
|
|
117
|
+
const postMessageClient = new PostMessageClient({
|
|
118
|
+
channel,
|
|
119
|
+
target: this.headless,
|
|
120
|
+
});
|
|
121
|
+
let resolved = false;
|
|
122
|
+
postMessageClient.setEventListeners({
|
|
123
|
+
[BridgeEvent.THREE_D_SECURE_ENABLED]: (data) => {
|
|
124
|
+
const enabled = typeof data === 'boolean' ? data : false;
|
|
125
|
+
if (!resolved) {
|
|
126
|
+
this.reportThreeDSecureFetched(data, paymentIntent);
|
|
127
|
+
resolved = true;
|
|
128
|
+
resolve(enabled);
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
const message = {
|
|
133
|
+
channel,
|
|
134
|
+
subject: 'fzi.is-enabled-three-d-secure-req',
|
|
135
|
+
data: {
|
|
136
|
+
merchant: this.fzConfig.username,
|
|
137
|
+
access_token: window.localStorage.getItem(LocalStorageAccessTokenKey),
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
postMessageClient.send(message);
|
|
141
|
+
window.setTimeout(() => {
|
|
142
|
+
if (!resolved) {
|
|
143
|
+
this.reportRequestThreedsEnabledTimeout(paymentIntent);
|
|
144
|
+
resolved = true;
|
|
145
|
+
resolve(false);
|
|
146
|
+
}
|
|
147
|
+
}, timeout);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
}
|
|
73
151
|
verifyCard(params) {
|
|
74
152
|
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
-
var _a;
|
|
153
|
+
var _a, _b;
|
|
154
|
+
console.log('verifyCard');
|
|
76
155
|
const valid = validateVerifyCardParams(params);
|
|
77
156
|
if (!valid) {
|
|
78
157
|
emit(PublicEvent.VALIDATION_ERROR, {
|
|
79
158
|
errors: toHumanizedErrors(validateVerifyCardParams.errors),
|
|
80
|
-
data: null
|
|
159
|
+
data: null,
|
|
81
160
|
});
|
|
82
161
|
return;
|
|
83
162
|
}
|
|
163
|
+
const threeDSEnabled = yield this.requestThreeDSEnabled(1000, params.paymentIntent);
|
|
84
164
|
switch (params.paymentMethod.type) {
|
|
85
|
-
case PaymentMethodType.CARD:
|
|
86
|
-
|
|
165
|
+
case PaymentMethodType.CARD: {
|
|
166
|
+
console.log('Verify card (new card)');
|
|
87
167
|
const card = params.paymentMethod.data;
|
|
88
|
-
this.cardDidTokenize(
|
|
89
|
-
var _a;
|
|
90
|
-
|
|
168
|
+
this.cardDidTokenize((data) => __awaiter(this, void 0, void 0, function* () {
|
|
169
|
+
var _a, _b;
|
|
170
|
+
if (threeDSEnabled) {
|
|
171
|
+
this.threeDSecure.run({
|
|
172
|
+
paymentIntent: params.paymentIntent,
|
|
173
|
+
cardToken: data.token,
|
|
174
|
+
merchantUsername: this.fzConfig.username,
|
|
175
|
+
challengeWindowSize: (_a = params.options) === null || _a === void 0 ? void 0 : _a.challengeWindowSize,
|
|
176
|
+
test: this.fzConfig.test,
|
|
177
|
+
tokenizeOnly: true,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
const bin = card.number.substr(0, 6);
|
|
182
|
+
this.sca.run({
|
|
183
|
+
cardToken: data.token,
|
|
184
|
+
customer: params.customer,
|
|
185
|
+
paymentIntent: params.paymentIntent,
|
|
186
|
+
bin,
|
|
187
|
+
challengeWindowSize: (_b = params.options) === null || _b === void 0 ? void 0 : _b.challengeWindowSize,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}));
|
|
191
|
+
this.tokenizeCard(card);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
case PaymentMethodType.CARD_ON_FILE: {
|
|
195
|
+
console.log('Verify card (card on file)');
|
|
196
|
+
const cardToken = params.paymentMethod.data.token;
|
|
197
|
+
if (threeDSEnabled) {
|
|
198
|
+
this.threeDSecure.run({
|
|
199
|
+
paymentIntent: params.paymentIntent,
|
|
200
|
+
cardToken,
|
|
201
|
+
merchantUsername: this.fzConfig.username,
|
|
202
|
+
challengeWindowSize: (_a = params.options) === null || _a === void 0 ? void 0 : _a.challengeWindowSize,
|
|
203
|
+
test: this.fzConfig.test,
|
|
204
|
+
tokenizeOnly: true,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
const bin = (yield this.gatewayClient.getCard({
|
|
209
|
+
card_token: cardToken,
|
|
210
|
+
})).data.bin;
|
|
91
211
|
this.sca.run({
|
|
92
|
-
cardToken
|
|
212
|
+
cardToken,
|
|
93
213
|
customer: params.customer,
|
|
94
214
|
paymentIntent: params.paymentIntent,
|
|
95
215
|
bin,
|
|
96
|
-
challengeWindowSize: (
|
|
216
|
+
challengeWindowSize: (_b = params.options) === null || _b === void 0 ? void 0 : _b.challengeWindowSize,
|
|
97
217
|
});
|
|
98
|
-
}
|
|
99
|
-
this.tokenizeCard(card, headless);
|
|
100
|
-
break;
|
|
101
|
-
case PaymentMethodType.CARD_ON_FILE:
|
|
102
|
-
const cardToken = params.paymentMethod.data.token;
|
|
103
|
-
const bin = (yield this.gatewayClient.getCard({ card_token: cardToken })).data.bin;
|
|
104
|
-
this.sca.run({
|
|
105
|
-
cardToken,
|
|
106
|
-
customer: params.customer,
|
|
107
|
-
paymentIntent: params.paymentIntent,
|
|
108
|
-
bin,
|
|
109
|
-
challengeWindowSize: (_a = params.options) === null || _a === void 0 ? void 0 : _a.challengeWindowSize,
|
|
110
|
-
});
|
|
218
|
+
}
|
|
111
219
|
break;
|
|
220
|
+
}
|
|
112
221
|
}
|
|
113
222
|
});
|
|
114
223
|
}
|
|
224
|
+
setThreeDSecureListeners() {
|
|
225
|
+
console.log('setThreeDSecureListeners');
|
|
226
|
+
if (this.threeDSecureListenersBound)
|
|
227
|
+
return;
|
|
228
|
+
const channel = 'sca';
|
|
229
|
+
const postMessageClient = new PostMessageClient({
|
|
230
|
+
channel,
|
|
231
|
+
target: this.headless,
|
|
232
|
+
});
|
|
233
|
+
const handlers = this.threeDSecure.messageHandlers();
|
|
234
|
+
postMessageClient.setEventListeners(handlers);
|
|
235
|
+
this.threeDSecureListenersBound = true;
|
|
236
|
+
}
|
|
115
237
|
renderPaymentsPage(params) {
|
|
238
|
+
var _a;
|
|
239
|
+
console.log('renderPaymentsPage');
|
|
116
240
|
const valid = validateHppLoadParams(params);
|
|
117
241
|
if (!valid) {
|
|
118
242
|
emit(PublicEvent.VALIDATION_ERROR, {
|
|
119
243
|
errors: toHumanizedErrors(validateHppLoadParams.errors),
|
|
120
|
-
data: null
|
|
244
|
+
data: null,
|
|
121
245
|
});
|
|
122
246
|
return;
|
|
123
247
|
}
|
|
248
|
+
if ((_a = window.HPP) === null || _a === void 0 ? void 0 : _a.destroy) {
|
|
249
|
+
window.HPP.destroy();
|
|
250
|
+
}
|
|
124
251
|
window.HPP = new Hpp({
|
|
125
252
|
version: params.version,
|
|
126
253
|
paymentIntent: params.paymentIntent,
|
|
@@ -128,6 +255,8 @@ export default class FatZebra {
|
|
|
128
255
|
username: this.fzConfig.username,
|
|
129
256
|
sca: this.sca,
|
|
130
257
|
test: this.fzConfig.test,
|
|
258
|
+
threeDSecure: this.threeDSecure,
|
|
259
|
+
requestThreeDSEnabled: () => this.requestThreeDSEnabled(1000, params.paymentIntent),
|
|
131
260
|
});
|
|
132
261
|
window.HPP.load(params);
|
|
133
262
|
}
|
|
@@ -136,19 +265,19 @@ export default class FatZebra {
|
|
|
136
265
|
if (!valid) {
|
|
137
266
|
emit(PublicEvent.VALIDATION_ERROR, {
|
|
138
267
|
errors: toHumanizedErrors(validateApplePayLoadParams.errors),
|
|
139
|
-
data: null
|
|
268
|
+
data: null,
|
|
140
269
|
});
|
|
141
270
|
return;
|
|
142
271
|
}
|
|
143
272
|
window.ApplePayButton = new ApplePay({
|
|
144
273
|
environment: params.environment,
|
|
145
274
|
paymentIntent: params.paymentIntent,
|
|
146
|
-
username: this.fzConfig.username
|
|
275
|
+
username: this.fzConfig.username,
|
|
147
276
|
});
|
|
148
277
|
window.ApplePayButton.load({
|
|
149
278
|
containerId: params.containerId,
|
|
150
279
|
paymentIntent: params.paymentIntent,
|
|
151
|
-
options: params.options
|
|
280
|
+
options: params.options,
|
|
152
281
|
});
|
|
153
282
|
}
|
|
154
283
|
renderClickToPay(params) {
|
|
@@ -156,7 +285,7 @@ export default class FatZebra {
|
|
|
156
285
|
if (!valid) {
|
|
157
286
|
emit(PublicEvent.VALIDATION_ERROR, {
|
|
158
287
|
errors: toHumanizedErrors(validateClickToPayLoadParams.errors),
|
|
159
|
-
data: null
|
|
288
|
+
data: null,
|
|
160
289
|
});
|
|
161
290
|
return;
|
|
162
291
|
}
|
|
@@ -167,6 +296,15 @@ export default class FatZebra {
|
|
|
167
296
|
});
|
|
168
297
|
window.HPP.load(params);
|
|
169
298
|
}
|
|
299
|
+
reportThreeDSecureFetchedOnInit(data) {
|
|
300
|
+
console.log("three_d_secure fetched on init", data);
|
|
301
|
+
}
|
|
302
|
+
reportThreeDSecureFetched(data, paymentIntent) {
|
|
303
|
+
console.log("three_d_secure fetched", data);
|
|
304
|
+
}
|
|
305
|
+
reportRequestThreedsEnabledTimeout(paymentIntent) {
|
|
306
|
+
console.log("3DS enabled check timed out");
|
|
307
|
+
}
|
|
170
308
|
checkout() {
|
|
171
309
|
window.HPP.purchase();
|
|
172
310
|
}
|
|
@@ -180,6 +318,18 @@ export default class FatZebra {
|
|
|
180
318
|
onOnce(event, callback);
|
|
181
319
|
}
|
|
182
320
|
}
|
|
321
|
+
__decorate([
|
|
322
|
+
logMethod({
|
|
323
|
+
mapArgs: (args) => {
|
|
324
|
+
const params = args[0];
|
|
325
|
+
return [
|
|
326
|
+
{
|
|
327
|
+
payment_intent: params === null || params === void 0 ? void 0 : params.paymentIntent
|
|
328
|
+
},
|
|
329
|
+
];
|
|
330
|
+
},
|
|
331
|
+
})
|
|
332
|
+
], FatZebra.prototype, "requestThreeDSEnabled", null);
|
|
183
333
|
__decorate([
|
|
184
334
|
logMethod({
|
|
185
335
|
mapArgs: (args) => {
|
|
@@ -195,4 +345,53 @@ __decorate([
|
|
|
195
345
|
},
|
|
196
346
|
})
|
|
197
347
|
], FatZebra.prototype, "verifyCard", null);
|
|
348
|
+
__decorate([
|
|
349
|
+
logMethod({
|
|
350
|
+
mapArgs: (args) => {
|
|
351
|
+
const params = args[0];
|
|
352
|
+
return [
|
|
353
|
+
{
|
|
354
|
+
payment_intent: params.paymentIntent,
|
|
355
|
+
version: params.version
|
|
356
|
+
},
|
|
357
|
+
];
|
|
358
|
+
},
|
|
359
|
+
})
|
|
360
|
+
], FatZebra.prototype, "renderPaymentsPage", null);
|
|
361
|
+
__decorate([
|
|
362
|
+
logMethod({
|
|
363
|
+
mapArgs: (args) => {
|
|
364
|
+
const data = args[0];
|
|
365
|
+
return [
|
|
366
|
+
{
|
|
367
|
+
data
|
|
368
|
+
},
|
|
369
|
+
];
|
|
370
|
+
},
|
|
371
|
+
})
|
|
372
|
+
], FatZebra.prototype, "reportThreeDSecureFetchedOnInit", null);
|
|
373
|
+
__decorate([
|
|
374
|
+
logMethod({
|
|
375
|
+
mapArgs: (args) => {
|
|
376
|
+
const data = args[0];
|
|
377
|
+
return [
|
|
378
|
+
{
|
|
379
|
+
data
|
|
380
|
+
},
|
|
381
|
+
];
|
|
382
|
+
},
|
|
383
|
+
})
|
|
384
|
+
], FatZebra.prototype, "reportThreeDSecureFetched", null);
|
|
385
|
+
__decorate([
|
|
386
|
+
logMethod({
|
|
387
|
+
mapArgs: (args) => {
|
|
388
|
+
const data = args[0];
|
|
389
|
+
return [
|
|
390
|
+
{
|
|
391
|
+
data
|
|
392
|
+
},
|
|
393
|
+
];
|
|
394
|
+
},
|
|
395
|
+
})
|
|
396
|
+
], FatZebra.prototype, "reportRequestThreedsEnabledTimeout", null);
|
|
198
397
|
export { FatZebra, };
|
|
@@ -5,8 +5,12 @@ import Sca from "../sca";
|
|
|
5
5
|
import GatewayClient from "../shared/api-gateway-client";
|
|
6
6
|
import { generateVerifyURL } from "./verifyUrl";
|
|
7
7
|
import useMessage from "./useMessage";
|
|
8
|
-
import { instrumentFunction } from "../logging/instrument";
|
|
9
|
-
|
|
8
|
+
import { configureLogger, instrumentFunction } from "../logging/instrument";
|
|
9
|
+
import env from "../shared/env";
|
|
10
|
+
const logUseFatZebra = instrumentFunction("useFatZebra", (meta) => meta, {
|
|
11
|
+
mapArgs: ([meta]) => meta,
|
|
12
|
+
endpoint: (meta) => `${env[meta.environment].payNowUrl}/log_sdk`,
|
|
13
|
+
});
|
|
10
14
|
const useFatZebra = ({ config, handlers, cardToken }) => {
|
|
11
15
|
const { options, accessToken, paymentIntent, username } = config;
|
|
12
16
|
const sca = useMemo(() => {
|
|
@@ -25,6 +29,9 @@ const useFatZebra = ({ config, handlers, cardToken }) => {
|
|
|
25
29
|
config
|
|
26
30
|
});
|
|
27
31
|
useEffect(() => {
|
|
32
|
+
configureLogger({
|
|
33
|
+
baseUrl: env[config.environment].payNowUrl
|
|
34
|
+
});
|
|
28
35
|
logUseFatZebra({
|
|
29
36
|
environment: config.environment,
|
|
30
37
|
reference: config.paymentIntent.payment.reference,
|
package/dist/react/useMessage.js
CHANGED
|
@@ -40,11 +40,14 @@ const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
|
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
42
|
if (options && options.sca_enabled && threeDSecureEnabled) {
|
|
43
|
+
const iframe = document.querySelector('[name="renderIframe"]');
|
|
43
44
|
threeDSecureRef.current.run({
|
|
44
45
|
paymentIntent,
|
|
45
46
|
cardToken: data.token,
|
|
46
47
|
merchantUsername: config.username,
|
|
47
|
-
test: config.environment !== Environment.production
|
|
48
|
+
test: config.environment !== Environment.production,
|
|
49
|
+
tokenizeOnly: config.options.tokenize_only,
|
|
50
|
+
iframe: iframe
|
|
48
51
|
});
|
|
49
52
|
return;
|
|
50
53
|
}
|
|
@@ -66,13 +69,11 @@ const useMessage = ({ paymentIntent, options, handlers, sca, config }) => {
|
|
|
66
69
|
const headless = el;
|
|
67
70
|
let onMessage;
|
|
68
71
|
headless.onload = () => {
|
|
69
|
-
const iframe = document.querySelector('[name="renderIframe"]');
|
|
70
72
|
const threeDS = new ThreeDSecure({
|
|
71
73
|
successCallback,
|
|
72
74
|
failureCallback,
|
|
73
75
|
bridge: headless,
|
|
74
76
|
environment: config.environment,
|
|
75
|
-
iframe: iframe
|
|
76
77
|
});
|
|
77
78
|
threeDSecureRef.current = threeDS;
|
|
78
79
|
const messages = threeDS.messageHandlers(); // { [subject]: (payload) => void }
|
package/dist/sca/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
declare const bridgeUrl = "
|
|
1
|
+
declare const bridgeUrl = "http://localhost:3006/sdk/bridge";
|
|
2
2
|
declare const apiUrl = "https://api.test/sdk";
|
|
3
3
|
declare const payNowUrl = "https://paynow.test";
|
|
4
4
|
declare const songbirdUrl = "https://songbirdstag.cardinalcommerce.com/edge/v1/songbird.js";
|
|
5
5
|
declare const cybersourceUrl = "https://centinelapistag.cardinalcommerce.com";
|
|
6
|
-
declare const returnCybersourceUrl = "https://
|
|
6
|
+
declare const returnCybersourceUrl = "https://48e5-115-130-65-211.ngrok-free.app/return";
|
|
7
7
|
export { bridgeUrl, apiUrl, payNowUrl, songbirdUrl, cybersourceUrl, returnCybersourceUrl };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const bridgeUrl = "
|
|
1
|
+
const bridgeUrl = "http://localhost:3006/sdk/bridge";
|
|
2
2
|
const apiUrl = "https://api.test/sdk";
|
|
3
3
|
const payNowUrl = "https://paynow.test";
|
|
4
4
|
const songbirdUrl = "https://songbirdstag.cardinalcommerce.com/edge/v1/songbird.js";
|
|
5
5
|
const cybersourceUrl = "https://centinelapistag.cardinalcommerce.com";
|
|
6
|
-
const returnCybersourceUrl = "https://
|
|
6
|
+
const returnCybersourceUrl = "https://48e5-115-130-65-211.ngrok-free.app/return";
|
|
7
7
|
export { bridgeUrl, apiUrl, payNowUrl, songbirdUrl, cybersourceUrl, returnCybersourceUrl };
|
|
@@ -20,14 +20,17 @@ declare class ThreeDSecure {
|
|
|
20
20
|
private challengeWindowSize;
|
|
21
21
|
private successCallback;
|
|
22
22
|
private failureCallback;
|
|
23
|
+
private tokenizeOnly;
|
|
23
24
|
private iframe?;
|
|
24
|
-
constructor({ successCallback, failureCallback, environment, bridge
|
|
25
|
-
run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test }: {
|
|
25
|
+
constructor({ successCallback, failureCallback, environment, bridge }: ThreeDSecureConfig);
|
|
26
|
+
run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test, tokenizeOnly, iframe }: {
|
|
26
27
|
paymentIntent: PaymentIntent;
|
|
27
28
|
cardToken: string;
|
|
28
29
|
merchantUsername: string;
|
|
29
30
|
challengeWindowSize?: ChallengeWindowSize;
|
|
30
31
|
test: boolean;
|
|
32
|
+
tokenizeOnly?: boolean;
|
|
33
|
+
iframe?: HTMLIFrameElement;
|
|
31
34
|
}): void;
|
|
32
35
|
setupResponse(data: DeviceDataCollectionMessage): void;
|
|
33
36
|
messageHandlers(): {
|
|
@@ -41,6 +44,7 @@ declare class ThreeDSecure {
|
|
|
41
44
|
private validateAuthentication;
|
|
42
45
|
private validationAuthenticationResponse;
|
|
43
46
|
private createPurchase;
|
|
47
|
+
private listenDeviceCollectionReady;
|
|
44
48
|
private setLoading;
|
|
45
49
|
}
|
|
46
50
|
export default ThreeDSecure;
|
|
@@ -18,15 +18,19 @@ import { getThreeDSecureValidationResult } from "./utility/getValidationResult";
|
|
|
18
18
|
import { ChallengeWindowSize } from "../sca/types";
|
|
19
19
|
import * as util from "../shared/util";
|
|
20
20
|
class ThreeDSecure {
|
|
21
|
-
constructor({ successCallback, failureCallback, environment, bridge
|
|
21
|
+
constructor({ successCallback, failureCallback, environment, bridge }) {
|
|
22
|
+
this.tokenizeOnly = false;
|
|
22
23
|
this.headlessBridge = bridge;
|
|
23
24
|
this.environment = environment;
|
|
24
25
|
this.successCallback = successCallback;
|
|
25
26
|
this.failureCallback = failureCallback;
|
|
26
|
-
this.iframe = iframe;
|
|
27
27
|
DeviceDataCollection.listenDataCollectionResponse(environment);
|
|
28
|
+
this.listenDeviceCollectionReady();
|
|
28
29
|
}
|
|
29
|
-
run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test }) {
|
|
30
|
+
run({ paymentIntent, cardToken, merchantUsername, challengeWindowSize, test, tokenizeOnly, iframe }) {
|
|
31
|
+
console.log('Running 3DS (ThreeDSecure)');
|
|
32
|
+
this.iframe = iframe;
|
|
33
|
+
this.tokenizeOnly = tokenizeOnly;
|
|
30
34
|
this.setLoading();
|
|
31
35
|
this.paymentIntent = paymentIntent;
|
|
32
36
|
this.test = test;
|
|
@@ -45,12 +49,6 @@ class ThreeDSecure {
|
|
|
45
49
|
handlers[BridgeEvent.SETUP_THREE_D_SECURE_SUCCESS_RESPONSE] = (data) => {
|
|
46
50
|
this.setupResponse(data);
|
|
47
51
|
};
|
|
48
|
-
on(PublicEvent.DEVICE_PROFILE_READY_THREE_D_SECURE_EVENT, () => this.checkEnrollment({
|
|
49
|
-
paymentIntent: this.paymentIntent,
|
|
50
|
-
cardToken: this.cardToken,
|
|
51
|
-
merchantUsername: this.merchantUsername,
|
|
52
|
-
cybersourceReferenceId: this.cybersourceReferenceId,
|
|
53
|
-
}));
|
|
54
52
|
handlers[BridgeEvent.ENROL_THREE_D_SECURE_RESPONSE] = (data) => {
|
|
55
53
|
this.enrolmentResponse(data);
|
|
56
54
|
};
|
|
@@ -61,7 +59,7 @@ class ThreeDSecure {
|
|
|
61
59
|
this.validationAuthenticationResponse(data);
|
|
62
60
|
};
|
|
63
61
|
handlers[BridgeEvent.THREE_D_SECURE_FAILURE_RESPONSE] = (data) => {
|
|
64
|
-
emit(PublicEvent.SCA_ERROR, { errors: [data.errors], data
|
|
62
|
+
emit(PublicEvent.SCA_ERROR, { errors: [data.errors], data });
|
|
65
63
|
};
|
|
66
64
|
return handlers;
|
|
67
65
|
}
|
|
@@ -123,6 +121,8 @@ class ThreeDSecure {
|
|
|
123
121
|
}
|
|
124
122
|
if (scenario.outcome.success) {
|
|
125
123
|
this.reportSuccess(`FatZebra.3DS: 3DS success - ${scenario.description}.`, threeDSecureData);
|
|
124
|
+
if (this.tokenizeOnly)
|
|
125
|
+
return; // DO NO process purchase if tokenizing only.
|
|
126
126
|
const extra = util.toObjectWithSnakeCaseKeys(threeDSecureData);
|
|
127
127
|
this.createPurchase(extra);
|
|
128
128
|
return;
|
|
@@ -149,6 +149,8 @@ class ThreeDSecure {
|
|
|
149
149
|
const extra = util.toObjectWithSnakeCaseKeys(threeDSecureData);
|
|
150
150
|
if (scenario.outcome.success) {
|
|
151
151
|
this.reportSuccess(`FatZebra.3DS: 3DS success - ${scenario.description}.`, threeDSecureData);
|
|
152
|
+
if (this.tokenizeOnly)
|
|
153
|
+
return; // DO NO process purchase if tokenizing only.
|
|
152
154
|
this.createPurchase(extra);
|
|
153
155
|
}
|
|
154
156
|
else {
|
|
@@ -176,6 +178,14 @@ class ThreeDSecure {
|
|
|
176
178
|
message.data.extra = Object.assign(Object.assign({}, extra), { sli: toFzSli(extra.eci) });
|
|
177
179
|
this.headlessBridge.contentWindow.postMessage(message, '*');
|
|
178
180
|
}
|
|
181
|
+
listenDeviceCollectionReady() {
|
|
182
|
+
on(PublicEvent.DEVICE_PROFILE_READY_THREE_D_SECURE_EVENT, () => this.checkEnrollment({
|
|
183
|
+
paymentIntent: this.paymentIntent,
|
|
184
|
+
cardToken: this.cardToken,
|
|
185
|
+
merchantUsername: this.merchantUsername,
|
|
186
|
+
cybersourceReferenceId: this.cybersourceReferenceId,
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
179
189
|
setLoading(loading = true) {
|
|
180
190
|
var _a;
|
|
181
191
|
if ((_a = this === null || this === void 0 ? void 0 : this.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow) {
|
|
@@ -12,8 +12,8 @@ export default class DeviceDataCollection {
|
|
|
12
12
|
private static readonly INPUT_ID;
|
|
13
13
|
createIframe(): void;
|
|
14
14
|
static listenDataCollectionResponse(environment: Environment): void;
|
|
15
|
-
private static hasEmittedProfileReady;
|
|
16
15
|
private static handleDataCollectionResponse;
|
|
16
|
+
private static handleCollectionResponse;
|
|
17
17
|
static collectDeviceData(): DeviceDataType;
|
|
18
18
|
static setIframeUrl(url: string, jwt: string): void;
|
|
19
19
|
static getForm(): HTMLFormElement | null;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
1
7
|
import { PublicEvent } from "../../shared/types";
|
|
2
8
|
import { emit } from "../../shared/event-manager";
|
|
3
9
|
import env from "../../shared/env";
|
|
10
|
+
import { logMethod } from "../../logging/logMethod";
|
|
4
11
|
class DeviceDataCollection {
|
|
5
12
|
// Create elements if they don't already exist
|
|
6
13
|
createIframe() {
|
|
@@ -43,17 +50,17 @@ class DeviceDataCollection {
|
|
|
43
50
|
// https://developer.cybersource.com/docs/cybs/en-us/payer-authentication/developer/all/so/payer-auth/pa2-ccdc-ddc-intro.html#reference_qmk_jrl_xpb
|
|
44
51
|
if (event.origin !== env[environment].cybersourceUrl)
|
|
45
52
|
return;
|
|
46
|
-
|
|
47
|
-
|
|
53
|
+
this.handleCollectionResponse(event);
|
|
54
|
+
}
|
|
55
|
+
static handleCollectionResponse(event) {
|
|
48
56
|
const response = JSON.parse(event.data);
|
|
49
57
|
if (response["MessageType"] == "profile.completed") {
|
|
50
58
|
emit(PublicEvent.DEVICE_PROFILE_READY_THREE_D_SECURE_EVENT, { message: null, data: null });
|
|
51
59
|
}
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
else if (response["Status"] == false) {
|
|
61
|
+
// Still proceed, even if status is false (as per recommendations from cybersource support team.
|
|
54
62
|
emit(PublicEvent.DEVICE_PROFILE_READY_THREE_D_SECURE_EVENT, { message: null, data: null });
|
|
55
63
|
}
|
|
56
|
-
this.hasEmittedProfileReady = true;
|
|
57
64
|
}
|
|
58
65
|
static collectDeviceData() {
|
|
59
66
|
var _a, _b, _c, _d;
|
|
@@ -115,5 +122,12 @@ DeviceDataCollection.IFRAME_ID = "cardinal_collection_iframe";
|
|
|
115
122
|
DeviceDataCollection.IFRAME_NAME = "collectionIframe";
|
|
116
123
|
DeviceDataCollection.FORM_ID = "cardinal_collection_form";
|
|
117
124
|
DeviceDataCollection.INPUT_ID = "cardinal_collection_form_input";
|
|
118
|
-
DeviceDataCollection.hasEmittedProfileReady = false;
|
|
119
125
|
export default DeviceDataCollection;
|
|
126
|
+
__decorate([
|
|
127
|
+
logMethod({
|
|
128
|
+
mapArgs: (args) => {
|
|
129
|
+
const params = args[0]; // grab the first argument.
|
|
130
|
+
return JSON.parse(params.data);
|
|
131
|
+
},
|
|
132
|
+
})
|
|
133
|
+
], DeviceDataCollection, "handleCollectionResponse", null);
|
|
@@ -66,11 +66,6 @@ class ThreeDSecureChallengeWindow {
|
|
|
66
66
|
});
|
|
67
67
|
content.appendChild(frameWrap);
|
|
68
68
|
overlay.appendChild(content);
|
|
69
|
-
// Backdrop click to close (optional)
|
|
70
|
-
overlay.addEventListener("click", (e) => {
|
|
71
|
-
if (e.target === overlay)
|
|
72
|
-
ThreeDSecureChallengeWindow.hide();
|
|
73
|
-
});
|
|
74
69
|
document.body.appendChild(overlay);
|
|
75
70
|
return { overlay, content, frameWrap };
|
|
76
71
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fat-zebra/sdk",
|
|
3
|
-
"version": "2.0.1-beta.
|
|
3
|
+
"version": "2.0.1-beta.10",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"ajv": "^8.17.1",
|
|
64
64
|
"ajv-formats": "^3.0.1",
|
|
65
65
|
"ajv-keywords": "^5.1.0",
|
|
66
|
-
"axios": "1.
|
|
66
|
+
"axios": "1.16.0",
|
|
67
67
|
"custom-event-polyfill": "^1.0.7",
|
|
68
68
|
"glob": "^13.0.6",
|
|
69
69
|
"ts-polyfill": "^3.8.2",
|