diff --git a/sop-java-picocli/src/main/java/sop/cli/picocli/commands/AbstractSopCmd.java b/sop-java-picocli/src/main/java/sop/cli/picocli/commands/AbstractSopCmd.java index 9cca658..c64922f 100644 --- a/sop-java-picocli/src/main/java/sop/cli/picocli/commands/AbstractSopCmd.java +++ b/sop-java-picocli/src/main/java/sop/cli/picocli/commands/AbstractSopCmd.java @@ -13,6 +13,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -21,6 +22,7 @@ import java.util.Collection; import java.util.Date; import java.util.Locale; import java.util.ResourceBundle; +import java.util.regex.Pattern; public abstract class AbstractSopCmd implements Runnable { @@ -40,6 +42,8 @@ public abstract class AbstractSopCmd implements Runnable { public static final Date BEGINNING_OF_TIME = new Date(0); public static final Date END_OF_TIME = new Date(8640000000000000L); + public static final Pattern PATTERN_FD = Pattern.compile("^\\d{1,3}$"); + protected final ResourceBundle messages; protected EnvironmentVariableResolver envResolver = System::getenv; @@ -141,9 +145,14 @@ public abstract class AbstractSopCmd implements Runnable { throw new SOPGPException.AmbiguousInput(errorMsg); } - String errorMsg = getMsg("sop.error.indirect_data_type.designator_fd_not_supported"); - throw new SOPGPException.UnsupportedSpecialPrefix(errorMsg); - + File fdFile = fileDescriptorFromString(trimmed); + try { + FileInputStream fileIn = new FileInputStream(fdFile); + return fileIn; + } catch (FileNotFoundException e) { + String errorMsg = getMsg("sop.error.indirect_data_type.file_descriptor_not_found", fdFile.getAbsolutePath()); + throw new IOException(errorMsg, e); + } } else { File file = new File(trimmed); if (!file.exists()) { @@ -176,9 +185,16 @@ public abstract class AbstractSopCmd implements Runnable { throw new SOPGPException.UnsupportedSpecialPrefix(errorMsg); } + // File Descriptor if (trimmed.startsWith(PRFX_FD)) { - String errorMsg = getMsg("sop.error.indirect_data_type.designator_fd_not_supported"); - throw new SOPGPException.UnsupportedSpecialPrefix(errorMsg); + File fdFile = fileDescriptorFromString(trimmed); + try { + FileOutputStream fout = new FileOutputStream(fdFile); + return fout; + } catch (FileNotFoundException e) { + String errorMsg = getMsg("sop.error.indirect_data_type.file_descriptor_not_found", fdFile.getAbsolutePath()); + throw new IOException(errorMsg, e); + } } File file = new File(trimmed); @@ -194,6 +210,21 @@ public abstract class AbstractSopCmd implements Runnable { return new FileOutputStream(file); } + + public File fileDescriptorFromString(String fdString) { + File fdDir = new File("/dev/fd/"); + if (!fdDir.exists()) { + String errorMsg = getMsg("sop.error.indirect_data_type.designator_fd_not_supported"); + throw new SOPGPException.UnsupportedSpecialPrefix(errorMsg); + } + String fdNumber = fdString.substring(PRFX_FD.length()); + if (!PATTERN_FD.matcher(fdNumber).matches()) { + throw new IllegalArgumentException("File descriptor must be a 1-3 digit, positive number."); + } + File descriptor = new File(fdDir, fdNumber); + return descriptor; + } + public static String stringFromInputStream(InputStream inputStream) throws IOException { try { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); diff --git a/sop-java-picocli/src/main/resources/msg_sop.properties b/sop-java-picocli/src/main/resources/msg_sop.properties index fce60c5..7530994 100644 --- a/sop-java-picocli/src/main/resources/msg_sop.properties +++ b/sop-java-picocli/src/main/resources/msg_sop.properties @@ -48,6 +48,7 @@ sop.error.input.stdin_not_openpgp_data=Standard Input appears not to contain val sop.error.indirect_data_type.ambiguous_filename=File name '%s' is ambiguous. File with the same name exists on the filesystem. sop.error.indirect_data_type.environment_variable_not_set=Environment variable '%s' not set. sop.error.indirect_data_type.environment_variable_empty=Environment variable '%s' is empty. +sop.error.indirect_data_type.file_descriptor_not_found=File descriptor '%s' not found. sop.error.indirect_data_type.input_file_does_not_exist=Input file '%s' does not exist. sop.error.indirect_data_type.input_not_a_file=Input file '%s' is not a file. sop.error.indirect_data_type.output_file_already_exists=Output file '%s' already exists. diff --git a/sop-java-picocli/src/main/resources/msg_sop_de.properties b/sop-java-picocli/src/main/resources/msg_sop_de.properties index acbfb68..6848777 100644 --- a/sop-java-picocli/src/main/resources/msg_sop_de.properties +++ b/sop-java-picocli/src/main/resources/msg_sop_de.properties @@ -48,6 +48,7 @@ sop.error.input.stdin_not_openpgp_data=Standard-Eingabe enth sop.error.indirect_data_type.ambiguous_filename=Dateiname '%s' ist mehrdeutig. Datei mit dem selben Namen existiert im Dateisystem. sop.error.indirect_data_type.environment_variable_not_set=Umgebungsvariable '%s' nicht gesetzt. sop.error.indirect_data_type.environment_variable_empty=Umgebungsvariable '%s' ist leer. +sop.error.indirect_data_type.file_descriptor_not_found=File Descriptor '%s' nicht gefunden. sop.error.indirect_data_type.input_file_does_not_exist=Quelldatei '%s' existiert nicht. sop.error.indirect_data_type.input_not_a_file=Quelldatei '%s' ist keine Datei. sop.error.indirect_data_type.output_file_already_exists=Zieldatei '%s' existiert bereits. diff --git a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/AbstractSopCmdTest.java b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/AbstractSopCmdTest.java index 9f383f5..aed420b 100644 --- a/sop-java-picocli/src/test/java/sop/cli/picocli/commands/AbstractSopCmdTest.java +++ b/sop-java-picocli/src/test/java/sop/cli/picocli/commands/AbstractSopCmdTest.java @@ -145,8 +145,8 @@ public class AbstractSopCmdTest { } @Test - public void getOutput_fdUnsupportedSpecialPrefix() { - assertThrows(SOPGPException.UnsupportedSpecialPrefix.class, () -> abstractCmd.getOutput("@FD:IS_ILLEGAL")); + public void getOutput_malformedFileDescriptor() { + assertThrows(IllegalArgumentException.class, () -> abstractCmd.getOutput("@FD:IS_ILLEGAL")); } @Test