Skip to content

Commit 6bb5c1f

Browse files
author
Darin Howard
committed
RT-44 - adding in log masking utility
1 parent 807fbf1 commit 6bb5c1f

7 files changed

Lines changed: 239 additions & 113 deletions

File tree

src/main/java/com/stackify/api/ErrorItem.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
*/
1616
package com.stackify.api;
1717

18-
import java.util.List;
19-
import java.util.Map;
20-
2118
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
2219
import com.fasterxml.jackson.annotation.JsonInclude;
2320
import com.fasterxml.jackson.annotation.JsonProperty;
2421
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
22+
import lombok.Setter;
23+
24+
import java.util.List;
25+
import java.util.Map;
2526

2627
/**
2728
* Contains the details of a single exception including the stack trace and any causes
@@ -47,8 +48,9 @@ public class ErrorItem {
4748
/**
4849
* The error message
4950
*/
51+
@Setter
5052
@JsonProperty("Message")
51-
private final String message;
53+
private String message;
5254

5355
/**
5456
* The error's class name

src/main/java/com/stackify/api/common/log/LogSender.java

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package com.stackify.api.common.log;
1717

1818
import com.fasterxml.jackson.databind.ObjectMapper;
19+
import com.stackify.api.ErrorItem;
1920
import com.stackify.api.LogMsg;
2021
import com.stackify.api.LogMsgGroup;
2122
import com.stackify.api.common.ApiConfiguration;
@@ -30,13 +31,14 @@
3031

3132
import java.io.IOException;
3233
import java.net.HttpURLConnection;
34+
import java.util.Map;
3335

3436
/**
3537
* LogSender
3638
* @author Eric Martin
3739
*/
3840
public class LogSender {
39-
41+
4042
/**
4143
* The service logger
4244
*/
@@ -46,7 +48,7 @@ public class LogSender {
4648
* REST path for log save
4749
*/
4850
private static final String LOG_SAVE_PATH = "/Log/Save";
49-
51+
5052
/**
5153
* The API configuration
5254
*/
@@ -56,7 +58,7 @@ public class LogSender {
5658
* JSON object mapper
5759
*/
5860
private final ObjectMapper objectMapper;
59-
61+
6062
/**
6163
* The queue of requests to be retransmitted (max of 20 batches of 100 messages)
6264
*/
@@ -80,18 +82,32 @@ public LogSender(@NonNull final ApiConfiguration apiConfig,
8082
}
8183

8284
/**
83-
* Returns LogMsgGroup after applying masker to data and msg properties.
85+
* Applies masking to passed in LogMsgGroup.
8486
*/
85-
private LogMsgGroup mask(final LogMsgGroup group) {
87+
private void mask(final LogMsgGroup group) {
8688
if (masker != null) {
8789
if (group.getMsgs().size() > 0) {
8890
for (LogMsg logMsg : group.getMsgs()) {
91+
if (logMsg.getEx() != null) {
92+
mask(logMsg.getEx().getError());
93+
}
8994
logMsg.setData(masker.mask(logMsg.getData()));
9095
logMsg.setMsg(masker.mask(logMsg.getMsg()));
9196
}
9297
}
9398
}
94-
return group;
99+
}
100+
101+
private void mask(final ErrorItem errorItem) {
102+
if (errorItem != null) {
103+
errorItem.setMessage(masker.mask(errorItem.getMessage()));
104+
if (errorItem.getData() != null) {
105+
for (Map.Entry<String, String> entry : errorItem.getData().entrySet()) {
106+
entry.setValue(masker.mask(entry.getValue()));
107+
}
108+
}
109+
mask(errorItem.getInnerError());
110+
}
95111
}
96112

97113
/**
@@ -103,35 +119,35 @@ private LogMsgGroup mask(final LogMsgGroup group) {
103119
public int send(final LogMsgGroup group) throws IOException {
104120
Preconditions.checkNotNull(group);
105121

106-
LogMsgGroup maskedGroup = mask(group);
122+
mask(group);
107123

108124
HttpClient httpClient = new HttpClient(apiConfig);
109125

110126
// retransmit any logs on the resend queue
111-
127+
112128
resendQueue.drain(httpClient, LOG_SAVE_PATH, true);
113-
129+
114130
// convert to json bytes
115-
116-
byte[] jsonBytes = objectMapper.writer().writeValueAsBytes(maskedGroup);
117-
131+
132+
byte[] jsonBytes = objectMapper.writer().writeValueAsBytes(group);
133+
118134
// post to stackify
119-
135+
120136
int statusCode = HttpURLConnection.HTTP_INTERNAL_ERROR;
121-
137+
122138
try {
123139
httpClient.post(LOG_SAVE_PATH, jsonBytes, true);
124140
statusCode = HttpURLConnection.HTTP_OK;
125141
} catch (IOException t) {
126142
LOGGER.info("Queueing logs for retransmission due to IOException");
127143
resendQueue.offer(jsonBytes, t);
128-
throw t;
144+
throw t;
129145
} catch (HttpException e) {
130146
statusCode = e.getStatusCode();
131147
LOGGER.info("Queueing logs for retransmission due to HttpException", e);
132148
resendQueue.offer(jsonBytes, e);
133149
}
134-
150+
135151
return statusCode;
136152
}
137153
}

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

Lines changed: 59 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
/**
1616
* Handles masking string values based on regex matching.
17+
* Class is Thread Safe.
1718
*
1819
* @author Darin Howard
1920
*/
@@ -41,66 +42,69 @@ public void clearMasks() {
4142
maskPatterns.clear();
4243
}
4344

45+
private final Object lock = new Object();
46+
4447
public void removeMask(@NonNull final String mask) {
48+
synchronized (lock) {
49+
if (mask.equals(MASK_CREDITCARD)) {
50+
removeMaskPattern(MASK_CC_VISA_REGEX);
51+
removeMaskPattern(MASK_CC_DISCOVER_REGEX);
52+
removeMaskPattern(MASK_CC_MASTERCARD_REGEX);
53+
removeMaskPattern(MASK_CC_AMEX_REGEX);
54+
removeMaskPattern(MASK_CC_DINERS_REGEX);
55+
return;
56+
}
4557

46-
if (mask.equals(MASK_CREDITCARD)) {
47-
removeMaskPattern(MASK_CC_VISA_REGEX);
48-
removeMaskPattern(MASK_CC_DISCOVER_REGEX);
49-
removeMaskPattern(MASK_CC_MASTERCARD_REGEX);
50-
removeMaskPattern(MASK_CC_AMEX_REGEX);
51-
removeMaskPattern(MASK_CC_DINERS_REGEX);
52-
return;
53-
}
58+
if (mask.equals(MASK_SSN)) {
59+
removeMaskPattern(MASK_SSN_REGEX);
60+
return;
61+
}
5462

55-
if (mask.equals(MASK_SSN)) {
56-
removeMaskPattern(MASK_SSN_REGEX);
57-
return;
58-
}
63+
if (mask.equals(MASK_IP)) {
64+
removeMaskPattern(MASK_IPV4_REGEX);
65+
return;
66+
}
5967

60-
if (mask.equals(MASK_IP)) {
61-
removeMaskPattern(MASK_IPV4_REGEX);
62-
return;
68+
removeMaskPattern(mask);
6369
}
64-
65-
removeMaskPattern(mask);
6670
}
6771

6872
public void addMask(@NonNull final String mask) {
73+
synchronized (lock) {
74+
if (mask.equals(MASK_CREDITCARD)) {
75+
addMaskPattern(MASK_CC_VISA_REGEX);
76+
addMaskPattern(MASK_CC_DISCOVER_REGEX);
77+
addMaskPattern(MASK_CC_MASTERCARD_REGEX);
78+
addMaskPattern(MASK_CC_AMEX_REGEX);
79+
addMaskPattern(MASK_CC_DINERS_REGEX);
80+
return;
81+
}
6982

70-
if (mask.equals(MASK_CREDITCARD)) {
71-
addMaskPattern(MASK_CC_VISA_REGEX);
72-
addMaskPattern(MASK_CC_DISCOVER_REGEX);
73-
addMaskPattern(MASK_CC_MASTERCARD_REGEX);
74-
addMaskPattern(MASK_CC_AMEX_REGEX);
75-
addMaskPattern(MASK_CC_DINERS_REGEX);
76-
return;
77-
}
83+
if (mask.equals(MASK_SSN)) {
84+
addMaskPattern(MASK_SSN_REGEX);
85+
return;
86+
}
7887

79-
if (mask.equals(MASK_SSN)) {
80-
addMaskPattern(MASK_SSN_REGEX);
81-
return;
82-
}
88+
if (mask.equals(MASK_IP)) {
89+
addMaskPattern(MASK_IPV4_REGEX);
90+
return;
91+
}
8392

84-
if (mask.equals(MASK_IP)) {
85-
addMaskPattern(MASK_IPV4_REGEX);
86-
return;
93+
addMaskPattern(mask);
8794
}
88-
89-
addMaskPattern(mask);
90-
9195
}
9296

93-
private void addMaskPattern(final String regex) {
97+
private synchronized void addMaskPattern(final String regex) {
9498
if (regex != null) {
9599
try {
96100
maskPatterns.put(regex, Pattern.compile(regex));
97101
} catch (PatternSyntaxException e) {
98-
log.error(String.format("%s: '%s'", e.getMessage(), regex));
102+
log.error(String.format("Error Adding Mask: %s: '%s'", e.getMessage(), regex));
99103
}
100104
}
101105
}
102106

103-
private void removeMaskPattern(final String regex) {
107+
private synchronized void removeMaskPattern(final String regex) {
104108
if (regex != null) {
105109
try {
106110
maskPatterns.remove(regex);
@@ -115,24 +119,29 @@ private void removeMaskPattern(final String regex) {
115119
*/
116120
public String mask(final String value) {
117121

118-
if (hasMasks()) {
122+
try {
123+
124+
if (hasMasks()) {
119125

120-
if (value == null) return null;
126+
if (value == null) return null;
121127

122-
String maskedValue = value;
128+
String maskedValue = value;
123129

124-
for (Pattern pattern : maskPatterns.values()) {
125-
Matcher matcher = pattern.matcher(maskedValue);
126-
while (matcher.find()) {
127-
String match = matcher.group();
128-
char[] symbols = new char[match.length()];
129-
Arrays.fill(symbols, '*');
130-
maskedValue = maskedValue.replace(match, new String(symbols));
130+
for (Map.Entry<String, Pattern> entry : maskPatterns.entrySet()) {
131+
Matcher matcher = entry.getValue().matcher(maskedValue);
132+
while (matcher.find()) {
133+
String match = matcher.group();
134+
char[] symbols = new char[match.length()];
135+
Arrays.fill(symbols, '*');
136+
maskedValue = maskedValue.replace(match, new String(symbols));
137+
}
131138
}
132-
}
133139

134-
return maskedValue;
140+
return maskedValue;
141+
}
135142

143+
} catch (Throwable e) {
144+
log.warn(e.getMessage(), e);
136145
}
137146

138147
return value;

0 commit comments

Comments
 (0)