Skip to content

Commit

Permalink
Enable Non String values in JsonFieldPatternBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
RandySun228 committed Nov 25, 2024
1 parent afcd8bc commit 727724c
Show file tree
Hide file tree
Showing 9 changed files with 805 additions and 18 deletions.
12 changes: 12 additions & 0 deletions ejmask-api/src/main/java/com/ebay/ejmask/api/IPatternBuilder.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.ebay.ejmask.api;

import java.util.Arrays;
import java.util.List;

/**
* Copyright (c) 2023 eBay Inc.
* <p>
Expand Down Expand Up @@ -36,6 +39,15 @@ public interface IPatternBuilder {
*/
String buildReplacement(int visibleCharacters, String... fieldNames);

/**
* Build pattern to match
* @param visibleCharacters as no of characters to be visible.
* @param fieldNames as list of field names
* @return list of pattern entities
*/
default List<PatternEntity> buildPatternEntities(int visibleCharacters, String... fieldNames) {
return Arrays.asList(new PatternEntity(buildPattern(visibleCharacters, fieldNames), buildReplacement(visibleCharacters, fieldNames)));
}
/**
* Set true if the build can be groupable.
*
Expand Down
53 changes: 53 additions & 0 deletions ejmask-api/src/main/java/com/ebay/ejmask/api/PatternEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.ebay.ejmask.api;

import javax.annotation.Nonnull;

/**
* Copyright (c) 2023 eBay Inc.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class PatternEntity {

private final String patternTemplate;

private final String replacementTemplate;

/**
* Constructor
* @param patternTemplate as instance of String
* @param replacementTemplate as instance of String
*/
public PatternEntity(@Nonnull String patternTemplate, @Nonnull String replacementTemplate) {
this.patternTemplate = patternTemplate;
this.replacementTemplate = replacementTemplate;
}

/**
* Get pattern template
*
* @return match pattern
*/
public String getPatternTemplate() {
return patternTemplate;
}

