Repository: joke2k/faker

Issue:
Credit card numbers' validity is not enforced
Credit card numbers generated by `credit_card_number()` are not always valid.

### Steps to reproduce

```python
fake = Faker()
fake.credit_card_number()
```

### Expected behavior

The credit card numbers generated should always be valid ones.

### Actual behavior

Some returned numbers are invalid. For example: "3337083863794024", "3337957986872777", "3088184514627042". You can verify it with http://www.validcreditcardnumber.com/

The problem is that the issuer identification is not always correct. You can check that by performing a RegEx, see as an example https://www.regular-expressions.info/creditcard.html

Could the generator be modified to ensure that credit card numbers are always valid?
Credit card numbers' validity is not enforced
Credit card numbers generated by `credit_card_number()` are not always valid.

### Steps to reproduce

```python
fake = Faker()
fake.credit_card_number()
```

### Expected behavior

The credit card numbers generated should always be valid ones.

### Actual behavior

Some returned numbers are invalid. For example: "3337083863794024", "3337957986872777", "3088184514627042". You can verify it with http://www.validcreditcardnumber.com/

The problem is that the issuer identification is not always correct. You can check that by performing a RegEx, see as an example https://www.regular-expressions.info/creditcard.html

Could the generator be modified to ensure that credit card numbers are always valid?


Discussion:
I'm not sure where the numbers in https://github.com/joke2k/faker/blob/master/faker/providers/credit_card/__init__.py#L33-L34 comes from, but based on https://www.regular-expressions.info/creditcard.html, they look completely wrong and need to be fixed.


I'm not sure where the numbers in https://github.com/joke2k/faker/blob/master/faker/providers/credit_card/__init__.py#L33-L34 comes from, but based on https://www.regular-expressions.info/creditcard.html, they look completely wrong and need to be fixed.



Resolving patch:
diff --git a/faker/providers/credit_card/__init__.py b/faker/providers/credit_card/__init__.py
--- a/faker/providers/credit_card/__init__.py
+++ b/faker/providers/credit_card/__init__.py
@@ -23,16 +23,19 @@ def __init__(
 
 class Provider(BaseProvider):
 
-    prefix_maestro = ['5018', '5020', '5038', '5612', '5893',
+    # Prefixes from:
+    # * https://en.wikipedia.org/wiki/Payment_card_number#Issuer_identification_number_.28IIN.29
+    # * https://www.regular-expressions.info/creditcard.html
+    # * https://creditcardjs.com/credit-card-type-detection
+    prefix_maestro = ['5018', '5020', '5038', '56##', '57##', '58##',
                       '6304', '6759', '6761', '6762', '6763', '0604', '6390']
-    prefix_mastercard = ['51', '52', '53', '54', '55']
+    prefix_mastercard = ['51', '52', '53', '54', '55', '222%']
     prefix_visa = ['4']
     prefix_amex = ['34', '37']
-    prefix_discover = ['6011']
-    prefix_diners = ['300', '301', '302', '303', '304', '305']
-    prefix_jcb16 = ['3088', '3096', '3112', '3158', '3337', '3528']
-    prefix_jcb15 = ['2100', '1800']
-    prefix_voyager = ['8699']
+    prefix_discover = ['6011', '65']
+    prefix_diners = ['300', '301', '302', '303', '304', '305', '36', '38']
+    prefix_jcb16 = ['35']
+    prefix_jcb15 = ['2131', '1800']
 
     credit_card_types = OrderedDict((
         ('maestro', CreditCard('Maestro',
@@ -47,7 +50,6 @@ class Provider(BaseProvider):
         ('diners', CreditCard('Diners Club / Carte Blanche', prefix_diners, 14)),
         ('jcb15', CreditCard('JCB 15 digit', prefix_jcb15, 15)),
         ('jcb16', CreditCard('JCB 16 digit', prefix_jcb16)),
-        ('voyager', CreditCard('Voyager', prefix_voyager, 15)),
     ))
     credit_card_types['visa'] = credit_card_types['visa16']
     credit_card_types['jcb'] = credit_card_types['jcb16']
@@ -65,7 +67,7 @@ def credit_card_number(self, card_type=None):
         """ Returns a valid credit card number. """
         card = self._credit_card_type(card_type)
         prefix = self.random_element(card.prefixes)
-        number = self._generate_number(prefix, card.length)
+        number = self._generate_number(self.numerify(prefix), card.length)
         return number
 
     def credit_card_expire(self, start='now', end='+10y', date_format='%m/%y'):


Test patch: