Skip to content

Commit b13798a

Browse files
author
Darin Howard
committed
RT-464 - adding in uuid, numeric, email masking.
1 parent 7a53749 commit b13798a

2 files changed

Lines changed: 108 additions & 17 deletions

File tree

src/main/java/com/stackify/api/common/mask/Masker.java

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

src/test/java/com/stackify/api/common/mask/MaskerTest.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,54 @@ public void maskIPV4() {
7373
Assert.assertEquals("IPV4 Multiple No Match", "a 3a3.44b.45.256 b 452.33.25 c", masker.mask("a 3a3.44b.45.256 b 452.33.25 c"));
7474
}
7575

76+
@Test
77+
public void maskUUID() {
78+
79+
Masker masker = new Masker();
80+
masker.addMask(Masker.MASK_UUID);
81+
82+
Assert.assertEquals("************************************", masker.mask("76e0571d-f758-49a8-b5e7-27e1ed34391c"));
83+
Assert.assertEquals("a ************************************ c", masker.mask("a 76e0571d-f758-49a8-b5e7-27e1ed34391c c"));
84+
Assert.assertEquals("{guid}", masker.mask("76e0571d-f758-49a8-b5e7-27e1ed34391c", "{guid}"));
85+
Assert.assertEquals("a {guid} c", masker.mask("a 76e0571d-f758-49a8-b5e7-27e1ed34391c c", "{guid}"));
86+
}
87+
88+
@Test
89+
public void maskNumeric() {
90+
91+
Masker masker = new Masker();
92+
masker.addMask(Masker.MASK_NUMERIC);
93+
94+
Assert.assertEquals("***", masker.mask("123"));
95+
Assert.assertEquals("a***c", masker.mask("a123c"));
96+
Assert.assertEquals("abc", masker.mask("abc"));
97+
Assert.assertEquals("{id}", masker.mask("123", "{id}"));
98+
Assert.assertEquals("a{id}c", masker.mask("a123c", "{id}"));
99+
}
100+
101+
102+
@Test
103+
public void maskEmail() {
104+
105+
Masker masker = new Masker();
106+
masker.addMask(Masker.MASK_EMAIL);
107+
108+
Assert.assertEquals("*****************", masker.mask("email@example.com"));
109+
Assert.assertEquals("******************************", masker.mask("firstname.lastname@example.com"));
110+
Assert.assertEquals("***************************", masker.mask("email@subdomain.example.com"));
111+
Assert.assertEquals("******************************", masker.mask("firstname+lastname@example.com"));
112+
Assert.assertEquals("**********************", masker.mask("1234567890@example.com"));
113+
Assert.assertEquals("********************", masker.mask("email@example.museum"));
114+
Assert.assertEquals("******************************", masker.mask("firstname-lastname@example.com"));
115+
Assert.assertEquals("{email}", masker.mask("firstname-lastname@example.com", "{email}"));
116+
Assert.assertEquals("[{email}]", masker.mask("[firstname-lastname@example.com]", "{email}"));
117+
Assert.assertEquals("a {email} c", masker.mask("a firstname-lastname@example.com c", "{email}"));
118+
119+
Assert.assertEquals("@example.com", masker.mask("@example.com"));
120+
Assert.assertEquals("email.example.com", masker.mask("email.example.com"));
121+
Assert.assertEquals("email@example", masker.mask("email@example"));
122+
123+
}
76124

77125
@Test
78126
public void maskPerformance() {

0 commit comments

Comments
 (0)