mirror of
https://github.com/str4d/rage.git
synced 2025-04-03 19:07:42 +03:00
Merge pull request #516 from str4d/515-cli-common-feature-bugs
age: Fix feature flag combination bugs in `cli_common` module
This commit is contained in:
commit
cf96347fbe
3 changed files with 110 additions and 50 deletions
|
@ -1,7 +1,10 @@
|
|||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
use crate::{wfl, wlnfl, DecryptError};
|
||||
use crate::{wfl, DecryptError};
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
use crate::wlnfl;
|
||||
|
||||
/// Errors that can occur while reading recipients or identities.
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use std::io::{self, BufReader};
|
||||
|
||||
use super::{file_io::InputReader, ReadError, StdinGuard, UiCallbacks};
|
||||
use super::{ReadError, StdinGuard, UiCallbacks};
|
||||
use crate::{identity::IdentityFile, Identity};
|
||||
|
||||
#[cfg(feature = "armor")]
|
||||
use crate::armor::ArmoredReader;
|
||||
use crate::{armor::ArmoredReader, cli_common::file_io::InputReader};
|
||||
|
||||
/// Reads identities from the provided files.
|
||||
///
|
||||
|
@ -23,10 +23,12 @@ pub fn read_identities(
|
|||
max_work_factor,
|
||||
stdin_guard,
|
||||
&mut identities,
|
||||
#[cfg(feature = "armor")]
|
||||
|identities, identity| {
|
||||
identities.push(Box::new(identity));
|
||||
Ok(())
|
||||
},
|
||||
#[cfg(feature = "ssh")]
|
||||
|identities, _, identity| {
|
||||
identities.push(Box::new(identity.with_callbacks(UiCallbacks)));
|
||||
Ok(())
|
||||
|
@ -62,7 +64,7 @@ pub fn read_identities(
|
|||
/// Parses the provided identity files.
|
||||
pub(super) fn parse_identity_files<Ctx, E: From<ReadError> + From<io::Error>>(
|
||||
filenames: Vec<String>,
|
||||
max_work_factor: Option<u8>,
|
||||
_max_work_factor: Option<u8>,
|
||||
stdin_guard: &mut StdinGuard,
|
||||
ctx: &mut Ctx,
|
||||
#[cfg(feature = "armor")] encrypted_identity: impl Fn(
|
||||
|
@ -73,6 +75,7 @@ pub(super) fn parse_identity_files<Ctx, E: From<ReadError> + From<io::Error>>(
|
|||
identity_file_entry: impl Fn(&mut Ctx, crate::IdentityFileEntry) -> Result<(), E>,
|
||||
) -> Result<(), E> {
|
||||
for filename in filenames {
|
||||
#[cfg_attr(not(any(feature = "armor", feature = "ssh")), allow(unused_mut))]
|
||||
let mut reader = PeekableReader::new(BufReader::new(
|
||||
stdin_guard.open(filename.clone()).map_err(|e| match e {
|
||||
ReadError::Io(e) if matches!(e.kind(), io::ErrorKind::NotFound) => {
|
||||
|
@ -88,7 +91,7 @@ pub(super) fn parse_identity_files<Ctx, E: From<ReadError> + From<io::Error>>(
|
|||
ArmoredReader::new_buffered(&mut reader),
|
||||
Some(filename.clone()),
|
||||
UiCallbacks,
|
||||
max_work_factor,
|
||||
_max_work_factor,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
|
@ -101,7 +104,7 @@ pub(super) fn parse_identity_files<Ctx, E: From<ReadError> + From<io::Error>>(
|
|||
ArmoredReader::new_buffered(reader.inner),
|
||||
Some(filename.clone()),
|
||||
UiCallbacks,
|
||||
max_work_factor,
|
||||
_max_work_factor,
|
||||
)
|
||||
.expect("already parsed the age ciphertext header");
|
||||
|
||||
|
@ -160,6 +163,7 @@ impl<R: io::BufRead> PeekableReader<R> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "armor", feature = "ssh"))]
|
||||
fn reset(&mut self) -> io::Result<()> {
|
||||
match &mut self.state {
|
||||
PeekState::Peeking { consumed } => {
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
use std::io::{self, BufReader};
|
||||
|
||||
use super::StdinGuard;
|
||||
use super::{identities::parse_identity_files, ReadError, UiCallbacks};
|
||||
use crate::{x25519, EncryptError, IdentityFileEntry, Recipient};
|
||||
use super::{identities::parse_identity_files, ReadError};
|
||||
use crate::{x25519, IdentityFileEntry, Recipient};
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
use crate::plugin;
|
||||
use crate::{cli_common::UiCallbacks, plugin};
|
||||
|
||||
#[cfg(not(feature = "plugin"))]
|
||||
use std::convert::Infallible;
|
||||
|
||||
#[cfg(feature = "ssh")]
|
||||
use crate::ssh;
|
||||
|
||||
#[cfg(any(feature = "armor", feature = "plugin"))]
|
||||
use crate::EncryptError;
|
||||
|
||||
/// Handles error mapping for the given SSH recipient parser.
|
||||
///
|
||||
/// Returns `Ok(None)` if the parser finds a parseable value that should be ignored. This
|
||||
|
@ -44,25 +50,35 @@ where
|
|||
|
||||
/// Parses a recipient from a string.
|
||||
fn parse_recipient(
|
||||
filename: &str,
|
||||
_filename: &str,
|
||||
s: String,
|
||||
recipients: &mut Vec<Box<dyn Recipient + Send>>,
|
||||
plugin_recipients: &mut Vec<plugin::Recipient>,
|
||||
#[cfg(feature = "plugin")] plugin_recipients: &mut Vec<plugin::Recipient>,
|
||||
) -> Result<(), ReadError> {
|
||||
if let Ok(pk) = s.parse::<x25519::Recipient>() {
|
||||
recipients.push(Box::new(pk));
|
||||
} else if let Some(pk) = {
|
||||
#[cfg(feature = "ssh")]
|
||||
{
|
||||
parse_ssh_recipient(|| s.parse::<ssh::Recipient>(), || Ok(None), filename)?
|
||||
parse_ssh_recipient(|| s.parse::<ssh::Recipient>(), || Ok(None), _filename)?
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "ssh"))]
|
||||
None
|
||||
} {
|
||||
recipients.push(pk);
|
||||
} else if let Ok(recipient) = s.parse::<plugin::Recipient>() {
|
||||
plugin_recipients.push(recipient);
|
||||
} else if let Some(_recipient) = {
|
||||
#[cfg(feature = "plugin")]
|
||||
{
|
||||
// TODO Do something with the error?
|
||||
s.parse::<plugin::Recipient>().ok()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "plugin"))]
|
||||
None::<Infallible>
|
||||
} {
|
||||
#[cfg(feature = "plugin")]
|
||||
plugin_recipients.push(_recipient);
|
||||
} else {
|
||||
return Err(ReadError::InvalidRecipient(s));
|
||||
}
|
||||
|
@ -75,7 +91,7 @@ fn read_recipients_list<R: io::BufRead>(
|
|||
filename: &str,
|
||||
buf: R,
|
||||
recipients: &mut Vec<Box<dyn Recipient + Send>>,
|
||||
plugin_recipients: &mut Vec<plugin::Recipient>,
|
||||
#[cfg(feature = "plugin")] plugin_recipients: &mut Vec<plugin::Recipient>,
|
||||
) -> Result<(), ReadError> {
|
||||
for (line_number, line) in buf.lines().enumerate() {
|
||||
let line = line?;
|
||||
|
@ -83,13 +99,19 @@ fn read_recipients_list<R: io::BufRead>(
|
|||
// Skip empty lines and comments
|
||||
if line.is_empty() || line.find('#') == Some(0) {
|
||||
continue;
|
||||
} else if let Err(e) = parse_recipient(filename, line, recipients, plugin_recipients) {
|
||||
} else if let Err(_e) = parse_recipient(
|
||||
filename,
|
||||
line,
|
||||
recipients,
|
||||
#[cfg(feature = "plugin")]
|
||||
plugin_recipients,
|
||||
) {
|
||||
#[cfg(feature = "ssh")]
|
||||
match e {
|
||||
match _e {
|
||||
ReadError::RsaModulusTooLarge
|
||||
| ReadError::RsaModulusTooSmall
|
||||
| ReadError::UnsupportedKey(_, _) => {
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, e.to_string()).into());
|
||||
return Err(io::Error::new(io::ErrorKind::InvalidData, _e.to_string()).into());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -119,11 +141,19 @@ pub fn read_recipients(
|
|||
stdin_guard: &mut StdinGuard,
|
||||
) -> Result<Vec<Box<dyn Recipient + Send>>, ReadError> {
|
||||
let mut recipients: Vec<Box<dyn Recipient + Send>> = vec![];
|
||||
#[cfg(feature = "plugin")]
|
||||
let mut plugin_recipients: Vec<plugin::Recipient> = vec![];
|
||||
#[cfg(feature = "plugin")]
|
||||
let mut plugin_identities: Vec<plugin::Identity> = vec![];
|
||||
|
||||
for arg in recipient_strings {
|
||||
parse_recipient("", arg, &mut recipients, &mut plugin_recipients)?;
|
||||
parse_recipient(
|
||||
"",
|
||||
arg,
|
||||
&mut recipients,
|
||||
#[cfg(feature = "plugin")]
|
||||
&mut plugin_recipients,
|
||||
)?;
|
||||
}
|
||||
|
||||
for arg in recipients_file_strings {
|
||||
|
@ -134,15 +164,29 @@ pub fn read_recipients(
|
|||
_ => e,
|
||||
})?;
|
||||
let buf = BufReader::new(f);
|
||||
read_recipients_list(&arg, buf, &mut recipients, &mut plugin_recipients)?;
|
||||
read_recipients_list(
|
||||
&arg,
|
||||
buf,
|
||||
&mut recipients,
|
||||
#[cfg(feature = "plugin")]
|
||||
&mut plugin_recipients,
|
||||
)?;
|
||||
}
|
||||
|
||||
#[cfg(feature = "plugin")]
|
||||
let ctx = &mut (&mut recipients, &mut plugin_identities);
|
||||
#[cfg(not(feature = "plugin"))]
|
||||
let ctx = &mut recipients;
|
||||
|
||||
parse_identity_files::<_, ReadError>(
|
||||
identity_strings,
|
||||
max_work_factor,
|
||||
stdin_guard,
|
||||
&mut (&mut recipients, &mut plugin_identities),
|
||||
|(recipients, _), identity| {
|
||||
ctx,
|
||||
#[cfg(feature = "armor")]
|
||||
|recipients, identity| {
|
||||
#[cfg(feature = "plugin")]
|
||||
let (recipients, _) = recipients;
|
||||
recipients.extend(identity.recipients().map_err(|e| {
|
||||
// Only one error can occur here.
|
||||
if let EncryptError::EncryptedIdentities(e) = e {
|
||||
|
@ -153,7 +197,10 @@ pub fn read_recipients(
|
|||
})?);
|
||||
Ok(())
|
||||
},
|
||||
|(recipients, _), filename, identity| {
|
||||
#[cfg(feature = "ssh")]
|
||||
|recipients, filename, identity| {
|
||||
#[cfg(feature = "plugin")]
|
||||
let (recipients, _) = recipients;
|
||||
let recipient = parse_ssh_recipient(
|
||||
|| ssh::Recipient::try_from(identity),
|
||||
|| Err(ReadError::InvalidRecipient(filename.to_owned())),
|
||||
|
@ -163,42 +210,48 @@ pub fn read_recipients(
|
|||
recipients.push(recipient);
|
||||
Ok(())
|
||||
},
|
||||
|(recipients, plugin_identities), entry| {
|
||||
|recipients, entry| {
|
||||
#[cfg(feature = "plugin")]
|
||||
let (recipients, plugin_identities) = recipients;
|
||||
match entry {
|
||||
IdentityFileEntry::Native(i) => recipients.push(Box::new(i.to_public())),
|
||||
#[cfg(feature = "plugin")]
|
||||
IdentityFileEntry::Plugin(i) => plugin_identities.push(i),
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
// Collect the names of the required plugins.
|
||||
let mut plugin_names = plugin_recipients
|
||||
.iter()
|
||||
.map(|r| r.plugin())
|
||||
.chain(plugin_identities.iter().map(|i| i.plugin()))
|
||||
.collect::<Vec<_>>();
|
||||
plugin_names.sort_unstable();
|
||||
plugin_names.dedup();
|
||||
#[cfg(feature = "plugin")]
|
||||
{
|
||||
// Collect the names of the required plugins.
|
||||
let mut plugin_names = plugin_recipients
|
||||
.iter()
|
||||
.map(|r| r.plugin())
|
||||
.chain(plugin_identities.iter().map(|i| i.plugin()))
|
||||
.collect::<Vec<_>>();
|
||||
plugin_names.sort_unstable();
|
||||
plugin_names.dedup();
|
||||
|
||||
// Find the required plugins.
|
||||
for plugin_name in plugin_names {
|
||||
recipients.push(Box::new(
|
||||
plugin::RecipientPluginV1::new(
|
||||
plugin_name,
|
||||
&plugin_recipients,
|
||||
&plugin_identities,
|
||||
UiCallbacks,
|
||||
)
|
||||
.map_err(|e| {
|
||||
// Only one error can occur here.
|
||||
if let EncryptError::MissingPlugin { binary_name } = e {
|
||||
ReadError::MissingPlugin { binary_name }
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
})?,
|
||||
))
|
||||
// Find the required plugins.
|
||||
for plugin_name in plugin_names {
|
||||
recipients.push(Box::new(
|
||||
plugin::RecipientPluginV1::new(
|
||||
plugin_name,
|
||||
&plugin_recipients,
|
||||
&plugin_identities,
|
||||
UiCallbacks,
|
||||
)
|
||||
.map_err(|e| {
|
||||
// Only one error can occur here.
|
||||
if let EncryptError::MissingPlugin { binary_name } = e {
|
||||
ReadError::MissingPlugin { binary_name }
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
})?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Ok(recipients)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue