'use strict';
/** @module braintree-web/three-d-secure */
var ThreeDSecure = require('./external/three-d-secure');
var isHTTPS = require('../lib/is-https').isHTTPS;
var basicComponentVerification = require('../lib/basic-component-verification');
var createDeferredClient = require('../lib/create-deferred-client');
var createAssetsUrl = require('../lib/create-assets-url');
var BraintreeError = require('../lib/braintree-error');
var analytics = require('../lib/analytics');
var errors = require('./shared/errors');
var VERSION = process.env.npm_package_version;
var Promise = require('../lib/promise');
var wrapPromise = require('@braintree/wrap-promise');
/**
* @static
* @function create
* @param {object} options Creation options:
* @param {object} [options.cardinalSDKConfig] A config for the underlying Cardinal SDK.
* @param {object} [options.cardinalSDKConfig.logging] The logging configuration for the Cardinal SDK. See [Cardinal's documentation for the logging object](https://cardinaldocs.atlassian.net/wiki/spaces/CC/pages/1409568/Configurations#Configurations-Logging) for more information.
* @param {number} [options.cardinalSDKConfig.timeout] The time in milliseconds to wait before a request to Cardinal's API times out. See [Cardinal's documentation for root level configuration](https://cardinaldocs.atlassian.net/wiki/spaces/CC/pages/1409568/Configurations#Configurations-RootLevelConfiguration) for more information.
* @param {number} [options.cardinalSDKConfig.maxRequestRetries] How many times a request should be re-attempted to Cardinal's API before giving up as a failure. See [Cardinal's documentation for root level configuration](https://cardinaldocs.atlassian.net/wiki/spaces/CC/pages/1409568/Configurations#Configurations-RootLevelConfiguration) for more information.
* @param {object} [options.cardinalSDKConfig.payment] An object to describe how you want the user interactions to behave. Only a subset of the [Cardinal SDK payment configuration object](https://cardinaldocs.atlassian.net/wiki/spaces/CC/pages/1409568/Configurations#Configurations-Payment) are supported: `displayLoading` and `displayExitButton`.
* @param {Client} [options.client] A {@link Client} instance.
* @param {string} [options.authorization] A tokenizationKey or clientToken. Can be used in place of `options.client`.
* @param {(number|string)} [options.version=1] The version of 3D Secure to use. Possible options:
* * 1 - The legacy 3D Secure v1.0 integration.
* * 2 - A 3D Secure v2.0 integration that uses a modal to host the 3D Secure iframe.
* * 2-bootstrap3-modal - A 3D Secure v2.0 integration that uses a modal styled with Bootstrap 3 styles to host the 3D Secure iframe. Requires having the Bootstrap 3 script files and stylesheets on your page.
* * 2-inline-iframe - A 3D Secure v2.0 integration that provides the authentication iframe directly to the merchant.
* @param {callback} [callback] The second argument, `data`, is the {@link ThreeDSecure} instance. If no callback is provided, it returns a promise that resolves the {@link ThreeDSecure} instance.
* @returns {(Promise|void)} Returns a promise if no callback is provided.
@example
* <caption>Creating a v2 3D Secure component using 2 version (Cardinal modal)</caption>
* braintree.threeDSecure.create({
* client: clientInstance,
* version: '2'
* }, function (createError, threeDSecure) {
* // set up lookup-complete listener
* threeDSecure.on('lookup-complete', function (data, next) {
* // check lookup data
*
* next();
* });
*
* // using Hosted Fields, use `tokenize` to get back a credit card nonce
*
* threeDSecure.verifyCard({
* nonce: nonceFromTokenizationPayload,,
* bin: binFromTokenizationPayload,
* amount: '100.00'
* }, function (verifyError, payload) {
* // inspect payload
* // send payload.nonce to your server
* });
* });
* @example
* <caption>Creating a v2 3D Secure component using 2-bootstrap3-modal version</caption>
* // must have the boostrap js, css and jquery files on your page
* braintree.threeDSecure.create({
* client: clientInstance,
* version: '2-bootstrap3-modal'
* }, function (createError, threeDSecure) {
* // set up lookup-complete listener
* threeDSecure.on('lookup-complete', function (data, next) {
* // check lookup data
*
* next();
* });
*
* // using Hosted Fields, use `tokenize` to get back a credit card nonce
*
* // challenge will be presented in a bootstrap 3 modal
* threeDSecure.verifyCard({
* nonce: nonceFromTokenizationPayload,
* bin: binFromTokenizationPayload,
* amount: '100.00'
* }, function (verifyError, payload) {
* // inspect payload
* // send payload.nonce to your server
* });
* });
* @example
* <caption>Creating a v2 3D Secure component using 2-inline-iframe version</caption>
* braintree.threeDSecure.create({
* client: clientInstance,
* version: '2-inline-iframe'
* }, function (createError, threeDSecure) {
* // set up lookup-complete listener
* threeDSecure.on('lookup-complete', function (data, next) {
* // check lookup data
*
* next();
* });
* // set up iframe listener
* threeDSecure.on('authentication-iframe-available', function (event, next) {
* var element = event.element; // an html element that contains the iframe
*
* document.body.appendChild(element); // put it on your page
*
* next(); // let the sdk know the element has been added to the page
* });
*
* // using Hosted Fields, use `tokenize` to get back a credit card nonce
*
* threeDSecure.verifyCard({
* nonce: nonceFromTokenizationPayload,,
* bin: binFromTokenizationPayload,
* amount: '100.00'
* }, function (verifyError, payload) {
* // inspect payload
* // send payload.nonce to your server
* });
* });
*/
function create(options) {
var name = '3D Secure';
return basicComponentVerification.verify({
name: name,
client: options.client,
authorization: options.authorization
}).then(function () {
var assetsUrl = createAssetsUrl.create(options.authorization);
var framework = getFramework(options);
var createPromise = createDeferredClient.create({
authorization: options.authorization,
client: options.client,
debug: options.debug,
assetsUrl: assetsUrl,
name: name
}).then(function (client) {
var error, isProduction;
var config = client.getConfiguration();
var gwConfig = config.gatewayConfiguration;
options.client = client;
if (!gwConfig.threeDSecureEnabled) {
error = errors.THREEDS_NOT_ENABLED;
}
if (config.authorizationType === 'TOKENIZATION_KEY') {
error = errors.THREEDS_CAN_NOT_USE_TOKENIZATION_KEY;
}
isProduction = gwConfig.environment === 'production';
if (isProduction && !isHTTPS()) {
error = errors.THREEDS_HTTPS_REQUIRED;
}
if (framework !== 'legacy' && !(gwConfig.threeDSecure && gwConfig.threeDSecure.cardinalAuthenticationJWT)) {
analytics.sendEvent(options.client, 'three-d-secure.initialization.failed.missing-cardinalAuthenticationJWT');
error = errors.THREEDS_NOT_ENABLED_FOR_V2;
}
if (error) {
return Promise.reject(new BraintreeError(error));
}
analytics.sendEvent(options.client, 'three-d-secure.initialized');
return client;
});
var instance = new ThreeDSecure({
client: options.client,
assetsUrl: assetsUrl,
createPromise: createPromise,
loggingEnabled: options.loggingEnabled,
cardinalSDKConfig: options.cardinalSDKConfig,
framework: framework
});
if (options.client) {
return createPromise.then(function () {
return instance;
});
}
return instance;
});
}
function getFramework(options) {
var version = String(options.version || '');
if (!version || version === '1') {
return 'legacy';
}
switch (version) {
case '2':
case '2-cardinal-modal':
return 'cardinal-modal';
case '2-bootstrap3-modal':
return 'bootstrap3-modal';
case '2-inline-iframe':
return 'inline-iframe';
default:
throw new BraintreeError({
code: errors.THREEDS_UNRECOGNIZED_VERSION.code,
type: errors.THREEDS_UNRECOGNIZED_VERSION.type,
message: 'Version `' + options.version + '` is not a recognized version. You may need to update the version of your Braintree SDK to support this version.'
});
}
}
module.exports = {
create: wrapPromise(create),
/**
* @description The current version of the SDK, i.e. `{@pkg version}`.
* @type {string}
*/
VERSION: VERSION
};