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

Adds functions for creating a PDF PAdES and adding a signature [SFEQS-966] #1

Open
wants to merge 27 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
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
8 changes: 4 additions & 4 deletions .github/workflows/code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b

- name: Set up JDK 11
uses: actions/setup-java@v3
uses: actions/setup-java@3c69e1510165c5aacae5625826cdf51001fe2723
with:
java-version: '11'
distribution: 'temurin'
Expand All @@ -29,9 +29,9 @@ jobs:

- name: Prettier check
run: mvn -B verify prettier:check

- name: Checkstyle
run: mvn -B verify checkstyle:checkstyle
- uses: jwgmeligmeyling/checkstyle-github-action@master
- uses: jwgmeligmeyling/checkstyle-github-action@a12be500c097a5cedab881d4785ef9b4a4d3ee6a
with:
path: '**/checkstyle-result.xml'
47 changes: 38 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,60 @@
# Requirements
The latest version of `java-digital-sign` has the following minimal requirements:

- Java 11 and higher (tested up to Java 17) for the build is required.
- Java 11 and higher (tested up to Java 17) for the build is required.
- Maven 3.6 and higher;
- Memory and Disk: see minimal requirements for the used JVM. In general the higher available is better;
- Operating system: no specific requirements (tested on Windows and Linux).

# Build and usage
# Build and Usage
A simple build of the `java-digital-sign` Maven project can be done with the following command:
```
mvn clean install
```
the package is complete with plugins for prettier and syntax check

### Prettier
### Validate
```
mvn prettier:write
mvn validate
```
## Compile

### Checkstyle
to compile the JAR
```
mvn checkstyle:check
mvn clean package
```

## Compile
## Usage
Add dependecy in pom.xml
```xml
<dependency>
<groupId>it.pagopa.dss</groupId>
<artifactId>java-digital-sign</artifactId>
<version>0.0.1</version>
</dependency>
```

Generate a PAdES PDF with a signature placeholder
```java
File inputFile = new File("input.pdf");
File outputFile = new File("pades.pdf");
String fieldId = "SignatureFieldId";

to compile the JAR with all dependencies:
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
SignatureServiceInterface serviceInterface = SignatureService.getInterface();

serviceInterface.generatePadesFile(inputFile, fileOutputStream, fieldId);
```
mvn compile exec:java

Put a signatureValue in a PAdES PDF
```java
File inputFile = new File("pades.pdf");
File outputFile = new File("signed.pdf");
String fieldId = "SignatureFieldId";
byte[] signatureValue = [.....];

FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
SignatureServiceInterface serviceInterface = SignatureService.getInterface();

serviceInterface.addSignatureToPadesFile(inputFile, fileOutputStream, fieldId, signatureValue);
```
1 change: 0 additions & 1 deletion checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@
<module name="MethodParamPad"/>
<module name="NoWhitespaceAfter"/>
<module name="NoWhitespaceBefore"/>
<module name="OperatorWrap"/>
<module name="ParenPad"/>
<module name="TypecastParenPad"/>
<module name="WhitespaceAfter"/>
Expand Down
Binary file added demo.pdf
Binary file not shown.
78 changes: 60 additions & 18 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@
</license>
</licenses>

<distributionManagement>
<repository>
<id>github</id>
<name>PagoPA Apache Maven Packages</name>
<url>https://maven.pkg.github.com/pagopa/java-digital-sign</url>
</repository>
</distributionManagement>

<developers>
<developer>
<name>Francesco Grauso</name>
Expand Down Expand Up @@ -115,20 +123,11 @@
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.2.1</version>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
Expand Down Expand Up @@ -165,7 +164,27 @@
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${checkstyle-maven-plugin.version}</version>
Expand Down Expand Up @@ -208,9 +227,32 @@
</goals>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
10 changes: 0 additions & 10 deletions src/main/java/it/pagopa/dss/App.java

This file was deleted.

164 changes: 164 additions & 0 deletions src/main/java/it/pagopa/dss/PdfBoxArray.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package it.pagopa.dss;

