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

Merge CheckSumPipe and HashPipe and add hashEncoding #7456

Merged
merged 8 commits into from
Sep 11, 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
180 changes: 50 additions & 130 deletions core/src/main/java/org/frankframework/pipes/ChecksumPipe.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2013, 2020 Nationale-Nederlanden, 2020, 2022 WeAreFrank!
Copyright 2013, 2020 Nationale-Nederlanden, 2020-2024 WeAreFrank!

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -16,163 +16,74 @@
package org.frankframework.pipes;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.Adler32;
import java.util.zip.CRC32;
import java.util.zip.Checksum;

import lombok.Getter;

import org.frankframework.configuration.ConfigurationException;
import org.frankframework.configuration.ConfigurationWarning;
import org.frankframework.core.PipeLineSession;
import org.frankframework.core.PipeRunException;
import org.frankframework.core.PipeRunResult;
import org.frankframework.pipes.hash.Algorithm;
import org.frankframework.stream.Message;

/**
* Pipe to calculate checksum on input.
*
* This pipe can be used to generate a hash for the given message using an algorithm. With this, you can prove integrity of the message. If you
* need to prove the authenticity of the message as well, please use the {@link HashPipe} which uses an algorithm and a secret to prove both
* integrity and authenticity.
* <p>
* The hash is generated based on the bytes of the given input message or on the bytes read from the file path if @{code inputIsFile} is @{code true}
* <p>
* The supported algorithms are:
* <ul>
* <li>CRC32</li>
* <li>Adler32</li>
* <li>MD5</li>
* <li>SHA</li>
* <li>SHA256</li>
* <li>SHA384</li>
* <li>SHA512</li>
Comment on lines +43 to +47
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Als ik dit zo terugzie is het eigenlijk helemaal niet zo lastig om van deze 2 pipes 1 te maken. Misschien toch maandag even in de groep gooien?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, ik heb de rest aangepast

* </ul>
*
* @author Gerrit van Brakel
* @since 4.9
* @author Gerrit van Brakel
* @since 4.9
* @deprecated please use the {@link HashPipe}
*/
public class ChecksumPipe extends FixedForwardPipe {
@Deprecated(forRemoval = true, since = "8.3.0")
@ConfigurationWarning("Use the HashPipe")
public class ChecksumPipe extends HashPipe {

private @Getter String charset;
private @Getter ChecksumType type=ChecksumType.MD5;
private @Getter boolean inputIsFile;

public enum ChecksumType {
MD5,
SHA,
SHA256("SHA-256"),
SHA512("SHA-512"),
CRC32,
ADLER32;

private final String algorithm;

ChecksumType(String algorithm) {
this.algorithm = algorithm;
}
ChecksumType() {
this(null);
}

public String getAlgorithm() {
return algorithm!=null ? algorithm : name();
}
}

protected interface ChecksumGenerator {
void update(int b);
void update(byte[] b, int offset, int length);
String getResult();
}

protected ChecksumGenerator createChecksumGenerator() throws NoSuchAlgorithmException {
switch(getType()) {
case MD5:
case SHA:
case SHA256:
case SHA512:
return new MessageDigestChecksumGenerator(getType());
case CRC32:
return new ZipChecksumGenerator(new CRC32());
case ADLER32:
return new ZipChecksumGenerator(new Adler32());
default:
throw new NoSuchAlgorithmException("unsupported algorithm ["+getType()+"]");
}
}

protected static class ZipChecksumGenerator implements ChecksumGenerator {

private final Checksum checksum;

ZipChecksumGenerator(Checksum checksum) {
super();
this.checksum=checksum;
checksum.reset();
}

@Override
public void update(int b){
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deze werd nergens gebruikt

checksum.update(b);
}

@Override
public void update(byte[] b, int offset, int length){
checksum.update(b,offset,length);
}

@Override
public String getResult(){
return Long.toHexString(checksum.getValue());
}
}

protected static class MessageDigestChecksumGenerator implements ChecksumGenerator {

private final MessageDigest messageDigest;

MessageDigestChecksumGenerator(ChecksumType type) throws NoSuchAlgorithmException {
super();
this.messageDigest=MessageDigest.getInstance(type.getAlgorithm());
}

@Override
public void update(int b){
messageDigest.update((byte)b);
@Override
public void configure() throws ConfigurationException {
// Set the defaults for this Pipe, these are different compared to the HashPipe
if (getAlgorithm() == null) {
setAlgorithm(Algorithm.MD5);
}

@Override
public void update(byte[] b, int offset, int length){
messageDigest.update(b,offset,length);
if (getHashEncoding() == null) {
setHashEncoding(HashPipe.HashEncoding.Hex);
}

@Override
public String getResult(){
return new BigInteger(1,messageDigest.digest()).toString(16);
}
super.configure();
}

@Override
public PipeRunResult doPipe(Message message, PipeLineSession session) throws PipeRunException {
try {
ChecksumGenerator cg=createChecksumGenerator();
byte[] barr=new byte[1000];
try (InputStream fis = isInputIsFile() ? new FileInputStream(message.asString()) : message.asInputStream(getCharset())){
int c;
while ((c=fis.read(barr))>=0) {
cg.update(barr, 0, c);
}
}
return new PipeRunResult(getSuccessForward(), cg.getResult());
} catch (Exception e) {
throw new PipeRunException(this,"cannot calculate ["+getType()+"]"+(isInputIsFile()?" on file ["+message+"]":" using charset ["+getCharset()+"]"),e);
}
}

/**
* Character encoding to be used to encode message before calculating checksum.
*/
public void setCharset(String string) {
charset = string;
}
try (InputStream fis = isInputIsFile() ? new FileInputStream(message.asString()) : message.asInputStream(getCharset())) {

/**
* Type of checksum to be calculated
* @ff.default MD5
*/
public void setType(ChecksumType value) {
type = value;
return super.doPipe(new Message(fis, message.getContext()), session);
} catch (IOException e) {
throw new PipeRunException(this, "Error reading input" + (isInputIsFile() ? " file [" + message + "]" : " using charset [" + getCharset() + "]"), e);
}
}

/**
* If set <code>true</code>, the input is assumed to be a filename; otherwise the input itself is used in the calculations.
*
* @ff.default false
*/
@Deprecated(forRemoval = true, since = "7.7.0")
Expand All @@ -181,4 +92,13 @@ public void setInputIsFile(boolean b) {
inputIsFile = b;
}

/**
* Type of checksum to be calculated
* @ff.default MD5
*/
@Deprecated(forRemoval = true, since = "8.3.0")
@ConfigurationWarning("Please use setAlgorithm to set the algorithm")
public void setType(Algorithm value) {
setAlgorithm(value);
}
}
99 changes: 50 additions & 49 deletions core/src/main/java/org/frankframework/pipes/FixedResultPipe.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@

import javax.xml.transform.TransformerException;

import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.xml.sax.SAXException;

import org.frankframework.configuration.ConfigurationException;
import org.frankframework.configuration.ConfigurationWarning;
import org.frankframework.core.ParameterException;
Expand All @@ -40,9 +43,6 @@
import org.frankframework.util.ClassLoaderUtils;
import org.frankframework.util.StringResolver;
import org.frankframework.util.TransformerPool;
import org.xml.sax.SAXException;

import lombok.Getter;

/**
* This Pipe opens and returns a file from the classpath. The filename is a mandatory parameter to use. You can
Expand Down Expand Up @@ -80,7 +80,7 @@
* <pipe name="make unique message" className="org.frankframework.pipes.FixedResultPipe"
* returnString="&lt;msg mid=&quot;MID&quot; action=&quot;ACTION&quot; /&gt;" replaceFixedParams="true">
* <param name="MID" sessionKey="mid" />
* <param name="ACTION" xpathExpression="request/@action" />
* <param name="ACTION" xpathExpression="request/@action" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Formatting fix voor wat we vanochtend zagen

* </pipe>
* }
* </pre>
Expand All @@ -90,8 +90,8 @@
* {@code
* <pipe name="make unique message" className="org.frankframework.pipes.ReplacerPipe"
* getInputFromFixedValue="&lt;msg mid=&quot;?{MID}&quot; action=&quot;?{ACTION}&quot; /&gt;">
* <param name="MID" sessionKey="mid" />
* <param name="ACTION" xpathExpression="request/@action" />
* <param name="MID" sessionKey="mid" />
* <param name="ACTION" xpathExpression="request/@action" />
* </pipe>
* }
* </pre>
Expand Down Expand Up @@ -128,59 +128,59 @@
* was also used to store information in the session. For example, a port of configuration in the JMS listener sender configuration looked like this:
* <pre>
* {@code
* <CompareStringPipe name="compareIdAndCid" >
* <param name="operand1" sessionKey="id"/>
* <param name="operand2" sessionKey="cid"/>
* <forward name="equals" path="IdAndCidSame" />
* <forward name="lessthan" path="IdAndCidDifferent" />
* <forward name="greaterthan" path="IdAndCidDifferent" />
* </CompareStringPipe>
* <FixedResultPipe name="IdAndCidSame" returnString="true" storeResultInSessionKey="IdAndCidSame">
* <forward name="success" path="displayKeys" />
* </FixedResultPipe>
* <FixedResultPipe name="IdAndCidDifferent" returnString="false" storeResultInSessionKey="IdAndCidSame">
* <forward name="success" path="displayKeys" />
* </FixedResultPipe>
* <CompareStringPipe name="compareIdAndCid" >
* <param name="operand1" sessionKey="id"/>
* <param name="operand2" sessionKey="cid"/>
* <forward name="equals" path="IdAndCidSame" />
* <forward name="lessthan" path="IdAndCidDifferent" />
* <forward name="greaterthan" path="IdAndCidDifferent" />
* </CompareStringPipe>
* <FixedResultPipe name="IdAndCidSame" returnString="true" storeResultInSessionKey="IdAndCidSame">
* <forward name="success" path="displayKeys" />
* </FixedResultPipe>
* <FixedResultPipe name="IdAndCidDifferent" returnString="false" storeResultInSessionKey="IdAndCidSame">
* <forward name="success" path="displayKeys" />
* </FixedResultPipe>
*
* <pipe name="displayKeys" className="org.frankframework.pipes.FixedResultPipe"
* returnString="branch [BRANCH] Orignal Id [MID] cid [CID] id=cid [SAME]" replaceFixedParams="true">
* <param name="BRANCH" sessionKey="originalMessage" xpathExpression="*&#47;@branch" />
* <param name="MID" sessionKey="id" />
* <param name="CID" sessionKey="cid" />
* <param name="SAME" sessionKey="IdAndCidSame" />
* <forward name="success" path="EXIT" />
* </pipe>
* <pipe name="displayKeys" className="org.frankframework.pipes.FixedResultPipe"
* returnString="branch [BRANCH] Orignal Id [MID] cid [CID] id=cid [SAME]" replaceFixedParams="true">
* <param name="BRANCH" sessionKey="originalMessage" xpathExpression="*&#47;@branch" />
* <param name="MID" sessionKey="id" />
* <param name="CID" sessionKey="cid" />
* <param name="SAME" sessionKey="IdAndCidSame" />
* <forward name="success" path="EXIT" />
* </pipe>
* }
* </pre>
*
* Was rewritten to the following:
* <pre>
* {@code
* <CompareStringPipe name="compareIdAndCid" >
* <param name="operand1" sessionKey="id"/>
* <param name="operand2" sessionKey="cid"/>
* <forward name="equals" path="IdAndCidSame" />
* <forward name="lessthan" path="IdAndCidDifferent" />
* <forward name="greaterthan" path="IdAndCidDifferent" />
* </CompareStringPipe>
* <CompareStringPipe name="compareIdAndCid" >
* <param name="operand1" sessionKey="id"/>
* <param name="operand2" sessionKey="cid"/>
* <forward name="equals" path="IdAndCidSame" />
* <forward name="lessthan" path="IdAndCidDifferent" />
* <forward name="greaterthan" path="IdAndCidDifferent" />
* </CompareStringPipe>
*
* <PutInSessionPipe name="IdAndCidSame" value="true" sessionKey="IdAndCidSame">
* <forward name="success" path="putOriginalMessageInSession" />
* </PutInSessionPipe>
* <PutInSessionPipe name="IdAndCidDifferent" value="false" sessionKey="IdAndCidSame">
* <forward name="success" path="putOriginalMessageInSession" />
* </PutInSessionPipe>
* <PutInSessionPipe name="IdAndCidSame" value="true" sessionKey="IdAndCidSame">
* <forward name="success" path="putOriginalMessageInSession" />
* </PutInSessionPipe>
* <PutInSessionPipe name="IdAndCidDifferent" value="false" sessionKey="IdAndCidSame">
* <forward name="success" path="putOriginalMessageInSession" />
* </PutInSessionPipe>
*
* <PutInSessionPipe name="putOriginalMessageInSession" sessionKey="incomingMessage"/>
* <PutInSessionPipe name="putOriginalMessageInSession" sessionKey="incomingMessage"/>
*
* <pipe name="displayKeys" className="org.frankframework.pipes.ReplacerPipe"
* getInputFromFixedValue="branch [?{BRANCH}] Original Id [?{MID}] cid [?{CID}] id=cid [?{SAME}]">
* <param name="BRANCH" sessionKey="originalMessage" xpathExpression="*&#47;@branch" />
* <param name="MID" sessionKey="id" />
* <param name="CID" sessionKey="cid" />
* <param name="SAME" sessionKey="IdAndCidSame" />
* <forward name="success" path="EXIT" />
* </pipe>
* <pipe name="displayKeys" className="org.frankframework.pipes.ReplacerPipe"
* getInputFromFixedValue="branch [?{BRANCH}] Original Id [?{MID}] cid [?{CID}] id=cid [?{SAME}]">
* <param name="BRANCH" sessionKey="originalMessage" xpathExpression="*&#47;@branch" />
* <param name="MID" sessionKey="id" />
* <param name="CID" sessionKey="cid" />
* <param name="SAME" sessionKey="IdAndCidSame" />
* <forward name="success" path="EXIT" />
* </pipe>
* }
* </pre>
* <p>
Expand Down Expand Up @@ -246,6 +246,7 @@ public class FixedResultPipe extends FixedForwardPipe {
* If a filename or filenameSessionKey was specified, the contents of the file is put in the
* <code>returnString</code>, so that the <code>returnString</code>
* may always be returned.
*
* @throws ConfigurationException
*/
@Override
Expand Down
Loading
Loading