Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@paypal/checkout-components

Package Overview
Dependencies
Maintainers
0
Versions
503
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@paypal/checkout-components - npm Package Compare versions

Comparing version 5.0.345-alpha-714509c.0 to 5.0.345-alpha-bb62853.0

src/three-domain-secure/types.js

2

package.json
{
"name": "@paypal/checkout-components",
"version": "5.0.345-alpha-714509c.0",
"version": "5.0.345-alpha-bb62853.0",
"description": "PayPal Checkout components, for integrating checkout products.",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -5,3 +5,4 @@ /* @flow */

import { type LoggerType } from "@krakenjs/beaver-logger/src";
import { create, type ZoidComponent } from "@krakenjs/zoid/src";
import { type ZoidComponent } from "@krakenjs/zoid/src";
import { ZalgoPromise } from "@krakenjs/zalgo-promise/src";
import { FPTI_KEY } from "@paypal/sdk-constants/src";

@@ -11,69 +12,12 @@

type MerchantPayloadData = {|
amount: string,
currency: string,
nonce: string,
threeDSRequested?: boolean, // do we want to keep this name or align it with other 3DS documentation
transactionContext?: Object,
// experience context
|};
import {
requestData,
responseBody,
Request,
MerchantPayloadData,
SdkConfig,
threeDSResponse,
} from "./types";
import { getThreeDomainSecureComponent } from "./utils";
// eslint-disable-next-line no-undef
type Request = <TRequestData, TResponse>({|
method?: string,
url: string,
// eslint-disable-next-line no-undef
data: TRequestData,
accessToken: ?string,
// eslint-disable-next-line no-undef
|}) => Promise<TResponse>;
type requestData = {|
intent: "THREE_DS_VERIFICATION",
payment_source: {|
card: {|
single_use_token: string,
verification_method: string,
|},
|},
amount: {|
currency_code: string,
value: string,
|},
transaction_context?: {|
soft_descriptor?: string,
|},
|};
type responseBody = {|
payment_id: string,
status: string,
intent: string,
payment_source: {|
card: {|
last_digits: string,
type: string,
name: string,
expiry: string,
|},
|},
amount: {|
currency_code: string,
value: string,
|},
transaction_context: {|
soft_descriptor: string,
|},
links: $ReadOnlyArray<{|
href: string,
rel: string,
method: string,
|}>,
|};
type SdkConfig = {|
authenticationToken: ?string,
paypalApiDomain: string,
|};
const parseSdkConfig = ({ sdkConfig, logger }): SdkConfig => {

@@ -98,11 +42,5 @@ if (!sdkConfig.authenticationToken) {

|}): requestData => {
// what validation on merchant input should we do here?
// empty object
const { threeDSRequested, amount, currency, nonce, transactionContext } =
merchantPayload;
// amount - validate that it's a string
// currency - validate that it's a string
// what validations are done on the API end - what client side validation is the API expecting
return {

@@ -128,3 +66,3 @@ intent: "THREE_DS_VERIFICATION",

isEligible(): Promise<boolean>;
show(): ZoidComponent<void>;
show(): Promise<threeDSResponse>;
}

@@ -136,3 +74,3 @@ export class ThreeDomainSecureComponent {

authenticationURL: string;
threeDSIframe: ZoidComponent;
constructor({

@@ -154,7 +92,7 @@ logger,

const data = parseMerchantPayload({ merchantPayload });
try {
// $FlowFixMe
const { status, links } = await this.request<requestData, responseBody>({
method: "POST",
url: `${this.sdkConfig.paypalApiDomain}/v2/payments/payment`,
url: `https://te-test-qa.qa.paypal.com:12326/v2/payments/payment`,
data,

@@ -165,6 +103,11 @@ accessToken: this.sdkConfig.authenticationToken,

let responseStatus = false;
if (status === "PAYER_ACTION_REQUIRED") {
this.authenticationURL = links[0].href;
// check for rel = payer action inside the object
this.authenticationURL = links.find(
(link) => link.rel === "payer-action"
).href;
responseStatus = true;
this.threeDSIframe = getThreeDomainSecureComponent(
this.authenticationURL
);
}

@@ -174,23 +117,49 @@ return responseStatus;

this.logger.warn(error);
return false;
throw error;
}
}
// change name to isContingent??
// will return true or false
// if payer action required, return true. obtain link from response for show method - check length of links
show(): Promise<threeDSResponse> {
if (!this.threeDSIframe) {
throw new ValidationError(`Ineligible for three domain secure`);
return;
}
const promise = new ZalgoPromise();
const cancelThreeDS = () => {
return ZalgoPromise.try(() => {
// eslint-disable-next-line no-console
console.log("cancelled");
}).then(() => {
// eslint-disable-next-line no-use-before-define
instance.close();
});
};
// if payer action not required, return false
const instance = this.threeDSIframe({
onSuccess: (data) => {
// const {threeDSRefID, authentication_status, liability_shift } = data;
// let enrichedNonce;
// if(threeDSRefID) {
// enrichedNonce = await updateNonceWith3dsData(threeDSRefID, this.fastlaneNonce)
// }
// will make API request to v2/payments/pamyment endpoint with merchant payload an grab sdktoken as
// bearer token
// will need to handle errors from API response
// What are the other options for status response and how do we handle them from a compliance standpoint
// What do we do if we get a 500 error from the API?
// do we throw an error or return false?
return promise.resolve(data);
},
onClose: cancelThreeDS,
onError: (err) => {
return promise.reject(
new Error(
`Error with obtaining 3DS contingency, ${JSON.stringify(err)}`
)
);
},
});
const TARGET_ELEMENT = {
BODY: "body",
};
return instance
.renderTo(window.parent, TARGET_ELEMENT.BODY)
.then(() => promise)
.finally(instance.close);
}
show() {
create({ tag: "", url: "" });
}
}
/* @flow */
/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable no-restricted-globals, promise/no-native, compat/compat */
import { describe, expect, vi } from "vitest";

@@ -10,6 +12,20 @@

const defaultEligibilityResponse = {
status: "PAYER_ACTION_REQUIRED",
links: [{ href: "https://testurl.com", rel: "payer-action" }],
};
const defaultMerchantPayload = {
amount: "1.00",
currency: "USD",
nonce: "test-nonce",
};
const mockEligibilityRequest = (body = defaultEligibilityResponse) => {
return vi.fn().mockResolvedValue(body);
};
const createThreeDomainSecureComponent = ({
sdkConfig = defaultSdkConfig,
// $FlowFixMe
request,
request = mockEligibilityRequest(),
logger = {

@@ -26,2 +42,3 @@ info: vi.fn().mockReturnThis(),

sdkConfig,
// $FlowIssue
request,

@@ -37,22 +54,83 @@ // $FlowIssue

describe("three domain secure component - isEligible method", () => {
test.skip("should return false", async () => {
// successful response
// true for payer_action - false for Completed
test("should return true if payer action required", async () => {
const threeDomainSecureClient = createThreeDomainSecureComponent();
const eligibility = await threeDomainSecureClient.isEligible(
defaultMerchantPayload
);
expect(eligibility).toEqual(true);
});
// parameter validation
// testing for negative parameter such as null or invalid value
// error handling for API response
// mock the getpaypalapidomain so that it always returns the value that we expect
const threeDomainSecuretClient = createThreeDomainSecureComponent();
// $FlowFixMe
const eligibility = await threeDomainSecuretClient.isEligible();
test("should return false if payer action is not returned", async () => {
const threeDomainSecureClient = createThreeDomainSecureComponent({
request: () =>
Promise.resolve({ ...defaultEligibilityResponse, status: "SUCCESS" }),
});
const eligibility = await threeDomainSecureClient.isEligible(
defaultMerchantPayload
);
expect(eligibility).toEqual(false);
});
test("should assign correct URL to authenticationURL", async () => {
const threeDomainSecureClient = createThreeDomainSecureComponent({
request: () =>
Promise.resolve({
...defaultEligibilityResponse,
links: [
{ href: "https://not-payer-action.com", rel: "not-payer-action" },
...defaultEligibilityResponse.links,
],
}),
});
await threeDomainSecureClient.isEligible(defaultMerchantPayload);
expect(threeDomainSecureClient.authenticationURL).toEqual(
"https://testurl.com"
);
});
test("create payload with correctly parameters", async () => {
const mockedRequest = mockEligibilityRequest();
const threeDomainSecureClient = createThreeDomainSecureComponent({
request: mockedRequest,
});
await threeDomainSecureClient.isEligible(defaultMerchantPayload);
expect(mockedRequest).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
intent: "THREE_DS_VERIFICATION",
payment_source: expect.objectContaining({
card: expect.objectContaining({
single_use_token: defaultMerchantPayload.nonce,
verification_method: "SCA_WHEN_REQUIRED",
}),
}),
amount: expect.objectContaining({
currency_code: defaultMerchantPayload.currency,
value: defaultMerchantPayload.amount,
}),
}),
})
);
});
test("catch errors from the API", async () => {
const mockRequest = vi.fn().mockRejectedValue(new Error("Error with API"));
const threeDomainSecureClient = createThreeDomainSecureComponent({
request: mockRequest,
});
expect.assertions(2);
await expect(() =>
threeDomainSecureClient.isEligible(defaultMerchantPayload)
).rejects.toThrow(new Error("Error with API"));
expect(mockRequest).toHaveBeenCalled();
});
});
describe("three domain descure component - show method", () => {
test.skip("should return a zoid component", () => {
const threeDomainSecuretClient = createThreeDomainSecureComponent();
threeDomainSecuretClient.show();
test.todo("should return a zoid component", () => {
const threeDomainSecureClient = createThreeDomainSecureComponent();
threeDomainSecureClient.show();
// create test for zoid component

@@ -59,0 +137,0 @@ });

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc