diff --git a/external-sop/src/main/java/sop/external/ExternalSOP.java b/external-sop/src/main/java/sop/external/ExternalSOP.java index 432a16d..add37c5 100644 --- a/external-sop/src/main/java/sop/external/ExternalSOP.java +++ b/external-sop/src/main/java/sop/external/ExternalSOP.java @@ -179,14 +179,17 @@ public class ExternalSOP implements SOP { * @throws IOException in case of an IO error */ private static void mapExitCodeOrException(@Nonnull Process process) throws InterruptedException, IOException { + // wait for process termination int exitCode = process.waitFor(); if (exitCode == 0) { + // we're good, bye return; } + // Read error message InputStream errIn = process.getErrorStream(); - String errorMessage = readFully(errIn); + String errorMessage = readString(errIn); switch (exitCode) { case SOPGPException.NoSignature.EXIT_CODE: @@ -285,7 +288,7 @@ public class ExternalSOP implements SOP { * @return string * @throws IOException in case of an IO error */ - public static String readFully(@Nonnull InputStream inputStream) throws IOException { + public static String readString(@Nonnull InputStream inputStream) throws IOException { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); byte[] buf = new byte[4096]; int r; @@ -297,13 +300,16 @@ public class ExternalSOP implements SOP { /** * Execute the given command on the given {@link Runtime} with the given list of environment variables. + * This command does not transform any input data, and instead is purely a producer. * * @param runtime runtime * @param commandList command * @param envList environment variables * @return ready to read the result from */ - public static Ready ready(@Nonnull Runtime runtime, @Nonnull List commandList, @Nonnull List envList) { + public static Ready executeProducingOperation(@Nonnull Runtime runtime, + @Nonnull List commandList, + @Nonnull List envList) { String[] command = commandList.toArray(new String[0]); String[] env = envList.toArray(new String[0]); @@ -322,6 +328,7 @@ public class ExternalSOP implements SOP { outputStream.flush(); outputStream.close(); + ExternalSOP.finish(process); } }; @@ -333,6 +340,7 @@ public class ExternalSOP implements SOP { /** * Execute the given command on the given runtime using the given environment variables. * The given input stream provides input for the process. + * This command is a transformation, meaning it is given input data and transforms it into output data. * * @param runtime runtime * @param commandList command @@ -340,7 +348,7 @@ public class ExternalSOP implements SOP { * @param standardIn stream of input data for the process * @return ready to read the result from */ - public static Ready ready(@Nonnull Runtime runtime, @Nonnull List commandList, @Nonnull List envList, @Nonnull InputStream standardIn) { + public static Ready executeTransformingOperation(@Nonnull Runtime runtime, @Nonnull List commandList, @Nonnull List envList, @Nonnull InputStream standardIn) { String[] command = commandList.toArray(new String[0]); String[] env = envList.toArray(new String[0]); try { @@ -362,7 +370,10 @@ public class ExternalSOP implements SOP { processOut.flush(); processOut.close(); } catch (IOException e) { - // ignore + // Perhaps the stream is already closed, in which case we ignore the exception. + if (!"Stream closed".equals(e.getMessage())) { + throw e; + } } while ((r = processIn.read(buf)) > 0) { diff --git a/external-sop/src/main/java/sop/external/operation/ArmorExternal.java b/external-sop/src/main/java/sop/external/operation/ArmorExternal.java index bf9ddcd..cb53573 100644 --- a/external-sop/src/main/java/sop/external/operation/ArmorExternal.java +++ b/external-sop/src/main/java/sop/external/operation/ArmorExternal.java @@ -38,6 +38,6 @@ public class ArmorExternal implements Armor { @Override public Ready data(InputStream data) throws SOPGPException.BadData, IOException { - return ExternalSOP.ready(Runtime.getRuntime(), commandList, envList, data); + return ExternalSOP.executeTransformingOperation(Runtime.getRuntime(), commandList, envList, data); } } diff --git a/external-sop/src/main/java/sop/external/operation/DearmorExternal.java b/external-sop/src/main/java/sop/external/operation/DearmorExternal.java index 2406131..7fa1fdc 100644 --- a/external-sop/src/main/java/sop/external/operation/DearmorExternal.java +++ b/external-sop/src/main/java/sop/external/operation/DearmorExternal.java @@ -31,6 +31,6 @@ public class DearmorExternal implements Dearmor { @Override public Ready data(InputStream data) throws SOPGPException.BadData, IOException { - return ExternalSOP.ready(Runtime.getRuntime(), commandList, envList, data); + return ExternalSOP.executeTransformingOperation(Runtime.getRuntime(), commandList, envList, data); } } diff --git a/external-sop/src/main/java/sop/external/operation/DecryptExternal.java b/external-sop/src/main/java/sop/external/operation/DecryptExternal.java index 84da064..0b91d5b 100644 --- a/external-sop/src/main/java/sop/external/operation/DecryptExternal.java +++ b/external-sop/src/main/java/sop/external/operation/DecryptExternal.java @@ -66,7 +66,7 @@ public class DecryptExternal implements Decrypt { throws SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException { String envVar = "VERIFY_WITH_" + verifyWithCounter++; commandList.add("--verify-with=@ENV:" + envVar); - envList.add(envVar + "=" + ExternalSOP.readFully(cert)); + envList.add(envVar + "=" + ExternalSOP.readString(cert)); return this; } @@ -93,7 +93,7 @@ public class DecryptExternal implements Decrypt { throws SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException { String envVar = "KEY_" + keyCounter++; commandList.add("@ENV:" + envVar); - envList.add(envVar + "=" + ExternalSOP.readFully(key)); + envList.add(envVar + "=" + ExternalSOP.readString(key)); return this; } @@ -151,7 +151,7 @@ public class DecryptExternal implements Decrypt { ExternalSOP.finish(process); FileInputStream sessionKeyOutIn = new FileInputStream(sessionKeyOut); - String line = ExternalSOP.readFully(sessionKeyOutIn); + String line = ExternalSOP.readString(sessionKeyOutIn); SessionKey sessionKey = SessionKey.fromString(line.trim()); sessionKeyOutIn.close(); sessionKeyOut.delete(); diff --git a/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java b/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java index 1f9aa81..3e369f1 100644 --- a/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java +++ b/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java @@ -52,7 +52,7 @@ public class DetachedSignExternal implements DetachedSign { public DetachedSign key(InputStream key) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException { String envVar = "KEY_" + keyCounter++; commandList.add("@ENV:" + envVar); - envList.add(envVar + "=" + ExternalSOP.readFully(key)); + envList.add(envVar + "=" + ExternalSOP.readString(key)); return this; } diff --git a/external-sop/src/main/java/sop/external/operation/DetachedVerifyExternal.java b/external-sop/src/main/java/sop/external/operation/DetachedVerifyExternal.java index ed658c7..05318d4 100644 --- a/external-sop/src/main/java/sop/external/operation/DetachedVerifyExternal.java +++ b/external-sop/src/main/java/sop/external/operation/DetachedVerifyExternal.java @@ -68,12 +68,12 @@ public class DetachedVerifyExternal implements DetachedVerify { @Override public List data(InputStream data) throws IOException, SOPGPException.NoSignature, SOPGPException.BadData { commandList.add("@ENV:SIGNATURE"); - envList.add("SIGNATURE=" + ExternalSOP.readFully(signatures)); + envList.add("SIGNATURE=" + ExternalSOP.readString(signatures)); for (InputStream cert : certs) { String envVar = "CERT_" + certCounter++; commandList.add("@ENV:" + envVar); - envList.add(envVar + "=" + ExternalSOP.readFully(cert)); + envList.add(envVar + "=" + ExternalSOP.readString(cert)); } String[] command = commandList.toArray(new String[0]); diff --git a/external-sop/src/main/java/sop/external/operation/EncryptExternal.java b/external-sop/src/main/java/sop/external/operation/EncryptExternal.java index f45cd12..ca8ddf1 100644 --- a/external-sop/src/main/java/sop/external/operation/EncryptExternal.java +++ b/external-sop/src/main/java/sop/external/operation/EncryptExternal.java @@ -53,7 +53,7 @@ public class EncryptExternal implements Encrypt { IOException { String envVar = "SIGN_WITH_" + SIGN_WITH_COUNTER++; commandList.add("--sign-with=@ENV:" + envVar); - envList.add(envVar + "=" + ExternalSOP.readFully(key)); + envList.add(envVar + "=" + ExternalSOP.readString(key)); return this; } @@ -81,13 +81,13 @@ public class EncryptExternal implements Encrypt { IOException { String envVar = "CERT_" + CERT_COUNTER++; commandList.add("@ENV:" + envVar); - envList.add(envVar + "=" + ExternalSOP.readFully(cert)); + envList.add(envVar + "=" + ExternalSOP.readString(cert)); return this; } @Override public Ready plaintext(InputStream plaintext) throws IOException, SOPGPException.KeyIsProtected { - return ExternalSOP.ready(Runtime.getRuntime(), commandList, envList, plaintext); + return ExternalSOP.executeTransformingOperation(Runtime.getRuntime(), commandList, envList, plaintext); } } 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 549b1ad..5fdcdc1 100644 --- a/external-sop/src/main/java/sop/external/operation/ExtractCertExternal.java +++ b/external-sop/src/main/java/sop/external/operation/ExtractCertExternal.java @@ -36,6 +36,6 @@ public class ExtractCertExternal implements ExtractCert { @Override public Ready key(InputStream keyInputStream) throws SOPGPException.BadData { - return ExternalSOP.ready(Runtime.getRuntime(), commandList, envList, keyInputStream); + return ExternalSOP.executeTransformingOperation(Runtime.getRuntime(), commandList, envList, keyInputStream); } } 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 d125fc0..95e86b8 100644 --- a/external-sop/src/main/java/sop/external/operation/GenerateKeyExternal.java +++ b/external-sop/src/main/java/sop/external/operation/GenerateKeyExternal.java @@ -54,6 +54,6 @@ public class GenerateKeyExternal implements GenerateKey { @Override public Ready generate() throws SOPGPException.MissingArg, SOPGPException.UnsupportedAsymmetricAlgo { - return ExternalSOP.ready(Runtime.getRuntime(), commandList, envList); + return ExternalSOP.executeProducingOperation(Runtime.getRuntime(), commandList, envList); } } diff --git a/external-sop/src/main/java/sop/external/operation/InlineSignExternal.java b/external-sop/src/main/java/sop/external/operation/InlineSignExternal.java index 17e5b12..d78dd7b 100644 --- a/external-sop/src/main/java/sop/external/operation/InlineSignExternal.java +++ b/external-sop/src/main/java/sop/external/operation/InlineSignExternal.java @@ -43,7 +43,7 @@ public class InlineSignExternal implements InlineSign { public InlineSign key(InputStream key) throws SOPGPException.KeyCannotSign, SOPGPException.BadData, SOPGPException.UnsupportedAsymmetricAlgo, IOException { String envVar = "KEY_" + keyCounter++; commandList.add("@ENV:" + envVar); - envList.add(envVar + "=" + ExternalSOP.readFully(key)); + envList.add(envVar + "=" + ExternalSOP.readString(key)); return this; } @@ -63,6 +63,6 @@ public class InlineSignExternal implements InlineSign { @Override public Ready data(InputStream data) throws IOException, SOPGPException.KeyIsProtected, SOPGPException.ExpectedText { - return ExternalSOP.ready(Runtime.getRuntime(), commandList, envList, data); + return ExternalSOP.executeTransformingOperation(Runtime.getRuntime(), commandList, envList, data); } } diff --git a/external-sop/src/main/java/sop/external/operation/InlineVerifyExternal.java b/external-sop/src/main/java/sop/external/operation/InlineVerifyExternal.java index 5fbdde6..8010367 100644 --- a/external-sop/src/main/java/sop/external/operation/InlineVerifyExternal.java +++ b/external-sop/src/main/java/sop/external/operation/InlineVerifyExternal.java @@ -57,7 +57,7 @@ public class InlineVerifyExternal implements InlineVerify { public InlineVerify cert(InputStream cert) throws SOPGPException.BadData, IOException { String envVar = "CERT_" + certCounter++; commandList.add("@ENV:" + envVar); - envList.add(envVar + "=" + ExternalSOP.readFully(cert)); + envList.add(envVar + "=" + ExternalSOP.readString(cert)); return this; } diff --git a/external-sop/src/test/java/sop/external/ExternalDetachedSignVerifyRoundTripTest.java b/external-sop/src/test/java/sop/external/ExternalDetachedSignVerifyRoundTripTest.java index cf04bd5..aaebe39 100644 --- a/external-sop/src/test/java/sop/external/ExternalDetachedSignVerifyRoundTripTest.java +++ b/external-sop/src/test/java/sop/external/ExternalDetachedSignVerifyRoundTripTest.java @@ -230,6 +230,7 @@ public class ExternalDetachedSignVerifyRoundTripTest extends AbstractExternalSOP @Test public void verifyMissingCertCausesMissingArg() { + ignoreIf("sqop", Is.leq, "0.27.3"); ignoreIf("PGPainless-SOP", Is.geq, "0.0.0"); // PGPainless uses picocli which throws // UNSUPPORTED_OPTION for missing arg byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); diff --git a/external-sop/src/test/java/sop/external/ExternalEncryptDecryptRoundTripTest.java b/external-sop/src/test/java/sop/external/ExternalEncryptDecryptRoundTripTest.java index 3011a03..2d6077e 100644 --- a/external-sop/src/test/java/sop/external/ExternalEncryptDecryptRoundTripTest.java +++ b/external-sop/src/test/java/sop/external/ExternalEncryptDecryptRoundTripTest.java @@ -281,6 +281,7 @@ public class ExternalEncryptDecryptRoundTripTest extends AbstractExternalSOPTest @Test public void missingArgsTest() throws IOException { + ignoreIf("sqop", Is.leq, "0.27.3"); byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8); assertThrows(SOPGPException.MissingArg.class, () -> getSop().encrypt()