Skip to content
Draft
13 changes: 7 additions & 6 deletions examples/card-form/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@
color: "#ababab",
},
},
exposeIIN8: true,
},
function (form) {
let preferredCardType = null;
form.getNumberField().on("input", function (e) {
if (e.card_number_length == 6) {
if (e.card_number_length == 8) {
client.getCardInformation(
e.card_iin,
Comment on lines +59 to 61
function(cardInfo) {
Expand All @@ -65,7 +66,7 @@
const radioGroup = document.createElement('div')
radioGroup.className = 'combo-card-types'
radioGroup.style.cssText = 'margin: 15px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; background: #f9f9f9;'

radioGroup.innerHTML = `
<h4 style="margin: 0 0 10px 0; color: #333;">Select Card Type:</h4>
${cardInfo.combo_card_types.map((type, index) => `
Expand All @@ -75,11 +76,11 @@ <h4 style="margin: 0 0 10px 0; color: #333;">Select Card Type:</h4>
</label>
`).join('')}
`

// Insert before the Pay button
const payButton = document.querySelector('.submit-button')
payButton.parentNode.insertBefore(radioGroup, payButton)

// Add event listener to track selection changes
const radioButtons = radioGroup.querySelectorAll('input[name="cardType"]')
radioButtons.forEach(radio => {
Expand All @@ -88,7 +89,7 @@ <h4 style="margin: 0 0 10px 0; color: #333;">Select Card Type:</h4>
console.log("User selected card type:", preferredCardType)
})
})

// Set initial value
preferredCardType = null
}
Expand All @@ -98,7 +99,7 @@ <h4 style="margin: 0 0 10px 0; color: #333;">Select Card Type:</h4>
}
)
}

document.getElementById("errors").innerHTML = ""
})

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "processout.js",
"version": "1.9.10",
"version": "1.9.11",
"description": "ProcessOut.js is a JavaScript library for ProcessOut's payment processing API.",
"scripts": {
"build:processout": "tsc -p src/processout && uglifyjs --compress --keep-fnames --ie8 dist/processout.js -o dist/processout.js",
Expand Down
8 changes: 7 additions & 1 deletion src/dynamic-checkout/payment-methods/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -933,7 +933,13 @@ module ProcessOut {
return
}

const isAllowedIin = restrictToIins.indexOf(iin) !== -1
// card_iin may carry 6 or 8 digits (8 when the merchant opted into
// exposeIIN8 and PCI rules allow), while configured entries can be 6 or
// 8 digits, so match on prefix: an allowed entry matches when the
// detected IIN starts with it.
const isAllowedIin = restrictToIins.some(function (allowedIin) {
return allowedIin.length > 0 && iin.substring(0, allowedIin.length) === allowedIin
})

this.setCardRestrictionState(!isAllowedIin)
}
Expand Down
57 changes: 57 additions & 0 deletions src/processout/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,63 @@ module ProcessOut {
return number.substring(0, l);
}

/**
* GetIIN8 returns the IIN of the card number, exposing up to 8 digits
* when PCI rules allow it (scheme in the allow-list and a 16-digit
* PAN) and 6 digits otherwise.
* @param {string} number
* @return {string}
*/
public static getIIN8(number: string): string {
Comment on lines +464 to +471
number = Card.parseNumber(number); // Remove potential spaces

if (number.length < 6)
return number;

if (Card.canExpose8DigitIIN(number))
return number.substring(0, 8);

return number.substring(0, 6);
}

/**
* Schemes permitted to surface an 8-digit IIN, mirroring the backend
* allow-list in api (controllers/card_inn.go). Every other scheme -
* notably American Express - is capped at 6 digits. Note the JS
* scheme key "union-pay" maps to the backend's "china union pay".
*/
private static iin8DigitSchemes: Array<string> = [
"visa", "mastercard", "discover", "jcb", "union-pay", "carte bancaire"
];

/**
* canExpose8DigitIIN reports whether an 8-digit IIN may be surfaced
* for the given card number. Mirrors binder's TruncateNumber: the PAN
* must be exactly 16 digits and every detected scheme must be in the
* allow-list. Conservative on co-badged or ambiguous prefixes (and
* unknown schemes), which fall back to 6 digits.
* @param {string} number
* @return {boolean}
*/
public static canExpose8DigitIIN(number: string): boolean {
number = Card.parseNumber(number); // Remove potential spaces

// PCI: 8-digit BINs are only defined for 16-digit PANs.
if (number.length != 16)
return false;

var schemes = Card.getPossibleSchemes(number);
if (schemes.length == 0)
return false;

for (var i = 0; i < schemes.length; i++) {
if (Card.iin8DigitSchemes.indexOf(schemes[i]) === -1)
return false;
}

return true;
}

/**
* GetLast4Digits returns the last4 digits of the card number
* @param {string} number
Expand Down
Loading
Loading