Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions examples/card-form/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
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,
function(cardInfo) {
Expand All @@ -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.7",
"version": "1.9.8",
"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
7 changes: 6 additions & 1 deletion src/dynamic-checkout/payment-methods/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,12 @@ module ProcessOut {
return
}

const isAllowedIin = restrictToIins.indexOf(iin) !== -1
// card_iin 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.
Comment thread
roshan-gorasia-cko marked this conversation as resolved.

this.setCardRestrictionState(!isAllowedIin)
}
Expand Down
53 changes: 49 additions & 4 deletions src/processout/card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,10 +455,55 @@ module ProcessOut {
public static getIIN(number: string): string {
number = Card.parseNumber(number); // Remove potential spaces

var l = number.length;
if (l > 6)
l = 6;
return number.substring(0, l);
if (number.length < 6)
return number;

// Only expose an 8-digit IIN when PCI rules allow it: the scheme
// must permit it and the full PAN must be exactly 16 digits.
// Everything else caps at 6 to avoid over-exposing the BIN.
// Mirrors binder's TruncateNumber / api (controllers/card_inn.go).
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 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Binder also does one extra check which I don't think API does: https://github.com/processout/binder/blob/master/services/binder/iindb/transformer.go#L42

It double checks the length https://www.pcisecuritystandards.org/faqs/1091/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;
}

/**
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