summaryrefslogtreecommitdiffstats
path: root/sq
diff options
context:
space:
mode:
authorNora Widdecke <nora@sequoia-pgp.org>2022-08-08 14:00:51 +0200
committerNora Widdecke <nora@sequoia-pgp.org>2022-08-09 21:30:41 +0200
commitcb792507391856c7b2f67b5c0b03006addbb1d0b (patch)
tree807c178f9fd8c9fa4b7f484f008bebad7bd835ec /sq
parentf0c2584d89d3652fff8514eefb46724569841f77 (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.rs2
-rw-r--r--sq/src/commands/certify.rs2
-rw-r--r--sq/src/commands/inspect.rs2
-rw-r--r--sq/src/commands/key.rs24
-rw-r--r--sq/src/commands/keyring.rs4
-rw-r--r--sq/src/commands/mod.rs6
-rw-r--r--sq/src/commands/net.rs8
-rw-r--r--sq/src/commands/revoke.rs10
-rw-r--r--sq/src/sq.rs2
-rw-r--r--sq/src/sq_cli.rs2989
-rw-r--r--sq/src/sq_cli/armor.rs71
-rw-r--r--sq/src/sq_cli/autocrypt.rs118
-rw-r--r--sq/src/sq_cli/certify.rs204
-rw-r--r--sq/src/sq_cli/dearmor.rs33
-rw-r--r--sq/src/sq_cli/decrypt.rs100
-rw-r--r--sq/src/sq_cli/encrypt.rs125
-rw-r--r--sq/src/sq_cli/inspect.rs43
-rw-r--r--sq/src/sq_cli/key.rs554
-rw-r--r--sq/src/sq_cli/keyring.rs311
-rw-r--r--sq/src/sq_cli/keyserver.rs73
-rw-r--r--sq/src/sq_cli/mod.rs368
-rw-r--r--sq/src/sq_cli/output_versions.rs13
-rw-r--r--sq/src/sq_cli/packet.rs214
-rw-r--r--sq/src/sq_cli/revoke.rs475
-rw-r--r--sq/src/sq_cli/sign.rs119
-rw-r--r--sq/src/sq_cli/verify.rs74
-rw-r--r--sq/src/sq_cli/wkd.rs141
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