You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2023/12/13 14:58:27 UTC

(camel) branch hash created (now 6a5eda68650)

This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a change to branch hash
in repository https://gitbox.apache.org/repos/asf/camel.git


      at 6a5eda68650 CAMEL-17825: Hash generator in the Simple language

This branch includes the following new commits:

     new 6a5eda68650 CAMEL-17825: Hash generator in the Simple language

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(camel) 01/01: CAMEL-17825: Hash generator in the Simple language

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch hash
in repository https://gitbox.apache.org/repos/asf/camel.git

commit 6a5eda686502eb8391249048303298fae01d3f5b
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Dec 13 15:58:15 2023 +0100

    CAMEL-17825: Hash generator in the Simple language
---
 .../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();
+    }
+
 }