diff --git a/README.md b/README.md
index 622e0bb..0bacd76 100644
--- a/README.md
+++ b/README.md
@@ -233,14 +233,14 @@ Alternatively you can pull it from the central Maven repositories:
com.ebay.ejmask
ejmask-bom
- 1.0.3
+ 1.1.0-SNAPSHOT
```
### Using in your Gradle Project.
```groovy
-compile group: 'com.ebay.ejmask', name: 'ejmask-bom', version: '1.0.3'
+compile group: 'com.ebay.ejmask', name: 'ejmask-bom', version: '1.1.0-SNAPSHOT'
```
## Roadmap
diff --git a/ejmask-api/pom.xml b/ejmask-api/pom.xml
index bb9d04b..d734bc4 100644
--- a/ejmask-api/pom.xml
+++ b/ejmask-api/pom.xml
@@ -3,7 +3,7 @@
com.ebay.ejmask
ejmask-parent
- 1.0.3
+ 1.1.0-SNAPSHOT
ejmask-api
diff --git a/ejmask-bom/pom.xml b/ejmask-bom/pom.xml
index 2dc9ad2..5cb7a58 100644
--- a/ejmask-bom/pom.xml
+++ b/ejmask-bom/pom.xml
@@ -3,7 +3,7 @@
com.ebay.ejmask
ejmask-parent
- 1.0.3
+ 1.1.0-SNAPSHOT
../pom.xml
diff --git a/ejmask-core/pom.xml b/ejmask-core/pom.xml
index e1c07fa..8c67437 100644
--- a/ejmask-core/pom.xml
+++ b/ejmask-core/pom.xml
@@ -3,7 +3,7 @@
com.ebay.ejmask
ejmask-parent
- 1.0.3
+ 1.1.0-SNAPSHOT
ejmask-core
diff --git a/ejmask-extensions/pom.xml b/ejmask-extensions/pom.xml
index c56039a..5a48825 100644
--- a/ejmask-extensions/pom.xml
+++ b/ejmask-extensions/pom.xml
@@ -3,7 +3,7 @@
com.ebay.ejmask
ejmask-parent
- 1.0.3
+ 1.1.0-SNAPSHOT
ejmask-extensions
diff --git a/ejmask-extensions/src/main/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilder.java b/ejmask-extensions/src/main/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilder.java
new file mode 100644
index 0000000..269ea69
--- /dev/null
+++ b/ejmask-extensions/src/main/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilder.java
@@ -0,0 +1,47 @@
+package com.ebay.ejmask.extenstion.builder.json;
+
+import com.ebay.ejmask.extenstion.builder.AbstractRegexPatternBuilder;
+
+/**
+ * An implementation of IPatternBuilder to support high sensitive JSON field, whose value
+ * need to be partially masked with relative field from end of the field.
+ *
+ * @author parasdharwal33
+ */
+public class JsonValueUnmaskFromEndPatternBuilder extends AbstractRegexPatternBuilder {
+
+ //https://regex101.com/r/LL3EY7/1/
+ private static final String PATTERN_TEMPLATE = "\\\"(%s)(\\\\*\\\"\\s*:\\s*\\\\*\\\")[^\\\"]*([^\\\\\"]{%d})(\\\\?\\\"|)";
+ //group $1 = field name
+ //group $2 = ":" (with json serialization support)
+ //group $3 = sensitive information -> unmasked
+ //group $4 = ending qts
+ private static final String REPLACEMENT_TEMPLATE = "\"$1$2xxxx-$3$4";
+
+ /**
+ * 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) {
+ if (visibleCharacters < 0) {
+ throw new IllegalArgumentException("visibleCharacters must be a value greater than zero instead of " + visibleCharacters);
+ }
+ return String.format(PATTERN_TEMPLATE, 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 REPLACEMENT_TEMPLATE;
+ }
+}
\ No newline at end of file
diff --git a/ejmask-extensions/src/test/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilderTest.java b/ejmask-extensions/src/test/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilderTest.java
new file mode 100644
index 0000000..c0304fd
--- /dev/null
+++ b/ejmask-extensions/src/test/java/com/ebay/ejmask/extenstion/builder/json/JsonValueUnmaskFromEndPatternBuilderTest.java
@@ -0,0 +1,105 @@
+package com.ebay.ejmask.extenstion.builder.json;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+
+public class JsonValueUnmaskFromEndPatternBuilderTest {
+
+ public static final JsonValueUnmaskFromEndPatternBuilder instance = new JsonValueUnmaskFromEndPatternBuilder();
+ public static final String[] fieldNames = new String[]{"ccNumber", "ssn"};
+
+ @Test
+ public void testBuildPattern() {
+ int visibleCharacters = 4;
+ String result = instance.buildPattern(visibleCharacters, fieldNames);
+ Assertions.assertEquals("\\\"(ccNumber|ssn)(\\\\*\\\"\\s*:\\s*\\\\*\\\")[^\\\"]*([^\\\\\"]{4})(\\\\?\\\"|)", result);
+ }
+
+ @Test
+ public void testBuildPattern_withNegativeVisibleCharacters() {
+ int visibleCharacters = -1;
+ Assertions.assertThrows(IllegalArgumentException.class, () -> instance.buildPattern(visibleCharacters, fieldNames));
+ }
+
+ @Test
+ public void testBuildReplacement() {
+ int visibleCharacters = 4;
+ String result = instance.buildReplacement(visibleCharacters, fieldNames);
+ Assertions.assertEquals("\"$1$2xxxx-$3$4", result);
+ }
+
+ @ParameterizedTest
+ @MethodSource("dataForTestMatch")
+ public void testMatch(String name, String data, String expected) {
+ String regex = instance.buildPattern(4, fieldNames);
+ String replacement = instance.buildReplacement(4, fieldNames);
+ Pattern pattern = Pattern.compile(regex);
+ String result = pattern.matcher(data).replaceAll(replacement);
+ Assertions.assertFalse(result.contains("1234567890"));
+ Assertions.assertEquals(expected, result);
+ }
+
+ static Stream dataForTestMatch() {
+ return Stream.of(
+ Arguments.arguments(
+ "test with normal json",
+ "{\"ccNumber\":\"1234567890123456\",\"ssn\":\"123456789\",\"nonSensitiveData\":\"data\"}",
+ "{\"ccNumber\":\"xxxx-3456\",\"ssn\":\"xxxx-6789\",\"nonSensitiveData\":\"data\"}"
+ ),
+ Arguments.arguments(
+ "test with empty values",
+ "{\"ccNumber\":\"\",\"ssn\":null,\"nonSensitiveData\":\"data\"}",
+ "{\"ccNumber\":\"\",\"ssn\":null,\"nonSensitiveData\":\"data\"}"
+ ),
+ Arguments.arguments(
+ "test with space",
+ "{\"ccNumber\" : \"1234567890123456\", \"ssn\" :\"123456789\",\"nonSensitiveData\":\"data\"}",
+ "{\"ccNumber\" : \"xxxx-3456\", \"ssn\" :\"xxxx-6789\",\"nonSensitiveData\":\"data\"}"
+ ),
+ Arguments.arguments(
+ "test with line break",
+ "{\n"
+ + " \"ccNumber\": \"1234567890123456\",\n"
+ + " \"ssn\": \"123456789\",\n"
+ + " \"nonSensitiveData\": \"data\"\n"
+ + "}",
+ "{\n"
+ + " \"ccNumber\": \"xxxx-3456\",\n"
+ + " \"ssn\": \"xxxx-6789\",\n"
+ + " \"nonSensitiveData\": \"data\"\n"
+ + "}"
+ ),
+ Arguments.arguments(
+ "test with broken json",
+ "{\"ccNumber\":\"1234567890123456\",\"ssn\":\"123456789",
+ "{\"ccNumber\":\"xxxx-3456\",\"ssn\":\"xxxx-6789"
+ ),
+ Arguments.arguments(
+ "test with json encoded json",
+ "{\\\"ccNumber\\\":\\\"1234567890123456\\\",\\\"ssn\\\":\\\"123456789\\\",\\\"nonSensitiveData\\\":\\\"data\\\"}",
+ "{\\\"ccNumber\\\":\\\"xxxx-3456\\\",\\\"ssn\\\":\\\"xxxx-6789\\\",\\\"nonSensitiveData\\\":\\\"data\\\"}"
+ ),
+ Arguments.arguments(
+ "test with double json encoded json",
+ "{\\\\\\\"ccNumber\\\\\\\":\\\\\\\"1234567890123456\\\\\\\",\\\\\\\"ssn\\\\\\\":\\\\\\\"123456789\\\\\\\",\\\\\\\"nonSensitiveData\\\\\\\":\\\\\\\"data\\\\\\\"}",
+ "{\\\\\\\"ccNumber\\\\\\\":\\\\\\\"xxxx-3456\\\\\\\",\\\\\\\"ssn\\\\\\\":\\\\\\\"xxxx-6789\\\\\\\",\\\\\\\"nonSensitiveData\\\\\\\":\\\\\\\"data\\\\\\\"}"
+ ),
+ Arguments.arguments(
+ "test with encoded broken json",
+ "{\\\"ccNumber\\\":\\\"1234567890123456\\\",\\\"ssn\\\":\\\"123456789",
+ "{\\\"ccNumber\\\":\\\"xxxx-3456\\\",\\\"ssn\\\":\\\"xxxx-6789"
+ ),
+ Arguments.arguments(
+ "test with encoded broken json 2",
+ "{\\\"ccNumber\\\":\\\"1234567890123456\\\",\\\"ssn\\\":\\\"123456789\\",
+ "{\\\"ccNumber\\\":\\\"xxxx-3456\\\",\\\"ssn\\\":\\\"xxxx-6789\\"
+ )
+ );
+ }
+}
\ No newline at end of file
diff --git a/ejmask-spring/ejmask-spring-autoconfig/pom.xml b/ejmask-spring/ejmask-spring-autoconfig/pom.xml
index bfe10bb..ec85e8c 100644
--- a/ejmask-spring/ejmask-spring-autoconfig/pom.xml
+++ b/ejmask-spring/ejmask-spring-autoconfig/pom.xml
@@ -3,7 +3,7 @@
com.ebay.ejmask
ejmask-spring
- 1.0.3
+ 1.1.0-SNAPSHOT
ejmask-spring-autoconfig
diff --git a/ejmask-spring/ejmask-spring-boot/pom.xml b/ejmask-spring/ejmask-spring-boot/pom.xml
index 90e73d1..71ddea0 100644
--- a/ejmask-spring/ejmask-spring-boot/pom.xml
+++ b/ejmask-spring/ejmask-spring-boot/pom.xml
@@ -3,7 +3,7 @@
com.ebay.ejmask
ejmask-spring
- 1.0.3
+ 1.1.0-SNAPSHOT
ejmask-spring-boot
diff --git a/ejmask-spring/ejmask-spring-core/pom.xml b/ejmask-spring/ejmask-spring-core/pom.xml
index 4572fac..120cb40 100644
--- a/ejmask-spring/ejmask-spring-core/pom.xml
+++ b/ejmask-spring/ejmask-spring-core/pom.xml
@@ -3,7 +3,7 @@
com.ebay.ejmask
ejmask-spring
- 1.0.3
+ 1.1.0-SNAPSHOT
ejmask-spring-core
diff --git a/ejmask-spring/pom.xml b/ejmask-spring/pom.xml
index 7def6ac..3c61ab0 100644
--- a/ejmask-spring/pom.xml
+++ b/ejmask-spring/pom.xml
@@ -3,7 +3,7 @@
com.ebay.ejmask
ejmask-parent
- 1.0.3
+ 1.1.0-SNAPSHOT
ejmask-spring
diff --git a/pom.xml b/pom.xml
index 56771a8..071c081 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
com.ebay.ejmask
ejmask-parent
- 1.0.3
+ 1.1.0-SNAPSHOT
pom