1 /**
2 * Copyright © DiamondMVC 2019
3 * License: MIT (https://github.com/DiamondMVC/Diamond/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 */
6 module diamond.security.validation.creditcard;
7 
8 /**
9 * Validates a credit-card number using luhn's algorithm.
10 * Params:
11 *   creditCardNumber = The number of the credit card.
12 *   allowedDigits =    The allowed length of digits. If it's null it allows credit card numbers to be any length.
13 * Returns:
14 *   True if the credit card number is valid according to the allowed digits and luhn's algorithm, false otherwise.
15 */
16 bool isValidCreditCard(string creditCardNumber, size_t[] allowedDigits = null)
17 {
18   import std.conv : to;
19   import std.algorithm : map, canFind;
20 
21   import diamond.errors.checks;
22 
23   import diamond.security.validation.types : isValidNumber;
24 
25   enforce(creditCardNumber && creditCardNumber.length, "A credit card number must be specified.");
26   enforce(isValidNumber(creditCardNumber), "The credit card number must be numeric");
27 
28   if (allowedDigits)
29   {
30     if (!allowedDigits.canFind(creditCardNumber.length))
31     {
32       return false;
33     }
34   }
35 
36   size_t sum;
37 
38   foreach (digit; creditCardNumber.map!(d => to!string(d)))
39   {
40     auto value = to!size_t(digit);
41 
42     if (value % 2 == 0)
43     {
44       value *= 2;
45 
46       if (value > 9)
47       {
48         value = 1 + (value % 10);
49       }
50     }
51 
52     sum += value;
53   }
54 
55   return (sum % 10) == 0;
56 }