Recipes by Category

App Distribution (2) Bundle logic, interface and services for distribution. App Logic (37) The Apex programming language, workflow and formulas for logic. Collaboration (6) The Salesforce Chatter collaboration platform. Database (29) Data persistence, reporting and analytics. Integration (33) Web Service APIs and toolkits for integration. Security (9) Platform, application and data security. Tools (4) Force.com tooling User Interface (36) Visualforce MVC and metadata-drive user interfaces. Web Sites (12) Public web sites and apps with optional user registration and login.
Beta Feedback
Cookbook Home » String Masking using RegEx

String Masking using RegEx

Post by Mike Boutin  (2012-01-23)

Status: Unverified
Level: intermediate

Problem

We are often asked to stop users from entering credit card numbers or filter inappropriate language from data entered by users. With the use of regular expressions and the code snippet below, this task becomes simple and quick to complete. Coupled with a before trigger, this code becomes an automated pattern driven masking tool that keeps watch over your data.

Solution

For this solution, let's assume that we have the need to mask Visa credit card numbers that are entered in Case Comments. Before we address the scenario, let's first look at the code used to mask the string.

public class StringUtils {
    static public string MaskString(string inString, List<string> inPatterns, string inMask, integer inVisibleCharacters) {
       // validate the passed in variables
       if (inString == null || instring.length() < 1 ||
       	   inPatterns == null || inPatterns.size() < 1 ||
       	   inMask == null) return inString;
       if (inVisibleCharacters < 0) inVisibleCharacters = 0;
       
       // prime the internal variables to be used during processing
       string stringToMask = inString;
	   string maskedString = inString;
	   
       // iterate through each pattern and mask any matches leaving the last visible characters
       for(string regEx : inPatterns) {
           Pattern p = Pattern.compile(regEx);
           Matcher m = p.matcher(stringToMask);
           while(m.find()) {
               // find the start and end indexes of the match
               integer startIdx = m.start();
               integer endIdx = m.end();
               
               // extract the matched string
               string patternMatch = stringToMask.substring(startIdx, endIdx);                    
               
               // mask the string leaving any visible characters
               string partToBeMasked = patternMatch.substring(0, patternMatch.length() - inVisibleCharacters);                                                             
               string mask = '';                                          
               for(integer i = 0; i < partToBeMasked.length(); i++) {
                   mask += inMask;
               }    
               
               // concatenate mask string with the last visible characters               
               string maskedNumber = mask + patternMatch.substring(patternMatch.length() - inVisibleCharacters);                   
               
               // replace the the card number with masked number
               maskedString = maskedString.replace(patternMatch, maskedNumber);
           }               
       }       
       return maskedString;     
   }
}
Now, we create the trigger needed to scrub the Case Comments body. For the code below, assume that we have placed the code snippet above in a class named StringUtils.
trigger MaskCaseComments on CaseComment (before insert, before update) {
    for(CaseComment cc : trigger.new) {
	if (cc.CommentBody != null) 
		cc.CommentBody = StringUtils.MaskString(cc.CommentBody, new list<string>{'4\\d{3}[- ]*\\d{4}[- ]*\\d{4}[- ]*\\d{4}'}, '*', 4);
    }
}
Now, each time a Case Comment is entered, the CommentBody value, if provided, will be scrubbed for Visa credit card numbers and masked with a star (*), leaving the last 4 characters. The test class below illustrates the masking results...
    static private testMethod void testMaskStirng()
   {
   	// create a pattern for matching, in this case we are looking for visa numbers
   	list<string> listPatterns = new list<string>{'4\\d{3}[- ]*\\d{4}[- ]*\\d{4}[- ]*\\d{4}'};
   	Test.startTest();
   	// test to make sure the credit card number is masked leaving the last 4 digits
   	System.Assert(StringUtils.MaskString('my visa number is 4111-1111-1111-1111', listPatterns, '*', 4) == 'my visa number is ***************1111');
   	Test.stopTest();
   }

Discussion

For this example, we used credit card masking as the scenario. By using regular expressions, this snippet of code is capable of masking a multitude of string values from words and sentences to numbers and symbols. When asked to mask values, regular expressions and this snippet are all you need.

Share

Recipe Activity - Please Log in to write a comment

Hi Mike,

Thank you for providing this to the community. I am very new to Salesforce and one of the problems that I have is being able to somehow implement something that will look through all of the email messages that have gone through Salesforce and "cleanse" that data by masking any credit card numbers/CVV information that may or may not be found. How would something like this be implemented in order to help us accomplish this?

Thanks!
Rafid Arian

by Rafid Arian  (2012-08-07)

X

Vote to Verify a Recipe

Verifying a recipe is a way to give feedback to others and broaden your own understanding of the capabilities on Force.com. When you verify a recipe, please make sure the code runs, and the functionality solves the articulated problem as expected.

Please make sure:
  • All the necessary pieces are mentioned
  • You have tested the recipe in practice
  • Have sent any suggestions for improvements to the author

Please Log in to verify a recipe

You have voted to verify this recipe.