"use strict";
/**
* Wrapper class for Braintree ThreeDSecure authentication flow
*
* @author Eugen Mihailescu <eugenmihailescux@gmail.com>
* @license {@link https://www.gnu.org/licenses/gpl-3.0.txt|GPLv3}
* @version 1.0
*
* @class
* @extends BraintreeClient3
* @since 1.0
* @param config
* The default authentication configuration
*
* @see https://braintree.github.io/braintree-web/3.6.3/ThreeDSecure.html
*/
function ThreeDSecure(config) {
// super class constructor
BraintreeClient3.call(this, config);
// /////////////////////////////
// PRIVATE METHODS & FUNCTIONS
// \\\\\\\\\\\\\\\\\\\\\\\\\\\\\
var that = this;
// returns true if the `data` shows the liability shifted to bank
function isLiabilityShifted(data) {
var result = data.liabilityShifted || data.liabilityShiftPossible;
result = result
|| (data.verificationDetails && (data.verificationDetails.liabilityShifted || data.verificationDetails.liabilityShiftPossible));
return result;
}
// the helper function to integrate the 3DS popup in our modal frame
function addFrame(err, iframe) {
if (that.frame3ds) {
that.frame3ds.bankFrame.append($(iframe));
that.frame3ds.modal.removeClass(that.frame3ds.hidden);
}
}
// ///////////////////////////////
// PRIVILEGED MEMBERS & FUNCTIONS
// \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
/**
* The instance to the Braintree ThreeDSecure object
*
* @since 1.0
* @member {Object}
* @default
*/
this.bt_threeDSecure = false;
/**
* The form inputs (here we need only access to `amount` field)
*
* @since 1.0
* @member {Object}
* @property {string} amount - The jQuery selector for the amount HTML element
*/
this.inputs = config.inputs;
/**
* The 3DS authentication wrapper frame HTML elements as provided via the constructor's {@link ThreeDSecure|configuration}
*
* @since 1.0
* @member {Object}
* @property {Object} bankFrame - The inner jQuery object that represents the 3DS bank frame body (eg. a DIV)
* @property {Object} modal - The outer jQuery object that represents the 3DS bank modal frame (eg. a DIV)
* @property {string} hidden - The CSS class name used to hide the 3DS bank frame
* @property {Object} closeBtn - The jQuery object that represents the 3DS bank frame close button
*/
this.frame3ds = config.frame3ds;
/**
* Set to true if integration accepts 3DS cards only
*
* @since 1.0
* @member {boolean}
* @default false
*/
this.allow3DSPaymentsOny = config.allow3DSPaymentsOny || false;
/**
* Overrides the {@link ThreeDSecure#allow3DSPaymentsOny} option: if non-3DS card but merchant has AVS rules then accept
* the payment. Hopefully it will be validated by the gateway.
*
* @since 1.0
* @member {boolean}
* @default false
*/
this.ignore3DSIfAVS = config.ignore3DSIfAVS || false;
/**
* Callback to notify after the 3DS instance is created|ready
*
* @since 1.0
* @member {callback}
* @default {@link ConfiguredClass#noop|noop}
*/
this.onReady = config.onReady || this.noop;
/**
* Callback to notify when the user closes the 3DS popup
*
* @since 1.0
* @member {callback}
* @default {@link ConfiguredClass#noop|noop}
*/
this.onUserClose = config.onUserClose || this.noop;
/**
* Callback to notify when 3DS liability cannot be shifted to bank
*
* @since 1.0
* @member {callback}
* @default {@link ConfiguredClass#noop|noop}
*/
this.onFailLiabilityShift = config.onFailLiabilityShift || this.noop
/**
* Callback to notify when the AVS is tried due to 3DS liability shift failure
*
* @since 1.0
* @member {callback}
* @default {@link ConfiguredClass#noop|noop}
*/
this.onUseAVSLiabilityShiftFailed = config.onUseAVSLiabilityShiftFailed || this.noop
/**
* The Remove the 3DS popup from our modal frame
*
* @since 1.0
* @function
* @param {Object}
* error - The Braintree error object passed to the function when called
* @param {string}
* paymentMethod - The payment method passed that called this function
*/
this.removeFrame = function(error, paymentMethod) {
var iframe = that.frame3ds.bankFrame.children('iframe');
that.frame3ds.modal.addClass(that.frame3ds.hidden);
iframe.remove();
};
/**
* Launches the 3DS authentication popup
*
* @since 1.0
* @param {Object}
* data - An object that contains the paymentMethodInfo and the callback used while calling the
* {@link https://braintree.github.io/braintree-web/3.6.3/ThreeDSecure.html#verifyCard|Braintree's verifyCard}
* method
* @see GenericIntegration#onPaymentMethodReceived
* @example myInstance.verifyCard({ paymentMethodInfo: { nonce: "5wh9memdzg", type: "CreditCard" }, onSuccess:
* function(nonce) {}, onError: function() {}, onBypass3DS: function(response) {} });
*/
this.verifyCard = function(data) {
if (!that.is_available()) {
return;
}
that.bt_threeDSecure.verifyCard({
amount : $(that.inputs.amount).val(),
nonce : data.paymentMethodInfo.nonce,
addFrame : addFrame,
removeFrame : that.removeFrame
}, function(err, response) {
if (err) {
that.onError(that.execModuleFn('utils', 'parseError', err));
return;
}
var success = isLiabilityShifted(response);
if (!success && that.ignore3DSIfAVS && that.execModuleFn('utils', 'getAVSChallenges').length) {
success = data.onBypass3DS ? data.onBypass3DS(response) : true;
if (that.onUseAVSLiabilityShiftFailed) {
that.onUseAVSLiabilityShiftFailed(response);
}
}
success = success || !that.allow3DSPaymentsOny;
if (!success) {
data.onError();
that.onFailLiabilityShift(response);
} else {
data.onSuccess(response.nonce);
}
});
};
/**
* Check whether the 3DS is available
*
* @since 1.0
* @returns {boolean} Returns true if 3DS authentication is available, false otherwise
* @see {@link ThreeDSecure#bt_threeDSecure|bt_threeDSecure}
*/
this.is_available = function() {
return that.bt_threeDSecure !== false;
};
this.init();
}
ThreeDSecure.prototype = Object.create(BraintreeClient3.prototype);
ThreeDSecure.prototype.constructor = ThreeDSecure;
/**
* @since 1.0
* @inheritdoc
* @override
*/
ThreeDSecure.prototype.init = function() {
var that = this;
this.frame3ds.closeBtn.off('click').on('click', function() {
that.bt_threeDSecure.cancelVerifyCard(that.removeFrame);
that.onError();
that.onUserClose();
});
this.onClientReady = function(clientInstance) {
braintree.threeDSecure.create({
client : clientInstance
}, function(threeDSecureErr, threeDSecureInstance) {
if (threeDSecureErr) {
that.onError(threeDSecureErr.message);
return;
}
that.bt_threeDSecure = threeDSecureInstance;
that.onReady(that);
});
};
BraintreeClient3.prototype.init.call(this);
};