This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push: new a4f82bb1acd CAMEL-17825: Hash generator in the Simple language (#12444) a4f82bb1acd is described below commit a4f82bb1acd2136e6035e6d75025857d56fb8026 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Wed Dec 13 16:12:44 2023 +0100 CAMEL-17825: Hash generator in the Simple language (#12444) --- .../modules/languages/pages/simple-language.adoc | 3 ++ .../language/simple/SimpleExpressionBuilder.java | 36 +++++++++++++++++ .../simple/ast/SimpleFunctionExpression.java | 20 ++++++++++ .../apache/camel/language/simple/SimpleTest.java | 46 ++++++++++++++++++++++ .../java/org/apache/camel/util/StringHelper.java | 12 ++++++ 5 files changed, 117 insertions(+) diff --git a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc index 32d75641fcc..4789404a6cb 100644 --- a/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc +++ b/core/camel-core-languages/src/main/docs/modules/languages/pages/simple-language.adoc @@ -255,6 +255,9 @@ If no type is given the default is used. It is also possible to use a custom `Uu and bind the bean to the xref:manual::registry.adoc[Registry] with an id. For example `${uuid(myGenerator}` where the ID is _myGenerator_. +|hash(exp,algorithm) |String |Returns a hashed value (string in hex decimal) using JDK MessageDigest. +The algorithm can be SHA-256 (default) or SHA3-256. + |jsonpath(exp) | Object | When working with JSon data, then this allows to use the JsonPath language for example to extract data from the message body (in JSon format). This requires having camel-jsonpath JAR on the classpath. diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java index b39e822adee..0be12c475a1 100644 --- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java +++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/SimpleExpressionBuilder.java @@ -16,6 +16,7 @@ */ package org.apache.camel.language.simple; +import java.security.MessageDigest; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; @@ -191,6 +192,41 @@ public final class SimpleExpressionBuilder { }; } + /** + * Hashes the value using the given algorithm + */ + public static Expression hashExpression(final String expression, final String algorithm) { + return new ExpressionAdapter() { + private Expression exp; + + @Override + public void init(CamelContext context) { + exp = context.resolveLanguage("simple").createExpression(expression); + exp.init(context); + } + + @Override + public Object evaluate(Exchange exchange) { + byte[] data = exp.evaluate(exchange, byte[].class); + if (data != null && data.length > 0) { + try { + MessageDigest digest = MessageDigest.getInstance(algorithm); + byte[] bytes = digest.digest(data); + return StringHelper.bytesToHex(bytes); + } catch (Exception e) { + throw CamelExecutionException.wrapCamelExecutionException(exchange, e); + } + } + return null; + } + + @Override + public String toString() { + return "hash(" + expression + "," + algorithm + ")"; + } + }; + } + /** * Returns a random number between min and max (exclusive) */ diff --git a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java index d9dfbf3474f..ddc8fd13425 100644 --- a/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java +++ b/core/camel-core-languages/src/main/java/org/apache/camel/language/simple/ast/SimpleFunctionExpression.java @@ -663,6 +663,26 @@ public class SimpleFunctionExpression extends LiteralExpression { return SimpleExpressionBuilder.uuidExpression(null); } + // hash function + remainder = ifStartsWithReturnRemainder("hash(", function); + if (remainder != null) { + String values = StringHelper.before(remainder, ")"); + if (values == null || ObjectHelper.isEmpty(values)) { + throw new SimpleParserException( + "Valid syntax: ${hash(value,algorithm)} or ${hash(value)} was: " + function, token.getIndex()); + } + if (values.contains(",")) { + String[] tokens = values.split(",", 2); + if (tokens.length > 2) { + throw new SimpleParserException( + "Valid syntax: ${hash(value,algorithm)} or ${hash(value)} was: " + function, token.getIndex()); + } + return SimpleExpressionBuilder.hashExpression(tokens[0].trim(), tokens[1].trim()); + } else { + return SimpleExpressionBuilder.hashExpression(values.trim(), "SHA-256"); + } + } + // empty function remainder = ifStartsWithReturnRemainder("empty(", function); if (remainder != null) { diff --git a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java index 63503dc95e1..4e54af27e31 100644 --- a/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java +++ b/core/camel-core/src/test/java/org/apache/camel/language/simple/SimpleTest.java @@ -16,6 +16,8 @@ */ package org.apache.camel.language.simple; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; @@ -44,6 +46,7 @@ import org.apache.camel.spi.PropertiesComponent; import org.apache.camel.spi.Registry; import org.apache.camel.spi.UuidGenerator; import org.apache.camel.util.InetAddressUtil; +import org.apache.camel.util.StringHelper; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.ResourceLock; import org.junit.jupiter.api.parallel.Resources; @@ -2153,6 +2156,49 @@ public class SimpleTest extends LanguageTestSupport { assertExpression("${uuid(mygen)}", "1234"); } + @Test + public void testHash() throws Exception { + Expression expression = context.resolveLanguage("simple").createExpression("${hash(hello)}"); + String s = expression.evaluate(exchange, String.class); + assertNotNull(s); + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + byte[] bytes = digest.digest("hello".getBytes(StandardCharsets.UTF_8)); + String expected = StringHelper.bytesToHex(bytes); + assertEquals(expected, s); + + expression = context.resolveLanguage("simple").createExpression("${hash(${body})}"); + s = expression.evaluate(exchange, String.class); + assertNotNull(s); + digest = MessageDigest.getInstance("SHA-256"); + bytes = digest.digest(exchange.getMessage().getBody(String.class).getBytes(StandardCharsets.UTF_8)); + expected = StringHelper.bytesToHex(bytes); + assertEquals(expected, s); + + expression = context.resolveLanguage("simple").createExpression("${hash(${header.foo})}"); + s = expression.evaluate(exchange, String.class); + assertNotNull(s); + + expression = context.resolveLanguage("simple").createExpression("${hash(hello,SHA3-256)}"); + s = expression.evaluate(exchange, String.class); + assertNotNull(s); + + expression = context.resolveLanguage("simple").createExpression("${hash(${body},SHA3-256)}"); + s = expression.evaluate(exchange, String.class); + assertNotNull(s); + digest = MessageDigest.getInstance("SHA3-256"); + bytes = digest.digest(exchange.getMessage().getBody(String.class).getBytes(StandardCharsets.UTF_8)); + expected = StringHelper.bytesToHex(bytes); + assertEquals(expected, s); + + expression = context.resolveLanguage("simple").createExpression("${hash(${header.foo},SHA3-256)}"); + s = expression.evaluate(exchange, String.class); + assertNotNull(s); + + expression = context.resolveLanguage("simple").createExpression("${hash(${header.unknown})}"); + s = expression.evaluate(exchange, String.class); + assertNull(s); + } + @Test public void testNewEmpty() { assertExpressionCreateNewEmpty("list", List.class, v -> ((List) v).isEmpty()); diff --git a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java index 6736b52ef8f..c5611e3ee33 100644 --- a/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java +++ b/core/camel-util/src/main/java/org/apache/camel/util/StringHelper.java @@ -1214,4 +1214,16 @@ public final class StringHelper { return true; } + public static String bytesToHex(byte[] hash) { + StringBuilder sb = new StringBuilder(2 * hash.length); + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + sb.append('0'); + } + sb.append(hex); + } + return sb.toString(); + } + }