From efec4d911055c40c02f6e509c10faf7716790b10 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 9 Jan 2023 14:56:53 +0100 Subject: [PATCH] Wip: working extract-cert, fix generate-key parameter passing --- .../main/java/sop/external/ExternalSOP.java | 141 +++++++++++++++++- .../operation/DetachedSignExternal.java | 43 ++++++ .../operation/ExtractCertExternal.java | 30 +++- .../operation/GenerateKeyExternal.java | 18 ++- .../external/operation/VersionExternal.java | 22 ++- .../main/resources/sop/external/.gitignore | 3 +- .../sop/external/AbstractExternalSOPTest.java | 75 ++++++++++ .../sop/external/ExternalExtractCertTest.java | 24 +++ .../sop/external/ExternalGenerateKeyTest.java | 30 ++++ .../java/sop/external/ExternalSOPTest.java | 100 ------------- .../sop/external/ExternalVersionTest.java | 40 +++++ .../java/sop/exception/SOPGPException.java | 26 +++- 12 files changed, 430 insertions(+), 122 deletions(-) create mode 100644 external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java create mode 100644 external-sop/src/test/java/sop/external/AbstractExternalSOPTest.java create mode 100644 external-sop/src/test/java/sop/external/ExternalExtractCertTest.java create mode 100644 external-sop/src/test/java/sop/external/ExternalGenerateKeyTest.java delete mode 100644 external-sop/src/test/java/sop/external/ExternalSOPTest.java create mode 100644 external-sop/src/test/java/sop/external/ExternalVersionTest.java diff --git a/external-sop/src/main/java/sop/external/ExternalSOP.java b/external-sop/src/main/java/sop/external/ExternalSOP.java index ff27d7c..28fda4d 100644 --- a/external-sop/src/main/java/sop/external/ExternalSOP.java +++ b/external-sop/src/main/java/sop/external/ExternalSOP.java @@ -5,6 +5,7 @@ package sop.external; import sop.SOP; +import sop.exception.SOPGPException; import sop.external.operation.ExtractCertExternal; import sop.external.operation.GenerateKeyExternal; import sop.external.operation.VersionExternal; @@ -21,27 +22,41 @@ import sop.operation.InlineSign; import sop.operation.InlineVerify; import sop.operation.Version; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Properties; + public class ExternalSOP implements SOP { private final String binaryName; + private final Properties properties; public ExternalSOP(String binaryName) { + this(binaryName, new Properties()); + } + + public ExternalSOP(String binaryName, Properties properties) { this.binaryName = binaryName; + this.properties = properties; } @Override public Version version() { - return new VersionExternal(binaryName); + return new VersionExternal(binaryName, properties); } @Override public GenerateKey generateKey() { - return new GenerateKeyExternal(binaryName); + return new GenerateKeyExternal(binaryName, properties); } @Override public ExtractCert extractCert() { - return new ExtractCertExternal(binaryName); + return new ExtractCertExternal(binaryName, properties); } @Override @@ -88,4 +103,124 @@ public class ExternalSOP implements SOP { public Dearmor dearmor() { return null; } + + public static void finish(Process process) throws IOException { + try { + mapExitCodeOrException(process); + } catch (SOPGPException e) { + InputStream errIn = process.getErrorStream(); + ByteArrayOutputStream errOut = new ByteArrayOutputStream(); + byte[] buf = new byte[512]; + int r; + while ((r = errIn.read(buf)) > 0 ) { + errOut.write(buf, 0, r); + } + + e.initCause(new IOException(errOut.toString())); + throw e; + } + catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + private static void mapExitCodeOrException(Process process) throws InterruptedException, IOException { + int exitCode = process.waitFor(); + + if (exitCode == 0) { + return; + } + + InputStream errIn = process.getErrorStream(); + ByteArrayOutputStream errOut = new ByteArrayOutputStream(); + byte[] buf = new byte[512]; + int r; + while ((r = errIn.read(buf)) > 0 ) { + errOut.write(buf, 0, r); + } + + String errorMessage = errOut.toString(); + + switch (exitCode) { + case SOPGPException.NoSignature.EXIT_CODE: + throw new SOPGPException.NoSignature("External SOP backend reported error NoSignature (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.UnsupportedAsymmetricAlgo.EXIT_CODE: + throw new UnsupportedOperationException("External SOP backend reported error UnsupportedAsymmetricAlgo (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.CertCannotEncrypt.EXIT_CODE: + throw new SOPGPException.CertCannotEncrypt("External SOP backend reported error CertCannotEncrypt (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.MissingArg.EXIT_CODE: + throw new SOPGPException.MissingArg("External SOP backend reported error MissingArg (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.IncompleteVerification.EXIT_CODE: + throw new SOPGPException.IncompleteVerification("External SOP backend reported error IncompleteVerification (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.CannotDecrypt.EXIT_CODE: + throw new SOPGPException.CannotDecrypt("External SOP backend reported error CannotDecrypt (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.PasswordNotHumanReadable.EXIT_CODE: + throw new SOPGPException.PasswordNotHumanReadable("External SOP backend reported error PasswordNotHumanReadable (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.UnsupportedOption.EXIT_CODE: + throw new SOPGPException.UnsupportedOption("External SOP backend reported error UnsupportedOption (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.BadData.EXIT_CODE: + throw new SOPGPException.BadData("External SOP backend reported error BadData (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.ExpectedText.EXIT_CODE: + throw new SOPGPException.ExpectedText("External SOP backend reported error ExpectedText (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.OutputExists.EXIT_CODE: + throw new SOPGPException.OutputExists("External SOP backend reported error OutputExists (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.MissingInput.EXIT_CODE: + throw new SOPGPException.MissingInput("External SOP backend reported error MissingInput (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.KeyIsProtected.EXIT_CODE: + throw new SOPGPException.KeyIsProtected("External SOP backend reported error KeyIsProtected (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.UnsupportedSubcommand.EXIT_CODE: + throw new SOPGPException.UnsupportedSubcommand("External SOP backend reported error UnsupportedSubcommand (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.UnsupportedSpecialPrefix.EXIT_CODE: + throw new SOPGPException.UnsupportedSpecialPrefix("External SOP backend reported error UnsupportedSpecialPrefix (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.AmbiguousInput.EXIT_CODE: + throw new SOPGPException.AmbiguousInput("External SOP backend reported error AmbiguousInput (" + + exitCode + "):\n" + errorMessage); + + case SOPGPException.KeyCannotSign.EXIT_CODE: + throw new SOPGPException.KeyCannotSign("External SOP backend reported error KeyCannotSign (" + + exitCode + "):\n" + errorMessage); + + default: + throw new RuntimeException("External SOP backend reported unknown exit code (" + + exitCode + "):\n" + errorMessage); + } + } + + public static List propertiesToEnv(Properties properties) { + List env = new ArrayList<>(); + for (Object key : properties.keySet()) { + env.add(key + "=" + properties.get(key)); + } + return env; + } } diff --git a/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java b/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java new file mode 100644 index 0000000..2ab126f --- /dev/null +++ b/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java @@ -0,0 +1,43 @@ +package sop.external.operation; + +import sop.ReadyWithResult; +import sop.SigningResult; +import sop.enums.SignAs; +import sop.exception.SOPGPException; +import sop.operation.DetachedSign; + +import java.io.IOException; +import java.io.InputStream; + +public class DetachedSignExternal implements DetachedSign { + + private boolean noArmor; + private byte[] keyPassword; + + @Override + public DetachedSign noArmor() { + this.noArmor = true; + return this; + } + + @Override + public DetachedSign key(InputStream key) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException { + return null; + } + + @Override + public DetachedSign withKeyPassword(byte[] password) throws SOPGPException.UnsupportedOption, SOPGPException.PasswordNotHumanReadable { + this.keyPassword = password; + return this; + } + + @Override + public DetachedSign mode(SignAs mode) throws SOPGPException.UnsupportedOption { + return null; + } + + @Override + public ReadyWithResult data(InputStream data) throws IOException, SOPGPException.KeyIsProtected, SOPGPException.ExpectedText { + return null; + } +} diff --git a/external-sop/src/main/java/sop/external/operation/ExtractCertExternal.java b/external-sop/src/main/java/sop/external/operation/ExtractCertExternal.java index 9349d4e..da7f3db 100644 --- a/external-sop/src/main/java/sop/external/operation/ExtractCertExternal.java +++ b/external-sop/src/main/java/sop/external/operation/ExtractCertExternal.java @@ -6,6 +6,7 @@ package sop.external.operation; import sop.Ready; import sop.exception.SOPGPException; +import sop.external.ExternalSOP; import sop.operation.ExtractCert; import java.io.IOException; @@ -13,16 +14,19 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import java.util.Properties; public class ExtractCertExternal implements ExtractCert { private final String binary; private final Runtime runtime = Runtime.getRuntime(); + private final Properties environment; private boolean noArmor; - public ExtractCertExternal(String binary) { + public ExtractCertExternal(String binary, Properties properties) { this.binary = binary; + this.environment = properties; } @Override @@ -32,7 +36,7 @@ public class ExtractCertExternal implements ExtractCert { } @Override - public Ready key(InputStream keyInputStream) throws IOException, SOPGPException.BadData { + public Ready key(InputStream keyInputStream) throws SOPGPException.BadData { List commandList = new ArrayList<>(); commandList.add(binary); @@ -42,11 +46,15 @@ public class ExtractCertExternal implements ExtractCert { commandList.add("--no-armor"); } + List envList = ExternalSOP.propertiesToEnv(environment); + String[] command = commandList.toArray(new String[0]); + String[] env = envList.toArray(new String[0]); + try { - Process process = runtime.exec(command); - OutputStream stdOut = process.getOutputStream(); - InputStream stdIn = process.getInputStream(); + Process process = runtime.exec(command, env); + OutputStream extractOut = process.getOutputStream(); + InputStream extractIn = process.getInputStream(); return new Ready() { @Override @@ -54,12 +62,20 @@ public class ExtractCertExternal implements ExtractCert { byte[] buf = new byte[4096]; int r; while ((r = keyInputStream.read(buf)) > 0) { - stdOut.write(buf, 0, r); + extractOut.write(buf, 0, r); } - while ((r = stdIn.read(buf)) > 0) { + keyInputStream.close(); + extractOut.close(); + + while ((r = extractIn.read(buf)) > 0) { outputStream.write(buf, 0 , r); } + + extractIn.close(); + outputStream.close(); + + ExternalSOP.finish(process); } }; } catch (IOException e) { diff --git a/external-sop/src/main/java/sop/external/operation/GenerateKeyExternal.java b/external-sop/src/main/java/sop/external/operation/GenerateKeyExternal.java index c91ce06..0c09304 100644 --- a/external-sop/src/main/java/sop/external/operation/GenerateKeyExternal.java +++ b/external-sop/src/main/java/sop/external/operation/GenerateKeyExternal.java @@ -6,6 +6,7 @@ package sop.external.operation; import sop.Ready; import sop.exception.SOPGPException; +import sop.external.ExternalSOP; import sop.operation.GenerateKey; import java.io.IOException; @@ -13,6 +14,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; +import java.util.Properties; public class GenerateKeyExternal implements GenerateKey { @@ -22,9 +24,11 @@ public class GenerateKeyExternal implements GenerateKey { private String keyPassword; private final Runtime runtime = Runtime.getRuntime(); + private final Properties properties; - public GenerateKeyExternal(String binary) { + public GenerateKeyExternal(String binary, Properties environment) { this.binary = binary; + this.properties = environment; } @Override @@ -60,16 +64,22 @@ public class GenerateKeyExternal implements GenerateKey { if (keyPassword != null) { commandList.add("--with-key-password"); - commandList.add(keyPassword); + commandList.add("@ENV:key_password"); } for (String userId : userIds) { commandList.add(userId); } + List envList = ExternalSOP.propertiesToEnv(properties); + if (keyPassword != null) { + envList.add("key_password=" + keyPassword); + } + String[] command = commandList.toArray(new String[0]); + String[] env = envList.toArray(new String[0]); try { - Process process = runtime.exec(command); + Process process = runtime.exec(command, env); InputStream stdIn = process.getInputStream(); return new Ready() { @@ -80,6 +90,8 @@ public class GenerateKeyExternal implements GenerateKey { while ((r = stdIn.read(buf)) >= 0) { outputStream.write(buf, 0, r); } + + ExternalSOP.finish(process); } }; } catch (IOException e) { diff --git a/external-sop/src/main/java/sop/external/operation/VersionExternal.java b/external-sop/src/main/java/sop/external/operation/VersionExternal.java index b40ed30..b4fc50b 100644 --- a/external-sop/src/main/java/sop/external/operation/VersionExternal.java +++ b/external-sop/src/main/java/sop/external/operation/VersionExternal.java @@ -4,31 +4,37 @@ package sop.external.operation; +import sop.external.ExternalSOP; import sop.operation.Version; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.util.Properties; public class VersionExternal implements Version { private final Runtime runtime = Runtime.getRuntime(); private final String binary; + private final Properties environment; - public VersionExternal(String binaryName) { + public VersionExternal(String binaryName, Properties environment) { this.binary = binaryName; + this.environment = environment; } @Override public String getName() { String[] command = new String[] {binary, "version"}; + String[] env = ExternalSOP.propertiesToEnv(environment).toArray(new String[0]); try { - Process process = runtime.exec(command); + Process process = runtime.exec(command, env); BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = stdInput.readLine().trim(); if (line.contains(" ")) { return line.substring(0, line.lastIndexOf(" ")); } + ExternalSOP.finish(process); return line; } catch (IOException e) { throw new RuntimeException(e); @@ -38,13 +44,15 @@ public class VersionExternal implements Version { @Override public String getVersion() { String[] command = new String[] {binary, "version"}; + String[] env = ExternalSOP.propertiesToEnv(environment).toArray(new String[0]); try { - Process process = runtime.exec(command); + Process process = runtime.exec(command, env); BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream())); String line = stdInput.readLine().trim(); if (line.contains(" ")) { return line.substring(line.lastIndexOf(" ") + 1); } + ExternalSOP.finish(process); return line; } catch (IOException e) { throw new RuntimeException(e); @@ -54,14 +62,16 @@ public class VersionExternal implements Version { @Override public String getBackendVersion() { String[] command = new String[] {binary, "version", "--backend"}; + String[] env = ExternalSOP.propertiesToEnv(environment).toArray(new String[0]); try { - Process process = runtime.exec(command); + Process process = runtime.exec(command, env); BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream())); StringBuilder sb = new StringBuilder(); String line; while ((line = stdInput.readLine()) != null) { sb.append(line).append('\n'); } + ExternalSOP.finish(process); return sb.toString(); } catch (IOException e) { throw new RuntimeException(e); @@ -71,14 +81,16 @@ public class VersionExternal implements Version { @Override public String getExtendedVersion() { String[] command = new String[] {binary, "version", "--extended"}; + String[] env = ExternalSOP.propertiesToEnv(environment).toArray(new String[0]); try { - Process process = runtime.exec(command); + Process process = runtime.exec(command, env); BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream())); StringBuilder sb = new StringBuilder(); String line; while ((line = stdInput.readLine()) != null) { sb.append(line).append('\n'); } + ExternalSOP.finish(process); return sb.toString(); } catch (IOException e) { throw new RuntimeException(e); diff --git a/external-sop/src/main/resources/sop/external/.gitignore b/external-sop/src/main/resources/sop/external/.gitignore index 4c2e2f3..b1790be 100644 --- a/external-sop/src/main/resources/sop/external/.gitignore +++ b/external-sop/src/main/resources/sop/external/.gitignore @@ -2,4 +2,5 @@ # # SPDX-License-Identifier: CC0-1.0 -backend.local.properties \ No newline at end of file +backend.local.properties +backend.env \ No newline at end of file diff --git a/external-sop/src/test/java/sop/external/AbstractExternalSOPTest.java b/external-sop/src/test/java/sop/external/AbstractExternalSOPTest.java new file mode 100644 index 0000000..3a779ca --- /dev/null +++ b/external-sop/src/test/java/sop/external/AbstractExternalSOPTest.java @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package sop.external; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sop.SOP; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public abstract class AbstractExternalSOPTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractExternalSOPTest.class); + + private final SOP sop; + + public AbstractExternalSOPTest() { + String backend = readSopBackendFromProperties(); + Properties environment = readBackendEnvironment(); + sop = new ExternalSOP(backend, environment); + } + + public SOP getSop() { + return sop; + } + + public static boolean isExternalSopInstalled() { + String binary = readSopBackendFromProperties(); + if (binary == null) { + return false; + } + return new File(binary).exists(); + } + + private static String readSopBackendFromProperties() { + Properties properties = new Properties(); + try { + InputStream resourceIn = AbstractExternalSOPTest.class.getResourceAsStream("backend.local.properties"); + if (resourceIn == null) { + LOGGER.info("Could not find backend.local.properties file. Try backend.properties instead."); + resourceIn = AbstractExternalSOPTest.class.getResourceAsStream("backend.properties"); + } + if (resourceIn == null) { + throw new FileNotFoundException("Could not find backend.properties file."); + } + + properties.load(resourceIn); + String backend = properties.getProperty("sop.backend"); + return backend; + } catch (IOException e) { + return null; + } + } + + protected static Properties readBackendEnvironment() { + Properties properties = new Properties(); + try { + InputStream resourceIn = AbstractExternalSOPTest.class.getResourceAsStream("backend.env"); + if (resourceIn == null) { + LOGGER.info("Could not read backend.env file."); + } else { + properties.load(resourceIn); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return properties; + } +} diff --git a/external-sop/src/test/java/sop/external/ExternalExtractCertTest.java b/external-sop/src/test/java/sop/external/ExternalExtractCertTest.java new file mode 100644 index 0000000..6849179 --- /dev/null +++ b/external-sop/src/test/java/sop/external/ExternalExtractCertTest.java @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package sop.external; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; + +import java.io.IOException; +import java.io.InputStream; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@EnabledIf("sop.external.AbstractExternalSOPTest#isExternalSopInstalled") +public class ExternalExtractCertTest extends AbstractExternalSOPTest { + + @Test + public void extractCertTest() throws IOException { + InputStream keyIn = getSop().generateKey().userId("Alice").generate().getInputStream(); + String cert = new String(getSop().extractCert().key(keyIn).getBytes()); + assertTrue(cert.startsWith("-----BEGIN PGP PUBLIC KEY BLOCK-----\n")); + } +} diff --git a/external-sop/src/test/java/sop/external/ExternalGenerateKeyTest.java b/external-sop/src/test/java/sop/external/ExternalGenerateKeyTest.java new file mode 100644 index 0000000..1ad4e51 --- /dev/null +++ b/external-sop/src/test/java/sop/external/ExternalGenerateKeyTest.java @@ -0,0 +1,30 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package sop.external; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@EnabledIf("sop.external.AbstractExternalSOPTest#isExternalSopInstalled") +public class ExternalGenerateKeyTest extends AbstractExternalSOPTest { + + @Test + public void generateKeyTest() throws IOException { + String key = new String(getSop().generateKey().userId("Alice").generate().getBytes()); + assertTrue(key.startsWith("-----BEGIN PGP PRIVATE KEY BLOCK-----\n")); + } + + @Test + public void generateKeyWithPasswordTest() throws IOException { + String key = new String(getSop().generateKey().userId("Alice").withKeyPassword("swßrdf1sh").generate().getBytes()); + assertEquals("asd", key); + } + +} diff --git a/external-sop/src/test/java/sop/external/ExternalSOPTest.java b/external-sop/src/test/java/sop/external/ExternalSOPTest.java deleted file mode 100644 index fa12246..0000000 --- a/external-sop/src/test/java/sop/external/ExternalSOPTest.java +++ /dev/null @@ -1,100 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Paul Schaub -// -// SPDX-License-Identifier: Apache-2.0 - -package sop.external; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIf; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import sop.SOP; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@EnabledIf("sop.external.ExternalSOPTest#externalSopInstalled") -public class ExternalSOPTest { - - private static final Logger LOGGER = LoggerFactory.getLogger(ExternalSOPTest.class); - - private final SOP sop; - - public ExternalSOPTest() { - String backend = readSopBackendFromProperties(); - sop = new ExternalSOP(backend); - } - - private static String readSopBackendFromProperties() { - Properties properties = new Properties(); - try { - InputStream resourceIn = ExternalSOPTest.class.getResourceAsStream("backend.local.properties"); - if (resourceIn == null) { - LOGGER.info("Could not find backend.local.properties file. Try backend.properties instead."); - resourceIn = ExternalSOPTest.class.getResourceAsStream("backend.properties"); - } - if (resourceIn == null) { - throw new FileNotFoundException("Could not find backend.properties file."); - } - - properties.load(resourceIn); - String backend = properties.getProperty("sop.backend"); - return backend; - } catch (IOException e) { - return null; - } - } - - public static boolean externalSopInstalled() { - String binary = readSopBackendFromProperties(); - if (binary == null) { - return false; - } - return new File(binary).exists(); - } - - @Test - public void versionNameTest() { - assertEquals("sqop", sop.version().getName()); - } - - @Test - public void versionVersionTest() { - String version = sop.version().getVersion(); - assertTrue(version.matches("\\d+(\\.\\d+)*")); - } - - @Test - public void backendVersionTest() { - String backend = sop.version().getBackendVersion(); - assertFalse(backend.isEmpty()); - } - - @Test - public void extendedVersionTest() { - String extended = sop.version().getExtendedVersion(); - assertFalse(extended.isEmpty()); - } - - @Test - public void generateKeyTest() throws IOException { - String key = new String(sop.generateKey().userId("Alice").generate().getBytes()); - assertTrue(key.startsWith("-----BEGIN PGP PRIVATE KEY BLOCK-----\n")); - } - - @Test - @Disabled - public void extractCertTest() throws IOException { - InputStream keyIn = sop.generateKey().userId("Alice").generate().getInputStream(); - String cert = new String(sop.extractCert().key(keyIn).getBytes()); - assertTrue(cert.startsWith("-----BEGIN PGP PUBLIC KEY BLOCK-----\n")); - } -} diff --git a/external-sop/src/test/java/sop/external/ExternalVersionTest.java b/external-sop/src/test/java/sop/external/ExternalVersionTest.java new file mode 100644 index 0000000..8fbf371 --- /dev/null +++ b/external-sop/src/test/java/sop/external/ExternalVersionTest.java @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package sop.external; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIf; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@EnabledIf("sop.external.AbstractExternalSOPTest#isExternalSopInstalled") +public class ExternalVersionTest extends AbstractExternalSOPTest { + + @Test + public void versionNameTest() { + assertEquals("sqop", getSop().version().getName()); + } + + @Test + public void versionVersionTest() { + String version = getSop().version().getVersion(); + assertTrue(version.matches("\\d+(\\.\\d+)*")); + } + + @Test + public void backendVersionTest() { + String backend = getSop().version().getBackendVersion(); + assertFalse(backend.isEmpty()); + } + + @Test + public void extendedVersionTest() { + String extended = getSop().version().getExtendedVersion(); + assertFalse(extended.isEmpty()); + } + +} diff --git a/sop-java/src/main/java/sop/exception/SOPGPException.java b/sop-java/src/main/java/sop/exception/SOPGPException.java index 4d8c9f6..b7032c3 100644 --- a/sop-java/src/main/java/sop/exception/SOPGPException.java +++ b/sop-java/src/main/java/sop/exception/SOPGPException.java @@ -32,7 +32,11 @@ public abstract class SOPGPException extends RuntimeException { public static final int EXIT_CODE = 3; public NoSignature() { - super("No verifiable signature found."); + this("No verifiable signature found."); + } + + public NoSignature(String message) { + super(message); } public NoSignature(String errorMsg, NoSignature e) { @@ -72,6 +76,10 @@ public abstract class SOPGPException extends RuntimeException { super(message, cause); } + public CertCannotEncrypt(String message) { + super(message); + } + @Override public int getExitCode() { return EXIT_CODE; @@ -85,8 +93,8 @@ public abstract class SOPGPException extends RuntimeException { public static final int EXIT_CODE = 19; - public MissingArg(String s) { - super(s); + public MissingArg(String message) { + super(message); } @Override @@ -127,6 +135,10 @@ public abstract class SOPGPException extends RuntimeException { super(errorMsg, e); } + public CannotDecrypt(String message) { + super(message); + } + @Override public int getExitCode() { return EXIT_CODE; @@ -144,6 +156,10 @@ public abstract class SOPGPException extends RuntimeException { super(); } + public PasswordNotHumanReadable(String message) { + super(message); + } + @Override public int getExitCode() { return EXIT_CODE; @@ -203,6 +219,10 @@ public abstract class SOPGPException extends RuntimeException { public static final int EXIT_CODE = 53; + public ExpectedText(String message) { + super(message); + } + @Override public int getExitCode() { return EXIT_CODE;