- * http://www.gnu.org/licenses/lgpl.html - *
- * 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. - */ - -/** - * @author CJ (power4j@outlook.com) - * @date 2021/6/2 - * @since 1.0 - */ -@NonNullApi -@NonNullFields -package com.power4j.fist.jackson; - -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; \ No newline at end of file diff --git a/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/ObfuscatedAnnotationIntrospector.java b/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/ObfuscatedAnnotationIntrospector.java new file mode 100644 index 00000000..9c6eee0b --- /dev/null +++ b/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/ObfuscatedAnnotationIntrospector.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024. ChenJun (power4j@outlook.com & https://github.com/John-Chan) + * + * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * 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. + */ + +package com.power4j.fist.jackson.support.obfuscation; + +import com.fasterxml.jackson.databind.introspect.Annotated; +import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector; +import com.power4j.fist.jackson.annotation.Obfuscation; + +import java.util.Objects; + +/** + * @author CJ (power4j@outlook.com) + * @since 1.0 + */ +public class ObfuscatedAnnotationIntrospector extends NopAnnotationIntrospector { + + private final StringObfuscate defaultProcessor = SimpleStringObfuscate.ofDefault(); + + @Override + public Object findSerializer(Annotated am) { + Obfuscation obfuscation = am.getAnnotation(Obfuscation.class); + if (Objects.nonNull(obfuscation)) { + return new ObfuscatedStringSerializer(defaultProcessor); + } + return super.findSerializer(am); + } + + @Override + public Object findDeserializer(Annotated am) { + Obfuscation obfuscation = am.getAnnotation(Obfuscation.class); + if (Objects.nonNull(obfuscation)) { + return new ObfuscatedStringDeserializer(defaultProcessor); + } + return super.findContentDeserializer(am); + } + +} diff --git a/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/ObfuscatedStringDeserializer.java b/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/ObfuscatedStringDeserializer.java new file mode 100644 index 00000000..84690160 --- /dev/null +++ b/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/ObfuscatedStringDeserializer.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024. ChenJun (power4j@outlook.com & https://github.com/John-Chan) + * + * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * http://www.gnu.org/licenses/lgpl.html + *
+ * 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.
+ */
+
+package com.power4j.fist.jackson.support.obfuscation;
+
+import com.fasterxml.jackson.core.JacksonException;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.BeanProperty;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
+import com.power4j.fist.jackson.annotation.Obfuscation;
+
+import java.io.IOException;
+import java.util.Optional;
+
+/**
+ * @author CJ (power4j@outlook.com)
+ * @since 1.0
+ * @see StringObfuscateRegistry
+ */
+public class ObfuscatedStringDeserializer extends StdDeserializer
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * 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.
+ */
+
+package com.power4j.fist.jackson.support.obfuscation;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.BeanProperty;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonSerializer;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.ser.ContextualSerializer;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+import com.power4j.fist.jackson.annotation.Obfuscation;
+
+import java.io.IOException;
+import java.util.Optional;
+
+/**
+ * @author CJ (power4j@outlook.com)
+ * @since 1.0
+ * @see StringObfuscateRegistry
+ */
+public class ObfuscatedStringSerializer extends StdSerializer
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * 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.
+ */
+
+package com.power4j.fist.jackson.support.obfuscation;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+/**
+ * @author CJ (power4j@outlook.com)
+ * @since 1.0
+ */
+public class SimpleStringObfuscate implements StringObfuscate {
+
+ public final static String ALGORITHM = "OBF.XOR_V1";
+
+ private final Base64.Encoder ENCODER = Base64.getEncoder();
+
+ private final Base64.Decoder DECODER = Base64.getDecoder();
+
+ private final byte[] key;
+
+ public static SimpleStringObfuscate ofDefault() {
+ return new SimpleStringObfuscate(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 });
+ }
+
+ public SimpleStringObfuscate(byte[] key) {
+ this.key = key;
+ }
+
+ @Override
+ public String algorithm() {
+ return ALGORITHM;
+ }
+
+ @Override
+ public String obfuscate(String value) {
+ if (value.isEmpty()) {
+ return value;
+ }
+ byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
+ byte[] result = new byte[bytes.length];
+ for (int i = 0; i < bytes.length; i++) {
+ result[i] = (byte) (bytes[i] ^ key[i % key.length]);
+ }
+ return ENCODER.encodeToString(result);
+ }
+
+ @Override
+ public String deobfuscate(String value) throws Exception {
+ if (value.isEmpty()) {
+ return value;
+ }
+ byte[] bytes;
+ try {
+ bytes = DECODER.decode(value);
+ }
+ catch (IllegalArgumentException e) {
+ throw new IllegalStateException("Base64 decode error", e);
+ }
+ byte[] result = new byte[bytes.length];
+ for (int i = 0; i < bytes.length; i++) {
+ result[i] = (byte) (bytes[i] ^ key[i % key.length]);
+ }
+ return new String(result, StandardCharsets.UTF_8);
+ }
+
+}
diff --git a/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/StringObfuscate.java b/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/StringObfuscate.java
new file mode 100644
index 00000000..de218adc
--- /dev/null
+++ b/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/StringObfuscate.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2024. ChenJun (power4j@outlook.com & https://github.com/John-Chan)
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * 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.
+ */
+
+package com.power4j.fist.jackson.support.obfuscation;
+
+/**
+ * @author CJ (power4j@outlook.com)
+ * @since 1.0
+ */
+public interface StringObfuscate {
+
+ /**
+ * The algorithm id
+ * @return String
+ */
+ String algorithm();
+
+ /**
+ * Obfuscate string value
+ * @param value the value to encode,must not be null,may be empty
+ * @return Obfuscated string
+ */
+ String obfuscate(String value) throws Exception;
+
+ /**
+ * Deobfuscate
+ * @param value the value to deobfuscate,must not be null,may be empty
+ * @return original string
+ */
+ String deobfuscate(String value) throws Exception;
+
+}
diff --git a/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/StringObfuscateRegistry.java b/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/StringObfuscateRegistry.java
new file mode 100644
index 00000000..456ae43c
--- /dev/null
+++ b/fist-kit-infra/fist-jackson/src/main/java/com/power4j/fist/jackson/support/obfuscation/StringObfuscateRegistry.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2024. ChenJun (power4j@outlook.com & https://github.com/John-Chan)
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * 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.
+ */
+
+package com.power4j.fist.jackson.support.obfuscation;
+
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+
+/**
+ * @author CJ (power4j@outlook.com)
+ * @since 1.0
+ */
+@Slf4j
+public class StringObfuscateRegistry {
+
+ private final static Map
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * 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.
+ */
+
+/**
+ * @author CJ (power4j@outlook.com)
+ * @date 2021/6/2
+ * @since 1.0
+ */
+@NonNullApi
+@NonNullFields
+package com.power4j.fist.jackson.support.obfuscation;
+
+import org.springframework.lang.NonNullApi;
+import org.springframework.lang.NonNullFields;
diff --git a/fist-kit-infra/fist-jackson/src/test/java/com/power4j/fist/jackson/support/obfuscation/JacksonSimpleStringObfuscateTest.java b/fist-kit-infra/fist-jackson/src/test/java/com/power4j/fist/jackson/support/obfuscation/JacksonSimpleStringObfuscateTest.java
new file mode 100644
index 00000000..67adda25
--- /dev/null
+++ b/fist-kit-infra/fist-jackson/src/test/java/com/power4j/fist/jackson/support/obfuscation/JacksonSimpleStringObfuscateTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2024. ChenJun (power4j@outlook.com & https://github.com/John-Chan)
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * 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.
+ */
+
+package com.power4j.fist.jackson.support.obfuscation;
+
+import com.fasterxml.jackson.databind.AnnotationIntrospector;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
+import com.power4j.fist.jackson.annotation.Obfuscation;
+import lombok.Data;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+/**
+ * @author CJ (power4j@outlook.com)
+ * @since 1.0
+ */
+public class JacksonSimpleStringObfuscateTest {
+
+ @Data
+ public static class Foo {
+
+ @Obfuscation
+ private String name;
+
+ }
+
+ private static ObjectMapper objectMapper;
+
+ @BeforeAll
+ public static void init() {
+ ObjectMapper mapper = new ObjectMapper();
+ AnnotationIntrospector sis = mapper.getSerializationConfig().getAnnotationIntrospector();
+ AnnotationIntrospector is1 = AnnotationIntrospectorPair.pair(sis, new ObfuscatedAnnotationIntrospector());
+ mapper.setAnnotationIntrospector(is1);
+ objectMapper = mapper;
+ }
+
+ @Test
+ public void testSerialize() throws IOException {
+ Foo foo = new Foo();
+ foo.setName("hello world");
+ String value = objectMapper.writeValueAsString(foo);
+ System.out.println("Serialized: " + value);
+ Assertions.assertEquals("{\"name\":\"OBF.XOR_V1.aGRub2slcWh6ZW4=\"}", value);
+ }
+
+ @Test
+ public void testSerializeNull() throws IOException {
+ Foo foo = new Foo();
+ foo.setName(null);
+ String value = objectMapper.writeValueAsString(foo);
+ System.out.println("Serialized: " + value);
+ Assertions.assertEquals("{\"name\":null}", value);
+ }
+
+ @Test
+ public void testSerializeEmpty() throws IOException {
+ Foo foo = new Foo();
+ foo.setName("");
+ String value = objectMapper.writeValueAsString(foo);
+ System.out.println("Serialized: " + value);
+ Assertions.assertEquals("{\"name\":\"\"}", value);
+ }
+
+ @Test
+ public void testDeserialize() throws IOException {
+ String json = "{\"name\":\"OBF.XOR_V1.aGRub2slcWh6ZW4=\"}";
+ Foo foo = objectMapper.readValue(json, Foo.class);
+ System.out.println("Deserialized: " + foo.getName());
+ Assertions.assertEquals("hello world", foo.getName());
+ }
+
+ @Test
+ public void testDeserializeNull() throws IOException {
+ String json = "{\"name\":null}";
+ Foo foo = objectMapper.readValue(json, Foo.class);
+ System.out.println("Deserialized: " + foo.getName());
+ Assertions.assertNull(foo.getName());
+ }
+
+ @Test
+ public void testDeserializeEmpty() throws IOException {
+ String json = "{\"name\":\"\"}";
+ Foo foo = objectMapper.readValue(json, Foo.class);
+ System.out.println("Deserialized: " + foo.getName());
+ Assertions.assertTrue(foo.getName().isEmpty());
+ }
+
+}
diff --git a/fist-kit-infra/fist-jackson/src/test/java/com/power4j/fist/jackson/support/obfuscation/SimpleStringObfuscateTest.java b/fist-kit-infra/fist-jackson/src/test/java/com/power4j/fist/jackson/support/obfuscation/SimpleStringObfuscateTest.java
new file mode 100644
index 00000000..52fefac1
--- /dev/null
+++ b/fist-kit-infra/fist-jackson/src/test/java/com/power4j/fist/jackson/support/obfuscation/SimpleStringObfuscateTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024. ChenJun (power4j@outlook.com & https://github.com/John-Chan)
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * 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.
+ */
+
+package com.power4j.fist.jackson.support.obfuscation;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author CJ (power4j@outlook.com)
+ * @since 1.0
+ */
+class SimpleStringObfuscateTest {
+
+ @Test
+ void handleEmptyString() throws Exception {
+ StringObfuscate obfuscate = SimpleStringObfuscate.ofDefault();
+ String original = "";
+ String obfuscated = obfuscate.obfuscate(original);
+ assertEquals("", obfuscated);
+ String deobfuscated = obfuscate.deobfuscate(obfuscated);
+ assertEquals(original, deobfuscated);
+ }
+
+ @Test
+ void obfuscate() throws Exception {
+ StringObfuscate obfuscate = SimpleStringObfuscate.ofDefault();
+ String original = "hello world";
+ String obfuscated = obfuscate.obfuscate(original);
+ String deobfuscated = obfuscate.deobfuscate(obfuscated);
+ assertEquals(original, deobfuscated);
+
+ original = "你好!世界";
+ obfuscated = obfuscate.obfuscate(original);
+ deobfuscated = obfuscate.deobfuscate(obfuscated);
+ assertEquals(original, deobfuscated);
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index 44d6d59b..60e64069 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,7 +52,7 @@