Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#20 Enable Non String values in JsonFieldPatternBuilder #20

Merged
merged 1 commit into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
RandySun228 marked this conversation as resolved.
Show resolved Hide resolved
* <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")
RandySun228 marked this conversation as resolved.
Show resolved Hide resolved
);

/**
* 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();
}

RandySun228 marked this conversation as resolved.
Show resolved Hide resolved
/**
* 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
Loading