-
Notifications
You must be signed in to change notification settings - Fork 20
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
feat: sign protected pdfs #498
base: main
Are you sure you want to change the base?
Changes from all commits
ff84ad3
6d00beb
84a311f
6eed34d
aad94b7
bb7c5a1
acb36d4
11ef8b9
553dd41
9d07e15
83bd4df
e74a283
065f674
56cc58a
2778cb2
f8a4f77
a8770c1
a8a2b5d
cf8473c
ff4eca7
3c03aef
2940dff
762b7b9
72d3337
39279d1
d6660e1
0a38cb2
1a51bca
d936977
6f99e22
a5d5899
7d94479
1cc94b5
6c15d52
e587086
5a1a71e
0df85f7
b846984
eebceae
5266922
c064992
a0a9e42
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,3 +32,5 @@ secret | |
/fakeTokenDriver | ||
|
||
/cache | ||
|
||
.classpath |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,7 @@ | |
<snakeyml.version>2.2</snakeyml.version> | ||
<jimfs.version>1.3.0</jimfs.version> | ||
<testExcludedGroups>HttpSmokeTest</testExcludedGroups> | ||
<skip-jdk-cache>false</skip-jdk-cache> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Toto vsetko mi pridu nerelevantne zmeny k tomuto PR. |
||
</properties> | ||
|
||
<dependencyManagement> | ||
|
@@ -313,6 +314,7 @@ | |
<goal>cache-jdk</goal> | ||
</goals> | ||
<configuration> | ||
<skip>${skip-jdk-cache}</skip> | ||
<jdkPathProperty>jlink.jdk.path</jdkPathProperty> | ||
<jdkCachePath>${project.build.directory}${file.separator}jdkCache</jdkCachePath> | ||
<authorization>${github.auth}</authorization> | ||
|
@@ -504,6 +506,14 @@ | |
</properties> | ||
</profile> | ||
|
||
<profile> | ||
<id>system-jdk</id> | ||
<properties> | ||
<jlink.jdk.path>${env.JAVA_HOME}</jlink.jdk.path> | ||
<skip-jdk-cache>true</skip-jdk-cache> | ||
</properties> | ||
</profile> | ||
|
||
<profile> | ||
<id>smoke</id> | ||
<build> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,10 +4,12 @@ | |
import digital.slovensko.autogram.core.visualization.DocumentVisualizationBuilder; | ||
import digital.slovensko.autogram.core.visualization.UnsupportedVisualization; | ||
import digital.slovensko.autogram.drivers.TokenDriver; | ||
import digital.slovensko.autogram.model.AutogramDocument; | ||
import digital.slovensko.autogram.ui.BatchUiResult; | ||
import digital.slovensko.autogram.ui.UI; | ||
import digital.slovensko.autogram.util.Logging; | ||
import digital.slovensko.autogram.util.PDFUtils; | ||
import eu.europa.esig.dss.enumerations.SignatureLevel; | ||
import eu.europa.esig.dss.model.DSSException; | ||
import eu.europa.esig.dss.pdfa.PDFAStructureValidator; | ||
import eu.europa.esig.dss.spi.x509.tsp.TSPSource; | ||
|
@@ -56,22 +58,45 @@ public void checkPDFACompliance(SigningJob job) { | |
return; | ||
|
||
ui.onWorkThreadDo(() -> { | ||
var result = new PDFAStructureValidator().validate(job.getDocument()); | ||
// PDF/A doesn't support encryption | ||
if (job.getDocument().hasOpenDocumentPassword()) { | ||
ui.onUIThreadDo(() -> ui.onPDFAComplianceCheckFailed(job)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ešte uvažujem, či sa neplatí vyrobiť pre tento prípad inú hlášku. Prípadne vedieť do toho There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Urcite ano. Poslime tam |
||
return; | ||
} | ||
|
||
var result = new PDFAStructureValidator().validate(job.getDocument().getDSSDocument()); | ||
if (!result.isCompliant()) { | ||
ui.onUIThreadDo(() -> ui.onPDFAComplianceCheckFailed(job)); | ||
} | ||
}); | ||
} | ||
|
||
public void handleProtectedPdfDocument(AutogramDocument document) { | ||
var protection = PDFUtils.determinePDFProtection(document.getDSSDocument()); | ||
if (protection == PDFUtils.PDFProtection.NONE) | ||
return; | ||
|
||
var password = ui.getDocumentPassword(document.getDSSDocument()); | ||
switch (protection) { | ||
case OPEN_DOCUMENT_PASSWORD -> document.setOpenDocumentPassword(password); | ||
case MASTER_PASSWORD -> document.setMasterPassword(password); | ||
} | ||
} | ||
|
||
public SigningJob buildSigningJobFromFile(File file, Responder responder, boolean checkPDFACompliance, SignatureLevel signatureType, boolean isEn319132, TSPSource tspSource, boolean plainXmlEnabled) { | ||
var document = SigningJob.createDSSFileDocumentFromFile(file); | ||
handleProtectedPdfDocument(document); | ||
|
||
var parameters = SigningJob.getParametersForFile(document, checkPDFACompliance, signatureType, isEn319132, tspSource, plainXmlEnabled); | ||
return SigningJob.build(document, parameters, responder); | ||
} | ||
|
||
public void wrapInWorkThread(Runnable callback) { | ||
ui.onWorkThreadDo(callback); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Toto sa pouziva presne na 1 mieste, cize dajme inline, nijako to nezvysuje prehladnost, skor naopak. |
||
} | ||
|
||
public void startVisualization(SigningJob job) { | ||
ui.onWorkThreadDo(() -> { | ||
if (PDFUtils.isPdfAndPasswordProtected(job.getDocument())) { | ||
ui.onUIThreadDo(() -> { | ||
ui.showError(new AutogramException("Nastala chyba", "Dokument je chránený heslom", "Snažíte sa podpísať dokument chránený heslom, čo je funkcionalita, ktorá nie je podporovaná.\n\nOdstráňte ochranu heslom a potom budete môcť dokument podpísať.")); | ||
}); | ||
return; | ||
} | ||
|
||
try { | ||
var visualization = DocumentVisualizationBuilder.fromJob(job, settings); | ||
ui.onUIThreadDo(() -> ui.showVisualization(visualization, this)); | ||
|
@@ -159,7 +184,7 @@ public void batchSign(SigningJob job, String batchId) { | |
ui.onWorkThreadDo(() -> { | ||
try { | ||
signCommonAndThen(job, batch.getSigningKey(), (jobNew) -> { | ||
Logging.log("GUI: Signing batch job: " + job.hashCode() + " file " + job.getDocument().getName()); | ||
Logging.log("GUI: Signing batch job: " + job.hashCode() + " file " + job.getDocument().getDSSDocument().getName()); | ||
}); | ||
} catch (AutogramException e) { | ||
job.onDocumentSignFailed(e); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,11 +6,11 @@ | |
import digital.slovensko.autogram.core.eforms.xdc.XDCBuilder; | ||
import digital.slovensko.autogram.core.eforms.xdc.XDCValidator; | ||
import digital.slovensko.autogram.core.errors.AutogramException; | ||
import digital.slovensko.autogram.model.AutogramDocument; | ||
import digital.slovensko.autogram.util.Logging; | ||
import eu.europa.esig.dss.asic.cades.signature.ASiCWithCAdESService; | ||
import eu.europa.esig.dss.asic.xades.signature.ASiCWithXAdESService; | ||
import eu.europa.esig.dss.cades.signature.CAdESService; | ||
import eu.europa.esig.dss.enumerations.MimeTypeEnum; | ||
import eu.europa.esig.dss.enumerations.SignatureLevel; | ||
import eu.europa.esig.dss.model.DSSDocument; | ||
import eu.europa.esig.dss.model.FileDocument; | ||
|
@@ -24,16 +24,16 @@ | |
|
||
public class SigningJob { | ||
private final Responder responder; | ||
private final DSSDocument document; | ||
private final AutogramDocument document; | ||
private final SigningParameters parameters; | ||
|
||
private SigningJob(DSSDocument document, SigningParameters parameters, Responder responder) { | ||
private SigningJob(AutogramDocument document, SigningParameters parameters, Responder responder) { | ||
this.document = document; | ||
this.parameters = parameters; | ||
this.responder = responder; | ||
} | ||
|
||
public DSSDocument getDocument() { | ||
public AutogramDocument getDocument() { | ||
return this.document; | ||
} | ||
|
||
|
@@ -46,8 +46,7 @@ public int getVisualizationWidth() { | |
} | ||
|
||
public void signWithKeyAndRespond(SigningKey key) throws InterruptedException, AutogramException { | ||
|
||
Logging.log("Signing Job: " + this.hashCode() + " file " + getDocument().getName()); | ||
Logging.log("Signing Job: " + this.hashCode() + " file " + getDocument().getDSSDocument().getName()); | ||
boolean isContainer = getParameters().getContainer() != null; | ||
var doc = switch (getParameters().getSignatureType()) { | ||
case XAdES -> isContainer ? signDocumentAsAsiCWithXAdeS(key) : signDocumentAsXAdeS(key); | ||
|
@@ -73,10 +72,10 @@ private DSSDocument signDocumentAsCAdeS(SigningKey key) { | |
signatureParameters.setCertificateChain(key.getCertificateChain()); | ||
signatureParameters.setSignWithExpiredCertificate(true); | ||
|
||
var dataToSign = service.getDataToSign(getDocument(), signatureParameters); | ||
var dataToSign = service.getDataToSign(getDocument().getDSSDocument(), signatureParameters); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tento "train-wreck" mozes uz schovat do AutogramDocument, kedze ho mame. Cize |
||
var signatureValue = key.sign(dataToSign, jobParameters.getDigestAlgorithm()); | ||
|
||
return service.signDocument(getDocument(), signatureParameters, signatureValue); | ||
return service.signDocument(getDocument().getDSSDocument(), signatureParameters, signatureValue); | ||
} | ||
|
||
private DSSDocument signDocumentAsAsiCWithXAdeS(SigningKey key) { | ||
|
@@ -91,10 +90,10 @@ private DSSDocument signDocumentAsAsiCWithXAdeS(SigningKey key) { | |
if (signatureParameters.getSignatureLevel().equals(SignatureLevel.XAdES_BASELINE_T)) | ||
service.setTspSource(getParameters().getTspSource()); | ||
|
||
var dataToSign = service.getDataToSign(getDocument(), signatureParameters); | ||
var dataToSign = service.getDataToSign(getDocument().getDSSDocument(), signatureParameters); | ||
var signatureValue = key.sign(dataToSign, getParameters().getDigestAlgorithm()); | ||
|
||
return service.signDocument(getDocument(), signatureParameters, signatureValue); | ||
return service.signDocument(getDocument().getDSSDocument(), signatureParameters, signatureValue); | ||
} | ||
|
||
private DSSDocument signDocumentAsXAdeS(SigningKey key) { | ||
|
@@ -107,10 +106,10 @@ private DSSDocument signDocumentAsXAdeS(SigningKey key) { | |
signatureParameters.setCertificateChain(key.getCertificateChain()); | ||
signatureParameters.setSignWithExpiredCertificate(true); | ||
|
||
var dataToSign = service.getDataToSign(getDocument(), signatureParameters); | ||
var dataToSign = service.getDataToSign(getDocument().getDSSDocument(), signatureParameters); | ||
var signatureValue = key.sign(dataToSign, jobParameters.getDigestAlgorithm()); | ||
|
||
return service.signDocument(getDocument(), signatureParameters, signatureValue); | ||
return service.signDocument(getDocument().getDSSDocument(), signatureParameters, signatureValue); | ||
} | ||
|
||
private DSSDocument signDocumentAsASiCWithCAdeS(SigningKey key) { | ||
|
@@ -126,10 +125,10 @@ private DSSDocument signDocumentAsASiCWithCAdeS(SigningKey key) { | |
if (signatureParameters.getSignatureLevel().equals(SignatureLevel.CAdES_BASELINE_T)) | ||
service.setTspSource(getParameters().getTspSource()); | ||
|
||
var dataToSign = service.getDataToSign(getDocument(), signatureParameters); | ||
var dataToSign = service.getDataToSign(getDocument().getDSSDocument(), signatureParameters); | ||
var signatureValue = key.sign(dataToSign, jobParameters.getDigestAlgorithm()); | ||
|
||
return service.signDocument(getDocument(), signatureParameters, signatureValue); | ||
return service.signDocument(getDocument().getDSSDocument(), signatureParameters, signatureValue); | ||
} | ||
|
||
private DSSDocument signDocumentAsPAdeS(SigningKey key) { | ||
|
@@ -141,19 +140,20 @@ private DSSDocument signDocumentAsPAdeS(SigningKey key) { | |
signatureParameters.setSigningCertificate(key.getCertificate()); | ||
signatureParameters.setCertificateChain(key.getCertificateChain()); | ||
signatureParameters.setSignWithExpiredCertificate(true); | ||
signatureParameters.setPasswordProtection(document.getSigningPassword()); | ||
|
||
if (signatureParameters.getSignatureLevel().equals(SignatureLevel.PAdES_BASELINE_T)) { | ||
service.setTspSource(getParameters().getTspSource()); | ||
signatureParameters.setContentSize(9472*2); | ||
} | ||
|
||
var dataToSign = service.getDataToSign(getDocument(), signatureParameters); | ||
var dataToSign = service.getDataToSign(getDocument().getDSSDocument(), signatureParameters); | ||
var signatureValue = key.sign(dataToSign, jobParameters.getDigestAlgorithm()); | ||
|
||
return service.signDocument(getDocument(), signatureParameters, signatureValue); | ||
return service.signDocument(getDocument().getDSSDocument(), signatureParameters, signatureValue); | ||
} | ||
|
||
public static FileDocument createDSSFileDocumentFromFile(File file) { | ||
public static AutogramDocument createDSSFileDocumentFromFile(File file) { | ||
var fileDocument = new FileDocument(file); | ||
|
||
if (fileDocument.getName().endsWith(".xdcf")) | ||
|
@@ -165,12 +165,13 @@ else if (isXDC(fileDocument.getMimeType()) || isXML(fileDocument.getMimeType()) | |
else if (isTxt(fileDocument.getMimeType())) | ||
fileDocument.setMimeType(AutogramMimeType.TEXT_WITH_CHARSET); | ||
|
||
return fileDocument; | ||
return new AutogramDocument(fileDocument); | ||
} | ||
|
||
private static SigningJob build(DSSDocument document, SigningParameters params, Responder responder) { | ||
public static SigningJob build(AutogramDocument autogramDocument, SigningParameters params, Responder responder) { | ||
DSSDocument document = autogramDocument.getDSSDocument(); | ||
if (params.shouldCreateXdc() && !isXDC(document.getMimeType()) && !isAsice(document.getMimeType())) | ||
document = XDCBuilder.transform(params, document.getName(), EFormUtils.getXmlFromDocument(document)); | ||
autogramDocument = new AutogramDocument(XDCBuilder.transform(params, document.getName(), EFormUtils.getXmlFromDocument(document))); | ||
|
||
if (isTxt(document.getMimeType())) | ||
document.setMimeType(AutogramMimeType.TEXT_WITH_CHARSET); | ||
|
@@ -180,47 +181,37 @@ private static SigningJob build(DSSDocument document, SigningParameters params, | |
document.setName(getXdcfFilename(document.getName())); | ||
} | ||
|
||
return new SigningJob(document, params, responder); | ||
} | ||
|
||
public static SigningJob buildFromRequest(DSSDocument document, SigningParameters params, Responder responder) { | ||
return build(document, params, responder); | ||
} | ||
|
||
public static SigningJob buildFromFile(File file, Responder responder, boolean checkPDFACompliance, SignatureLevel signatureType, boolean isEn319132, TSPSource tspSource, boolean plainXmlEnabled) { | ||
var document = createDSSFileDocumentFromFile(file); | ||
var parameters = getParametersForFile(document, checkPDFACompliance, signatureType, isEn319132, tspSource, plainXmlEnabled); | ||
return build(document, parameters, responder); | ||
return new SigningJob(autogramDocument, params, responder); | ||
} | ||
|
||
private static SigningParameters getParametersForFile(FileDocument document, boolean checkPDFACompliance, SignatureLevel signatureType, boolean isEn319132, TSPSource tspSource, boolean plainXmlEnabled) { | ||
public static SigningParameters getParametersForFile(AutogramDocument document, boolean checkPDFACompliance, SignatureLevel signatureType, boolean isEn319132, TSPSource tspSource, boolean plainXmlEnabled) { | ||
var level = SignatureValidator.getSignedDocumentSignatureLevel(SignatureValidator.getSignedDocumentSimpleReport(document)); | ||
if (level != null) switch (level.getSignatureForm()) { | ||
case PAdES: | ||
return SigningParameters.buildForPDF(document, checkPDFACompliance, isEn319132, tspSource); | ||
return SigningParameters.buildForPDF(document.getDSSDocument(), checkPDFACompliance, isEn319132, tspSource); | ||
case XAdES: | ||
return SigningParameters.buildForASiCWithXAdES(document, checkPDFACompliance, isEn319132, tspSource, plainXmlEnabled); | ||
return SigningParameters.buildForASiCWithXAdES(document.getDSSDocument(), checkPDFACompliance, isEn319132, tspSource, plainXmlEnabled); | ||
case CAdES: | ||
return SigningParameters.buildForASiCWithCAdES(document, checkPDFACompliance, isEn319132, tspSource, plainXmlEnabled); | ||
return SigningParameters.buildForASiCWithCAdES(document.getDSSDocument(), checkPDFACompliance, isEn319132, tspSource, plainXmlEnabled); | ||
default: | ||
; | ||
} | ||
|
||
if (isPDF(document.getMimeType())) switch (signatureType) { | ||
if (isPDF(document.getDSSDocument().getMimeType())) switch (signatureType) { | ||
case PAdES_BASELINE_B: | ||
return SigningParameters.buildForPDF(document, checkPDFACompliance, isEn319132, tspSource); | ||
return SigningParameters.buildForPDF(document.getDSSDocument(), checkPDFACompliance, isEn319132, tspSource); | ||
case XAdES_BASELINE_B: | ||
return SigningParameters.buildForASiCWithXAdES(document, checkPDFACompliance, isEn319132, tspSource, plainXmlEnabled); | ||
return SigningParameters.buildForASiCWithXAdES(document.getDSSDocument(), checkPDFACompliance, isEn319132, tspSource, plainXmlEnabled); | ||
case CAdES_BASELINE_B: | ||
return SigningParameters.buildForASiCWithCAdES(document, checkPDFACompliance, isEn319132, tspSource, plainXmlEnabled); | ||
return SigningParameters.buildForASiCWithCAdES(document.getDSSDocument(), checkPDFACompliance, isEn319132, tspSource, plainXmlEnabled); | ||
default: | ||
; | ||
} | ||
|
||
return SigningParameters.buildForASiCWithXAdES(document, checkPDFACompliance, isEn319132, tspSource, plainXmlEnabled); | ||
return SigningParameters.buildForASiCWithXAdES(document.getDSSDocument(), checkPDFACompliance, isEn319132, tspSource, plainXmlEnabled); | ||
} | ||
|
||
public boolean shouldCheckPDFCompliance() { | ||
return parameters.getCheckPDFACompliance() && isPDF(document.getMimeType()); | ||
return parameters.getCheckPDFACompliance() && isPDF(document.getDSSDocument().getMimeType()); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tohto sa preco chytame?