diff options
author | Nora Widdecke <nora@sequoia-pgp.org> | 2022-08-08 14:00:51 +0200 |
---|---|---|
committer | Nora Widdecke <nora@sequoia-pgp.org> | 2022-08-09 21:30:41 +0200 |
commit | cb792507391856c7b2f67b5c0b03006addbb1d0b (patch) | |
tree | 807c178f9fd8c9fa4b7f484f008bebad7bd835ec /sq | |
parent | f0c2584d89d3652fff8514eefb46724569841f77 (diff) |
sq: Extract each first level subcommand into module.
- sq_cli.rs has become unwieldy.
- Refactor, so that each first level subcommand has its own module.
Diffstat (limited to 'sq')
-rw-r--r-- | sq/build.rs | 2 | ||||
-rw-r--r-- | sq/src/commands/certify.rs | 2 | ||||
-rw-r--r-- | sq/src/commands/inspect.rs | 2 | ||||
-rw-r--r-- | sq/src/commands/key.rs | 24 | ||||
-rw-r--r-- | sq/src/commands/keyring.rs | 4 | ||||
-rw-r--r-- | sq/src/commands/mod.rs | 6 | ||||
-rw-r--r-- | sq/src/commands/net.rs | 8 | ||||
-rw-r--r-- | sq/src/commands/revoke.rs | 10 | ||||
-rw-r--r-- | sq/src/sq.rs | 2 | ||||
-rw-r--r-- | sq/src/sq_cli.rs | 2989 | ||||
-rw-r--r-- | sq/src/sq_cli/armor.rs | 71 | ||||
-rw-r--r-- | sq/src/sq_cli/autocrypt.rs | 118 | ||||
-rw-r--r-- | sq/src/sq_cli/certify.rs | 204 | ||||
-rw-r--r-- | sq/src/sq_cli/dearmor.rs | 33 | ||||
-rw-r--r-- | sq/src/sq_cli/decrypt.rs | 100 | ||||
-rw-r--r-- | sq/src/sq_cli/encrypt.rs | 125 | ||||
-rw-r--r-- | sq/src/sq_cli/inspect.rs | 43 | ||||
-rw-r--r-- | sq/src/sq_cli/key.rs | 554 | ||||
-rw-r--r-- | sq/src/sq_cli/keyring.rs | 311 | ||||
-rw-r--r-- | sq/src/sq_cli/keyserver.rs | 73 | ||||
-rw-r--r-- | sq/src/sq_cli/mod.rs | 368 | ||||
-rw-r--r-- | sq/src/sq_cli/output_versions.rs | 13 | ||||
-rw-r--r-- | sq/src/sq_cli/packet.rs | 214 | ||||
-rw-r--r-- | sq/src/sq_cli/revoke.rs | 475 | ||||
-rw-r--r-- | sq/src/sq_cli/sign.rs | 119 | ||||
-rw-r--r-- | sq/src/sq_cli/verify.rs | 74 | ||||
-rw-r--r-- | sq/src/sq_cli/wkd.rs | 141 |
27 files changed, 3066 insertions, 3019 deletions
diff --git a/sq/build.rs b/sq/build.rs index 04336019..8a743d68 100644 --- a/sq/build.rs +++ b/sq/build.rs @@ -6,7 +6,7 @@ use clap_complete::Shell; use anyhow::Result; pub mod sq_cli { - include!("src/sq_cli.rs"); + include!("src/sq_cli/mod.rs"); } fn main() { diff --git a/sq/src/commands/certify.rs b/sq/src/commands/certify.rs index b0d6f34a..ff790b7d 100644 --- a/sq/src/commands/certify.rs +++ b/sq/src/commands/certify.rs @@ -18,7 +18,7 @@ use crate::SECONDS_IN_YEAR; use crate::commands::get_certification_keys; use crate::commands::GetKeysOptions; -use crate::sq_cli::CertifyCommand; +use crate::sq_cli::certify::CertifyCommand; pub fn certify(config: Config, c: CertifyCommand) -> Result<()> diff --git a/sq/src/commands/inspect.rs b/sq/src/commands/inspect.rs index 50463324..57069c65 100644 --- a/sq/src/commands/inspect.rs +++ b/sq/src/commands/inspect.rs @@ -17,7 +17,7 @@ use super::dump::Convert; use crate::SECONDS_IN_YEAR; use crate::SECONDS_IN_DAY; -use crate::sq_cli::InspectCommand; +use crate::sq_cli::inspect::InspectCommand; pub fn inspect(c: InspectCommand, policy: &dyn Policy, output: &mut dyn io::Write) -> Result<()> { diff --git a/sq/src/commands/key.rs b/sq/src/commands/key.rs index b132adf4..7c07f242 100644 --- a/sq/src/commands/key.rs +++ b/sq/src/commands/key.rs @@ -24,16 +24,16 @@ use crate::SECONDS_IN_YEAR; use crate::parse_duration; use crate::decrypt_key; -use crate::sq_cli::KeyCommand; -use crate::sq_cli::KeyGenerateCommand; -use crate::sq_cli::KeyPasswordCommand; -use crate::sq_cli::KeyUseridCommand; -use crate::sq_cli::KeyUseridAddCommand; -use crate::sq_cli::KeyUseridStripCommand; -use crate::sq_cli::KeyExtractCertCommand; -use crate::sq_cli::KeyAdoptCommand; -use crate::sq_cli::KeyAttestCertificationsCommand; -use crate::sq_cli::KeySubcommands::*; +use crate::sq_cli::key::KeyCommand; +use crate::sq_cli::key::KeyGenerateCommand; +use crate::sq_cli::key::KeyPasswordCommand; +use crate::sq_cli::key::KeyUseridCommand; +use crate::sq_cli::key::KeyUseridAddCommand; +use crate::sq_cli::key::KeyUseridStripCommand; +use crate::sq_cli::key::KeyExtractCertCommand; +use crate::sq_cli::key::KeyAdoptCommand; +use crate::sq_cli::key::KeyAttestCertificationsCommand; +use crate::sq_cli::key::KeySubcommands::*; pub fn dispatch(config: Config, command: KeyCommand) -> Result<()> { match command.subcommand { @@ -91,7 +91,7 @@ fn generate(config: Config, command: KeyGenerateCommand) -> Result<()> { } // Cipher Suite - use crate::sq_cli::KeyCipherSuite::*; + use crate::sq_cli::key::KeyCipherSuite::*; match command.cipher_suite { Rsa3k => { builder = builder.set_cipher_suite(CipherSuite::RSA3k); @@ -130,7 +130,7 @@ fn generate(config: Config, command: KeyGenerateCommand) -> Result<()> { } // Encryption Capability - use crate::sq_cli::KeyEncryptPurpose::*; + use crate::sq_cli::key::KeyEncryptPurpose::*; match (command.can_encrypt, command.cannot_encrypt) { (Some(Universal), false) | (None, false) => { builder = builder.add_subkey(KeyFlags::empty() diff --git a/sq/src/commands/keyring.rs b/sq/src/commands/keyring.rs index d0ad45f9..c707a5e0 100644 --- a/sq/src/commands/keyring.rs +++ b/sq/src/commands/keyring.rs @@ -33,8 +33,8 @@ use crate::{ output::KeyringListItem, }; -use crate::sq_cli::KeyringCommand; -use crate::sq_cli::KeyringSubcommands::*; +use crate::sq_cli::keyring::KeyringCommand; +use crate::sq_cli::keyring::KeyringSubcommands::*; pub fn dispatch(config: Config, c: KeyringCommand) -> Result<()> { match c.subcommand { diff --git a/sq/src/commands/mod.rs b/sq/src/commands/mod.rs index ca91bc58..d82b2dca 100644 --- a/sq/src/commands/mod.rs +++ b/sq/src/commands/mod.rs @@ -36,9 +36,9 @@ use crate::{ Config, }; -use crate::sq_cli::EncryptCompressionMode; -use crate::sq_cli::EncryptEncryptionMode; -use crate::sq_cli::PacketJoinCommand; +use crate::sq_cli::encrypt::EncryptCompressionMode; +use crate::sq_cli::encrypt::EncryptEncryptionMode; +use crate::sq_cli::packet::PacketJoinCommand; #[cfg(feature = "autocrypt")] pub mod autocrypt; diff --git a/sq/src/commands/net.rs b/sq/src/commands/net.rs index 715ced61..92c939fe 100644 --- a/sq/src/commands/net.rs +++ b/sq/src/commands/net.rs @@ -30,10 +30,10 @@ use crate::{ output::WkdUrlVariant, }; -use crate::sq_cli::KeyserverCommand; -use crate::sq_cli::KeyserverSubcommands; -use crate::sq_cli::WkdCommand; -use crate::sq_cli::WkdSubcommands; +use crate::sq_cli::keyserver::KeyserverCommand; +use crate::sq_cli::keyserver::KeyserverSubcommands; +use crate::sq_cli::wkd::WkdCommand; +use crate::sq_cli::wkd::WkdSubcommands; pub fn dispatch_keyserver(config: Config, c: KeyserverCommand) -> Result<()> { let network_policy = c.network_policy.into(); diff --git a/sq/src/commands/revoke.rs b/sq/src/commands/revoke.rs index 5b04b8a6..dd530025 100644 --- a/sq/src/commands/revoke.rs +++ b/sq/src/commands/revoke.rs @@ -44,11 +44,11 @@ impl RevocationTarget { } } -use crate::sq_cli::RevokeCommand; -use crate::sq_cli::RevokeSubcommands; -use crate::sq_cli::RevokeCertificateCommand; -use crate::sq_cli::RevokeSubkeyCommand; -use crate::sq_cli::RevokeUseridCommand; +use crate::sq_cli::revoke::RevokeCommand; +use crate::sq_cli::revoke::RevokeSubcommands; +use crate::sq_cli::revoke::RevokeCertificateCommand; +use crate::sq_cli::revoke::RevokeSubkeyCommand; +use crate::sq_cli::revoke::RevokeUseridCommand; pub fn dispatch(config: Config, c: RevokeCommand) -> Result<()> { diff --git a/sq/src/sq.rs b/sq/src/sq.rs index e5ba9860..48f7fe0b 100644 --- a/sq/src/sq.rs +++ b/sq/src/sq.rs @@ -29,7 +29,7 @@ use crate::openpgp::cert::prelude::*; use crate::openpgp::policy::StandardPolicy as P; use clap::FromArgMatches; -use crate::sq_cli::PacketSubcommands; +use crate::sq_cli::packet::PacketSubcommands; use sq_cli::SqSubcommands; mod sq_cli; diff --git a/sq/src/sq_cli.rs b/sq/src/sq_cli.rs deleted file mode 100644 index aff78c71..00000000 --- a/sq/src/sq_cli.rs +++ /dev/null @@ -1,2989 +0,0 @@ -/// Command-line parser for sq. -use clap::{ArgGroup, Command, ArgEnum, Args, Subcommand}; -use clap::{CommandFactory, Parser}; - -use sequoia_openpgp as openpgp; -use openpgp::crypto::SessionKey; -use openpgp::types::SymmetricAlgorithm; -use openpgp::fmt::hex; - -pub fn build() -> Command<'static> { - let sq_version = Box::leak( - format!( - "{} (sequoia-openpgp {}, using {})", - env!("CARGO_PKG_VERSION"), - sequoia_openpgp::VERSION, - sequoia_openpgp::crypto::backend() - ) - .into_boxed_str(), - ) as &str; - SqCommand::command().version(sq_version) -} - -/// Defines the CLI. -#[derive(Parser, Debug)] -#[clap( - name = "sq", - about = "A command-line frontend for Sequoia, an implementation of OpenPGP", - long_about = "A command-line frontend for Sequoia, an implementation of OpenPGP - -Functionality is grouped and available using subcommands. Currently, -this interface is completely stateless. Therefore, you need to supply -all configuration and certificates explicitly on each invocation. - -OpenPGP data can be provided in binary or ASCII armored form. This -will be handled automatically. Emitted OpenPGP data is ASCII armored -by default. - -We use the term \"certificate\", or cert for short, to refer to OpenPGP -keys that do not contain secrets. Conversely, we use the term \"key\" -to refer to OpenPGP keys that do contain secrets. -", - subcommand_required = true, - arg_required_else_help = true, - disable_colored_help = true, - setting(clap::AppSettings::DeriveDisplayOrder), -)] -pub struct SqCommand { - #[clap( - short = 'f', - long = "force", - help = "Overwrites existing files", - )] - pub force: bool, - #[clap( - long = "output-format", - value_name = "FORMAT", - possible_values = ["human-readable", "json"], - default_value = "human-readable", - env = "SQ_OUTPUT_FORMAT", - help = "Produces output in FORMAT, if possible", - )] - pub output_format: String, - #[clap( - long = "output-version", - value_name = "VERSION", - env = "SQ_OUTPUT_VERSION", - help = "Produces output variant VERSION.", - long_help = "Produces output variant VERSION, such as 0.0.0. \ - The default is the newest version. The output version \ - is separate from the version of the sq program. To see \ - the current supported versions, use output-versions \ - subcommand." - )] - pub output_version: Option<String>, - #[clap( - long = "known-notation", - value_name = "NOTATION", - multiple_occurrences = true, - help = "Adds NOTATION to the list of known notations", - long_help = "Adds NOTATION to the list of known notations. \ - This is used when validating signatures. \ - Signatures that have unknown notations with the \ - critical bit set are considered invalid." - )] - // TODO is this the right type? - pub known_notation: Vec<String>, - #[clap(subcommand)] - pub subcommand: SqSubcommands, -} - -/// The order of top-level subcommands is: -/// -/// - Encryption & decryption -/// - Signing & verification -/// - Key & cert-ring management -/// - Key discovery & networking -/// - Armor -/// - Inspection & packet manipulation -/// -/// The order is derived from the order of variants in this enum. -#[derive(Debug, Subcommand)] -pub enum SqSubcommands { - Encrypt(EncryptCommand), - Decrypt(DecryptCommand), - - Sign(SignCommand), - Verify(VerifyCommand), - - Key(KeyCommand), - Keyring(KeyringCommand), - Certify(CertifyCommand), - - #[cfg(feature = "autocrypt")] - Autocrypt(autocrypt::AutocryptCommand), - Keyserver(KeyserverCommand), - Wkd(WkdCommand), - - Armor(ArmorCommand), - Dearmor(DearmorCommand), - - Inspect(InspectCommand), - Packet(PacketCommand), - - Revoke(RevokeCommand), - - OutputVersions(OutputVersionsCommand), -} - -use chrono::{offset::Utc, DateTime}; -#[derive(Debug)] -pub struct CliTime { - pub time: DateTime<Utc>, -} - -impl std::str::FromStr for CliTime { - type Err = anyhow::Error; - - fn from_str(s: &str) -> anyhow::Result<CliTime> { - let time = - CliTime::parse_iso8601(s, chrono::NaiveTime::from_hms(0, 0, 0))?; - Ok(CliTime { time }) - } -} - -impl CliTime { - /// Parses the given string depicting a ISO 8601 timestamp. - fn parse_iso8601( - s: &str, - pad_date_with: chrono::NaiveTime, - ) -> anyhow::Result<DateTime<Utc>> { - // If you modify this function this function, synchronize the - // changes with the copy in sqv.rs! - for f in &[ - "%Y-%m-%dT%H:%M:%S%#z", - "%Y-%m-%dT%H:%M:%S", - "%Y-%m-%dT%H:%M%#z", - "%Y-%m-%dT%H:%M", - "%Y-%m-%dT%H%#z", - "%Y-%m-%dT%H", - "%Y%m%dT%H%M%S%#z", - "%Y%m%dT%H%M%S", - "%Y%m%dT%H%M%#z", - "%Y%m%dT%H%M", - "%Y%m%dT%H%#z", - "%Y%m%dT%H", - ] { - if f.ends_with("%#z") { - if let Ok(d) = DateTime::parse_from_str(s, *f) { - return Ok(d.into()); - } - } else if let Ok(d) = chrono::NaiveDateTime::parse_from_str(s, *f) { - return Ok(DateTime::from_utc(d, Utc)); - } - } - for f in &[ - "%Y-%m-%d", - "%Y-%m", - "%Y-%j", - "%Y%m%d", - "%Y%m", - "%Y%j", - "%Y", - ] { - if let Ok(d) = chrono::NaiveDate::parse_from_str(s, *f) { - return Ok(DateTime::from_utc(d.and_time(pad_date_with), Utc)); - } - } - Err(anyhow::anyhow!("Malformed ISO8601 timestamp: {}", s)) - } -} - -#[derive(Debug, Args)] -pub struct IoArgs { - #[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")] - pub input: Option<String>, - #[clap( - short, - long, - value_name = "FILE", - help = "Writes to FILE or stdout if omitted" - )] - pub output: Option<String>, -} - -// TODO?: Option<_> conflicts with default value -// TODO: Use PathBuf as input type for more type safety? Investigate conversion -// TODO: use indoc to transparently (de-)indent static strings -#[derive(Parser, Debug)] -#[clap( - name = "armor", - about = "Converts binary to ASCII", - long_about = -"Converts binary to ASCII - -To make encrypted data easier to handle and transport, OpenPGP data -can be transformed to an ASCII representation called ASCII Armor. sq -emits armored data by default, but this subcommand can be used to -convert existing OpenPGP data to its ASCII-encoded representation. - -The converse operation is \"sq dearmor\". -", - after_help = -"EXAMPLES: - -# Convert a binary certificate to ASCII -$ sq armor binary-juliet.pgp - -# Convert a binary message to ASCII -$ sq armor binary-message.pgp -" - )] -pub struct ArmorCommand { - #[clap(flatten)] - pub io: IoArgs, - #[clap( - long = "label", - value_name = "LABEL", - help = "Selects the kind of armor header", - default_value_t = CliArmorKind::Auto, - arg_enum - )] - pub kind: CliArmorKind, -} - -#[derive(ArgEnum)] -#[derive(Debug, Clone)] -pub enum CliArmorKind { - Auto, - Message, - #[clap(name = "cert")] - PublicKey, - #[clap(name = "key")] - SecretKey, - #[clap(name = "sig")] - Signature, - File, -} - -use sequoia_openpgp::armor::Kind as OpenPGPArmorKind; -impl From<CliArmorKind> for Option<OpenPGPArmorKind> { - fn from(c: CliArmorKind) -> Self { - match c { - CliArmorKind::Auto => None, - CliArmorKind::Message => Some(OpenPGPArmorKind::Message), - CliArmorKind::PublicKey => Some(OpenPGPArmorKind::PublicKey), - CliArmorKind::SecretKey => Some(OpenPGPArmorKind::SecretKey), - CliArmorKind::Signature => Some(OpenPGPArmorKind::Signature), - CliArmorKind::File => Some(OpenPGPArmorKind::File), - } - } -} - -#[derive(Parser, Debug)] -#[clap( - name = "dearmor", - about = "Converts ASCII to binary", - long_about = -"Converts ASCII to binary - -To make encrypted data easier to handle and transport, OpenPGP data -can be transformed to an ASCII representation called ASCII Armor. sq -transparently handles armored data, but this subcommand can be used to -explicitly convert existing ASCII-encoded OpenPGP data to its binary -representation. - -The converse operation is \"sq armor\". -", - after_help = -"EXAMPLES: - -# Convert a ASCII certificate to binary -$ sq dearmor ascii-juliet.pgp - -# Convert a ASCII message to binary -$ sq dearmor ascii-message.pgp -", - )] -pub struct DearmorCommand { - #[clap(flatten)] - pub io: IoArgs, -} - -#[derive(Parser, Debug)] -#[clap( - name = "verify", - about = "Verifies signed messages or detached signatures", - long_about = "Verifies signed messages or detached signatures - -When verifying signed messages, the message is written to stdout or -the file given to --output. - -When a detached message is verified, no output is produced. Detached -signatures are often used to sign software packages. - -Verification is only successful if there is no bad signature, and the -number of successfully verified signatures reaches the threshold -configured with the \"--signatures\" parameter. If the verification -fails, the program terminates with an exit status indicating failure. -In addition to that, the last 25 MiB of the message are withheld, -i.e. if the message is smaller than 25 MiB, no output is produced, and -if it is larger, then the output will be truncated. - -The converse operation is \"sq sign\". -", - after_help = -"EXAMPLES: - -# Verify a signed message -$ sq verify --signer-cert juliet.pgp signed-message.pgp - -# Verify a detached message -$ sq verify --signer-cert juliet.pgp --detached message.sig message.txt - -SEE ALSO: - -If you are looking for a standalone program to verify detached -signatures, consider using sequoia-sqv. -", - )] -pub struct VerifyCommand { - #[clap(flatten)] - pub io: IoArgs, - #[clap( - long = "detached", - value_name = "SIG", - help = "Verifies a detached signature" - )] - pub detached: Option<String>, - #[clap( - short = 'n', - long = "signatures", - value_name = "N", - default_value_t = 1, - help = "Sets the threshold of valid signatures to N", - long_help = "Sets the threshold of valid signatures to N. \ - If this threshold is not reached, the message \ - will not be considered verified." - )] - pub signatures: usize, - #[clap( - long = "signer-cert", - value_name = "CERT", - help = "Verifies signatures with CERT", - )] - // TODO: Should at least one sender_cert_file be required? Verification does not make sense - // without one, does it? - // TODO Use PathBuf instead of String. Path representation is platform dependent, so Rust's - // utf-8 Strings are not quite appropriate. - // TODO: And adapt load_certs in sq.rs - pub sender_cert_file: Vec<String>, -} - -#[derive(Parser, Debug)] -#[clap( - name = "sign", - about = "Signs messages or data files", - long_about = -"Signs messages or data files - -Creates signed messages or detached signatures. Detached signatures -are often used to sign software packages. - -The converse operation is \"sq verify\". -", - after_help = -"EXAMPLES: - -# Create a signed message -$ sq sign --signer-key juliet.pgp message.txt - -# Create a detached signature -$ sq sign --detached --signer-key juliet.pgp message.txt -", - )] -pub struct SignCommand { - #[clap(flatten)] - pub io: IoArgs, - // TODO: Why capital B? - #[clap( - short = 'B', - long, - help = "Emits binary data", - )] - pub binary: bool, - #[clap( - long = "private-key-store", - value_name = "KEY_STORE", - help = "Provides parameters for private key store", - )] - pub private_key_store: Option<String>, - #[clap( - long, - help = "Creates a detached signature", - )] - pub detached: bool, - #[clap( - long = "cleartext-signature", - help = "Creates a cleartext signature", - conflicts_with_all = &[ - "detached", - "append", - "notarize", - "binary", - ], - )] - pub clearsign: bool, - #[clap( - short, - long, - conflicts_with = "notarize", - help = "Appends a signature to existing signature", - )] - pub append: bool, - #[clap( - short, - long, - conflicts_with = "append", - help = "Signs a message and all existing signatures", - )] - pub notarize: bool, - #[clap( - long, - value_name = "SIGNED-MESSAGE", - conflicts_with_all = &[ - "append", - "detached", - "clearsign", - "notarize", - "secret-key-file", - "time", - ], - help = "Merges signatures from the input and SIGNED-MESSAGE", - )] - pub merge: Option<String>, - #[clap( - lon |