fix signature logo not loading and add option to disable it (#2143)

* fix signature logo not loading and add option to disable it

* Hardening suggestions for Stirling-PDF / fix-sig-logo (#2144)

Modernize and secure temp file creation

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>

---------

Co-authored-by: pixeebot[bot] <104101892+pixeebot[bot]@users.noreply.github.com>
This commit is contained in:
Eric 2024-10-31 16:18:42 -04:00 committed by GitHub
parent febc3cf48b
commit 94702dbafa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 29 additions and 9 deletions

View File

@ -8,6 +8,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.file.Files;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
@ -21,6 +22,7 @@ import java.security.cert.X509Certificate;
import java.util.Calendar; import java.util.Calendar;
import java.util.List; import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.examples.signature.CreateSignatureBase; import org.apache.pdfbox.examples.signature.CreateSignatureBase;
import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPage;
@ -92,7 +94,7 @@ public class CertSignController {
} }
class CreateSignature extends CreateSignatureBase { class CreateSignature extends CreateSignatureBase {
File imageFile; File logoFile;
public CreateSignature(KeyStore keystore, char[] pin) public CreateSignature(KeyStore keystore, char[] pin)
throws KeyStoreException, throws KeyStoreException,
@ -102,11 +104,17 @@ public class CertSignController {
CertificateException { CertificateException {
super(keystore, pin); super(keystore, pin);
ClassPathResource resource = new ClassPathResource("static/images/signature.png"); ClassPathResource resource = new ClassPathResource("static/images/signature.png");
imageFile = resource.getFile(); try (InputStream is = resource.getInputStream()) {
logoFile = Files.createTempFile("signature", ".png").toFile();
FileUtils.copyInputStreamToFile(is, logoFile);
} catch (IOException e) {
logger.error("Failed to load image signature file");
throw e;
}
} }
public InputStream createVisibleSignature( public InputStream createVisibleSignature(
PDDocument srcDoc, PDSignature signature, Integer pageNumber, Boolean showImage) PDDocument srcDoc, PDSignature signature, Integer pageNumber, Boolean showLogo)
throws IOException { throws IOException {
// modified from org.apache.pdfbox.examples.signature.CreateVisibleSignature2 // modified from org.apache.pdfbox.examples.signature.CreateVisibleSignature2
try (PDDocument doc = new PDDocument()) { try (PDDocument doc = new PDDocument()) {
@ -145,7 +153,7 @@ public class CertSignController {
widget.setAppearance(appearance); widget.setAppearance(appearance);
try (PDPageContentStream cs = new PDPageContentStream(doc, appearanceStream)) { try (PDPageContentStream cs = new PDPageContentStream(doc, appearanceStream)) {
if (showImage) { if (showLogo) {
cs.saveGraphicsState(); cs.saveGraphicsState();
PDExtendedGraphicsState extState = new PDExtendedGraphicsState(); PDExtendedGraphicsState extState = new PDExtendedGraphicsState();
extState.setBlendMode(BlendMode.MULTIPLY); extState.setBlendMode(BlendMode.MULTIPLY);
@ -153,7 +161,7 @@ public class CertSignController {
cs.setGraphicsStateParameters(extState); cs.setGraphicsStateParameters(extState);
cs.transform(Matrix.getScaleInstance(0.08f, 0.08f)); cs.transform(Matrix.getScaleInstance(0.08f, 0.08f));
PDImageXObject img = PDImageXObject img =
PDImageXObject.createFromFileByExtension(imageFile, doc); PDImageXObject.createFromFileByExtension(logoFile, doc);
cs.drawImage(img, 100, 0); cs.drawImage(img, 100, 0);
cs.restoreGraphicsState(); cs.restoreGraphicsState();
} }
@ -219,6 +227,7 @@ public class CertSignController {
String location = request.getLocation(); String location = request.getLocation();
String name = request.getName(); String name = request.getName();
Integer pageNumber = request.getPageNumber() - 1; Integer pageNumber = request.getPageNumber() - 1;
Boolean showLogo = request.isShowLogo();
if (certType == null) { if (certType == null) {
throw new IllegalArgumentException("Cert type must be provided"); throw new IllegalArgumentException("Cert type must be provided");
@ -258,7 +267,8 @@ public class CertSignController {
pageNumber, pageNumber,
name, name,
location, location,
reason); reason,
showLogo);
return WebResponseUtils.boasToWebResponse( return WebResponseUtils.boasToWebResponse(
baos, baos,
Filenames.toSimpleFileName(pdf.getOriginalFilename()).replaceFirst("[.][^.]+$", "") Filenames.toSimpleFileName(pdf.getOriginalFilename()).replaceFirst("[.][^.]+$", "")
@ -274,7 +284,8 @@ public class CertSignController {
Integer pageNumber, Integer pageNumber,
String name, String name,
String location, String location,
String reason) { String reason,
Boolean showLogo) {
try (PDDocument doc = pdfDocumentFactory.load(input)) { try (PDDocument doc = pdfDocumentFactory.load(input)) {
PDSignature signature = new PDSignature(); PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE); signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
@ -287,7 +298,7 @@ public class CertSignController {
if (showSignature) { if (showSignature) {
SignatureOptions signatureOptions = new SignatureOptions(); SignatureOptions signatureOptions = new SignatureOptions();
signatureOptions.setVisualSignature( signatureOptions.setVisualSignature(
instance.createVisibleSignature(doc, signature, pageNumber, true)); instance.createVisibleSignature(doc, signature, pageNumber, showLogo));
signatureOptions.setPage(pageNumber); signatureOptions.setPage(pageNumber);
doc.addSignature(signature, instance, signatureOptions); doc.addSignature(signature, instance, signatureOptions);

View File

@ -50,4 +50,7 @@ public class SignPDFWithCertRequest extends PDFFile {
description = description =
"The page number where the signature should be visible. This is required if showSignature is set to true") "The page number where the signature should be visible. This is required if showSignature is set to true")
private Integer pageNumber; private Integer pageNumber;
@Schema(description = "Whether to visually show a signature logo along with the signature")
private boolean showLogo;
} }

View File

@ -750,6 +750,7 @@ certSign.showSig=Show Signature
certSign.reason=Reason certSign.reason=Reason
certSign.location=Location certSign.location=Location
certSign.name=Name certSign.name=Name
certSign.showLogo=Show Logo
certSign.submit=Sign PDF certSign.submit=Sign PDF

View File

@ -750,6 +750,7 @@ certSign.showSig=Show Signature
certSign.reason=Reason certSign.reason=Reason
certSign.location=Location certSign.location=Location
certSign.name=Name certSign.name=Name
certSign.showLogo=Show Logo
certSign.submit=Sign PDF certSign.submit=Sign PDF

View File

@ -71,7 +71,11 @@
<label for="name" th:text="#{certSign.name}"></label> <input type="text" class="form-control" id="name" name="name"> <label for="name" th:text="#{certSign.name}"></label> <input type="text" class="form-control" id="name" name="name">
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="pageNumber" th:text="#{pageNum}"></label> <input type="number" class="form-control" id="pageNumber" name="pageNumber" min="1"> <label for="pageNumber" th:text="#{pageNum}"></label> <input type="number" class="form-control" id="pageNumber" name="pageNumber" min="1" value="1">
</div>
<div class="form-check mb-3">
<input type="checkbox" id="showLogo" name="showLogo" checked />
<label th:text="#{certSign.showLogo}" for="showLogo"></label>
</div> </div>
</div> </div>
<div class="mb-3 text-left"> <div class="mb-3 text-left">