function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Greg HGreg H 

Pattern for a credit card number?

I wrote a trigger to check if certain fields contain credit card numbers when they are saved.  If I find a credit card I will eliminate the digits from the first portion of the string and replace with a sequence of star characters (************0000).  The code works fine in all test cases except when the credit card is entered with spaces between the digits (ie 0000 0000 0000 0000).  I'm thinking that the only way to address this test case is with the Pattern & Matcher methods.  However, I am not having any luck matching possible patterns within my code.
 
Does anyone have a pattern for checking credit card numbers that they would be willing to post here?  I would greatly appreciate the assistance.
-greg
werewolfwerewolf
Have you tried Encrypted Fields?  Contact Salesforce Support and have them turn it on for you -- I think it might do what you're looking for even without any trigger.
Greg HGreg H
The issue is that users are entering credit card numbers into various fields and shouldn't be.  The encrypted fields is a valid idea but we are trying to prevent users from entering credit card numbers at all - the policy is that no credit card details should be stored in the app and I am simply trying to enforce this policy using a trigger.
-greg
werewolfwerewolf
Well, why not do a replace or replaceAll on all dashes and spaces in there, replacing them with nothing, and then run that preprocessed string through your filter?  That should cover it.
Greg HGreg H
The original code that I wrote was flawed in that it was looking for spaces between the various sub-strings to determine where credit cards may or may not begin/end in my text fields.  This processing was causing me to miss valid credit card numbers that had spaces between the digits and I thought that the only way to remedy the problem was by using the pattern/matcher methods.
 
It turns out that I was able to alter my logic to look for sequences of numbers while ignoring the separators between number characters (specifically the white space). My code now works for all test cases so I will not be needing any credit card patterns. Werewolf - although I wasn't able to make use of any of your suggestions, I do appreciate your responses.
-greg
Rune B. WaageRune B. Waage
Hi Greg.
I hope you have found an answer by now, but just want to answer if other finds this blog post as I did. I have created two solutions for this that handles Visa, Mastercard and American Express cards. For handling of other cards as well, you can find credit cards bin ranges here, BIN List & Range for MasterCard, Visa, Amex +++ (https://neapay.com/post/bin-list-range-for-mastercard-visa-amex-diners-discover-jcb-cup_94.html).
The sample code assume that there are no more than one . or space for every 4 digits in the card number.
Alternative one, using Pattern, will mask the credit card number and show maximum the 6 first and 4 last digits. The other alternative replaces the credit card number with the text "<<possible CC number>>".

Sample Code in APEX:
String body='Hi Support, this is my card number 4569971012345432. I have another Visa as well 45679876.1234.5432 and you know what? I also have a Mastercard 5432 2345.5432.2345 and an AMEX 3737.771234.51234. Best regards, Easy Target';
String regEx = '(^| )(4[0-9 .]{11,24})|((22|23|24|25|26|27|51|52|53|54|55)[0-9 .]{13,17})|((34|37)[0-9 .]{12,15}[0-9])\\D';
String safeBody = body;
String safeBody2 = body;

//Alternative 1
Pattern ccard = Pattern.compile(regEx);
Matcher ccardMatch = ccard.matcher(body);
while(ccardMatch.find()){
    safeBody = safeBody.replace(body.substring(ccardMatch.start()+6,ccardMatch.end()-4), '***');
}
//Alternative 2
safeBody2 = body.replaceAll(regEx, '<<possible CC number>>');

System.debug('Body: '+body);
System.debug('Body after Pattern: '+safeBody);
System.debug('Body using String.replaceAll: ' + safeBody2);

Output:
Body: Hi Support, this is my card number 4569971012345432. I have another Visa as well 45679876.1234.5432 and you know what? I also have a Mastercard 5432 2345.5432.2345 and an AMEX 3737.771234.51234. Best regards, Easy Target

Body after Pattern: Hi Support, this is my card number 45699***32. I have another Visa as well 45679***432 and you know what? I also have a Mastercard 5432 2***2345 and an AMEX 3737.7***234. Best regards, Easy Target

Body using String.replaceAll: Hi Support, this is my card number<<possible CC number>>I have another Visa as well<<possible CC number>>and you know what? I also have a Mastercard <<possible CC number>> and an AMEX <<possible CC number>> Best regards, Easy Target

 
Nadula Karunaratna 8Nadula Karunaratna 8

Hi Rune B. Waage, thanks for sharing. I've tried your regex and it seems to be picking up ABN numbers as well.
Example - 56 009 296 824

Greg H, have you had a success? 
Care to share the credit card identying logic you have used?