import eu.europa.esig.dss.model.DSSException;
import eu.europa.esig.dss.pdf.PdfArray;
import eu.europa.esig.dss.pdf.PdfDict;
import eu.europa.esig.dss.spi.DSSUtils;
import java.io.IOException;
import java.io.InputStream;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSBoolean;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSFloat;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSNull;
import org.apache.pdfbox.cos.COSNumber;
import org.apache.pdfbox.cos.COSObject;
import org.apache.pdfbox.cos.COSStream;
import org.apache.pdfbox.cos.COSString;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The PDFBox implementation of {@code eu.europa.esig.dss.pdf.PdfArray}.
*/
class PdfBoxArray implements PdfArray {

private static final Logger LOG = LoggerFactory.getLogger(PdfBoxArray.class);

/** The PDFBox object */
private COSArray wrapped;

/**
* The document
*
* NOTE for developers: Retain this reference ! PDDocument must not be garbage collected
*/
private PDDocument document;

/**
* Default constructor
*
* @param wrapped {@link COSArray}
* @param document {@link PDDocument}
*/
PdfBoxArray(COSArray wrapped, PDDocument document) {
this.wrapped = wrapped;
this.document = document;
}

@Override
public int size() {
return wrapped.size();
}

@Override
public byte[] getStreamBytes(int i) throws IOException {
COSBase val = wrapped.get(i);
return toBytes(val);
}

private byte[] toBytes(COSBase val) throws IOException {
COSStream cosStream = null;
if (val instanceof COSObject) {
COSObject o = (COSObject) val;
final COSBase object = o.getObject();
if (object instanceof COSStream) {
cosStream = (COSStream) object;
}
}
if (cosStream == null) {
throw new DSSException(
"Cannot find value for " + val + " of class " + val.getClass()
);
}
try (InputStream is = cosStream.createInputStream()) {
byte[] result = DSSUtils.toByteArray(is);
cosStream.close();
return result;
}
}

@Override
public Long getObjectNumber(int i) {
COSBase val = wrapped.get(i);
if (val instanceof COSObject) {
return ((COSObject) val).getObjectNumber();
}
return null;
}

@Override
public Number getNumber(int i) {
COSBase val = wrapped.get(i);
if (val != null) {
if (val instanceof COSFloat) {
return ((COSFloat) val).floatValue();
} else if (val instanceof COSNumber) {
return ((COSNumber) val).longValue();
}
}
return null;
}

@Override
public String getString(int i) {
return wrapped.getString(i);
}

@Override
public PdfDict getAsDict(int i) {
COSDictionary cosDictionary = null;
COSBase cosBaseObject = wrapped.get(i);
if (cosBaseObject instanceof COSDictionary) {
cosDictionary = (COSDictionary) cosBaseObject;
} else if (cosBaseObject instanceof COSObject) {
COSObject cosObject = (COSObject) cosBaseObject;
cosDictionary = (COSDictionary) cosObject.getObject();
}
if (cosDictionary != null) {
return new PdfBoxDict(cosDictionary, document);
}
LOG.warn("Unable to extract array entry as dictionary!");
return null;
}

@Override
public Object getObject(int i) {
COSBase dictionaryObject = wrapped.getObject(i);
if (dictionaryObject == null) {
return null;
}
if (
dictionaryObject instanceof COSDictionary || dictionaryObject instanceof COSObject
) {
return getAsDict(i);
} else if (dictionaryObject instanceof COSArray) {
return new PdfBoxArray((COSArray) dictionaryObject, document);
} else if (dictionaryObject instanceof COSString) {
return getString(i);
} else if (dictionaryObject instanceof COSName) {
return wrapped.getName(i);
} else if (dictionaryObject instanceof COSNumber) {
return getNumber(i);
} else if (dictionaryObject instanceof COSBoolean) {
return ((COSBoolean) dictionaryObject).getValueAsObject();
} else if (dictionaryObject instanceof COSNull) {
return null;
} else {
LOG.warn(
"Unable to process an entry on position '{}' of type '{}'.",
i,
dictionaryObject.getClass()
);
}
return null;
}

@Override
public String toString() {
return wrapped.toString();
}
}
Loading