haterapps / fake-data

Fake Data - A form filler you won't hate
39 stars 2 forks source link

Implement credit card generator (sample code inside) #15

Closed Strongground closed 2 years ago

Strongground commented 2 years ago

Hi again,

I noticed there is no standard generator to generate some common credit card data. I did this with custom generators, but it may benefit all to have something like this included:

// Generate valid credit card number of either Visa, Mastercard, Amex or Discover
var pos
var str = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
var sum = 0
var final_digit = 0
var t = 0
var len_offset = 0
var len = 0
var issuer

// VISA
let visa = {
    str: [4],
    pos: 1,
    len: 13
}

// Mastercard
let mastercard = {
    t: Math.floor(Math.random() * 5) % 5,
    str: [5,1+t],
    pos: 2,
    len: 16
}

// American Express
let amex = {
    t: Math.floor(Math.random() * 4) % 4,
    str: [3,4+t],
    pos: 2,
    len: 15
}

// Discover
let discover = {
    str: [6,0,1,1],
    pos: 4,
    len: 16
}

str = visa.str
pos = visa.pos
len = visa.len

// Fill all the remaining numbers except for the last one with random values.
while (pos < len - 1) {
    str[pos++] = Math.floor(Math.random() * 10) % 10
}

// Calculate the Luhn checksum of the values thus far.
len_offset = (len + 1) % 2
for (pos = 0; pos < len - 1; pos++) {
    if ((pos + len_offset) % 2) {
        t = str[pos] * 2
        if (t > 9) {
            t -= 9
        }
        sum += t
    }
    else {
        sum += str[pos]
    }
}

// Choose the last digit so that it causes the entire string to pass the checksum.
final_digit = (10 - (sum % 10)) % 10
str[len - 1] = final_digit

// Output the CC value.
t = str.join('')
t = t.substr(0, len)
return t

It allows to select between four credit card issuers (replace where str, len and pos get their values from - mid script). Other helpful trivial generators:

// Generate CVC
// Doesn't cover 4-digit Amex CVC yet
return Math.floor(Math.random() * (999 - 100 + 1)) + 100
// Generate Expiration Date
// Random date between now and now + 15 years
let now = new Date()
return new Date(now.getTime() + Math.random() * (new Date(now.getFullYear()+15,now.getMonth(),now.getDate()).getTime() - now.getTime())).toLocaleDateString("en-US", {month: "2-digit", year: "2-digit"})
// Fill Card Holder
// This should ideally use FakeData.getLastGeneratedValue('last_name') and ('first_name') since that can differ from 'full_name' but it destroys the promise in the process so it never gets filled :(
// Doesn't work at the moment
// Replace german umlaute and special characters with international replacements - make this depending on 
const umlautMap = {
  '\u00dc': 'UE',
  '\u00c4': 'AE',
  '\u00d6': 'OE',
  '\u00fc': 'ue',
  '\u00e4': 'ae',
  '\u00f6': 'oe',
  '\u00df': 'ss',
}

function replaceUmlaute(str) {
  return str
    .replace(/[\u00dc|\u00c4|\u00d6][a-z]/g, (a) => {
      const big = umlautMap[a.slice(0, 1)];
      return big.charAt(0) + big.charAt(1).toLowerCase() + a.slice(1);
    })
    .replace(new RegExp('['+Object.keys(umlautMap).join('|')+']',"g"),
      (a) => umlautMap[a]
    );
}

return replaceUmlaute(`${fakeData.getLastGeneratedValue('first_name')} ${fakeData.getLastGeneratedValue('last_name')}`.toUpperCase())
haterapps commented 2 years ago

Hello,

Looking at the last snippet of code, I can see that you mentioned that it's not working because the fakeData.getLastGeneratedValue method returns a promise.

You can easily make this code work by wrapping it in a Promise with an async function and then await for the rest of the promises to finish. Here is how to do that with your code:

return new Promise(async function(resolve) {
    const umlautMap = {
      '\u00dc': 'UE',
      '\u00c4': 'AE',
      '\u00d6': 'OE',
      '\u00fc': 'ue',
      '\u00e4': 'ae',
      '\u00f6': 'oe',
      '\u00df': 'ss',
    }

    function replaceUmlaute(str) {
      return str
        .replace(/[\u00dc|\u00c4|\u00d6][a-z]/g, (a) => {
          const big = umlautMap[a.slice(0, 1)];
          return big.charAt(0) + big.charAt(1).toLowerCase() + a.slice(1);
        })
        .replace(new RegExp('['+Object.keys(umlautMap).join('|')+']',"g"),
          (a) => umlautMap[a]
        );
    }

    var result = replaceUmlaute(`${await fakeData.getLastGeneratedValue('first_name')} ${await fakeData.getLastGeneratedValue('last_name')}`.toUpperCase());

    resolve(result);
});

Also, while Fake Data doesn't have by default a generator for fake credit card numbers, the internal faker.js library comes with one. So an alternative to your code would be to use this for generating a card number: faker.finance.creditCardNumber() and this for generating a CVV code: faker.finance.creditCardCVV()

You can find more about these functions and the API that faker.js library provides here: https://github.com/faker-js/faker

Strongground commented 2 years ago

That is very solid info - thanks a lot! I've almost never before experienced such good support on a free plugin/software project!