@@ -25,7 +25,10 @@ public class Masker {
2525 public static final String MASK_CREDITCARD = "CREDITCARD" ;
2626 public static final String MASK_SSN = "SSN" ;
2727 public static final String MASK_IP = "IP" ;
28- public static final String [] MASKS = new String []{MASK_CREDITCARD , MASK_SSN , MASK_IP };
28+ public static final String MASK_UUID = "UUID" ;
29+ public static final String MASK_NUMERIC = "NUMERIC" ;
30+ public static final String MASK_EMAIL = "EMAIL" ;
31+ public static final String [] MASKS = new String []{MASK_CREDITCARD , MASK_SSN , MASK_IP , MASK_UUID , MASK_NUMERIC , MASK_EMAIL };
2932
3033 protected static final String MASK_CC_VISA_REGEX = "4[0-9]{12}(?:[0-9]{3})" ;
3134 protected static final String MASK_CC_DISCOVER_REGEX = "6(?:011|5[0-9]{2})[0-9]{12}" ;
@@ -34,6 +37,11 @@ public class Masker {
3437 protected static final String MASK_CC_DINERS_REGEX = "3(?:0[0-5]|[68][0-9])?[0-9]{11}" ;
3538 protected static final String MASK_SSN_REGEX = "[0-9]{3}-[0-9]{2}-[0-9]{4}" ;
3639 protected static final String MASK_IPV4_REGEX = "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\ .(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\ .(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\ .(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)" ;
40+ protected static final String MASK_NUMERIC_REGEX = "(\\ d+)" ;
41+ protected static final String MASK_UUID_REGEX = "(?i)(\\ b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\\ b)" ;
42+ protected static final String MASK_EMAIL_REGEX = "((([!#$%&'*+\\ -/=?^_`{|}~\\ w])|([!#$%&'*+\\ -/=?^_`{|}~\\ w][!#$%&'*+\\ -/=?^_`{|}~\\ .\\ w]{0,}[!#$%&'*+\\ -/=?^_`{|}~\\ w]))[@]\\ w+([-.]\\ w+)*\\ .\\ w+([-.]\\ w+)*)" ;
43+
44+ private static final String DEFAULT_MASK_VALUE = "*" ;
3745
3846 @ Getter
3947 private final Map <String , Pattern > maskPatterns = new ConcurrentHashMap <String , Pattern >();
@@ -46,23 +54,29 @@ public void clearMasks() {
4654
4755 public void removeMask (@ NonNull final String mask ) {
4856 synchronized (lock ) {
57+
4958 if (mask .equals (MASK_CREDITCARD )) {
5059 removeMaskPattern (MASK_CC_VISA_REGEX );
5160 removeMaskPattern (MASK_CC_DISCOVER_REGEX );
5261 removeMaskPattern (MASK_CC_MASTERCARD_REGEX );
5362 removeMaskPattern (MASK_CC_AMEX_REGEX );
5463 removeMaskPattern (MASK_CC_DINERS_REGEX );
5564 return ;
56- }
57-
58- if (mask .equals (MASK_SSN )) {
65+ } else if (mask .equals (MASK_SSN )) {
5966 removeMaskPattern (MASK_SSN_REGEX );
6067 return ;
61- }
62-
63- if (mask .equals (MASK_IP )) {
68+ } else if (mask .equals (MASK_IP )) {
6469 removeMaskPattern (MASK_IPV4_REGEX );
6570 return ;
71+ } else if (mask .equals (MASK_UUID )) {
72+ removeMaskPattern (MASK_UUID_REGEX );
73+ return ;
74+ } else if (mask .equals (MASK_NUMERIC )) {
75+ removeMaskPattern (MASK_NUMERIC_REGEX );
76+ return ;
77+ } else if (mask .equals (MASK_EMAIL )) {
78+ removeMaskPattern (MASK_EMAIL_REGEX );
79+ return ;
6680 }
6781
6882 removeMaskPattern (mask );
@@ -71,23 +85,29 @@ public void removeMask(@NonNull final String mask) {
7185
7286 public void addMask (@ NonNull final String mask ) {
7387 synchronized (lock ) {
88+
7489 if (mask .equals (MASK_CREDITCARD )) {
7590 addMaskPattern (MASK_CC_VISA_REGEX );
7691 addMaskPattern (MASK_CC_DISCOVER_REGEX );
7792 addMaskPattern (MASK_CC_MASTERCARD_REGEX );
7893 addMaskPattern (MASK_CC_AMEX_REGEX );
7994 addMaskPattern (MASK_CC_DINERS_REGEX );
8095 return ;
81- }
82-
83- if (mask .equals (MASK_SSN )) {
96+ } else if (mask .equals (MASK_SSN )) {
8497 addMaskPattern (MASK_SSN_REGEX );
8598 return ;
86- }
87-
88- if (mask .equals (MASK_IP )) {
99+ } else if (mask .equals (MASK_IP )) {
89100 addMaskPattern (MASK_IPV4_REGEX );
90101 return ;
102+ } else if (mask .equals (MASK_UUID )) {
103+ addMaskPattern (MASK_UUID_REGEX );
104+ return ;
105+ } else if (mask .equals (MASK_NUMERIC )) {
106+ addMaskPattern (MASK_NUMERIC_REGEX );
107+ return ;
108+ } else if (mask .equals (MASK_EMAIL )) {
109+ addMaskPattern (MASK_EMAIL_REGEX );
110+ return ;
91111 }
92112
93113 addMaskPattern (mask );
@@ -116,8 +136,22 @@ private synchronized void removeMaskPattern(final String regex) {
116136
117137 /**
118138 * Returns string with '*' replacing any value matching a configured mask.
139+ *
140+ * @param value Value to mask.
119141 */
120142 public String mask (final String value ) {
143+ return mask (value , DEFAULT_MASK_VALUE );
144+ }
145+
146+ /**
147+ * Returns string with [replacementValue] replacing any value matching a configured mask.
148+ *
149+ * @param value Value to mask.
150+ * @param replacementValue Value to use when replacing original content.
151+ * If a single character string is supplied, it will be repeated to keep original value's length.
152+ */
153+ public String mask (final String value ,
154+ final String replacementValue ) {
121155
122156 try {
123157
@@ -130,10 +164,19 @@ public String mask(final String value) {
130164 for (Map .Entry <String , Pattern > entry : maskPatterns .entrySet ()) {
131165 Matcher matcher = entry .getValue ().matcher (maskedValue );
132166 while (matcher .find ()) {
167+
133168 String match = matcher .group ();
134- char [] symbols = new char [match .length ()];
135- Arrays .fill (symbols , '*' );
136- maskedValue = maskedValue .replace (match , new String (symbols ));
169+ String matchReplace ;
170+
171+ if (replacementValue .length () == 1 ) {
172+ char [] symbols = new char [match .length ()];
173+ Arrays .fill (symbols , replacementValue .toCharArray ()[0 ]);
174+ matchReplace = new String (symbols );
175+ } else {
176+ matchReplace = replacementValue ;
177+ }
178+
179+ maskedValue = maskedValue .replace (match , matchReplace );
137180 }
138181 }
139182
@@ -151,4 +194,4 @@ public boolean hasMasks() {
151194 return maskPatterns .size () > 0 ;
152195 }
153196
154- }
197+ }
0 commit comments