diff --git a/.vscode/launch.json b/.vscode/launch.json
index 44c150235..898495d31 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -33,6 +33,28 @@
// this is because of some escaping problem with zsh
"console": "externalTerminal"
}
+ },
+ {
+ "type": "java",
+ "name": "Autogram CLI",
+ "request": "launch",
+ "mainClass": "digital.slovensko.autogram.Main",
+ "projectName": "autogram",
+ "vmArgs": "--add-exports javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED",
+ "args": "${input:commandLineArguments}",
+ "osx": {
+ // this is because of some escaping problem with zsh
+ "console": "integratedTerminal"
+ }
+ },
+
+ ],
+ "inputs": [
+ {
+ "id": "commandLineArguments",
+ "type": "promptString",
+ "description": "Please enter command line arguments",
+ "default": "--cli --source src/test/resources/digital/slovensko/autogram/crystal_test_data/rozhodnutie_X4564-2.pdf --target target/out.pdf"
}
]
}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 14af2b630..e133a1ab9 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -103,6 +103,25 @@
},
"problemMatcher": [],
"type": "shell"
+ },
+ {
+ "label": "Run Autogram CLI",
+ "command": "./mvnw exec:java -Dexec.mainClass=\"digital.slovensko.autogram.Main\" -Dexec.args=\"${input:commandLineArguments}\"",
+ "type": "shell",
+ "problemMatcher": [],
+ "options": {
+ "env": {
+ "JAVA_HOME": "${config:java.jdt.ls.java.home}"
+ }
+ }
+ }
+ ],
+ "inputs": [
+ {
+ "id": "commandLineArguments",
+ "type": "promptString",
+ "description": "Please enter command line arguments",
+ "default": "--cli"
}
]
}
diff --git a/DEVELOPER.md b/DEVELOPER.md
index 129c517e3..faa3a4bb5 100644
--- a/DEVELOPER.md
+++ b/DEVELOPER.md
@@ -1,5 +1,13 @@
# Info for developers
+# Trying out CLI mode
+
+Useful command how to run project from CLI.
+
+```bash
+./mvnw exec:java -Dexec.mainClass="digital.slovensko.autogram.Main" -Dexec.args="--cli ..."
+```
+
# More info about inner workings of builds for MacOS
To run signed mac build add follwing to `.vscode/settings.json` (or you can do unsigned build by setting `mac.sign=0` in `build.properties`)
diff --git a/README.md b/README.md
index 1deef457f..6aaba5d54 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Autogram
-Autogram je multi-platformová (Windows, MacOS, Linux) desktopová JavaFX aplikácia, ktorá slúži na podpisovanie dokumentov v súlade s eIDAS reguláciou. Používateľ ňou môže podpisovať súbory priamo alebo je možné aplikáciu jednoducho zaintegrovať do vlastného (webového) informačného systému pomocou HTTP API.
+Autogram je multi-platformová (Windows, MacOS, Linux) desktopová JavaFX aplikácia, ktorá slúži na podpisovanie dokumentov v súlade s eIDAS reguláciou. Používateľ ňou môže podpisovať súbory priamo alebo je možné aplikáciu jednoducho zaintegrovať do vlastného (webového) informačného systému pomocou HTTP API. Podpisovanie je možné spúšať aj z príkazového riadku, čo je vhodné pre hromadné podpisovanie veľkého množstva súborov naraz.
**Inštalačné balíky pre Windows, MacOS a Linux sú dostupné v časti [Releases](https://github.com/slovensko-digital/autogram/releases).** Na použitie na existujúcich štátnych weboch bude potrebné doinštalovať aj [rozšírenie do prehliadača](https://github.com/slovensko-digital/autogram-extension#readme).
@@ -12,6 +12,10 @@ Swagger dokumentácia pre HTTP API je [dostupná na githube](https://generator3.
Vyvolať spustenie programu je možné priamo z webového prehliadača otvorením adresy so špeciálnym protokolom `autogram://`. Napríklad cez `autogram://go`.
+## Konzolový mód
+
+Autogram je možné spúšťať aj z príkazového riadku (CLI mód), ktoré umožňuje aj hromadné podpisovanie súborov. Detailné informácie o prepínačoch je sú popísané v nápovede po spustení `autogram --help`
+
### Štýlovanie
Aplikácia momentálne podporuje len jeden štýl - štátny IDSK dizajn. Ďalšie štýly sú plánované. Štýlovanie sa však už teraz deje výhradne cez kaskádové štýly, viď [idsk.css](https://github.com/slovensko-digital/autogram/blob/main/src/main/resources/digital/slovensko/autogram/ui/gui/idsk.css)
diff --git a/pom.xml b/pom.xml
index 35805109c..e32474932 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,6 +1,6 @@
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
@@ -24,7 +24,9 @@
2.0.7
5.9.3
5.4.0
+ 1.5.0
2.9.1
+ 1.2
@@ -113,6 +115,11 @@
${mockito.version}
test
+
+ commons-cli
+ commons-cli
+ ${commons-cli.version}
+
org.xmlunit
@@ -126,6 +133,12 @@
${xmlunit.version}
test
+
+ com.google.jimfs
+ jimfs
+ ${jimfs.version}
+ test
+
@@ -207,7 +220,7 @@
org.codehaus.mojo
- versions-maven-plugin
+ versions-maven-plugin
2.16.0
@@ -259,8 +272,10 @@
download-single
- https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/build/pdf.min.js
- ${project.resources[0].directory}/digital/slovensko/autogram/ui/gui/vendor/pdfjs
+
+ https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/build/pdf.min.js
+
+ ${project.resources[0].directory}/digital/slovensko/autogram/ui/gui/vendor/pdfjs
true
@@ -271,8 +286,10 @@
download-single
- https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js
- ${project.resources[0].directory}/digital/slovensko/autogram/ui/gui/vendor/pdfjs
+
+ https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js
+
+ ${project.resources[0].directory}/digital/slovensko/autogram/ui/gui/vendor/pdfjs
true
@@ -285,7 +302,8 @@
https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}
cmaps
- ${project.resources[0].directory}/digital/slovensko/autogram/ui/gui/vendor/pdfjs/cmaps
+
+ ${project.resources[0].directory}/digital/slovensko/autogram/ui/gui/vendor/pdfjs/cmaps
@@ -321,7 +339,8 @@
jdeps
-
+
true
@@ -332,7 +351,8 @@
-
+
@@ -363,7 +383,8 @@
javafx.fxml
javafx.graphics
javafx.web
-
+
jdk.unsupported
jdk.httpserver
@@ -409,13 +430,16 @@
3.1.0
bash
- ${project.build.scriptSourceDirectory}${file.separator}resources
+
+ ${project.build.scriptSourceDirectory}${file.separator}resources
${project.build.scriptSourceDirectory}${file.separator}package.sh
${jlink.jdk.path}${file.separator}bin${file.separator}jpackage
- ${project.build.directory}${file.separator}${project.artifactId}-${project.version}-${platform}
+
+ ${project.build.directory}${file.separator}${project.artifactId}-${project.version}-${platform}
${project.build.directory}${file.separator}preparedJDK
- ${project.basedir}${file.separator}src${file.separator}main${file.separator}resources${file.separator}digital${file.separator}slovensko${file.separator}autogram
+
+ ${project.basedir}${file.separator}src${file.separator}main${file.separator}resources${file.separator}digital${file.separator}slovensko${file.separator}autogram
${platform}
${project.version}
${project.build.directory}
@@ -492,4 +516,4 @@
-
+
\ No newline at end of file
diff --git a/src/main/java/digital/slovensko/autogram/Main.java b/src/main/java/digital/slovensko/autogram/Main.java
index 552a02dfb..6c6c383fc 100644
--- a/src/main/java/digital/slovensko/autogram/Main.java
+++ b/src/main/java/digital/slovensko/autogram/Main.java
@@ -1,17 +1,12 @@
package digital.slovensko.autogram;
-import digital.slovensko.autogram.ui.gui.GUIApp;
-import javafx.application.Application;
-
-import java.util.Arrays;
+import digital.slovensko.autogram.core.AppStarter;
import static java.util.Objects.requireNonNullElse;
public class Main {
public static void main(String[] args) {
- System.out.println("Starting with args: " + Arrays.toString(args));
-
- Application.launch(GUIApp.class, args);
+ AppStarter.start(args);
}
public static String getVersion() {
diff --git a/src/main/java/digital/slovensko/autogram/core/AppStarter.java b/src/main/java/digital/slovensko/autogram/core/AppStarter.java
new file mode 100644
index 000000000..a27cf2ea3
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/AppStarter.java
@@ -0,0 +1,77 @@
+package digital.slovensko.autogram.core;
+
+import digital.slovensko.autogram.ui.cli.CliApp;
+import digital.slovensko.autogram.ui.gui.GUIApp;
+import javafx.application.Application;
+import org.apache.commons.cli.*;
+
+import java.io.PrintWriter;
+
+public class AppStarter {
+ private static final Options options = new Options().
+ addOptionGroup(new OptionGroup().
+ addOption(new Option(null, "url", true, "Start in GUI mode with API server listening on given port and protocol (HTTP/HTTPS). Application starts minimised when is not empty.")).
+ addOption(new Option("c", "cli", false, "Run application in CLI mode."))
+ ).
+ addOption("h", "help", false, "Print this command line help.").
+ addOption("u", "usage", false, "Print usage examples.").
+ addOption("s", "source", true, "Source file or directory of files to sign.").
+ addOption("t", "target", true, "Target file or directory for signed files. Type (file/directory) must match the source.").
+ addOption("f", "force", false, "Overwrite existing file(s).").
+ addOption(null, "pdfa", false, "Check PDF/A compliance before signing.").
+ addOption(null, "parents", false, "Create all parent directories for target if needed.").
+ addOption("d", "driver", true, "PCKS driver for signing. Supported drivers: eid, secure_store, monet, gemalto.");
+
+ public static void start(String[] args) {
+ try {
+ CommandLine cmd = new DefaultParser().parse(options, args);
+
+ if (cmd.hasOption("h")) {
+ printHelp();
+ } else if (cmd.hasOption("u")) {
+ printUsage();
+ } else if (cmd.hasOption("c")) {
+ CliApp.start(cmd);
+ } else {
+ Application.launch(GUIApp.class, args);
+ }
+ } catch (ParseException e) {
+ System.err.println("Unable to parse program args");
+ System.err.println(e);
+ }
+ }
+
+ public static void printHelp() {
+ final HelpFormatter formatter = new HelpFormatter();
+ final String syntax = "autogram";
+ final String footer = """
+
+ In CLI mode, signed files are saved with the same name as the source file, but with the suffix "_signed" if no target is specified. If the source is a directory, the target must also be a directory. If the source is a file, the target must also be a file. If the source is a driectory and no target is specified, a target directory is created with the same name as the source directory, but with the suffix "_signed".
+
+ If no target is specified and generated target name already exists, number is added to the target's name suffix if --force is not enabled. For example, if the source is "file.pdf" and the target is not specified, the target will be "file_signed.pdf". If the target already exists, the target will be "file_signed (1).pdf". If that target already exists, the target will be "file_signed (2).pdf", and so on.
+
+ If --force is enabled, the target will be overwritten if it already exists.
+
+ If target is specified with missing parent directories, they are created onyl if --parents is enabled. Otherwise, the signing fails. For example, if the source is "file.pdf" and the target is "target/file_signed.pdf", the target directory "target" must exist. If it does not exist, the signing fails. If --parents is enabled, the target directory "target" is created if it does not exist.
+ """;
+
+ formatter.printHelp(80, syntax, "", options, footer, true);
+ }
+
+ public static void printUsage() {
+ final HelpFormatter formatter = new HelpFormatter();
+ final String syntax = """
+ autogram [options]
+ autogram --url=http://localhost:32700
+ autogram --cli [options]
+ autogram --cli -s target/directory-example/file-example.pdf -t target/output-example/out-example.pdf
+ autogram --cli -s target/directory-example -t target/output-example -f
+ autogram --cli -s target/directory-example -t target/non-existent-dir/output-example --parents
+ autogram --cli -s target/directory-example/file-example.pdf -pdfa
+ autogram --cli -s target/directory-example/file-example.pdf -d eid
+ """;
+ final PrintWriter pw = new PrintWriter(System.out);
+ formatter.printUsage(pw, 80, syntax);
+ pw.flush();
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/core/Autogram.java b/src/main/java/digital/slovensko/autogram/core/Autogram.java
index 9a5cbcb29..9d72b753e 100644
--- a/src/main/java/digital/slovensko/autogram/core/Autogram.java
+++ b/src/main/java/digital/slovensko/autogram/core/Autogram.java
@@ -26,18 +26,19 @@ public Autogram(UI ui, DriverDetector driverDetector) {
}
public void sign(SigningJob job) {
- ui.onUIThreadDo(() -> ui.startSigning(job, this));
-
- if (job.shouldCheckPDFCompliance()) {
- ui.onWorkThreadDo(() -> checkPDFACompliance(job));
- }
+ ui.onUIThreadDo(()
+ -> ui.startSigning(job, this));
}
- private void checkPDFACompliance(SigningJob job) {
- var result = new PDFAStructureValidator().validate(job.getDocument());
- if (!result.isCompliant()) {
- ui.onUIThreadDo(() -> ui.onPDFAComplianceCheckFailed(job));
- }
+ public void checkPDFACompliance(SigningJob job) {
+ if(!job.shouldCheckPDFCompliance()) return;
+
+ ui.onWorkThreadDo(() -> {
+ var result = new PDFAStructureValidator().validate(job.getDocument());
+ if (!result.isCompliant()) {
+ ui.onUIThreadDo(() -> ui.onPDFAComplianceCheckFailed(job));
+ }
+ });
}
public void startVisualization(SigningJob job) {
diff --git a/src/main/java/digital/slovensko/autogram/core/CliParameters.java b/src/main/java/digital/slovensko/autogram/core/CliParameters.java
new file mode 100644
index 000000000..cebb6fe72
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/CliParameters.java
@@ -0,0 +1,75 @@
+package digital.slovensko.autogram.core;
+
+import digital.slovensko.autogram.core.errors.SourceDoesNotExistException;
+import digital.slovensko.autogram.core.errors.TokenDriverDoesNotExistException;
+import digital.slovensko.autogram.drivers.TokenDriver;
+import org.apache.commons.cli.CommandLine;
+
+import java.io.File;
+import java.util.Optional;
+
+public class CliParameters {
+ private final File source;
+ private final String target;
+ private final boolean force;
+ private final TokenDriver driver;
+ private final boolean checkPDFACompliance;
+ private final boolean makeParentDirectories;
+
+
+ public CliParameters(CommandLine cmd) {
+ source = getValidSource(cmd.getOptionValue("s"));
+ target = cmd.getOptionValue("t");
+ driver = getValidTokenDriver(cmd.getOptionValue("d"));
+ force = cmd.hasOption("f");
+ checkPDFACompliance = cmd.hasOption("pdfa");
+ makeParentDirectories = cmd.hasOption("parents");
+ }
+
+ public File getSource() {
+ return source;
+ }
+
+ public TokenDriver getDriver() {
+ return driver;
+ }
+
+ public boolean isForce() {
+ return force;
+ }
+
+ public String getTarget() {
+ return target;
+ }
+
+ public boolean shouldCheckPDFACompliance() {
+ return checkPDFACompliance;
+ }
+
+ public boolean shouldMakeParentDirectories() {
+ return makeParentDirectories;
+ }
+
+ private static File getValidSource(String sourcePath) {
+ if (sourcePath != null && !new File(sourcePath).exists())
+ throw new SourceDoesNotExistException(sourcePath);
+
+ return sourcePath == null ? null : new File(sourcePath);
+ }
+
+ private static TokenDriver getValidTokenDriver(String driverName) {
+ if (driverName == null)
+ return null;
+
+ Optional tokenDriver = new DefaultDriverDetector()
+ .getAvailableDrivers()
+ .stream()
+ .filter(d -> d.getShortname().equals(driverName))
+ .findFirst();
+
+ if (tokenDriver.isEmpty())
+ throw new TokenDriverDoesNotExistException(driverName);
+
+ return tokenDriver.get();
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/core/DefaultDriverDetector.java b/src/main/java/digital/slovensko/autogram/core/DefaultDriverDetector.java
index 03586a49b..f8a01478c 100644
--- a/src/main/java/digital/slovensko/autogram/core/DefaultDriverDetector.java
+++ b/src/main/java/digital/slovensko/autogram/core/DefaultDriverDetector.java
@@ -8,25 +8,32 @@
import java.util.List;
public class DefaultDriverDetector implements DriverDetector {
+ public static class TokenDriverShortnames {
+ public static final String EID = "eid";
+ public static final String SECURE_STORE = "secure_store";
+ public static final String MONET = "monet";
+ public static final String GEMALTO = "gemalto";
+ }
+
public static final List LINUX_DRIVERS = List.of(
- new PKCS11TokenDriver("Občiansky preukaz (eID klient)", Path.of("/usr/lib/eID_klient/libpkcs11_x64.so"), false),
- new PKCS11TokenDriver("I.CA SecureStore", Path.of("/usr/lib/pkcs11/libICASecureStorePkcs11.so"), true),
- new PKCS11TokenDriver("MONET+ ProID+Q", Path.of("/usr/lib/x86_64-linux-gnu/libproidqcm11.so"), true),
- new PKCS11TokenDriver("Gemalto IDPrime 940", Path.of("/usr/lib/libIDPrimePKCS11.so"), true)
+ new PKCS11TokenDriver("Občiansky preukaz (eID klient)", Path.of("/usr/lib/eID_klient/libpkcs11_x64.so"), false, TokenDriverShortnames.EID),
+ new PKCS11TokenDriver("I.CA SecureStore", Path.of("/usr/lib/pkcs11/libICASecureStorePkcs11.so"), true, TokenDriverShortnames.SECURE_STORE),
+ new PKCS11TokenDriver("MONET+ ProID+Q", Path.of("/usr/lib/x86_64-linux-gnu/libproidqcm11.so"), true, TokenDriverShortnames.MONET),
+ new PKCS11TokenDriver("Gemalto IDPrime 940", Path.of("/usr/lib/libIDPrimePKCS11.so"), true, TokenDriverShortnames.GEMALTO)
);
public static final List WINDOWS_DRIVERS = List.of(
- new PKCS11TokenDriver("Občiansky preukaz (eID klient)", Path.of("C:\\Program Files (x86)\\eID_klient\\pkcs11_x64.dll"), false),
- new PKCS11TokenDriver("I.CA SecureStore", Path.of("C:\\Windows\\System32\\SecureStorePkcs11.dll"), true),
- new PKCS11TokenDriver("MONET+ ProID+Q", Path.of( "C:\\Windows\\system32\\proidqcm11.dll"), true),
- new PKCS11TokenDriver("Gemalto IDPrime 940", Path.of("C:\\Windows\\System32\\eTPKCS11.dll"), true)
+ new PKCS11TokenDriver("Občiansky preukaz (eID klient)", Path.of("C:\\Program Files (x86)\\eID_klient\\pkcs11_x64.dll"), false, TokenDriverShortnames.EID),
+ new PKCS11TokenDriver("I.CA SecureStore", Path.of("C:\\Windows\\System32\\SecureStorePkcs11.dll"), true, TokenDriverShortnames.SECURE_STORE),
+ new PKCS11TokenDriver("MONET+ ProID+Q", Path.of( "C:\\Windows\\system32\\proidqcm11.dll"), true, TokenDriverShortnames.MONET),
+ new PKCS11TokenDriver("Gemalto IDPrime 940", Path.of("C:\\Windows\\System32\\eTPKCS11.dll"), true, TokenDriverShortnames.GEMALTO)
);
public static final List MAC_DRIVERS = List.of(
- new PKCS11TokenDriver("Občiansky preukaz (eID klient)", Path.of("/Applications/eID_klient.app/Contents/Frameworks/libPkcs11.dylib"), false),
- new PKCS11TokenDriver("I.CA SecureStore", Path.of("/usr/local/lib/pkcs11/libICASecureStorePkcs11.dylib"), true),
- new PKCS11TokenDriver("MONET+ ProID+Q", Path.of("/usr/local/lib/ProIDPlus/libproidqcm11.dylib"), true),
- new PKCS11TokenDriver("Gemalto IDPrime 940", Path.of("/usr/local/lib/libIDPrimePKCS11.dylib"), true)
+ new PKCS11TokenDriver("Občiansky preukaz (eID klient)", Path.of("/Applications/eID_klient.app/Contents/Frameworks/libPkcs11.dylib"), false, TokenDriverShortnames.EID),
+ new PKCS11TokenDriver("I.CA SecureStore", Path.of("/usr/local/lib/pkcs11/libICASecureStorePkcs11.dylib"), true, TokenDriverShortnames.SECURE_STORE),
+ new PKCS11TokenDriver("MONET+ ProID+Q", Path.of("/usr/local/lib/ProIDPlus/libproidqcm11.dylib"), true, TokenDriverShortnames.MONET),
+ new PKCS11TokenDriver("Gemalto IDPrime 940", Path.of("/usr/local/lib/libIDPrimePKCS11.dylib"), true, TokenDriverShortnames.GEMALTO)
);
public List getAvailableDrivers() {
diff --git a/src/main/java/digital/slovensko/autogram/core/SigningJob.java b/src/main/java/digital/slovensko/autogram/core/SigningJob.java
index 584c0a960..355ca8a18 100644
--- a/src/main/java/digital/slovensko/autogram/core/SigningJob.java
+++ b/src/main/java/digital/slovensko/autogram/core/SigningJob.java
@@ -3,7 +3,6 @@
import java.io.File;
import digital.slovensko.autogram.core.errors.AutogramException;
-import digital.slovensko.autogram.ui.SaveFileResponder;
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;
@@ -47,7 +46,7 @@ public SigningParameters getParameters() {
public int getVisualizationWidth() {
return parameters.getVisualizationWidth();
}
-
+
private boolean isDocumentXDC() {
return document.getMimeType().equals(AutogramMimeType.XML_DATACONTAINER);
}
@@ -150,19 +149,18 @@ private DSSDocument signDocumentAsPAdeS(SigningKey key) {
return service.signDocument(getDocument(), signatureParameters, signatureValue);
}
- public static SigningJob buildFromFile(File file, Autogram autogram) {
+ public static SigningJob buildFromFile(File file, Responder responder, boolean checkPDFACompliance) {
var document = new FileDocument(file);
SigningParameters parameters;
var filename = file.getName();
if (filename.endsWith(".pdf")) {
- parameters = SigningParameters.buildForPDF(filename);
+ parameters = SigningParameters.buildForPDF(filename, checkPDFACompliance);
} else {
parameters = SigningParameters.buildForASiCWithXAdES(filename);
}
- var responder = new SaveFileResponder(file, autogram);
return new SigningJob(document, parameters, responder);
}
diff --git a/src/main/java/digital/slovensko/autogram/core/SigningParameters.java b/src/main/java/digital/slovensko/autogram/core/SigningParameters.java
index f96c1e4c9..b760b0311 100644
--- a/src/main/java/digital/slovensko/autogram/core/SigningParameters.java
+++ b/src/main/java/digital/slovensko/autogram/core/SigningParameters.java
@@ -50,7 +50,6 @@ public SigningParameters(SignatureLevel level, ASiCContainerType container,
this.visualizationWidth = preferredPreviewWidth;
}
-
public ASiCWithXAdESSignatureParameters getASiCWithXAdESSignatureParameters() {
var parameters = new ASiCWithXAdESSignatureParameters();
@@ -163,15 +162,21 @@ public String getKeyInfoCanonicalization() {
: CanonicalizationMethod.INCLUSIVE;
}
- public static SigningParameters buildForPDF(String filename) {
- return new SigningParameters(SignatureLevel.PAdES_BASELINE_B, null, null, null,
- DigestAlgorithm.SHA256, false, null, null, null, null, null, "", false, 600);
+ public static SigningParameters buildForPDF(String filename, boolean checkPDFACompliance) {
+ return new SigningParameters(
+ SignatureLevel.PAdES_BASELINE_B,
+ null,
+ null, null,
+ DigestAlgorithm.SHA256,
+ false, null,
+ null, null,
+ null, null, "", checkPDFACompliance, 640);
}
public static SigningParameters buildForASiCWithXAdES(String filename) {
return new SigningParameters(SignatureLevel.XAdES_BASELINE_B, ASiCContainerType.ASiC_E,
null, SignaturePackaging.ENVELOPING, DigestAlgorithm.SHA256, false, null, null,
- null, null, null, "", false, 600);
+ null, null, null, "", false, 640);
}
public String getIdentifier() {
diff --git a/src/main/java/digital/slovensko/autogram/core/TargetPath.java b/src/main/java/digital/slovensko/autogram/core/TargetPath.java
new file mode 100644
index 000000000..2b009b94b
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/TargetPath.java
@@ -0,0 +1,179 @@
+package digital.slovensko.autogram.core;
+
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import digital.slovensko.autogram.core.errors.SourceAndTargetTypeMismatchException;
+import digital.slovensko.autogram.core.errors.TargetAlreadyExistsException;
+import digital.slovensko.autogram.core.errors.TargetDirectoryDoesNotExistException;
+import digital.slovensko.autogram.core.errors.UnableToCreateDirectoryException;
+
+public class TargetPath {
+ private final Path targetDirectory;
+ private final String targetName;
+ private final Path sourceFile;
+ private final boolean isForce;
+ private final boolean isGenerated;
+ private final boolean isForMultipleFiles;
+ private final boolean isParents;
+
+ private final FileSystem fs;
+
+ public TargetPath(String target, Path source, boolean force, boolean parents, FileSystem fileSystem) {
+ fs = fileSystem;
+ sourceFile = source;
+ isForce = force;
+ isParents = parents;
+
+ isGenerated = target == null;
+ isForMultipleFiles = Files.isDirectory(source);
+ if (isGenerated) {
+ if (isForMultipleFiles) {
+
+ targetDirectory = fs.getPath(
+ generateUniqueName(source.toAbsolutePath().getParent().toString(), source.getFileName().toString() + "_signed",
+ ""));
+ targetName = null;
+
+ } else {
+ targetDirectory = source.toAbsolutePath().getParent();
+ targetName = null;
+ }
+
+ } else {
+ var targetFile = fs.getPath(target);
+ if (!hasSourceAndTargetMatchingType(sourceFile, targetFile))
+ throw new SourceAndTargetTypeMismatchException();
+
+ if (Files.exists(targetFile) && !isForce)
+ throw new TargetAlreadyExistsException();
+
+ if (isForMultipleFiles) {
+ targetDirectory = targetFile;
+ targetName = null;
+
+ } else {
+ targetDirectory = targetFile.getParent();
+ targetName = targetFile.getFileName().toString();
+ }
+ }
+ }
+
+ public static TargetPath fromParams(CliParameters params) {
+ return new TargetPath(params.getTarget(), params.getSource().toPath(), params.isForce(),
+ params.shouldMakeParentDirectories(), FileSystems.getDefault());
+ }
+
+ public static TargetPath fromSource(Path source) {
+ return new TargetPath(null, source, false, false, FileSystems.getDefault());
+ }
+
+ /**
+ * Create directory when we want to fill it out
+ */
+ public void mkdirIfDir() {
+ if (targetDirectory == null || Files.exists(targetDirectory))
+ return;
+
+ if (isParents) {
+ try {
+ Files.createDirectories(targetDirectory);
+ } catch (Exception e) {
+ throw new UnableToCreateDirectoryException();
+ }
+
+ return;
+ }
+
+ if (!isForMultipleFiles)
+ throw new TargetDirectoryDoesNotExistException();
+
+ try {
+ Files.createDirectory(targetDirectory);
+ } catch (Exception e) {
+ throw new UnableToCreateDirectoryException();
+ }
+ }
+
+ private static boolean hasSourceAndTargetMatchingType(Path source, Path target) {
+ if (!Files.exists(target))
+ return true;
+
+ var bothAreFiles = Files.isRegularFile(target) && Files.isRegularFile(source);
+ var bothAreDirectories = Files.isDirectory(target) && Files.isDirectory(source);
+
+ return (bothAreDirectories || bothAreFiles);
+ }
+
+ /*
+ * Use these functions to get concrete file to be saved to
+ *
+ */
+
+ public Path getSaveFilePath(Path singleSourceFile) {
+ var file = _getSaveFilePath(singleSourceFile);
+
+ if (Files.exists(file) && !isForce)
+ throw new TargetAlreadyExistsException();
+
+ return file;
+ }
+
+ private Path _getSaveFilePath(Path singleSourceFile) {
+ var targetName = this.targetName == null ? generateTargetName(singleSourceFile) : this.targetName;
+ var targetDirectoryPath = targetDirectory == null ? "" : targetDirectory.toString();
+ Path targetSingleFile = fs.getPath(targetDirectoryPath, targetName);
+
+ if (!Files.exists(targetSingleFile))
+ return targetSingleFile;
+
+ if (isForce)
+ return targetSingleFile;
+
+ if (isGenerated) {
+ var parent = targetSingleFile.getParent();
+ var baseName = com.google.common.io.Files
+ .getNameWithoutExtension(targetSingleFile.getFileName().toString());
+ var extension = "."
+ + com.google.common.io.Files.getFileExtension(targetSingleFile.getFileName().toString());
+ return fs.getPath(generateUniqueName(parent.toString(), baseName, extension));
+ }
+
+ throw new TargetAlreadyExistsException();
+ }
+
+ private String generateUniqueName(String parent, String baseName, String extension) {
+ var count = 1;
+ var newBaseName = baseName;
+ parent = parent == null ? "" : parent;
+ while (true) {
+ var newTargetFile = _generateUniqueNameGetNewTargetFile(parent, newBaseName, extension);
+ if (!Files.exists(newTargetFile))
+ return newTargetFile.toString();
+
+ if (count > 1000)
+ throw new TargetAlreadyExistsException();
+
+ newBaseName = baseName + " (" + count + ")";
+ count++;
+ }
+ }
+
+ private Path _generateUniqueNameGetNewTargetFile(String parent, String baseName, String extension) {
+ return fs.getPath(parent, baseName + extension);
+ }
+
+ private String generateTargetName(Path singleSourceFile) {
+ var extension = singleSourceFile.getFileName().toString().endsWith(".pdf") ? ".pdf" : ".asice";
+ if (isGenerated || isForMultipleFiles)
+ return com.google.common.io.Files.getNameWithoutExtension(singleSourceFile.getFileName().toString())
+ + "_signed"
+ + extension;
+
+ else
+ return com.google.common.io.Files.getNameWithoutExtension(targetDirectory.getFileName().toString())
+ + extension;
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/core/errors/PDFAComplianceException.java b/src/main/java/digital/slovensko/autogram/core/errors/PDFAComplianceException.java
new file mode 100644
index 000000000..7a46b55d2
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/errors/PDFAComplianceException.java
@@ -0,0 +1,7 @@
+package digital.slovensko.autogram.core.errors;
+
+public class PDFAComplianceException extends AutogramException {
+ public PDFAComplianceException() {
+ super("Nastala chyba", "Dokument nie je vo formáte PDF/A", "Dokument, ktorý ste chceli podpísať je vo formáte, ktorý úrady nemusia akceptovať.");
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/core/errors/SourceAndTargetTypeMismatchException.java b/src/main/java/digital/slovensko/autogram/core/errors/SourceAndTargetTypeMismatchException.java
new file mode 100644
index 000000000..4656eca8d
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/errors/SourceAndTargetTypeMismatchException.java
@@ -0,0 +1,8 @@
+package digital.slovensko.autogram.core.errors;
+
+public class SourceAndTargetTypeMismatchException extends AutogramException {
+ public SourceAndTargetTypeMismatchException() {
+ super("Nastala chyba", "Zdrojové a cieľové umiestnenia sú rôzneho typu (súbor / adresár)", "Zadali ste zdrojové a cieľové umiestnenia, ktoré sú rôzneho typu (súbor / adresár)");
+ }
+
+}
diff --git a/src/main/java/digital/slovensko/autogram/core/errors/SourceDoesNotExistException.java b/src/main/java/digital/slovensko/autogram/core/errors/SourceDoesNotExistException.java
new file mode 100644
index 000000000..1dc7fb13c
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/errors/SourceDoesNotExistException.java
@@ -0,0 +1,11 @@
+package digital.slovensko.autogram.core.errors;
+
+public class SourceDoesNotExistException extends AutogramException {
+ public SourceDoesNotExistException() {
+ super("Nastala chyba", "Zdrojový súbor / adresár neexistuje", "Zadali ste zdrojový súbor / adresár, ktorý neexistuje");
+ }
+
+ public SourceDoesNotExistException(String sourcePath) {
+ super("Nastala chyba", "Zdrojový súbor / adresár neexistuje", "Zadali ste zdrojový súbor / adresár \"" + sourcePath + "\", ktorý neexistuje");
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/core/errors/SourceNotDefindedException.java b/src/main/java/digital/slovensko/autogram/core/errors/SourceNotDefindedException.java
new file mode 100644
index 000000000..d22b35830
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/errors/SourceNotDefindedException.java
@@ -0,0 +1,8 @@
+package digital.slovensko.autogram.core.errors;
+
+public class SourceNotDefindedException extends AutogramException {
+ public SourceNotDefindedException() {
+ super("Nastala chyba", "Zdrojový súbor / adresár nebol definovaný", "Nezadali ste zdrojový súbor / adresár na podpis");
+ }
+
+}
diff --git a/src/main/java/digital/slovensko/autogram/core/errors/TargetAlreadyExistsException.java b/src/main/java/digital/slovensko/autogram/core/errors/TargetAlreadyExistsException.java
new file mode 100644
index 000000000..08da262de
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/errors/TargetAlreadyExistsException.java
@@ -0,0 +1,7 @@
+package digital.slovensko.autogram.core.errors;
+
+public class TargetAlreadyExistsException extends AutogramException {
+ public TargetAlreadyExistsException() {
+ super("Nastala chyba", "Cieľový súbor / adresár už existuje", "Zadali ste cieľový súbor / adresár, ktorý už existuje");
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/core/errors/TargetDirectoryDoesNotExistException.java b/src/main/java/digital/slovensko/autogram/core/errors/TargetDirectoryDoesNotExistException.java
new file mode 100644
index 000000000..a54324243
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/errors/TargetDirectoryDoesNotExistException.java
@@ -0,0 +1,7 @@
+package digital.slovensko.autogram.core.errors;
+
+public class TargetDirectoryDoesNotExistException extends AutogramException {
+ public TargetDirectoryDoesNotExistException() {
+ super("Nastala chyba", "Cieľový adresár neexistuje", "Zadali ste cieľový adresár, ktorý neexistuje");
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/core/errors/TokenDriverDoesNotExistException.java b/src/main/java/digital/slovensko/autogram/core/errors/TokenDriverDoesNotExistException.java
new file mode 100644
index 000000000..eb8b5ff30
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/errors/TokenDriverDoesNotExistException.java
@@ -0,0 +1,11 @@
+package digital.slovensko.autogram.core.errors;
+
+public class TokenDriverDoesNotExistException extends AutogramException {
+ public TokenDriverDoesNotExistException() {
+ super("Nastala chyba", "Token driver neexistuje", "Zadali ste token driver, ktorý neexistuje");
+ }
+
+ public TokenDriverDoesNotExistException(String tokenDriver) {
+ super("Nastala chyba", "Token driver neexistuje", "Zadali ste token driver \"" + tokenDriver + "\", ktorý neexistuje");
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/core/errors/UnableToCreateDirectoryException.java b/src/main/java/digital/slovensko/autogram/core/errors/UnableToCreateDirectoryException.java
new file mode 100644
index 000000000..21c611dd0
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/errors/UnableToCreateDirectoryException.java
@@ -0,0 +1,8 @@
+package digital.slovensko.autogram.core.errors;
+
+public class UnableToCreateDirectoryException extends AutogramException {
+ public UnableToCreateDirectoryException() {
+ super("Nastala chyba", "Nepodarilo sa vytvoriť adresár", "Nepodarilo sa vytvoriť adresár");
+ }
+
+}
diff --git a/src/main/java/digital/slovensko/autogram/drivers/PKCS11TokenDriver.java b/src/main/java/digital/slovensko/autogram/drivers/PKCS11TokenDriver.java
index c8d3c7d70..070b3e1c9 100644
--- a/src/main/java/digital/slovensko/autogram/drivers/PKCS11TokenDriver.java
+++ b/src/main/java/digital/slovensko/autogram/drivers/PKCS11TokenDriver.java
@@ -7,8 +7,8 @@
import java.security.KeyStore;
public class PKCS11TokenDriver extends TokenDriver {
- public PKCS11TokenDriver(String name, Path path, boolean needsPassword) {
- super(name, path, needsPassword);
+ public PKCS11TokenDriver(String name, Path path, boolean needsPassword, String shortname) {
+ super(name, path, needsPassword, shortname);
}
@Override
diff --git a/src/main/java/digital/slovensko/autogram/drivers/TokenDriver.java b/src/main/java/digital/slovensko/autogram/drivers/TokenDriver.java
index df539da28..14397c939 100644
--- a/src/main/java/digital/slovensko/autogram/drivers/TokenDriver.java
+++ b/src/main/java/digital/slovensko/autogram/drivers/TokenDriver.java
@@ -1,20 +1,20 @@
package digital.slovensko.autogram.drivers;
-import digital.slovensko.autogram.util.OperatingSystem;
import eu.europa.esig.dss.token.AbstractKeyStoreTokenConnection;
import java.nio.file.Path;
-import java.util.List;
public abstract class TokenDriver {
protected final String name;
private final Path path;
private final boolean needsPassword;
+ private final String shortname;
- public TokenDriver(String name, Path path, boolean needsPassword) {
+ public TokenDriver(String name, Path path, boolean needsPassword, String shortname) {
this.name = name;
this.path = path;
this.needsPassword = needsPassword;
+ this.shortname = shortname;
}
public String getName() {
@@ -36,4 +36,8 @@ public boolean isInstalled() {
public boolean needsPassword() {
return needsPassword;
}
+
+ public String getShortname() {
+ return shortname;
+ }
}
diff --git a/src/main/java/digital/slovensko/autogram/server/SignEndpoint.java b/src/main/java/digital/slovensko/autogram/server/SignEndpoint.java
index 714be6a13..1782459da 100644
--- a/src/main/java/digital/slovensko/autogram/server/SignEndpoint.java
+++ b/src/main/java/digital/slovensko/autogram/server/SignEndpoint.java
@@ -5,7 +5,6 @@
import com.sun.net.httpserver.HttpHandler;
import digital.slovensko.autogram.core.Autogram;
import digital.slovensko.autogram.core.SigningJob;
-import digital.slovensko.autogram.core.errors.AutogramException;
import digital.slovensko.autogram.core.visualization.DocumentVisualizationBuilder;
import digital.slovensko.autogram.server.dto.ErrorResponse;
import digital.slovensko.autogram.server.dto.SignRequestBody;
diff --git a/src/main/java/digital/slovensko/autogram/server/dto/ErrorResponse.java b/src/main/java/digital/slovensko/autogram/server/dto/ErrorResponse.java
index 08f0346a7..afceb0c43 100644
--- a/src/main/java/digital/slovensko/autogram/server/dto/ErrorResponse.java
+++ b/src/main/java/digital/slovensko/autogram/server/dto/ErrorResponse.java
@@ -1,11 +1,6 @@
package digital.slovensko.autogram.server.dto;
import digital.slovensko.autogram.core.errors.AutogramException;
-import digital.slovensko.autogram.core.errors.SigningCanceledByUserException;
-import digital.slovensko.autogram.core.errors.UnrecognizedException;
-import digital.slovensko.autogram.server.errors.MalformedBodyException;
-import digital.slovensko.autogram.server.errors.RequestValidationException;
-import digital.slovensko.autogram.server.errors.UnsupportedSignatureLevelExceptionError;
public class ErrorResponse {
private final int statusCode;
diff --git a/src/main/java/digital/slovensko/autogram/server/dto/InfoResponse.java b/src/main/java/digital/slovensko/autogram/server/dto/InfoResponse.java
index cb9ae3c3f..36673af3e 100644
--- a/src/main/java/digital/slovensko/autogram/server/dto/InfoResponse.java
+++ b/src/main/java/digital/slovensko/autogram/server/dto/InfoResponse.java
@@ -1,8 +1,5 @@
package digital.slovensko.autogram.server.dto;
-import digital.slovensko.autogram.Main;
-import static java.util.Objects.requireNonNullElse;
-
public class InfoResponse {
private final String version;
private final String status;
diff --git a/src/main/java/digital/slovensko/autogram/server/dto/ServerSigningParameters.java b/src/main/java/digital/slovensko/autogram/server/dto/ServerSigningParameters.java
index 69f8b9c99..f50099e02 100644
--- a/src/main/java/digital/slovensko/autogram/server/dto/ServerSigningParameters.java
+++ b/src/main/java/digital/slovensko/autogram/server/dto/ServerSigningParameters.java
@@ -11,12 +11,7 @@
import digital.slovensko.autogram.server.errors.UnsupportedSignatureLevelExceptionError;
import eu.europa.esig.dss.enumerations.*;
-import javax.xml.crypto.dsig.CanonicalizationMethod;
import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Base64;
-
-import static digital.slovensko.autogram.server.dto.ServerSigningParameters.LocalCanonicalizationMethod.*;
public class ServerSigningParameters {
public enum LocalCanonicalizationMethod {
diff --git a/src/main/java/digital/slovensko/autogram/ui/SaveFileResponder.java b/src/main/java/digital/slovensko/autogram/ui/SaveFileResponder.java
index b249ff3b6..fe00721d0 100644
--- a/src/main/java/digital/slovensko/autogram/ui/SaveFileResponder.java
+++ b/src/main/java/digital/slovensko/autogram/ui/SaveFileResponder.java
@@ -1,29 +1,34 @@
package digital.slovensko.autogram.ui;
-import com.google.common.io.Files;
import digital.slovensko.autogram.core.Autogram;
import digital.slovensko.autogram.core.Responder;
import digital.slovensko.autogram.core.SignedDocument;
+import digital.slovensko.autogram.core.TargetPath;
import digital.slovensko.autogram.core.errors.AutogramException;
import java.io.File;
import java.io.IOException;
-import java.nio.file.Paths;
public class SaveFileResponder extends Responder {
private final File file;
private final Autogram autogram;
+ private final TargetPath targetPathBuilder;
public SaveFileResponder(File file, Autogram autogram) {
+ this(file, autogram, TargetPath.fromSource(file.toPath()));
+ }
+
+ public SaveFileResponder(File file, Autogram autogram, TargetPath targetPathBuilder) {
this.file = file;
this.autogram = autogram;
+ this.targetPathBuilder = targetPathBuilder;
}
public void onDocumentSigned(SignedDocument signedDocument) {
try {
- var targetFile = getTargetFile();
- signedDocument.getDocument().save(targetFile.getPath());
- autogram.onDocumentSaved(targetFile);
+ var targetFile = targetPathBuilder.getSaveFilePath(file.toPath());
+ signedDocument.getDocument().save(targetFile.toString());
+ autogram.onDocumentSaved(targetFile.toFile());
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -32,25 +37,4 @@ public void onDocumentSigned(SignedDocument signedDocument) {
public void onDocumentSignFailed(AutogramException error) {
System.err.println("Sign failed error occurred: " + error.toString());
}
-
- private File getTargetFile() {
- var directory = file.getParent();
- var name = Files.getNameWithoutExtension(file.getName());
-
- var extension = ".asice";
- if (file.getName().endsWith(".pdf"))
- extension = ".pdf";
-
- var baseName = Paths.get(directory, name + "_signed").toString();
- var newBaseName = baseName;
-
- var count = 1;
- while(true) {
- var targetFile = new File(newBaseName + extension);
- if(!targetFile.exists()) return targetFile;
-
- newBaseName = baseName + " (" + count + ")";
- count++;
- }
- }
}
diff --git a/src/main/java/digital/slovensko/autogram/ui/cli/CliApp.java b/src/main/java/digital/slovensko/autogram/ui/cli/CliApp.java
new file mode 100644
index 000000000..d2f53bc7d
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/ui/cli/CliApp.java
@@ -0,0 +1,58 @@
+package digital.slovensko.autogram.ui.cli;
+
+import digital.slovensko.autogram.core.Autogram;
+import digital.slovensko.autogram.core.CliParameters;
+import digital.slovensko.autogram.core.SigningJob;
+import digital.slovensko.autogram.core.errors.SourceNotDefindedException;
+import digital.slovensko.autogram.core.TargetPath;
+import digital.slovensko.autogram.core.errors.AutogramException;
+import digital.slovensko.autogram.core.errors.SourceDoesNotExistException;
+import digital.slovensko.autogram.ui.SaveFileResponder;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.commons.cli.CommandLine;
+
+public class CliApp {
+ public static void start(CommandLine cmd) {
+ var ui = new CliUI();
+
+ try {
+ var params = new CliParameters(cmd);
+
+ var autogram = params.getDriver() == null ? new Autogram(ui)
+ : new Autogram(ui, () -> Collections.singletonList(params.getDriver()));
+
+ if (params.getSource() == null)
+ throw new SourceNotDefindedException();
+
+ if (!params.getSource().exists())
+ throw new SourceDoesNotExistException();
+
+ var targetPathBuilder = TargetPath.fromParams(params);
+ targetPathBuilder.mkdirIfDir();
+
+ var source = params.getSource();
+ var sourceList = source.isDirectory() ? source.listFiles() : new File[] { source };
+ var jobs = Arrays
+ .stream(sourceList).filter(f -> f.isFile()).map(f -> SigningJob.buildFromFile(f,
+ new SaveFileResponder(f, autogram, targetPathBuilder), params.shouldCheckPDFACompliance()))
+ .toList();
+ if (params.shouldCheckPDFACompliance()) {
+ jobs.forEach(job -> {
+ System.out.println("Checking PDF/A file compatibility for " + job.getDocument().getName());
+ autogram.checkPDFACompliance(job);
+ });
+ }
+
+ ui.setJobsCount(jobs.size());
+
+ jobs.forEach(autogram::sign);
+
+ } catch (AutogramException e) {
+ ui.showError(e);
+ }
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/ui/cli/CliUI.java b/src/main/java/digital/slovensko/autogram/ui/cli/CliUI.java
index ae63bd625..f8dcb147c 100644
--- a/src/main/java/digital/slovensko/autogram/ui/cli/CliUI.java
+++ b/src/main/java/digital/slovensko/autogram/ui/cli/CliUI.java
@@ -1,14 +1,14 @@
package digital.slovensko.autogram.ui.cli;
-import digital.slovensko.autogram.core.Autogram;
-import digital.slovensko.autogram.core.SigningJob;
-import digital.slovensko.autogram.core.SigningKey;
-import digital.slovensko.autogram.core.errors.AutogramException;
-import digital.slovensko.autogram.core.visualization.Visualization;
+import digital.slovensko.autogram.Main;
+import digital.slovensko.autogram.core.*;
+import digital.slovensko.autogram.core.errors.*;
import digital.slovensko.autogram.drivers.TokenDriver;
import digital.slovensko.autogram.ui.UI;
+import digital.slovensko.autogram.core.visualization.Visualization;
import digital.slovensko.autogram.ui.gui.IgnorableException;
-import digital.slovensko.autogram.util.DSSUtils;
+import static digital.slovensko.autogram.util.DSSUtils.parseCN;
+
import eu.europa.esig.dss.token.DSSPrivateKeyEntry;
import java.io.File;
@@ -18,29 +18,42 @@
public class CliUI implements UI {
SigningKey activeKey;
+ int nJobsSigned = 1;
+ int nJobsTotal = 0;
@Override
public void startSigning(SigningJob job, Autogram autogram) {
- System.out.println("Starting signing for " + job);
if (activeKey == null) {
autogram.pickSigningKeyAndThen(key -> {
activeKey = key;
- autogram.sign(job, activeKey);
+ sign(job, autogram);
});
} else {
- autogram.sign(job, activeKey);
+ sign(job, autogram);
}
}
+ private void sign(SigningJob job, Autogram autogram) {
+ System.out.println("Starting signing file \"%s\" [%d/%d]".formatted(job.getDocument().getName(), nJobsSigned++, nJobsTotal));
+ autogram.sign(job, activeKey);
+ }
+
+ public void setJobsCount(int nJobsTotal) {
+ this.nJobsTotal = nJobsTotal;
+ }
+
@Override
public void pickTokenDriverAndThen(List drivers, Consumer callback) {
TokenDriver pickedDriver;
- if (drivers.size() == 1) {
+ if (drivers.isEmpty()) {
+ showError(new NoDriversDetectedException());
+ return;
+ } else if (drivers.size() == 1) {
pickedDriver = drivers.get(0);
} else {
var i = new AtomicInteger(1);
- System.out.println("Vyberte ulozisko certifikatov");
+ System.out.println("Pick driver:");
drivers.forEach(driver -> {
System.out.print("[" + i + "] ");
System.out.println(driver.getName());
@@ -57,19 +70,34 @@ public void requestPasswordAndThen(TokenDriver driver, Consumer callback
callback.accept(null);
return;
}
- System.out.println("Zadajte bezpecnostny kod k ulozisku certifikatov: ");
- callback.accept(CliUtils.readLine()); // TODO do not show pin
+
+ // Read password from CLI
+ var password = System.console().readPassword("Enter security code for driver (hidden): ");
+ callback.accept(password);
}
@Override
public void pickKeyAndThen(List keys, Consumer callback) {
- if (keys.size() > 1) {
- System.out.println("Found multiple keys:");
- keys.forEach(key -> System.out.println(DSSUtils.buildTooltipLabel(key)));
+ if (keys.isEmpty()) {
+ showError(new NoKeysDetectedException());
+ return;
}
- System.out.println("Picking key: " + DSSUtils.buildTooltipLabel(keys.get(0)));
- callback.accept(keys.get(0));
+ if (keys.size() == 1) {
+ callback.accept(keys.get(0));
+ return;
+ }
+
+ var i = new AtomicInteger(1);
+ System.out.println("Pick Key:");
+ keys.forEach(key -> {
+ System.out.print("[" + i + "] ");
+ System.out.println(parseCN(key.getCertificate().getSubject().getRFC2253()));
+ i.addAndGet(1);
+ });
+ var pickedKey = keys.get(CliUtils.readInteger() - 1);
+
+ callback.accept(pickedKey);
}
@Override
@@ -84,36 +112,50 @@ public void onUIThreadDo(Runnable callback) {
@Override
public void onSigningSuccess(SigningJob job) {
- System.out.println("Success for " + job);
+
}
@Override
public void onSigningFailed(AutogramException e) {
- System.err.println(e);
+ throw e;
}
@Override
- public void onDocumentSaved(File filename) {
-
+ public void onDocumentSaved(File file) {
+ var directory = file.getParent() != null ? " in \"%s\"".formatted(file.getParent()) : "";
+ System.out.println("File successfully signed. Signed file saved as \"%s\"".formatted(file.getName()) + directory);
}
@Override
public void onPickSigningKeyFailed(AutogramException e) {
- System.err.println(e);
+ showError(e);
}
@Override
public void onUpdateAvailable() {
- System.out.println("Newer version of Autogram exists. Visit ");
+ System.out.println("Nová verzia");
+ System.out.println(String.format(
+ "Je dostupná nová verzia a odporúčame stiahnuť aktualizáciu. Najnovšiu verziu si možete vždy stiahnuť na %s.",
+ Updater.LATEST_RELEASE_URL));
}
@Override
public void onAboutInfo() {
- System.out.println("About autograms");
+ System.out.println(
+ """
+ O projekte Autogram
+ Autogram je jednoduchý nástroj na podpisovanie podľa európskej regulácie eIDAS, slovenských zákonov a štandardov. Môžete ho používať komerčne aj nekomerčne a úplne zadarmo.
+ Autori a sponzori
+ Autormi tohto projektu sú Jakub Ďuraš, Slovensko.Digital, CRYSTAL CONSULTING, s.r.o, Solver IT s.r.o. a ďalší spoluautori.
+ Licencia a zdrojové kódy
+ Tento softvér pôvodne vychádza projektu z Octosign White Label od Jakuba Ďuraša, ktorý je licencovaný pod MIT licenciou. So súhlasom autora je táto verzia distribuovaná pod licenciou EUPL v1.2.
+ Zdrojové kódy sú dostupné na https://github.com/slovensko-digital/autogram.""");
+ System.out.println(String.format("Verzia: %s", Main.getVersion()));
}
@Override
public void onPDFAComplianceCheckFailed(SigningJob job) {
+ throw new PDFAComplianceException();
}
@Override
@@ -123,6 +165,51 @@ public void showVisualization(Visualization visualization, Autogram autogram) {
@Override
public void showIgnorableExceptionDialog(IgnorableException exception) {
+ throw exception;
+ }
+ public void showError(AutogramException e) {
+ String errMessage = "";
+ if (e instanceof FunctionCanceledException) {
+ errMessage = "No security code entered";
+ } else if (e instanceof InitializationFailedException) {
+ errMessage = "Unable to read card";
+ } else if (e instanceof NoDriversDetectedException) {
+ errMessage = "No available drivers found";
+ } else if (e instanceof NoKeysDetectedException) {
+ errMessage = "No signing keys found";
+ } else if (e instanceof PDFAComplianceException) {
+ errMessage = "Document is not PDF/A compliant";
+ } else if (e instanceof PINIncorrectException) {
+ errMessage = "Incorrect security code";
+ } else if (e instanceof PINLockedException) {
+ errMessage = "PIN is blocked";
+ } else if (e instanceof SigningCanceledByUserException) {
+ errMessage = "Signing canceled by user";
+ } else if (e instanceof SigningWithExpiredCertificateException) {
+ errMessage = "Signing with expired certificate";
+ } else if (e instanceof TokenNotRecognizedException) {
+ errMessage = "Token not recognized";
+ } else if (e instanceof TokenRemovedException) {
+ errMessage = "Token removed";
+ } else if (e instanceof TargetAlreadyExistsException) {
+ errMessage = "Target already exists";
+ } else if (e instanceof SourceAndTargetTypeMismatchException) {
+ errMessage = "Source and target type mismatch (file / directory)";
+ } else if (e instanceof SourceDoesNotExistException) {
+ errMessage = "Source does not exist";
+ } else if (e instanceof SourceNotDefindedException) {
+ errMessage = "Source not defined";
+ } else if (e instanceof UnableToCreateDirectoryException) {
+ errMessage = "Unable to create directory";
+ } else if (e instanceof TokenDriverDoesNotExistException) {
+ errMessage = "Token driver does not exist";
+ } else if (e instanceof TargetDirectoryDoesNotExistException) {
+ errMessage = "Target directory does not exist";
+ } else {
+ errMessage = "Unknown error occurred";
+ e.printStackTrace();
+ }
+ System.err.println(errMessage);
}
}
diff --git a/src/main/java/digital/slovensko/autogram/ui/gui/MainMenuController.java b/src/main/java/digital/slovensko/autogram/ui/gui/MainMenuController.java
index 1a419fe16..727fa7564 100644
--- a/src/main/java/digital/slovensko/autogram/ui/gui/MainMenuController.java
+++ b/src/main/java/digital/slovensko/autogram/ui/gui/MainMenuController.java
@@ -2,6 +2,7 @@
import digital.slovensko.autogram.core.Autogram;
import digital.slovensko.autogram.core.SigningJob;
+import digital.slovensko.autogram.ui.SaveFileResponder;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.input.TransferMode;
@@ -38,7 +39,8 @@ public void initialize() {
dropZone.setOnDragDropped(event -> {
for (File file : event.getDragboard().getFiles()) {
- autogram.sign(SigningJob.buildFromFile(file, autogram));
+ SigningJob job = SigningJob.buildFromFile(file, new SaveFileResponder(file, autogram), false);
+ autogram.sign(job);
}
});
}
@@ -49,7 +51,8 @@ public void onUploadButtonAction() {
if (list != null) {
for (File file : list) {
- autogram.sign(SigningJob.buildFromFile(file, autogram));
+ SigningJob job = SigningJob.buildFromFile(file, new SaveFileResponder(file, autogram), false);
+ autogram.sign(job);
}
}
}
diff --git a/src/main/java/digital/slovensko/autogram/ui/gui/PasswordController.java b/src/main/java/digital/slovensko/autogram/ui/gui/PasswordController.java
index f5a244bb6..f6317d1a7 100644
--- a/src/main/java/digital/slovensko/autogram/ui/gui/PasswordController.java
+++ b/src/main/java/digital/slovensko/autogram/ui/gui/PasswordController.java
@@ -4,7 +4,6 @@
import javafx.scene.control.PasswordField;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
-import javafx.stage.Stage;
import java.util.function.Consumer;
diff --git a/src/main/java/digital/slovensko/autogram/ui/gui/PickDriverDialogController.java b/src/main/java/digital/slovensko/autogram/ui/gui/PickDriverDialogController.java
index be2441b6a..48dfc8a9a 100644
--- a/src/main/java/digital/slovensko/autogram/ui/gui/PickDriverDialogController.java
+++ b/src/main/java/digital/slovensko/autogram/ui/gui/PickDriverDialogController.java
@@ -6,7 +6,6 @@
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
-import javafx.stage.Stage;
import java.util.List;
import java.util.function.Consumer;
diff --git a/src/main/java/digital/slovensko/autogram/ui/gui/PickKeyDialogController.java b/src/main/java/digital/slovensko/autogram/ui/gui/PickKeyDialogController.java
index fb42b41d6..79b181611 100644
--- a/src/main/java/digital/slovensko/autogram/ui/gui/PickKeyDialogController.java
+++ b/src/main/java/digital/slovensko/autogram/ui/gui/PickKeyDialogController.java
@@ -8,7 +8,6 @@
import javafx.scene.control.Tooltip;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
-import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.List;
diff --git a/src/main/java/digital/slovensko/autogram/ui/gui/SigningDialogController.java b/src/main/java/digital/slovensko/autogram/ui/gui/SigningDialogController.java
index 13e42ff55..a6c742566 100644
--- a/src/main/java/digital/slovensko/autogram/ui/gui/SigningDialogController.java
+++ b/src/main/java/digital/slovensko/autogram/ui/gui/SigningDialogController.java
@@ -1,15 +1,11 @@
package digital.slovensko.autogram.ui.gui;
import digital.slovensko.autogram.core.Autogram;
-import digital.slovensko.autogram.core.SigningJob;
import digital.slovensko.autogram.core.SigningKey;
import digital.slovensko.autogram.core.visualization.Visualization;
import digital.slovensko.autogram.ui.Visualizer;
import digital.slovensko.autogram.util.DSSUtils;
import eu.europa.esig.dss.model.CommonDocument;
-import javafx.animation.Interpolator;
-import javafx.animation.RotateTransition;
-import javafx.animation.Timeline;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.event.Event;
@@ -23,7 +19,6 @@
import javafx.scene.image.ImageView;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.layout.VBox;
-import javafx.scene.transform.Rotate;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
diff --git a/src/main/java/digital/slovensko/autogram/util/OperatingSystem.java b/src/main/java/digital/slovensko/autogram/util/OperatingSystem.java
index 3c63a8fe3..b4541ab36 100644
--- a/src/main/java/digital/slovensko/autogram/util/OperatingSystem.java
+++ b/src/main/java/digital/slovensko/autogram/util/OperatingSystem.java
@@ -17,7 +17,7 @@ public static OperatingSystem current() {
} else if (osName.contains("nux")) {
return LINUX;
} else {
- return null;
+ throw new RuntimeException("Unsupported OS");
}
}
}
diff --git a/src/test/java/digital/slovensko/autogram/AutogramTests.java b/src/test/java/digital/slovensko/autogram/AutogramTests.java
index 9d83b6def..4ae981f2a 100644
--- a/src/test/java/digital/slovensko/autogram/AutogramTests.java
+++ b/src/test/java/digital/slovensko/autogram/AutogramTests.java
@@ -75,7 +75,7 @@ public List getAvailableDrivers() {
private static class FakeTokenDriver extends TokenDriver {
public FakeTokenDriver(String name) {
- super(name, Path.of(""), true);
+ super(name, Path.of(""), true, "fake");
}
@Override
@@ -92,7 +92,7 @@ public AbstractKeyStoreTokenConnection createTokenWithPassword(char[] password)
private static class FakeTokenDriverWithExpiredCertificate extends TokenDriver {
public FakeTokenDriverWithExpiredCertificate() {
- super("fake-token-driver-with-expired-certificate", Path.of(""), true);
+ super("fake-token-driver-with-expired-certificate", Path.of(""), true, "fake");
}
@Override
diff --git a/src/test/java/digital/slovensko/autogram/XDCTransformerTests.java b/src/test/java/digital/slovensko/autogram/XDCTransformerTests.java
index 03eef0b1c..d16d1ee46 100644
--- a/src/test/java/digital/slovensko/autogram/XDCTransformerTests.java
+++ b/src/test/java/digital/slovensko/autogram/XDCTransformerTests.java
@@ -4,7 +4,6 @@
import digital.slovensko.autogram.core.XDCTransformer;
import eu.europa.esig.dss.enumerations.ASiCContainerType;
import eu.europa.esig.dss.enumerations.DigestAlgorithm;
-import eu.europa.esig.dss.enumerations.MimeType;
import eu.europa.esig.dss.enumerations.MimeTypeEnum;
import eu.europa.esig.dss.enumerations.SignatureLevel;
import eu.europa.esig.dss.enumerations.SignaturePackaging;
diff --git a/src/test/java/digital/slovensko/autogram/core/TargetPathTest.java b/src/test/java/digital/slovensko/autogram/core/TargetPathTest.java
new file mode 100644
index 000000000..2a834cb7e
--- /dev/null
+++ b/src/test/java/digital/slovensko/autogram/core/TargetPathTest.java
@@ -0,0 +1,268 @@
+package digital.slovensko.autogram.core;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.Test;
+
+import com.google.common.jimfs.Jimfs;
+
+public class TargetPathTest {
+ // @Rule
+ // public MockitoRule rule =
+ // MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+
+ /**
+ * Used in GUI mode with single file
+ * or used in CLI mode without target eg. `--cli -s /test/virtual/source.pdf`
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testSingleFileNoTarget() throws IOException {
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceFile = fs.getPath("/test/virtual/source.pdf");
+ Files.createDirectories(sourceFile.getParent());
+ Files.createFile(sourceFile);
+
+ var targetPath = new TargetPath(null, sourceFile, false, false, fs);
+ var target = targetPath.getSaveFilePath(sourceFile);
+
+ assertEqualPath(fs, "/test/virtual/source_signed.pdf", target);
+ }
+
+ /**
+ * Used in GUI mode with single file
+ * or used in CLI mode without target eg. `--cli -s source.pdf` on path `/test/virtual/`
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testSingleFileNoTargetNoParent() throws IOException {
+ var config = com.google.common.jimfs.Configuration.unix().toBuilder().setWorkingDirectory("/test/virtual/").build();
+ FileSystem fs = Jimfs.newFileSystem(config);
+ Files.createDirectories(fs.getPath("/test/virtual/"));
+ var sourceFile = fs.getPath("source.pdf");
+ Files.createFile(sourceFile);
+
+ var targetPath = new TargetPath(null, sourceFile, false, false, fs);
+ var target = targetPath.getSaveFilePath(sourceFile);
+
+ assertEqualPath(fs, "/test/virtual/source_signed.pdf", target);
+ }
+
+ /**
+ * Used in GUI mode with single file and no target when generated target file
+ * exits
+ * or used in CLI mode without target eg. `--cli -s /test/virtual/source.pdf`
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testSingleFileNoTargetFileExists() throws IOException {
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceFile = fs.getPath("/test/virtual/source.pdf");
+ Files.createDirectories(sourceFile.getParent());
+ Files.createFile(sourceFile);
+ Files.createFile(fs.getPath("/test/virtual/source_signed.pdf"));
+
+ var targetPath = new TargetPath(null, sourceFile, false, false, fs);
+ var target = targetPath.getSaveFilePath(sourceFile);
+
+ assertEqualPath(fs, "/test/virtual/source_signed (1).pdf", target);
+ }
+
+ /**
+ * Used in GUI mode with single file
+ * or used in CLI mode without target eg. `--cli -s /test/virtual/source.pdf`
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testSingleFileNoTargetAsice() throws IOException {
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceFile = fs.getPath("/test/virtual/source.xml");
+ Files.createDirectories(sourceFile.getParent());
+ Files.createFile(sourceFile);
+
+ var targetPath = new TargetPath(null, sourceFile, false, false, fs);
+ var target = targetPath.getSaveFilePath(sourceFile);
+
+ assertEqualPath(fs, "/test/virtual/source_signed.asice", target);
+ }
+
+ /**
+ * Used in CLI mode eg. `--cli -s /test/virtual/source.pdf -t
+ * /test/virtual/target.pdf`
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testSingleFileWithTarget() throws IOException {
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceFile = fs.getPath("/test/virtual/source.pdf");
+ Files.createDirectories(sourceFile.getParent());
+ Files.createFile(sourceFile);
+
+ var targetPath = new TargetPath("/test/virtual/other/target.pdf", sourceFile, false, false, fs);
+ var target = targetPath.getSaveFilePath(sourceFile);
+
+ assertEqualPath(fs, "/test/virtual/other/target.pdf", target);
+ }
+
+
+
+ /**
+ * `--cli -s /test/virtual/ -t /test/virtual/target/`
+ */
+ @Test
+ public void testDirectoryWithTarget() throws IOException {
+
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceDirectory = fs.getPath("/test/virtual/");
+ Files.createDirectories(sourceDirectory);
+
+ var source1 = fs.getPath("/test/virtual/source", "source1.pdf");
+ var source2 = fs.getPath("/test/virtual/source", "source2.pdf");
+
+ var targetPath = new TargetPath("/test/virtual/target/", sourceDirectory, false, false, fs);
+ var target1 = targetPath.getSaveFilePath(source1);
+ var target2 = targetPath.getSaveFilePath(source2);
+
+ assertEqualPath(fs, "/test/virtual/target/source1_signed.pdf", target1);
+ assertEqualPath(fs, "/test/virtual/target/source2_signed.pdf", target2);
+ }
+
+ /**
+ * `--cli -s /test/virtual/`
+ */
+ @Test
+ public void testDirectoryNoTarget() throws IOException {
+
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceDirectory = fs.getPath("/test/virtual/source/");
+ Files.createDirectories(sourceDirectory);
+
+ var source1 = fs.getPath("/test/virtual/source", "source1.pdf");
+ var source2 = fs.getPath("/test/virtual/source", "source2.pdf");
+
+ var targetPath = new TargetPath(null, sourceDirectory, false, false, fs);
+ var target1 = targetPath.getSaveFilePath(source1);
+ var target2 = targetPath.getSaveFilePath(source2);
+
+ assertEqualPath(fs, "/test/virtual/source_signed/source1_signed.pdf", target1);
+ assertEqualPath(fs, "/test/virtual/source_signed/source2_signed.pdf", target2);
+ }
+
+
+ /**
+ * `--cli -s /test/virtual/`
+ */
+ @Test
+ public void testDirectoryNoTargetNoParent() throws IOException {
+
+ var config = com.google.common.jimfs.Configuration.unix().toBuilder().setWorkingDirectory("/test/virtual/").build();
+ FileSystem fs = Jimfs.newFileSystem(config);
+ var sourceDirectory = fs.getPath("source/");
+ Files.createDirectories(sourceDirectory);
+
+ var source1 = fs.getPath("source", "source1.pdf");
+ var source2 = fs.getPath("source", "source2.pdf");
+
+ var targetPath = new TargetPath(null, sourceDirectory, false, false, fs);
+ var target1 = targetPath.getSaveFilePath(source1);
+ var target2 = targetPath.getSaveFilePath(source2);
+
+ assertEqualPath(fs, "/test/virtual/source_signed/source1_signed.pdf", target1);
+ assertEqualPath(fs, "/test/virtual/source_signed/source2_signed.pdf", target2);
+ }
+
+ @Test
+ public void testMkdirIfDirNotExists() throws IllegalArgumentException,
+ IllegalAccessException, IOException {
+
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceDirectory = fs.getPath("/test/virtual/source");
+ Files.createDirectories(sourceDirectory);
+
+ var targetPath = new TargetPath(null, sourceDirectory, false, false, fs);
+ targetPath.mkdirIfDir();
+
+ assertTrue(Files.exists(fs.getPath("/test/virtual/source_signed")));
+ }
+
+ @Test()
+ public void testTargetDirExits() throws IllegalArgumentException,
+ IllegalAccessException, IOException {
+
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceDirectory = fs.getPath("/test/virtual/");
+ Files.createDirectories(sourceDirectory);
+ Files.createDirectories(fs.getPath("/test/output"));
+
+ assertThrows(digital.slovensko.autogram.core.errors.TargetAlreadyExistsException.class, () -> {
+ var targetPath = new TargetPath("/test/output", sourceDirectory, false, false, fs);
+ });
+ }
+
+ @Test()
+ public void testTargetFileExits() throws IllegalArgumentException,
+ IllegalAccessException, IOException {
+
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceFile = fs.getPath("/test/virtual/source.pdf");
+ Files.createDirectories(sourceFile.getParent());
+ Files.createFile(sourceFile);
+ Files.createFile(fs.getPath("/test/output.pdf"));
+
+ assertThrows(digital.slovensko.autogram.core.errors.TargetAlreadyExistsException.class, () -> {
+ var targetPath = new TargetPath("/test/output.pdf", sourceFile, false, false, fs);
+ });
+ }
+
+ @Test()
+ public void testMkdirIfDirExistsForce() throws IllegalArgumentException,
+ IllegalAccessException, IOException {
+
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceDirectory = fs.getPath("/test/virtual/");
+ Files.createDirectories(sourceDirectory);
+ Files.createDirectories(fs.getPath("/test/output"));
+
+ var targetPath = new TargetPath("/test/output", sourceDirectory, true, false, fs);
+ targetPath.mkdirIfDir();
+ }
+
+ @Test()
+ public void testMkdirIfDirExistsParents() throws IllegalArgumentException,
+ IllegalAccessException, IOException {
+
+ FileSystem fs = Jimfs.newFileSystem(com.google.common.jimfs.Configuration.unix());
+ var sourceDirectory = fs.getPath("/test/virtual/");
+ Files.createDirectories(sourceDirectory);
+ var targetPath = new TargetPath("/test/output/parent/directories", sourceDirectory, false, true, fs);
+ targetPath.mkdirIfDir();
+
+ }
+
+ /* Assert helpers */
+
+ private void assertEqualPath(FileSystem fs, String expected, String actual) {
+ assertEqualPath(fs.getPath(expected), fs.getPath(actual));
+ }
+
+ private void assertEqualPath(FileSystem fs, String expected, Path actual) {
+ assertEqualPath(fs.getPath(expected), actual);
+ }
+
+ private void assertEqualPath(Path expected, Path actual) {
+ assertEquals(expected.normalize().toString(), actual.normalize().toString());
+ }
+
+}