diff --git a/rage/CHANGELOG.md b/rage/CHANGELOG.md index e49f64f9..50a288c4 100644 --- a/rage/CHANGELOG.md +++ b/rage/CHANGELOG.md @@ -12,6 +12,10 @@ to 1.0.0 are beta releases. ### Added - Partial French translation! +### Fixed +- [Unix] Files can now be encrypted with `rage --passphrase` when piped over + stdin, without requiring an explicit `-` argument as `INPUT`. + ## [0.10.0] - 2024-02-04 ### Added - Russian translation! diff --git a/rage/src/bin/rage/error.rs b/rage/src/bin/rage/error.rs index 3cb4a3ef..596e52b3 100644 --- a/rage/src/bin/rage/error.rs +++ b/rage/src/bin/rage/error.rs @@ -23,7 +23,10 @@ macro_rules! wlnfl { pub(crate) enum EncryptError { Age(age::EncryptError), - BrokenPipe { is_stdout: bool, source: io::Error }, + BrokenPipe { + is_stdout: bool, + source: io::Error, + }, IdentityRead(age::cli_common::ReadError), Io(io::Error), MissingRecipients, @@ -31,6 +34,7 @@ pub(crate) enum EncryptError { MixedRecipientAndPassphrase, MixedRecipientsFileAndPassphrase, PassphraseTimedOut, + #[cfg(not(unix))] PassphraseWithoutFileArgument, PluginNameFlag, } @@ -84,6 +88,7 @@ impl fmt::Display for EncryptError { wfl!(f, "err-enc-mixed-recipients-file-passphrase") } EncryptError::PassphraseTimedOut => wfl!(f, "err-passphrase-timed-out"), + #[cfg(not(unix))] EncryptError::PassphraseWithoutFileArgument => { wfl!(f, "err-enc-passphrase-without-file") } diff --git a/rage/src/bin/rage/main.rs b/rage/src/bin/rage/main.rs index a75a3972..545e2513 100644 --- a/rage/src/bin/rage/main.rs +++ b/rage/src/bin/rage/main.rs @@ -108,6 +108,7 @@ fn encrypt(opts: AgeOptions) -> Result<(), error::EncryptError> { (Format::Binary, file_io::OutputFormat::Binary) }; + #[cfg(not(unix))] let has_file_argument = opts.input.is_some(); let (input, output) = set_up_io(opts.input, opts.output, output_format)?; @@ -134,8 +135,13 @@ fn encrypt(opts: AgeOptions) -> Result<(), error::EncryptError> { return Err(error::EncryptError::MixedRecipientsFileAndPassphrase); } - if !has_file_argument { - return Err(error::EncryptError::PassphraseWithoutFileArgument); + // The `rpassword` crate opens `/dev/tty` directly on Unix, so we don't have + // any conflict with stdin. + #[cfg(not(unix))] + { + if !has_file_argument { + return Err(error::EncryptError::PassphraseWithoutFileArgument); + } } match read_or_generate_passphrase() { diff --git a/rage/tests/cli_tests.rs b/rage/tests/cli_tests.rs index 5c4acf5b..adc87821 100644 --- a/rage/tests/cli_tests.rs +++ b/rage/tests/cli_tests.rs @@ -1,4 +1,12 @@ #[test] fn cli_tests() { - trycmd::TestCases::new().case("tests/cmd/*/*.toml"); + let tests = trycmd::TestCases::new(); + + tests.case("tests/cmd/*/*.toml"); + + #[cfg(unix)] + tests.case("tests/unix/*/*.toml"); + + #[cfg(not(unix))] + tests.case("tests/windows/*/*.toml"); } diff --git a/rage/tests/unix/rage/encrypt-passphrase-without-file-argument.toml b/rage/tests/unix/rage/encrypt-passphrase-without-file-argument.toml new file mode 100644 index 00000000..4b0c6bee --- /dev/null +++ b/rage/tests/unix/rage/encrypt-passphrase-without-file-argument.toml @@ -0,0 +1,16 @@ +bin.name = "rage" +args = "-p" +status = "failed" +stdin = "" +stdout = "" +stderr = """ +Error: Parsing Error: Error { input: "", code: Tag } + +[ Did rage not do what you expected? Could an error be more useful? ] +[ Tell us: https://str4d.xyz/rage/report ] +""" + +# We get an error from the `pinentry` crate because we've passed a real but invalid binary +# that does not speak the pinentry protocol. +[env.add] +PINENTRY_PROGRAM = "true" diff --git a/rage/tests/cmd/rage/encrypt-passphrase-without-file-argument.toml b/rage/tests/windows/rage/encrypt-passphrase-without-file-argument.toml similarity index 100% rename from rage/tests/cmd/rage/encrypt-passphrase-without-file-argument.toml rename to rage/tests/windows/rage/encrypt-passphrase-without-file-argument.toml