UNPKG

@open-tender/utils

Version:

A library of utils for use with Open Tender applications that utilize our cloud-based Order API.

164 lines (163 loc) 5.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateCreditCard = exports.formatCard = exports.formatCardField = exports.makeAcctNumber = exports.makeAlphaNumeric = exports.makeNumeric = exports.getCardType = exports.cardNumbersRegex = exports.cardNames = void 0; const helpers_1 = require("./helpers"); exports.cardNames = { VISA: 'Visa', MC: 'Mastercard', DISC: 'Discover', AMEX: 'American Express', OTHER: 'Other Credit Card' }; // https://github.com/jasminmif/react-interactive-paycard exports.cardNumbersRegex = { VISA: '^4', MC: '^5[1-5]', DISC: '^6011', AMEX: '^(34|37)' // unionpay: '^62', // troy: '^9792' }; const getCardType = (cardNumber) => { const number = cardNumber; let re; for (const [card, pattern] of Object.entries(exports.cardNumbersRegex)) { re = new RegExp(pattern); if (number.match(re) !== null) { return card; } } return 'OTHER'; // default type }; exports.getCardType = getCardType; const chunks = [ [0, 4], [4, 8], [8, 12], [12, 16] ]; const amexChunks = [ [0, 4], [4, 10], [10, 15] ]; const makeNumeric = (str) => { const strMatches = str.match(/\d+/g); // limit to numerical input, returns an array if (!strMatches) return ''; return strMatches.join('').replace(/\s/g, ''); }; exports.makeNumeric = makeNumeric; const makeAlphaNumeric = (str) => { const strMatches = str.match(/[a-zA-Z0-9]+/g); // limit to alphanumeric input, returns an array if (!strMatches) return ''; return strMatches.join('').replace(/\s/g, ''); }; exports.makeAlphaNumeric = makeAlphaNumeric; const makeAcctNumber = (str, cardType) => { const strMatches = str.match(/\d+/g); // limit to numerical input, returns an array if (!strMatches) return ''; str = strMatches.join('').replace(/\s/g, ''); if (cardType === 'AMEX') { return amexChunks .map(([start, end]) => str.slice(start, end)) .filter(i => i.length) .join(' ') .slice(0, 18); } else { return chunks .map(([start, end]) => str.slice(start, end)) .filter(i => i.length) .join(' ') .slice(0, 19); } }; exports.makeAcctNumber = makeAcctNumber; const formatCardField = (field, value) => { const cleanValue = field === 'addr' || field === 'cardholder_name' || field === 'zip' ? value : (0, exports.makeNumeric)(value); switch (field) { case 'acct': { const currentType = (0, exports.getCardType)(value.replace(/\s/g, '')); return (0, exports.makeAcctNumber)(value, currentType); } case 'exp': { value = cleanValue.slice(0, 4); if (value.length > 2) { value = `${value.slice(0, 2)} / ${value.slice(2, 4)}`; } return value; } case 'cvv': return cleanValue.slice(0, 4); case 'zip': return (0, exports.makeAlphaNumeric)(cleanValue); default: return cleanValue; } }; exports.formatCardField = formatCardField; const formatCard = (card) => { if (!card) return [null, null]; const creditCardType = (0, exports.getCardType)(card.acct.replace(/\s/g, '')); const creditCard = { acct: (0, exports.formatCardField)('acct', card.acct), exp: (0, exports.formatCardField)('exp', card.exp), cvv: (0, exports.formatCardField)('cvv', card.cvv), zip: (0, exports.formatCardField)('zip', card.zip), save: card.save || true }; if ('addr' in card) creditCard.addr = card.addr; if ('cardholder_name' in card) creditCard.cardholder_name = card.cardholder_name; return [creditCard, creditCardType]; }; exports.formatCard = formatCard; const validateCreditCard = (card, cardType, requireCardholderName = false) => { const errors = {}; let { acct, exp, cvv, cardholder_name } = card; const acctLength = cardType === 'AMEX' ? 15 : 16; acct = acct ? acct.replace(/\s/g, '') : ''; if (acct.length !== acctLength) { errors.acct = `Card number must be ${acctLength} digits`; } else if (!(0, helpers_1.isNum)(acct)) { errors.acct = 'Card number must be only numbers'; } exp = (exp ? exp.replace(/\s/g, '') : '').replace('/', '').padStart(4, '0'); const expMonth = parseInt(exp.slice(0, 2)); const expYear = parseInt(exp.slice(2, 4)); if (!(0, helpers_1.isNum)(exp) || exp.length !== 4) { errors.exp = 'Expiration must be 4 digits in MMYY format'; } else if (expMonth < 1 || expMonth > 12) { errors.exp = 'Expiration month must be number between 1 and 12'; } else if (expYear < 20) { errors.exp = 'Expiration year must be 2020 or later'; } const cvvLength = cardType === 'AMEX' ? 4 : 3; cvv = cvv ? cvv.replace(/\s/g, '') : ''; if (cvv.length !== cvvLength) { errors.cvv = `CVV must be ${cvvLength} digits for this card type`; } else if (!(0, helpers_1.isNum)(cvv)) { errors.cvv = 'CVV must be only numbers'; } cardholder_name = cardholder_name === null || cardholder_name === void 0 ? void 0 : cardholder_name.trim(); if (requireCardholderName && !cardholder_name) { errors.cardholder_name = 'Cardholder name is required'; } if (!(0, helpers_1.isEmpty)(errors)) { return { card, cardType, errors }; } card = Object.assign(Object.assign({}, card), { acct, exp, cvv, cardholder_name }); return { card, cardType, errors: null }; }; exports.validateCreditCard = validateCreditCard;