Skip to content
Open
10 changes: 5 additions & 5 deletions examples/card-form/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,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 +75,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 +88,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 +98,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
16 changes: 13 additions & 3 deletions src/dynamic-checkout/payment-methods/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,10 @@ module ProcessOut {
const eventData = e.data ? JSON.parse(e.data) : {}

if (eventData.action === "inputEvent") {
if (eventData.data && eventData.data.card_iin !== undefined) {
if (
eventData.data &&
(eventData.data.card_iin8 !== undefined || eventData.data.card_iin !== undefined)
) {
this.handleIinRestrictionFromMessage(eventData.data)
}

Expand Down Expand Up @@ -926,14 +929,21 @@ module ProcessOut {
return
}

const iin = data.card_iin || ""
// Prefer the 8-digit IIN when present so 8-digit allowlist entries can
// match; fall back to the legacy 6-digit card_iin.
const iin = data.card_iin8 || data.card_iin || ""

if (iin.length === 0) {
this.setCardRestrictionState(false)
return
}

const isAllowedIin = restrictToIins.indexOf(iin) !== -1
// card_iin8 may carry more digits than the configured entries (IINs 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
})
Comment thread
lukasz-k-bieszczad-cko marked this conversation as resolved.

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 {
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 {
Comment thread
lukasz-k-bieszczad-cko marked this conversation as resolved.
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
5 changes: 4 additions & 1 deletion src/processout/processout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1676,7 +1676,10 @@ module ProcessOut {
return
}

const iin = cardNumber.substring(0, 6)
// Support up to 8-digit IINs (some networks issue 8-digit IINs, which
// yield more accurate issuer information); fall back to whatever is
// available when fewer digits were provided.
const iin = cardNumber.substring(0, 8)
Comment thread
roshan-gorasia-cko marked this conversation as resolved.
const apiEndpoint = `iins/${iin}`

this.apiRequest(
Expand Down
Loading