Move cli parser for sq key subkey add to its own module.
This commit is contained in:
parent
26c14e1a54
commit
0dffab8d50
@ -12,7 +12,6 @@ use crate::cli::types::FileOrStdout;
|
||||
use crate::cli::types::Time;
|
||||
|
||||
use crate::cli::key::{
|
||||
CipherSuite,
|
||||
EncryptPurpose,
|
||||
KeyReasonForRevocation,
|
||||
};
|
||||
@ -26,6 +25,8 @@ use crate::cli::types::CertDesignators;
|
||||
use crate::cli::types::KeyDesignators;
|
||||
use crate::cli::types::cert_designator;
|
||||
|
||||
pub mod add;
|
||||
|
||||
#[derive(Debug, Subcommand)]
|
||||
#[clap(
|
||||
name = "subkey",
|
||||
@ -40,7 +41,7 @@ and revoke them.",
|
||||
)]
|
||||
#[non_exhaustive]
|
||||
pub enum Command {
|
||||
Add(AddCommand),
|
||||
Add(add::Command),
|
||||
Export(ExportCommand),
|
||||
Delete(DeleteCommand),
|
||||
Password(PasswordCommand),
|
||||
@ -49,176 +50,6 @@ pub enum Command {
|
||||
Bind(BindCommand),
|
||||
}
|
||||
|
||||
const SUBKEY_ADD_EXAMPLES: Actions = Actions {
|
||||
actions: &[
|
||||
Action::Setup(Setup {
|
||||
command: &[
|
||||
"sq", "key", "import",
|
||||
"alice-secret.pgp",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Add a new signing-capable subkey to Alice's key.",
|
||||
command: &[
|
||||
"sq", "key", "subkey", "add",
|
||||
"--without-password",
|
||||
"--can-sign",
|
||||
"--cert=EB28F26E2739A4870ECC47726F0073F60FD0CBF0",
|
||||
],
|
||||
}),
|
||||
]
|
||||
};
|
||||
test_examples!(sq_key_subkey_add, SUBKEY_ADD_EXAMPLES);
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
#[clap(
|
||||
about = "Add a new subkey to a certificate",
|
||||
long_about = "\
|
||||
Add a new subkey to a certificate.
|
||||
|
||||
A subkey has one or more capabilities.
|
||||
|
||||
`--can-sign` sets the signing capability, and means that the key may \
|
||||
be used for signing. `--can-authenticate` sets the authentication \
|
||||
capability, and means that the key may be used for authentication \
|
||||
(e.g., as an SSH key). `--can-certify` sets the certificate \
|
||||
capability, and means that the key may be used to make third-party \
|
||||
certifications. These capabilities may be combined.
|
||||
|
||||
`--can-encrypt=storage` sets the storage encryption capability, and \
|
||||
means that the key may be used for storage \
|
||||
encryption. `--can-encrypt=transport` sets the transport encryption \
|
||||
capability, and means that the key may be used for transport \
|
||||
encryption. `--can-encrypt=universal` sets both the storage and the \
|
||||
transport encryption capability, and means that the key may be used \
|
||||
for both storage and transport encryption. The encryption \
|
||||
capabilities must not be combined with the signing or authentication \
|
||||
capability.
|
||||
|
||||
Normally, `sq` prompts the user for a password to use to encrypt the \
|
||||
secret key material. The password for the new subkey may be different \
|
||||
from the other keys. When using `--without-password`, `sq` doesn't \
|
||||
prompt for a password, and doesn't password-protect the subkey.
|
||||
|
||||
By default a new subkey doesn't expire on its own. However, its \
|
||||
validity period is limited by that of the certificate. Using the \
|
||||
`--expiration` argument allows setting a different expiration time.
|
||||
|
||||
`sq key subkey add` respects the reference time set by the top-level \
|
||||
`--time` argument. It sets the creation time of the subkey to the specified \
|
||||
time.
|
||||
",
|
||||
after_help = SUBKEY_ADD_EXAMPLES,
|
||||
)]
|
||||
#[clap(group(ArgGroup::new("authentication-group").args(&["can_authenticate", "can_encrypt"])))]
|
||||
#[clap(group(ArgGroup::new("sign-group").args(&["can_sign", "can_encrypt"])))]
|
||||
#[clap(group(ArgGroup::new("required-group").args(&["can_authenticate", "can_sign", "can_encrypt"]).required(true)))]
|
||||
pub struct AddCommand {
|
||||
#[command(flatten)]
|
||||
pub cert: CertDesignators<
|
||||
cert_designator::CertUserIDEmailFileArgs,
|
||||
cert_designator::NoPrefix,
|
||||
cert_designator::OneValueAndFileRequiresOutput,
|
||||
SubkeyAddDoc>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "CIPHER-SUITE",
|
||||
default_value_t = CipherSuite::Cv25519,
|
||||
help = "Select the cryptographic algorithms for the subkey",
|
||||
value_enum,
|
||||
)]
|
||||
pub cipher_suite: CipherSuite,
|
||||
|
||||
#[command(flatten)]
|
||||
pub expiration: ExpirationArg,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "Add a signing-capable subkey",
|
||||
)]
|
||||
pub can_sign: bool,
|
||||
#[clap(
|
||||
long,
|
||||
help = "Add an authentication-capable subkey",
|
||||
)]
|
||||
pub can_authenticate: bool,
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "PURPOSE",
|
||||
help = "Add an encryption-capable subkey [default: universal]",
|
||||
long_help = "\
|
||||
Add an encryption-capable subkey.
|
||||
|
||||
Encryption-capable subkeys can be marked as suitable for transport \
|
||||
encryption, storage encryption, or both, i.e., universal. [default: \
|
||||
universal]",
|
||||
value_enum,
|
||||
)]
|
||||
pub can_encrypt: Option<EncryptPurpose>,
|
||||
|
||||
#[clap(
|
||||
long = "new-password-file",
|
||||
value_name = "PASSWORD_FILE",
|
||||
help = "\
|
||||
File containing password to encrypt the secret key material",
|
||||
long_help = "\
|
||||
File containing password to encrypt the secret key material.
|
||||
|
||||
Note that the entire key file will be used as the password including \
|
||||
any surrounding whitespace like a trailing newline.",
|
||||
conflicts_with = "without_password",
|
||||
)]
|
||||
pub new_password_file: Option<PathBuf>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "Don't protect the subkey's secret key material with a password",
|
||||
)]
|
||||
pub without_password: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = FileOrStdout::VALUE_NAME,
|
||||
help = "Write to the specified FILE",
|
||||
long_help = "\
|
||||
Write to the specified FILE.
|
||||
|
||||
If not specified, and the certificate was read from the certificate \
|
||||
store, imports the modified certificate into the key store. If not \
|
||||
specified, and the certificate was read from a file, writes the \
|
||||
modified certificate to stdout.",
|
||||
)]
|
||||
pub output: Option<FileOrStdout>,
|
||||
#[clap(
|
||||
long,
|
||||
help = "Emit binary data",
|
||||
)]
|
||||
pub binary: bool,
|
||||
}
|
||||
|
||||
|
||||
/// Documentation for the cert designators for the key subkey add
|
||||
/// command.
|
||||
pub struct SubkeyAddDoc {}
|
||||
|
||||
impl cert_designator::AdditionalDocs for SubkeyAddDoc {
|
||||
fn help(arg: &'static str, help: &'static str) -> clap::builder::StyledStr {
|
||||
match arg {
|
||||
"file" =>
|
||||
"Add a subkey to the key read from PATH"
|
||||
.into(),
|
||||
_ => {
|
||||
debug_assert!(help.starts_with("Use certificates"));
|
||||
help.replace("Use certificates",
|
||||
"Add a subkey to the key")
|
||||
.into()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SUBKEY_EXPORT_EXAMPLES: Actions = Actions {
|
||||
actions: &[
|
||||
Action::Setup(Setup {
|
||||
|
185
src/cli/key/subkey/add.rs
Normal file
185
src/cli/key/subkey/add.rs
Normal file
@ -0,0 +1,185 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::Args;
|
||||
use clap::ArgGroup;
|
||||
|
||||
use crate::cli::examples;
|
||||
use examples::Action;
|
||||
use examples::Actions;
|
||||
use examples::Example;
|
||||
use examples::Setup;
|
||||
|
||||
use crate::cli::key::CipherSuite;
|
||||
use crate::cli::types::CertDesignators;
|
||||
use crate::cli::types::ClapData;
|
||||
use crate::cli::types::EncryptPurpose;
|
||||
use crate::cli::types::ExpirationArg;
|
||||
use crate::cli::types::FileOrStdout;
|
||||
use crate::cli::types::cert_designator;
|
||||
|
||||
pub struct AdditionalDocs {}
|
||||
|
||||
impl cert_designator::AdditionalDocs for AdditionalDocs {
|
||||
fn help(arg: &'static str, help: &'static str) -> clap::builder::StyledStr {
|
||||
match arg {
|
||||
"file" =>
|
||||
"Add a subkey to the key read from PATH"
|
||||
.into(),
|
||||
_ => {
|
||||
debug_assert!(help.starts_with("Use certificates"));
|
||||
help.replace("Use certificates",
|
||||
"Add a subkey to the key")
|
||||
.into()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Args)]
|
||||
#[clap(
|
||||
about = "Add a new subkey to a certificate",
|
||||
long_about = "\
|
||||
Add a new subkey to a certificate.
|
||||
|
||||
A subkey has one or more capabilities.
|
||||
|
||||
`--can-sign` sets the signing capability, and means that the key may \
|
||||
be used for signing. `--can-authenticate` sets the authentication \
|
||||
capability, and means that the key may be used for authentication \
|
||||
(e.g., as an SSH key). `--can-certify` sets the certificate \
|
||||
capability, and means that the key may be used to make third-party \
|
||||
certifications. These capabilities may be combined.
|
||||
|
||||
`--can-encrypt=storage` sets the storage encryption capability, and \
|
||||
means that the key may be used for storage \
|
||||
encryption. `--can-encrypt=transport` sets the transport encryption \
|
||||
capability, and means that the key may be used for transport \
|
||||
encryption. `--can-encrypt=universal` sets both the storage and the \
|
||||
transport encryption capability, and means that the key may be used \
|
||||
for both storage and transport encryption. The encryption \
|
||||
capabilities must not be combined with the signing or authentication \
|
||||
capability.
|
||||
|
||||
Normally, `sq` prompts the user for a password to use to encrypt the \
|
||||
secret key material. The password for the new subkey may be different \
|
||||
from the other keys. When using `--without-password`, `sq` doesn't \
|
||||
prompt for a password, and doesn't password-protect the subkey.
|
||||
|
||||
By default a new subkey doesn't expire on its own. However, its \
|
||||
validity period is limited by that of the certificate. Using the \
|
||||
`--expiration` argument allows setting a different expiration time.
|
||||
|
||||
`sq key subkey add` respects the reference time set by the top-level \
|
||||
`--time` argument. It sets the creation time of the subkey to the specified \
|
||||
time.
|
||||
",
|
||||
after_help = EXAMPLES,
|
||||
)]
|
||||
#[clap(group(ArgGroup::new("authentication-group").args(&["can_authenticate", "can_encrypt"])))]
|
||||
#[clap(group(ArgGroup::new("sign-group").args(&["can_sign", "can_encrypt"])))]
|
||||
#[clap(group(ArgGroup::new("required-group").args(&["can_authenticate", "can_sign", "can_encrypt"]).required(true)))]
|
||||
pub struct Command {
|
||||
#[command(flatten)]
|
||||
pub cert: CertDesignators<
|
||||
cert_designator::CertUserIDEmailFileArgs,
|
||||
cert_designator::NoPrefix,
|
||||
cert_designator::OneValueAndFileRequiresOutput,
|
||||
AdditionalDocs>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "CIPHER-SUITE",
|
||||
default_value_t = CipherSuite::Cv25519,
|
||||
help = "Select the cryptographic algorithms for the subkey",
|
||||
value_enum,
|
||||
)]
|
||||
pub cipher_suite: CipherSuite,
|
||||
|
||||
#[command(flatten)]
|
||||
pub expiration: ExpirationArg,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "Add a signing-capable subkey",
|
||||
)]
|
||||
pub can_sign: bool,
|
||||
#[clap(
|
||||
long,
|
||||
help = "Add an authentication-capable subkey",
|
||||
)]
|
||||
pub can_authenticate: bool,
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "PURPOSE",
|
||||
help = "Add an encryption-capable subkey [default: universal]",
|
||||
long_help = "\
|
||||
Add an encryption-capable subkey.
|
||||
|
||||
Encryption-capable subkeys can be marked as suitable for transport \
|
||||
encryption, storage encryption, or both, i.e., universal. [default: \
|
||||
universal]",
|
||||
value_enum,
|
||||
)]
|
||||
pub can_encrypt: Option<EncryptPurpose>,
|
||||
|
||||
#[clap(
|
||||
long = "new-password-file",
|
||||
value_name = "PASSWORD_FILE",
|
||||
help = "\
|
||||
File containing password to encrypt the secret key material",
|
||||
long_help = "\
|
||||
File containing password to encrypt the secret key material.
|
||||
|
||||
Note that the entire key file will be used as the password including \
|
||||
any surrounding whitespace like a trailing newline.",
|
||||
conflicts_with = "without_password",
|
||||
)]
|
||||
pub new_password_file: Option<PathBuf>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "Don't protect the subkey's secret key material with a password",
|
||||
)]
|
||||
pub without_password: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = FileOrStdout::VALUE_NAME,
|
||||
help = "Write to the specified FILE",
|
||||
long_help = "\
|
||||
Write to the specified FILE.
|
||||
|
||||
If not specified, and the certificate was read from the certificate \
|
||||
store, imports the modified certificate into the key store. If not \
|
||||
specified, and the certificate was read from a file, writes the \
|
||||
modified certificate to stdout.",
|
||||
)]
|
||||
pub output: Option<FileOrStdout>,
|
||||
#[clap(
|
||||
long,
|
||||
help = "Emit binary data",
|
||||
)]
|
||||
pub binary: bool,
|
||||
}
|
||||
|
||||
const EXAMPLES: Actions = Actions {
|
||||
actions: &[
|
||||
Action::Setup(Setup {
|
||||
command: &[
|
||||
"sq", "key", "import",
|
||||
"alice-secret.pgp",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Add a new signing-capable subkey to Alice's key.",
|
||||
command: &[
|
||||
"sq", "key", "subkey", "add",
|
||||
"--without-password",
|
||||
"--can-sign",
|
||||
"--cert=EB28F26E2739A4870ECC47726F0073F60FD0CBF0",
|
||||
],
|
||||
}),
|
||||
]
|
||||
};
|
||||
test_examples!(sq_key_subkey_add, EXAMPLES);
|
@ -19,8 +19,8 @@ use openpgp::Packet;
|
||||
use openpgp::Result;
|
||||
|
||||
use crate::Sq;
|
||||
use crate::cli::key::subkey::AddCommand;
|
||||
use crate::cli::key::subkey::Command;
|
||||
use crate::cli::key::subkey::add::Command as AddCommand;
|
||||
use crate::cli::key::subkey::DeleteCommand;
|
||||
use crate::cli::key::subkey::ExpireCommand;
|
||||
use crate::cli::key::subkey::ExportCommand;
|
||||
|
Loading…
Reference in New Issue
Block a user