/**
* Get replacement template
*
* @return replacement pattern
*/
public String getReplacementTemplate() {
return replacementTemplate;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.ebay.ejmask.api.IFilter;
import com.ebay.ejmask.api.IPatternBuilder;
import com.ebay.ejmask.api.MaskingPattern;
import com.ebay.ejmask.api.PatternEntity;
import com.ebay.ejmask.core.util.CommonUtils;
import com.ebay.ejmask.core.util.LoggerUtil;

Expand All @@ -33,6 +34,8 @@
import java.util.List;
import java.util.Map;

import static com.ebay.ejmask.core.util.CommonUtils.emptyIfNull;

/**
* The objective of this class it to wrap all complications in adding and
* maintaining masking fields inside this class and keep the recurring jobs
Expand Down Expand Up @@ -104,7 +107,7 @@ public static void addContentProcessor(IContentProcessor... contentProcessors) {
* @param contentProcessors new value of contentProcessors
*/
public static synchronized void addContentProcessors(Collection<IContentProcessor> contentProcessors) {
for (IContentProcessor contentPreProcessor : CommonUtils.emptyIfNull(contentProcessors)) {
for (IContentProcessor contentPreProcessor : emptyIfNull(contentProcessors)) {
EJMask.register(contentPreProcessor);
LoggerUtil.info("data-filter-initializer", "processors", "adding " + contentPreProcessor.getName());
}
Expand Down Expand Up @@ -137,10 +140,11 @@ public static synchronized void addFilters(Collection<IFilter> filters) {
//avoid empty due to duplicate
if (CommonUtils.isNotEmpty(filter.getFieldNames())) {
final String[] fieldNames = toArray(filter.getFieldNames());
final String pattern = filter.getBuilder().buildPattern(filter.getVisibleCharacters(), fieldNames);
final String replacement = filter.getBuilder().buildReplacement(filter.getVisibleCharacters(), fieldNames);
//add masking pattern to data masking utility
addMaskingPattern(filter.getOrder(), pattern, replacement);
List<PatternEntity> patternEntityList = filter.getBuilder().buildPatternEntities(filter.getVisibleCharacters(), fieldNames);
emptyIfNull(patternEntityList).forEach(patternEntity -> {
//add masking pattern to data masking utility
addMaskingPattern(filter.getOrder(), patternEntity.getPatternTemplate(), patternEntity.getReplacementTemplate());
});
}
}
addNonGroupedFilters(filters);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.ebay.ejmask.extenstion.builder.json;
/**
* Copyright (c) 2024 eBay Inc.
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import com.ebay.ejmask.api.PatternEntity;
import com.ebay.ejmask.extenstion.builder.AbstractRegexPatternBuilder;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
* An implementation of IPatternBuilder to support sensitive JSON field, whose value need to be partially masked.
* This builder is for masking the field value with a Boolean type.
*
* @author fsun1
*/
public class JsonBooleanFieldPatternBuilder extends AbstractRegexPatternBuilder {

private static final List<PatternEntity> PATTERN_ENTITY_LIST = Arrays.asList(
/**
* Boolean field with value to be masked
* @see <a href="https://regex101.com/r/AEwc99/1">Regular Expresseion For Testing</a>
*/
new PatternEntity("\\\"(%s)(\\\\*\\\"\\s*:\\s*\\\\*)(\\b(true|TRUE|True|false|FALSE|False)\\b)([^\\\"]{1,3})[^\\\"]*(\\\\?\\\"|)", "\"$1$2\"xxxx\"$5$6")
);

/**
* Build pattern to match
*
* @param visibleCharacters as no of characters to be visible.
* @param fieldNames as list of field names
* @return match pattern
*/
@Override
public String buildPattern(int visibleCharacters, String... fieldNames) {
return this.buildPattern(null, visibleCharacters, fieldNames);
}

/**
* Build pattern to match
*
* @param patternEntity as instance of PatternEntity
* @param visibleCharacters as no of characters to be visible.
* @param fieldNames as list of field names
* @return
*/
private String buildPattern(PatternEntity patternEntity, int visibleCharacters, String... fieldNames) {
if (visibleCharacters < 1) {
throw new IllegalArgumentException("visibleCharacters must be a possessive value instead of " + visibleCharacters);
}
if (patternEntity == null) {
patternEntity = PATTERN_ENTITY_LIST.get(0);
}
return String.format(patternEntity.getPatternTemplate(), super.buildFieldNamesForRegexOr(fieldNames), visibleCharacters);
}


/**
* Build pattern to replace.
*
* @param visibleCharacters as no of characters to be visible.
* @param fieldNames as list of field names
* @return match pattern
*/
@Override
public String buildReplacement(int visibleCharacters, String... fieldNames) {
return this.buildReplacement(null, visibleCharacters, fieldNames);
}

/**
* Build pattern to replace.
*
* @param patternEntity as instance of PatternEntity
* @param visibleCharacters as no of characters to be visible.
* @param fieldNames as list of field names
* @return match pattern
*/
private String buildReplacement(PatternEntity patternEntity, int visibleCharacters, String... fieldNames) {
if (patternEntity == null) {
patternEntity = PATTERN_ENTITY_LIST.get(0);
}
return patternEntity.getReplacementTemplate();
}

/**
* Build list of PatternEntity
*
* @param visibleCharacters as no of characters to be visible.
* @param fieldNames as list of field names
* @return match pattern list
*/
@Override
public List<PatternEntity> buildPatternEntities(int visibleCharacters, String... fieldNames) {
List<PatternEntity> result = new LinkedList<>();
PATTERN_ENTITY_LIST.forEach(patternEntity -> {
result.add(new PatternEntity(this.buildPattern(patternEntity, visibleCharacters, fieldNames), this.buildReplacement(patternEntity, visibleCharacters, fieldNames)));
});
return result;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,28 @@
* limitations under the License.
*/

import com.ebay.ejmask.api.PatternEntity;
import com.ebay.ejmask.extenstion.builder.AbstractRegexPatternBuilder;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
* An implementation of IPatternBuilder to support sensitive JSON field, whose value need to be partially masked.
* This builder is for masking the field value with a String type.
*
* @author prakv
*/
public class JsonFieldPatternBuilder extends AbstractRegexPatternBuilder {

//https://regex101.com/r/ZDQWod/5
//unescaped string --------------------------> \"(%s)(\\*\"\s*:\s*\\*\")([^\"]{1,%d})[^\"]*(\\?\"|)
private static final String PATTERN_TEMPLATE = "\\\"(%s)(\\\\*\\\"\\s*:\\s*\\\\*\\\")([^\\\"]{1,%d})[^\\\"]*(\\\\?\\\"|)";
//group $1 = field name
//group $2 = ":" (with json serialization support)
//group $3 = masked sting
private static final String REPLACEMENT_TEMPLATE = "\"$1$2$3-xxxx$4";
private static final List<PatternEntity> PATTERN_ENTITY_LIST = Arrays.asList(
/**
* String field with value to be masked
* @see <a href="https://regex101.com/r/ZDQWod/5">Regular Expresseion For Testing</a>
*/
new PatternEntity("\\\"(%s)(\\\\*\\\"\\s*:\\s*\\\\*\\\")([^\\\"]{1,%d})[^\\\"]*(\\\\?\\\"|)", "\"$1$2$3-xxxx$4")
);

/**
* Build pattern to match
Expand All @@ -41,12 +47,28 @@ public class JsonFieldPatternBuilder extends AbstractRegexPatternBuilder {
*/
@Override
public String buildPattern(int visibleCharacters, String... fieldNames) {
return this.buildPattern(null, visibleCharacters, fieldNames);
}

/**
* Build pattern to match
*
* @param patternEntity as instance of PatternEntity
* @param visibleCharacters as no of characters to be visible.
* @param fieldNames as list of field names
* @return
*/
private String buildPattern(PatternEntity patternEntity, int visibleCharacters, String... fieldNames) {
if (visibleCharacters < 1) {
throw new IllegalArgumentException("visibleCharacters must be a possessive value instead of " + visibleCharacters);
}
return String.format(PATTERN_TEMPLATE, super.buildFieldNamesForRegexOr(fieldNames), visibleCharacters);
if (patternEntity == null) {
patternEntity = PATTERN_ENTITY_LIST.get(0);
}
return String.format(patternEntity.getPatternTemplate(), super.buildFieldNamesForRegexOr(fieldNames), visibleCharacters);
}


/**
* Build pattern to replace.
*
Expand All @@ -56,6 +78,38 @@ public String buildPattern(int visibleCharacters, String... fieldNames) {
*/
@Override
public String buildReplacement(int visibleCharacters, String... fieldNames) {
return REPLACEMENT_TEMPLATE;
return this.buildReplacement(null, visibleCharacters, fieldNames);
}

/**
* Build pattern to replace.
*
* @param patternEntity as instance of PatternEntity
* @param visibleCharacters as no of characters to be visible.
* @param fieldNames as list of field names
* @return match pattern
*/
private String buildReplacement(PatternEntity patternEntity, int visibleCharacters, String... fieldNames) {
if (patternEntity == null) {
patternEntity = PATTERN_ENTITY_LIST.get(0);
}
return patternEntity.getReplacementTemplate();
}

/**
* Build list of PatternEntity
*
* @param visibleCharacters as no of characters to be visible.
* @param fieldNames as list of field names
* @return match pattern list
*/
@Override
public List<PatternEntity> buildPatternEntities(int visibleCharacters, String... fieldNames) {
List<PatternEntity> result = new LinkedList<>();
PATTERN_ENTITY_LIST.forEach(patternEntity -> {
result.add(new PatternEntity(this.buildPattern(patternEntity, visibleCharacters, fieldNames), this.buildReplacement(patternEntity, visibleCharacters, fieldNames)));
});
return result;
}

}
Loading

0 comments on commit 727724c

Please sign in to comment.