diff --git a/Cargo.lock b/Cargo.lock index b2d793d4..5721935d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,7 +126,7 @@ dependencies = [ "base64", "bech32", "chrono", - "gumdrop", + "clap", ] [[package]] @@ -497,6 +497,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb690e81c7840c0d7aade59f242ea3b41b9bc27bcd5997890e7702ae4b32e487" dependencies = [ "clap_builder", + "clap_derive", + "once_cell", ] [[package]] @@ -505,8 +507,10 @@ version = "4.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ed2e96bc16d8d740f6f48d663eddf4b8a0983e79210fd55479b7bcd0a69860e" dependencies = [ + "anstream", "anstyle", "clap_lex", + "strsim", ] [[package]] @@ -518,6 +522,18 @@ dependencies = [ "clap", ] +[[package]] +name = "clap_derive" +version = "4.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.46", +] + [[package]] name = "clap_lex" version = "0.5.0" @@ -1118,26 +1134,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" -[[package]] -name = "gumdrop" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc700f989d2f6f0248546222d9b4258f5b02a171a431f8285a81c08142629e3" -dependencies = [ - "gumdrop_derive", -] - -[[package]] -name = "gumdrop_derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "729f9bd3449d77e7831a18abfb7ba2f99ee813dfd15b8c2167c9a54ba20aa99d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "half" version = "1.8.2" @@ -1150,6 +1146,12 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.3.3" @@ -2002,7 +2004,6 @@ dependencies = [ "flate2", "fuse_mt", "fuser", - "gumdrop", "i18n-embed", "i18n-embed-fl", "lazy_static", @@ -2521,7 +2522,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", - "quote", "unicode-ident", ] diff --git a/Cargo.toml b/Cargo.toml index 0084cf25..ae8fcf28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,7 @@ rust-embed = "8" # CLI chrono = "0.4" +clap = { version = "4.3", features = ["derive"] } console = { version = "0.15", default-features = false } env_logger = "0.10" -gumdrop = "0.8" log = "0.4" diff --git a/age-plugin/Cargo.toml b/age-plugin/Cargo.toml index 4a972788..12712258 100644 --- a/age-plugin/Cargo.toml +++ b/age-plugin/Cargo.toml @@ -21,7 +21,7 @@ bech32.workspace = true chrono.workspace = true [dev-dependencies] -gumdrop.workspace = true +clap.workspace = true [lib] bench = false diff --git a/age-plugin/README.md b/age-plugin/README.md index 22caf6df..d1300f32 100644 --- a/age-plugin/README.md +++ b/age-plugin/README.md @@ -67,7 +67,7 @@ users will use identity files containing identities that specify that plugin nam ## Example plugin binary -The following example uses `gumdrop` to parse CLI arguments, but any argument parsing +The following example uses `clap` to parse CLI arguments, but any argument parsing logic will work as long as it can detect the `--age-plugin=STATE_MACHINE` flag. ```rust @@ -78,7 +78,8 @@ use age_plugin::{ recipient::{self, RecipientPluginV1}, Callbacks, run_state_machine, }; -use gumdrop::Options; +use clap::Parser; + use std::collections::HashMap; use std::io; @@ -133,17 +134,14 @@ impl IdentityPluginV1 for IdentityPlugin { } } -#[derive(Debug, Options)] +#[derive(Debug, Parser)] struct PluginOptions { - #[options(help = "print help message")] - help: bool, - - #[options(help = "run the given age plugin state machine", no_short)] + #[arg(help = "run the given age plugin state machine", long)] age_plugin: Option, } fn main() -> io::Result<()> { - let opts = PluginOptions::parse_args_default_or_exit(); + let opts = PluginOptions::parse(); if let Some(state_machine) = opts.age_plugin { // The plugin was started by an age client; run the state machine. diff --git a/age-plugin/examples/age-plugin-unencrypted.rs b/age-plugin/examples/age-plugin-unencrypted.rs index 86cc64f1..e287f289 100644 --- a/age-plugin/examples/age-plugin-unencrypted.rs +++ b/age-plugin/examples/age-plugin-unencrypted.rs @@ -8,7 +8,7 @@ use age_plugin::{ recipient::{self, RecipientPluginV1}, run_state_machine, Callbacks, }; -use gumdrop::Options; +use clap::Parser; use std::collections::HashMap; use std::env; @@ -139,17 +139,14 @@ impl IdentityPluginV1 for IdentityPlugin { } } -#[derive(Debug, Options)] +#[derive(Debug, Parser)] struct PluginOptions { - #[options(help = "print help message")] - help: bool, - - #[options(help = "run the given age plugin state machine", no_short)] + #[arg(help = "run the given age plugin state machine", long)] age_plugin: Option, } fn main() -> io::Result<()> { - let opts = PluginOptions::parse_args_default_or_exit(); + let opts = PluginOptions::parse(); if let Some(state_machine) = opts.age_plugin { run_state_machine( diff --git a/age-plugin/src/lib.rs b/age-plugin/src/lib.rs index 5dc2563d..fedd7251 100644 --- a/age-plugin/src/lib.rs +++ b/age-plugin/src/lib.rs @@ -65,7 +65,7 @@ //! //! # Example plugin binary //! -//! The following example uses `gumdrop` to parse CLI arguments, but any argument parsing +//! The following example uses `clap` to parse CLI arguments, but any argument parsing //! logic will work as long as it can detect the `--age-plugin=STATE_MACHINE` flag. //! //! ``` @@ -76,7 +76,8 @@ //! recipient::{self, RecipientPluginV1}, //! Callbacks, run_state_machine, //! }; -//! use gumdrop::Options; +//! use clap::Parser; +//! //! use std::collections::HashMap; //! use std::io; //! @@ -131,17 +132,14 @@ //! } //! } //! -//! #[derive(Debug, Options)] +//! #[derive(Debug, Parser)] //! struct PluginOptions { -//! #[options(help = "print help message")] -//! help: bool, -//! -//! #[options(help = "run the given age plugin state machine", no_short)] +//! #[arg(help = "run the given age plugin state machine", long)] //! age_plugin: Option, //! } //! //! fn main() -> io::Result<()> { -//! let opts = PluginOptions::parse_args_default_or_exit(); +//! let opts = PluginOptions::parse(); //! //! if let Some(state_machine) = opts.age_plugin { //! // The plugin was started by an age client; run the state machine. diff --git a/rage/CHANGELOG.md b/rage/CHANGELOG.md index 1fc70fc9..4c352264 100644 --- a/rage/CHANGELOG.md +++ b/rage/CHANGELOG.md @@ -11,6 +11,7 @@ to 1.0.0 are beta releases. ## [Unreleased] ### Changed - MSRV is now 1.65.0. +- Migrated from `gumdrop` to `clap` for argument parsing. ### Fixed - OpenSSH private keys passed to `-i/--identity` that contain invalid public diff --git a/rage/Cargo.toml b/rage/Cargo.toml index 8ff9cd08..76389d5e 100644 --- a/rage/Cargo.toml +++ b/rage/Cargo.toml @@ -56,9 +56,9 @@ maintenance = { status = "experimental" } # rage and rage-keygen dependencies age = { workspace = true, features = ["armor", "cli-common", "plugin"] } chrono.workspace = true +clap = { workspace = true, features = ["string", "unstable-styles"] } console.workspace = true env_logger.workspace = true -gumdrop.workspace = true i18n-embed = { workspace = true, features = ["desktop-requester"] } i18n-embed-fl.workspace = true lazy_static.workspace = true @@ -76,7 +76,6 @@ time = { version = ">=0.3.7, <0.3.24", optional = true } # time 0.3.24 has MSRV zip = { version = "0.6.2", optional = true } [dev-dependencies] -clap = { version = "4", default-features = false } clap_complete = "4" flate2 = "1" man = "0.3" diff --git a/rage/i18n/en-US/rage.ftl b/rage/i18n/en-US/rage.ftl index cb3446c6..04952016 100644 --- a/rage/i18n/en-US/rage.ftl +++ b/rage/i18n/en-US/rage.ftl @@ -9,6 +9,7 @@ ### Localization for strings in the rage CLI tools -age = age +-age-plugin- = age-plugin- -rage = rage ## CLI flags @@ -27,31 +28,45 @@ ## Usage --input = INPUT --output = OUTPUT --identity = IDENTITY --recipient = RECIPIENT --recipients-file = PATH +usage-header = Usage -usage-header = Usage: +recipient = RECIPIENT +recipients-file = PATH +identity = IDENTITY +plugin-name = PLUGIN-NAME +input = INPUT +output = OUTPUT -rage-usage = - {usage-header} - {" "}{$usage_a} - {" "}{$usage_b} +args-header = Arguments - {$flags} +help-arg-input = Path to a file to read from. - {-input} defaults to standard input, and {-output} defaults to standard output. +flags-header = Options - {-recipient} can be: +help-flag-help = Print this help message and exit. +help-flag-version = Print version info and exit. +help-flag-encrypt = Encrypt the input (the default). +help-flag-decrypt = Decrypt the input. +help-flag-passphrase = Encrypt with a passphrase instead of recipients. +help-flag-max-work-factor = Maximum work factor to allow for passphrase decryption. +help-flag-armor = Encrypt to a PEM encoded format. +help-flag-recipient = Encrypt to the specified {recipient}. May be repeated. +help-flag-recipients-file = Encrypt to the recipients listed at {recipients-file}. May be repeated. +help-flag-identity = Use the identity file at {identity}. May be repeated. +help-flag-plugin-name = Use {-age-plugin-}{plugin-name} in its default mode as an identity. +help-flag-output = Write the result to the file at path {output}. + +rage-after-help = + {input} defaults to standard input, and {output} defaults to standard output. + + {recipient} can be: - An {-age} public key, as generated by {$keygen_name} ("age1..."). - An SSH public key ("ssh-ed25519 AAAA...", "ssh-rsa AAAA..."). - {-recipients-file} is a path to a file containing {-age} recipients, one per line + {recipients-file} is a path to a file containing {-age} recipients, one per line (ignoring "#" prefixed comments and empty lines). - {-identity} is a path to a file with {-age} identities, one per line + {identity} is a path to a file with {-age} identities, one per line (ignoring "#" prefixed comments and empty lines), or to an SSH key file. Passphrase-encrypted {-age} identity files can be used as identity files. Multiple identities may be provided, and any unused ones will be ignored. @@ -62,6 +77,8 @@ rage-usage = {" "}{$example_b} {" "}{$example_c} +keygen-help-flag-output = {help-flag-output} Defaults to standard output. + ## Formatting warning-msg = Warning: {$warning} @@ -161,6 +178,14 @@ rec-dec-recipient-flag = Did you mean to use {-flag-identity} to specify a priva -flag-mnt-types = -t/--types +mnt-filename = FILENAME +mnt-mountpoint = MOUNTPOINT +mnt-types = TYPES + +help-arg-mnt-filename = The encrypted filesystem to mount. +help-arg-mnt-mountpoint = The directory to mount the filesystem at. +help-arg-mnt-types = Indicates the filesystem type (one of {$types}). + info-decrypting = Decrypting {$filename} info-mounting-as-fuse = Mounting as FUSE filesystem diff --git a/rage/i18n/es-AR/rage.ftl b/rage/i18n/es-AR/rage.ftl index e1e00fb9..fec5a5df 100644 --- a/rage/i18n/es-AR/rage.ftl +++ b/rage/i18n/es-AR/rage.ftl @@ -9,6 +9,7 @@ ### Localization for strings in the rage CLI tools -age = age +-age-plugin- = age-plugin- -rage = rage ## CLI flags @@ -27,31 +28,26 @@ ## Usage --input = INPUT --output = OUTPUT --identity = IDENTITY --recipient = RECIPIENT --recipients-file = PATH +usage-header = Usage -usage-header = Usage: +recipient = RECIPIENT +recipients-file = PATH +identity = IDENTITY +plugin-name = PLUGIN-NAME +input = INPUT +output = OUTPUT -rage-usage = - {usage-header} - {" "}{$usage_a} - {" "}{$usage_b} +rage-after-help = + {input} por defecto a standard input, y {output} por defecto standard output. - {$flags} - - {-input} por defecto a standard input, y {-output} por defecto standard output. - - {-recipient} puede ser: + {recipient} puede ser: - Una clave pública {-age}, como es generada por {$keygen_name} ("age1..."). - Una clave pública SSH ("ssh-ed25519 AAAA...", "ssh-rsa AAAA..."). - {-recipients-file} es una ruta a un archivo que contenga un destinatario {-age} por línea + {recipients-file} es una ruta a un archivo que contenga un destinatario {-age} por línea (ignorando comentarios con el prefijo "#" y líneas vacías). - {-identity} es una ruta a una archivo con una identidad {-age} por línea + {identity} es una ruta a una archivo con una identidad {-age} por línea (ignorando comentarios con el prefijo "#" y líneas vacías), o a un archivo de claves SSH. Passphrase-encrypted {-age} identity files can be used as identity files. diff --git a/rage/i18n/it/rage.ftl b/rage/i18n/it/rage.ftl index 32b0e179..da7305ce 100644 --- a/rage/i18n/it/rage.ftl +++ b/rage/i18n/it/rage.ftl @@ -9,6 +9,7 @@ ### Localization for strings in the rage CLI tools -age = age +-age-plugin- = age-plugin- -rage = rage ## CLI flags @@ -27,32 +28,27 @@ ## Usage --input = INPUT --output = OUTPUT --identity = IDENTITY --recipient = RECIPIENT --recipients-file = PATH +usage-header = Usage -usage-header = Usage: +recipient = RECIPIENT +recipients-file = PATH +identity = IDENTITY +plugin-name = PLUGIN-NAME +input = INPUT +output = OUTPUT -rage-usage = - {usage-header} - {" "}{$usage_a} - {" "}{$usage_b} - - {$flags} - - {-input} ha come valore predefinito lo standard input, e {-output} ha come +rage-after-help = + {input} ha come valore predefinito lo standard input, e {output} ha come valore predefinito lo standard output. - {-recipient} può essere: + {recipient} può essere: - Una chiave pubblica {-age}, come generata da {$keygen_name} ("age1..."). - Una chiave pubblica SSH ("ssh-ed25519 AAAA...", "ssh-rsa AAAA..."). - {-recipients-file} è il percorso ad un file contenente dei destinatari {-age}, + {recipients-file} è il percorso ad un file contenente dei destinatari {-age}, uno per riga (ignorando i commenti che iniziano con "#" e le righe vuote). - {-identity} è il percorso ad un file contenente identità {-age}, una per + {identity} è il percorso ad un file contenente identità {-age}, una per riga (ignorando i commenti che iniziano con "#" e le righe vuote), o ad un file contenente una chiave SSH. I file di identità possono essere cifrati con {-age} e una passphrase. diff --git a/rage/i18n/zh-CN/rage.ftl b/rage/i18n/zh-CN/rage.ftl index 4823f5e5..558b4c23 100644 --- a/rage/i18n/zh-CN/rage.ftl +++ b/rage/i18n/zh-CN/rage.ftl @@ -9,6 +9,7 @@ ### Localization for strings in the rage CLI tools -age = age +-age-plugin- = age-plugin- -rage = rage ## CLI flags @@ -27,31 +28,26 @@ ## Usage --input = INPUT --output = OUTPUT --identity = IDENTITY --recipient = RECIPIENT --recipients-file = PATH +usage-header = Usage -usage-header = Usage: +recipient = RECIPIENT +recipients-file = PATH +identity = IDENTITY +plugin-name = PLUGIN-NAME +input = INPUT +output = OUTPUT -rage-usage = - {usage-header} - {" "}{$usage_a} - {" "}{$usage_b} +rage-after-help = + {input} 默认为标准输入 (stdin), 而 {output} 默认为标准输出 (stdout) 。 - {$flags} - - {-input} 默认为标准输入 (stdin), 而 {-output} 默认为标准输出 (stdout) 。 - - {-recipient} 可为: + {recipient} 可为: - 一把以 {$keygen_name} 生成的 {-age} 公钥 ("age1...")。 - 一把 SSH 公钥 ("ssh-ed25519 AAAA...", "ssh-rsa AAAA...")。 - {-recipients-file} 是一个文件路径。该文件应含有 {-age} 接收方, 每行一个 + {recipients-file} 是一个文件路径。该文件应含有 {-age} 接收方, 每行一个 (前缀为 "#" 的注释以及空行将被忽略)。 - {-identity} 是一个文件路径。该文件或含 {-age} 身份, 每行一个(前缀为 "#" 的注释以及空行将被忽略), + {identity} 是一个文件路径。该文件或含 {-age} 身份, 每行一个(前缀为 "#" 的注释以及空行将被忽略), 亦或为 SSH 密钥文件。 Passphrase-encrypted {-age} identity files can be used as identity files. 您可提供多份身份, 未使用的身份将被忽略。 diff --git a/rage/i18n/zh-TW/rage.ftl b/rage/i18n/zh-TW/rage.ftl index 58d4fea7..72206a6e 100644 --- a/rage/i18n/zh-TW/rage.ftl +++ b/rage/i18n/zh-TW/rage.ftl @@ -9,6 +9,7 @@ ### Localization for strings in the rage CLI tools -age = age +-age-plugin- = age-plugin- -rage = rage ## CLI flags @@ -27,31 +28,26 @@ ## Usage --input = INPUT --output = OUTPUT --identity = IDENTITY --recipient = RECIPIENT --recipients-file = PATH +usage-header = Usage -usage-header = Usage: +recipient = RECIPIENT +recipients-file = PATH +identity = IDENTITY +plugin-name = PLUGIN-NAME +input = INPUT +output = OUTPUT -rage-usage = - {usage-header} - {" "}{$usage_a} - {" "}{$usage_b} +rage-after-help = + {input} 默認為標準輸入 (stdin), 而 {output} 默認為標準輸出 (stdout) 。 - {$flags} - - {-input} 默認為標準輸入 (stdin), 而 {-output} 默認為標準輸出 (stdout) 。 - - {-recipient} 可為: + {recipient} 可為: - 一把以 {$keygen_name} 生成的 {-age} 公鑰 ("age1...")。 - 一把 SSH 公鑰 ("ssh-ed25519 AAAA...", "ssh-rsa AAAA...")。 - {-recipients-file} 是一個文件路徑。該文件應含有 {-age} 接收方, 每行一個 + {recipients-file} 是一個文件路徑。該文件應含有 {-age} 接收方, 每行一個 (前綴為 "#" 的注釋以及空行將被忽略)。 - {-identity} 是一個文件路徑。該文件或含 {-age} 身份, 每行一個(前綴為 "#" 的注釋以及空行將被忽略), + {identity} 是一個文件路徑。該文件或含 {-age} 身份, 每行一個(前綴為 "#" 的注釋以及空行將被忽略), 亦或為 SSH 密鑰文件。 Passphrase-encrypted {-age} identity files can be used as identity files. 您可提供多份身份, 未使用的身份將被忽略。 diff --git a/rage/src/bin/rage-keygen/main.rs b/rage/src/bin/rage-keygen/main.rs index a00d7559..9f7e318a 100644 --- a/rage/src/bin/rage-keygen/main.rs +++ b/rage/src/bin/rage-keygen/main.rs @@ -1,7 +1,7 @@ #![forbid(unsafe_code)] use age::{cli_common::file_io, secrecy::ExposeSecret}; -use gumdrop::Options; +use clap::{builder::Styles, ArgAction, Parser}; use i18n_embed::{ fluent::{fluent_language_loader, FluentLanguageLoader}, DesktopLanguageRequester, @@ -31,15 +31,34 @@ macro_rules! fl { }}; } -#[derive(Debug, Options)] +#[derive(Debug, Parser)] +#[command(display_name = "rage-keygen")] +#[command(name = "rage-keygen")] +#[command(version)] +#[command(help_template = format!("\ +{{before-help}}{{about-with-newline}} +{}{}:{} {{usage}} + +{{all-args}}{{after-help}}\ + ", + Styles::default().get_usage().render(), + fl!("usage-header"), + Styles::default().get_usage().render_reset()))] +#[command(next_help_heading = fl!("flags-header"))] +#[command(disable_help_flag(true))] +#[command(disable_version_flag(true))] struct AgeOptions { - #[options(help = "Print this help message and exit.")] - help: bool, + #[arg(action = ArgAction::Help, short, long)] + #[arg(help = fl!("help-flag-help"))] + help: Option, - #[options(help = "Print version info and exit.", short = "V")] - version: bool, + #[arg(action = ArgAction::Version, short = 'V', long)] + #[arg(help = fl!("help-flag-version"))] + version: Option, - #[options(help = "Write the result to the file at path OUTPUT. Defaults to standard output.")] + #[arg(short, long)] + #[arg(value_name = fl!("output"))] + #[arg(help = fl!("keygen-help-flag-output"))] output: Option, } @@ -57,40 +76,35 @@ fn main() -> Result<(), error::Error> { // Isolation Marks, so we disable them for now. LANGUAGE_LOADER.set_use_isolating(false); - let opts = AgeOptions::parse_args_default_or_exit(); + let opts = AgeOptions::parse(); + + let mut output = file_io::OutputWriter::new( + opts.output, + false, + file_io::OutputFormat::Text, + 0o600, + false, + ) + .map_err(error::Error::FailedToOpenOutput)?; + + let sk = age::x25519::Identity::generate(); + let pk = sk.to_public(); + + (|| { + writeln!( + output, + "# {}: {}", + fl!("identity-file-created"), + chrono::Local::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true) + )?; + writeln!(output, "# {}: {}", fl!("identity-file-pubkey"), pk)?; + writeln!(output, "{}", sk.to_string().expose_secret())?; + + if !output.is_terminal() { + eprintln!("{}: {}", fl!("tty-pubkey"), pk); + } - if opts.version { - println!("rage-keygen {}", env!("CARGO_PKG_VERSION")); Ok(()) - } else { - let mut output = file_io::OutputWriter::new( - opts.output, - false, - file_io::OutputFormat::Text, - 0o600, - false, - ) - .map_err(error::Error::FailedToOpenOutput)?; - - let sk = age::x25519::Identity::generate(); - let pk = sk.to_public(); - - (|| { - writeln!( - output, - "# {}: {}", - fl!("identity-file-created"), - chrono::Local::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true) - )?; - writeln!(output, "# {}: {}", fl!("identity-file-pubkey"), pk)?; - writeln!(output, "{}", sk.to_string().expose_secret())?; - - if !output.is_terminal() { - eprintln!("{}: {}", fl!("tty-pubkey"), pk); - } - - Ok(()) - })() - .map_err(error::Error::FailedToWriteOutput) - } + })() + .map_err(error::Error::FailedToWriteOutput) } diff --git a/rage/src/bin/rage-mount/main.rs b/rage/src/bin/rage-mount/main.rs index 3d19bc78..6030b8c4 100644 --- a/rage/src/bin/rage-mount/main.rs +++ b/rage/src/bin/rage-mount/main.rs @@ -5,9 +5,9 @@ use age::{ cli_common::{read_identities, read_secret}, stream::StreamReader, }; +use clap::{builder::Styles, ArgAction, CommandFactory, Parser}; use fuse_mt::FilesystemMT; use fuser::MountOption; -use gumdrop::Options; use i18n_embed::{ fluent::{fluent_language_loader, FluentLanguageLoader}, DesktopLanguageRequester, @@ -125,31 +125,53 @@ impl fmt::Debug for Error { } } -#[derive(Debug, Options)] +#[derive(Debug, Parser)] +#[command(display_name = "rage-mount")] +#[command(name = "rage-mount")] +#[command(version)] +#[command(help_template = format!("\ +{{before-help}}{{about-with-newline}} +{}{}:{} {{usage}} + +{{all-args}}{{after-help}}\ + ", + Styles::default().get_usage().render(), + fl!("usage-header"), + Styles::default().get_usage().render_reset()))] +#[command(next_help_heading = fl!("flags-header"))] +#[command(disable_help_flag(true))] +#[command(disable_version_flag(true))] struct AgeMountOptions { - #[options(free, help = "The encrypted filesystem to mount.")] + #[arg(help_heading = fl!("args-header"))] + #[arg(value_name = fl!("mnt-filename"))] + #[arg(help = fl!("help-arg-mnt-filename"))] filename: String, - #[options(free, help = "The directory to mount the filesystem at.")] + #[arg(help_heading = fl!("args-header"))] + #[arg(value_name = fl!("mnt-mountpoint"))] + #[arg(help = fl!("help-arg-mnt-mountpoint"))] mountpoint: String, - #[options(help = "Print this help message and exit.")] - help: bool, + #[arg(action = ArgAction::Help, short, long)] + #[arg(help = fl!("help-flag-help"))] + help: Option, - #[options(help = "Print version info and exit.", short = "V")] - version: bool, + #[arg(action = ArgAction::Version, short = 'V', long)] + #[arg(help = fl!("help-flag-version"))] + version: Option, - #[options(help = "Indicates the filesystem type (one of \"tar\", \"zip\").")] + #[arg(short, long)] + #[arg(value_name = fl!("mnt-types"))] + #[arg(help = fl!("help-arg-mnt-types", types = "\"tar\", \"zip\""))] types: String, - #[options( - help = "Maximum work factor to allow for passphrase decryption.", - meta = "WF", - no_short - )] + #[arg(long, value_name = "WF")] + #[arg(help = fl!("help-flag-max-work-factor"))] max_work_factor: Option, - #[options(help = "Use the private key file at IDENTITY. May be repeated.")] + #[arg(short, long)] + #[arg(value_name = fl!("identity"))] + #[arg(help = fl!("help-flag-identity"))] identity: Vec, } @@ -219,24 +241,13 @@ fn main() -> Result<(), Error> { // Isolation Marks, so we disable them for now. LANGUAGE_LOADER.set_use_isolating(false); - let args = args().collect::>(); - - if console::user_attended() && args.len() == 1 { - // If gumdrop ever merges that PR, that can be used here - // instead. - println!("{} {} [OPTIONS]", fl!("usage-header"), args[0]); - println!(); - println!("{}", AgeMountOptions::usage()); - + if console::user_attended() && args().len() == 1 { + AgeMountOptions::command().print_help()?; return Ok(()); } - let opts = AgeMountOptions::parse_args_default_or_exit(); + let opts = AgeMountOptions::parse(); - if opts.version { - println!("rage-mount {}", env!("CARGO_PKG_VERSION")); - return Ok(()); - } if opts.filename.is_empty() { return Err(Error::MissingFilename); } diff --git a/rage/src/bin/rage/main.rs b/rage/src/bin/rage/main.rs index 1c4481a8..d2adbeb6 100644 --- a/rage/src/bin/rage/main.rs +++ b/rage/src/bin/rage/main.rs @@ -9,7 +9,7 @@ use age::{ secrecy::ExposeSecret, Identity, IdentityFile, IdentityFileEntry, Recipient, }; -use gumdrop::{Options, ParsingStyle}; +use clap::{builder::Styles, ArgAction, CommandFactory, Parser}; use i18n_embed::{ fluent::{fluent_language_loader, FluentLanguageLoader}, DesktopLanguageRequester, @@ -233,56 +233,128 @@ fn read_recipients( Ok(recipients) } -#[derive(Debug, Options)] +fn binary_name() -> String { + if let Some(arg) = std::env::args_os().next() { + Path::new(&arg) + .file_name() + .expect("is not directory") + .to_string_lossy() + .to_string() + } else { + "rage".into() + } +} + +fn usage() -> String { + let binary_name = binary_name(); + let recipient = fl!("recipient"); + let identity = fl!("identity"); + let input = fl!("input"); + let output = fl!("output"); + + format!( + "{binary_name} [--encrypt] -r {recipient} [-i {identity}] [-a] [-o {output}] [{input}]\n \ + {binary_name} --decrypt [-i {identity}] [-o {output}] [{input}]", + ) +} + +fn after_help() -> String { + let binary_name = binary_name(); + let keygen_name = format!("{}-keygen", binary_name); + let example_a = format!("$ {} -o key.txt", keygen_name); + let example_a_output = "age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p"; + let example_b = format!( + "$ tar cvz ~/data | {} -r {} > data.tar.gz.age", + binary_name, example_a_output, + ); + let example_c = format!( + "$ {} -d -i key.txt -o data.tar.gz data.tar.gz.age", + binary_name, + ); + + fl!( + "rage-after-help", + keygen_name = keygen_name, + example_a = example_a, + example_a_output = example_a_output, + example_b = example_b, + example_c = example_c, + ) +} + +#[derive(Debug, Parser)] +#[command(version)] +#[command(help_template = format!("\ +{{before-help}}{{about-with-newline}} +{}{}:{} {{usage}} + +{{all-args}}{{after-help}}\ + ", + Styles::default().get_usage().render(), + fl!("usage-header"), + Styles::default().get_usage().render_reset()))] +#[command(override_usage(usage()))] +#[command(next_help_heading = fl!("flags-header"))] +#[command(disable_help_flag(true))] +#[command(disable_version_flag(true))] +#[command(after_help(after_help()))] struct AgeOptions { - #[options(free, help = "Path to a file to read from.")] + #[arg(help_heading = fl!("args-header"))] + #[arg(value_name = fl!("input"))] + #[arg(help = fl!("help-arg-input"))] input: Option, - #[options(help = "Print this help message and exit.")] - help: bool, + #[arg(action = ArgAction::Help, short, long)] + #[arg(help = fl!("help-flag-help"))] + help: Option, - #[options(help = "Print version info and exit.", short = "V")] - version: bool, + #[arg(action = ArgAction::Version, short = 'V', long)] + #[arg(help = fl!("help-flag-version"))] + version: Option, - #[options(help = "Encrypt the input (the default).")] + #[arg(short, long)] + #[arg(help = fl!("help-flag-encrypt"))] encrypt: bool, - #[options(help = "Decrypt the input.")] + #[arg(short, long)] + #[arg(help = fl!("help-flag-decrypt"))] decrypt: bool, - #[options(help = "Encrypt with a passphrase instead of recipients.")] + #[arg(short, long)] + #[arg(help = fl!("help-flag-passphrase"))] passphrase: bool, - #[options( - help = "Maximum work factor to allow for passphrase decryption.", - meta = "WF", - no_short - )] + #[arg(long, value_name = "WF")] + #[arg(help = fl!("help-flag-max-work-factor"))] max_work_factor: Option, - #[options(help = "Encrypt to a PEM encoded format.")] + #[arg(short, long)] + #[arg(help = fl!("help-flag-armor"))] armor: bool, - #[options(help = "Encrypt to the specified RECIPIENT. May be repeated.")] + #[arg(short, long)] + #[arg(value_name = fl!("recipient"))] + #[arg(help = fl!("help-flag-recipient"))] recipient: Vec, - #[options( - help = "Encrypt to the recipients listed at PATH. May be repeated.", - meta = "PATH" - )] + #[arg(short = 'R', long)] + #[arg(value_name = fl!("recipients-file"))] + #[arg(help = fl!("help-flag-recipients-file"))] recipients_file: Vec, - #[options(help = "Use the identity file at IDENTITY. May be repeated.")] + #[arg(short, long)] + #[arg(value_name = fl!("identity"))] + #[arg(help = fl!("help-flag-identity"))] identity: Vec, - #[options( - help = "Use age-plugin-PLUGIN-NAME in its default mode as an identity.", - no_long, - short = "j" - )] - plugin_name: String, + #[arg(short = 'j')] + #[arg(value_name = fl!("plugin-name"))] + #[arg(help = fl!("help-flag-plugin-name"))] + plugin_name: Option, - #[options(help = "Write the result to the file at path OUTPUT.")] + #[arg(short, long)] + #[arg(value_name = fl!("output"))] + #[arg(help = fl!("help-flag-output"))] output: Option, } @@ -344,7 +416,7 @@ impl io::Read for ReadChecker { } fn encrypt(opts: AgeOptions) -> Result<(), error::EncryptError> { - if !opts.plugin_name.is_empty() { + if opts.plugin_name.is_some() { return Err(error::EncryptError::PluginNameFlag); } @@ -479,7 +551,7 @@ fn decrypt(opts: AgeOptions) -> Result<(), error::DecryptError> { return Err(error::DecryptError::RecipientsFileFlag); } - if !(opts.identity.is_empty() || opts.plugin_name.is_empty()) { + if !(opts.identity.is_empty() || opts.plugin_name.is_none()) { return Err(error::DecryptError::MixedIdentityAndPluginName); } @@ -549,13 +621,14 @@ fn decrypt(opts: AgeOptions) -> Result<(), error::DecryptError> { } } age::Decryptor::Recipients(decryptor) => { - let identities = if opts.plugin_name.is_empty() { + let plugin_name = opts.plugin_name.as_deref().unwrap_or_default(); + let identities = if plugin_name.is_empty() { read_identities(opts.identity, opts.max_work_factor)? } else { // Construct the default plugin. vec![Box::new(plugin::IdentityPluginV1::new( - &opts.plugin_name, - &[plugin::Identity::default_for_plugin(&opts.plugin_name)], + plugin_name, + &[plugin::Identity::default_for_plugin(plugin_name)], UiCallbacks, )?) as Box] }; @@ -588,82 +661,39 @@ fn main() -> Result<(), error::Error> { // Isolation Marks, so we disable them for now. LANGUAGE_LOADER.set_use_isolating(false); - let args = args().collect::>(); - - let opts = AgeOptions::parse_args(&args[1..], ParsingStyle::default()).unwrap_or_else(|e| { - eprintln!("{}: {}", args[0], e); - std::process::exit(2); - }); - // If you are piping input with no other args, this will not allow // it. - if (console::user_attended() && args.len() == 1) || opts.help_requested() { - let binary_name = args[0].as_str(); - let keygen_name = format!("{}-keygen", binary_name); - let usage_a = format!( - "{} [--encrypt] -r RECIPIENT [-i IDENTITY] [-a] [-o OUTPUT] [INPUT]", - binary_name - ); - let usage_b = format!( - "{} --decrypt [-i IDENTITY] [-o OUTPUT] [INPUT]", - binary_name - ); - let example_a = format!("$ {} -o key.txt", keygen_name); - let example_a_output = "age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p"; - let example_b = format!( - "$ tar cvz ~/data | {} -r {} > data.tar.gz.age", - binary_name, example_a_output - ); - let example_c = format!( - "$ {} -d -i key.txt -o data.tar.gz data.tar.gz.age", - binary_name - ); - - println!( - "{}", - fl!( - "rage-usage", - usage_a = usage_a, - usage_b = usage_b, - flags = AgeOptions::usage(), - keygen_name = keygen_name, - example_a = example_a, - example_a_output = example_a_output, - example_b = example_b, - example_c = example_c, - ) - ); - + if console::user_attended() && args().len() == 1 { + AgeOptions::command() + .print_help() + .map_err(error::EncryptError::Io)?; return Ok(()); } - if opts.version { - println!("rage {}", env!("CARGO_PKG_VERSION")); - Ok(()) - } else { - if opts.encrypt && opts.decrypt { - return Err(error::Error::MixedEncryptAndDecrypt); - } - if !(opts.identity.is_empty() || opts.encrypt || opts.decrypt) { - return Err(error::Error::IdentityFlagAmbiguous); - } + let opts = AgeOptions::parse(); - if let (Some(in_file), Some(out_file)) = (&opts.input, &opts.output) { - // Check that the given filenames do not correspond to the same file. - let in_path = Path::new(&in_file); - let out_path = Path::new(&out_file); - match (in_path.canonicalize(), out_path.canonicalize()) { - (Ok(in_abs), Ok(out_abs)) if in_abs == out_abs => { - return Err(error::Error::SameInputAndOutput(out_file.clone())); - } - _ => (), + if opts.encrypt && opts.decrypt { + return Err(error::Error::MixedEncryptAndDecrypt); + } + if !(opts.identity.is_empty() || opts.encrypt || opts.decrypt) { + return Err(error::Error::IdentityFlagAmbiguous); + } + + if let (Some(in_file), Some(out_file)) = (&opts.input, &opts.output) { + // Check that the given filenames do not correspond to the same file. + let in_path = Path::new(&in_file); + let out_path = Path::new(&out_file); + match (in_path.canonicalize(), out_path.canonicalize()) { + (Ok(in_abs), Ok(out_abs)) if in_abs == out_abs => { + return Err(error::Error::SameInputAndOutput(out_file.clone())); } + _ => (), } + } - if opts.decrypt { - decrypt(opts).map_err(error::Error::from) - } else { - encrypt(opts).map_err(error::Error::from) - } + if opts.decrypt { + decrypt(opts).map_err(error::Error::from) + } else { + encrypt(opts).map_err(error::Error::from) } } diff --git a/rage/tests/cmd/rage-keygen/help.toml b/rage/tests/cmd/rage-keygen/help.toml index 96883960..58ef3fdb 100644 --- a/rage/tests/cmd/rage-keygen/help.toml +++ b/rage/tests/cmd/rage-keygen/help.toml @@ -1,11 +1,11 @@ bin.name = "rage-keygen" args = "--help" -stdout = "" -stderr = """ -Usage: [..]rage-keygen[EXE] [OPTIONS] +stdout = """ +Usage: rage-keygen[EXE] [OPTIONS] -Optional arguments: - -h, --help Print this help message and exit. - -V, --version Print version info and exit. - -o, --output OUTPUT Write the result to the file at path OUTPUT. Defaults to standard output. +Options: + -h, --help Print this help message and exit. + -V, --version Print version info and exit. + -o, --output Write the result to the file at path OUTPUT. Defaults to standard output. """ +stderr = "" diff --git a/rage/tests/cmd/rage-keygen/help_it.toml b/rage/tests/cmd/rage-keygen/help_it.toml index 2e2814de..3922b9e4 100644 --- a/rage/tests/cmd/rage-keygen/help_it.toml +++ b/rage/tests/cmd/rage-keygen/help_it.toml @@ -1,12 +1,12 @@ bin.name = "rage-keygen" args = "--help" env.add.LANG = "it" -stdout = "" -stderr = """ -Usage: [..]rage-keygen[EXE] [OPTIONS] +stdout = """ +Usage: rage-keygen[EXE] [OPTIONS] -Optional arguments: - -h, --help Print this help message and exit. - -V, --version Print version info and exit. - -o, --output OUTPUT Write the result to the file at path OUTPUT. Defaults to standard output. +Options: + -h, --help Print this help message and exit. + -V, --version Print version info and exit. + -o, --output Write the result to the file at path OUTPUT. Defaults to standard output. """ +stderr = "" diff --git a/rage/tests/cmd/rage-mount/help.toml b/rage/tests/cmd/rage-mount/help.toml index 52e91e0b..9d41fbd9 100644 --- a/rage/tests/cmd/rage-mount/help.toml +++ b/rage/tests/cmd/rage-mount/help.toml @@ -1,17 +1,17 @@ bin.name = "rage-mount" args = "--help" -stdout = "" -stderr = """ -Usage: [..]rage-mount[EXE] [OPTIONS] +stdout = """ +Usage: rage-mount[EXE] [OPTIONS] --types -Positional arguments: - filename The encrypted filesystem to mount. - mountpoint The directory to mount the filesystem at. +Arguments: + The encrypted filesystem to mount. + The directory to mount the filesystem at. -Optional arguments: - -h, --help Print this help message and exit. - -V, --version Print version info and exit. - -t, --types TYPES Indicates the filesystem type (one of "tar", "zip"). - --max-work-factor WF Maximum work factor to allow for passphrase decryption. - -i, --identity IDENTITY Use the private key file at IDENTITY. May be repeated. +Options: + -h, --help Print this help message and exit. + -V, --version Print version info and exit. + -t, --types Indicates the filesystem type (one of "tar", "zip"). + --max-work-factor Maximum work factor to allow for passphrase decryption. + -i, --identity Use the identity file at IDENTITY. May be repeated. """ +stderr = "" diff --git a/rage/tests/cmd/rage-mount/help_it.toml b/rage/tests/cmd/rage-mount/help_it.toml index c4730f21..eff77d63 100644 --- a/rage/tests/cmd/rage-mount/help_it.toml +++ b/rage/tests/cmd/rage-mount/help_it.toml @@ -1,18 +1,18 @@ bin.name = "rage-mount" args = "--help" env.add.LANG = "it" -stdout = "" -stderr = """ -Usage: [..]rage-mount[EXE] [OPTIONS] +stdout = """ +Usage: rage-mount[EXE] [OPTIONS] --types -Positional arguments: - filename The encrypted filesystem to mount. - mountpoint The directory to mount the filesystem at. +Arguments: + The encrypted filesystem to mount. + The directory to mount the filesystem at. -Optional arguments: - -h, --help Print this help message and exit. - -V, --version Print version info and exit. - -t, --types TYPES Indicates the filesystem type (one of "tar", "zip"). - --max-work-factor WF Maximum work factor to allow for passphrase decryption. - -i, --identity IDENTITY Use the private key file at IDENTITY. May be repeated. +Options: + -h, --help Print this help message and exit. + -V, --version Print version info and exit. + -t, --types Indicates the filesystem type (one of "tar", "zip"). + --max-work-factor Maximum work factor to allow for passphrase decryption. + -i, --identity Use the identity file at IDENTITY. May be repeated. """ +stderr = "" diff --git a/rage/tests/cmd/rage/help.toml b/rage/tests/cmd/rage/help.toml index 95d47361..7e875b07 100644 --- a/rage/tests/cmd/rage/help.toml +++ b/rage/tests/cmd/rage/help.toml @@ -1,31 +1,30 @@ bin.name = "rage" args = "--help" stdout = """ -Usage: - [..]rage[EXE] [--encrypt] -r RECIPIENT [-i IDENTITY] [-a] [-o OUTPUT] [INPUT] - [..]rage[EXE] --decrypt [-i IDENTITY] [-o OUTPUT] [INPUT] +Usage: rage[EXE] [--encrypt] -r RECIPIENT [-i IDENTITY] [-a] [-o OUTPUT] [INPUT] + rage[EXE] --decrypt [-i IDENTITY] [-o OUTPUT] [INPUT] -Positional arguments: - input Path to a file to read from. +Arguments: + [INPUT] Path to a file to read from. -Optional arguments: - -h, --help Print this help message and exit. - -V, --version Print version info and exit. - -e, --encrypt Encrypt the input (the default). - -d, --decrypt Decrypt the input. - -p, --passphrase Encrypt with a passphrase instead of recipients. - --max-work-factor WF Maximum work factor to allow for passphrase decryption. - -a, --armor Encrypt to a PEM encoded format. - -r, --recipient RECIPIENT Encrypt to the specified RECIPIENT. May be repeated. - -R, --recipients-file PATH Encrypt to the recipients listed at PATH. May be repeated. - -i, --identity IDENTITY Use the identity file at IDENTITY. May be repeated. - -j PLUGIN-NAME Use age-plugin-PLUGIN-NAME in its default mode as an identity. - -o, --output OUTPUT Write the result to the file at path OUTPUT. +Options: + -h, --help Print this help message and exit. + -V, --version Print version info and exit. + -e, --encrypt Encrypt the input (the default). + -d, --decrypt Decrypt the input. + -p, --passphrase Encrypt with a passphrase instead of recipients. + --max-work-factor Maximum work factor to allow for passphrase decryption. + -a, --armor Encrypt to a PEM encoded format. + -r, --recipient Encrypt to the specified RECIPIENT. May be repeated. + -R, --recipients-file Encrypt to the recipients listed at PATH. May be repeated. + -i, --identity Use the identity file at IDENTITY. May be repeated. + -j Use age-plugin-PLUGIN-NAME in its default mode as an identity. + -o, --output Write the result to the file at path OUTPUT. INPUT defaults to standard input, and OUTPUT defaults to standard output. RECIPIENT can be: -- An age public key, as generated by [..]rage-keygen ("age1..."). +- An age public key, as generated by rage-keygen ("age1..."). - An SSH public key ("ssh-ed25519 AAAA...", "ssh-rsa AAAA..."). PATH is a path to a file containing age recipients, one per line @@ -37,9 +36,9 @@ Passphrase-encrypted age identity files can be used as identity files. Multiple identities may be provided, and any unused ones will be ignored. Example: - $ [..]rage-keygen -o key.txt + $ rage-keygen -o key.txt Public key: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p - $ tar cvz ~/data | [..]rage -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p > data.tar.gz.age - $ [..]rage -d -i key.txt -o data.tar.gz data.tar.gz.age + $ tar cvz ~/data | rage -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p > data.tar.gz.age + $ rage -d -i key.txt -o data.tar.gz data.tar.gz.age """ stderr = "" diff --git a/rage/tests/cmd/rage/help_it.toml b/rage/tests/cmd/rage/help_it.toml index 8d742bcc..6d4f81d0 100644 --- a/rage/tests/cmd/rage/help_it.toml +++ b/rage/tests/cmd/rage/help_it.toml @@ -2,32 +2,31 @@ bin.name = "rage" args = "--help" env.add.LANG = "it" stdout = """ -Usage: - [..]rage[EXE] [--encrypt] -r RECIPIENT [-i IDENTITY] [-a] [-o OUTPUT] [INPUT] - [..]rage[EXE] --decrypt [-i IDENTITY] [-o OUTPUT] [INPUT] +Usage: rage[EXE] [--encrypt] -r RECIPIENT [-i IDENTITY] [-a] [-o OUTPUT] [INPUT] + rage[EXE] --decrypt [-i IDENTITY] [-o OUTPUT] [INPUT] -Positional arguments: - input Path to a file to read from. +Arguments: + [INPUT] Path to a file to read from. -Optional arguments: - -h, --help Print this help message and exit. - -V, --version Print version info and exit. - -e, --encrypt Encrypt the input (the default). - -d, --decrypt Decrypt the input. - -p, --passphrase Encrypt with a passphrase instead of recipients. - --max-work-factor WF Maximum work factor to allow for passphrase decryption. - -a, --armor Encrypt to a PEM encoded format. - -r, --recipient RECIPIENT Encrypt to the specified RECIPIENT. May be repeated. - -R, --recipients-file PATH Encrypt to the recipients listed at PATH. May be repeated. - -i, --identity IDENTITY Use the identity file at IDENTITY. May be repeated. - -j PLUGIN-NAME Use age-plugin-PLUGIN-NAME in its default mode as an identity. - -o, --output OUTPUT Write the result to the file at path OUTPUT. +Options: + -h, --help Print this help message and exit. + -V, --version Print version info and exit. + -e, --encrypt Encrypt the input (the default). + -d, --decrypt Decrypt the input. + -p, --passphrase Encrypt with a passphrase instead of recipients. + --max-work-factor Maximum work factor to allow for passphrase decryption. + -a, --armor Encrypt to a PEM encoded format. + -r, --recipient Encrypt to the specified RECIPIENT. May be repeated. + -R, --recipients-file Encrypt to the recipients listed at PATH. May be repeated. + -i, --identity Use the identity file at IDENTITY. May be repeated. + -j Use age-plugin-PLUGIN-NAME in its default mode as an identity. + -o, --output Write the result to the file at path OUTPUT. INPUT ha come valore predefinito lo standard input, e OUTPUT ha come valore predefinito lo standard output. RECIPIENT può essere: -- Una chiave pubblica age, come generata da [..]rage-keygen ("age1..."). +- Una chiave pubblica age, come generata da rage-keygen ("age1..."). - Una chiave pubblica SSH ("ssh-ed25519 AAAA...", "ssh-rsa AAAA..."). PATH è il percorso ad un file contenente dei destinatari age, @@ -40,9 +39,9 @@ I file di identità possono essere cifrati con age e una passphrase. Possono essere fornite più identità, quelle inutilizzate verranno ignorate. Esempio: - $ [..]rage-keygen -o key.txt + $ rage-keygen -o key.txt Chiave pubblica: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p - $ tar cvz ~/data | [..]rage -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p > data.tar.gz.age - $ [..]rage -d -i key.txt -o data.tar.gz data.tar.gz.age + $ tar cvz ~/data | rage -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p > data.tar.gz.age + $ rage -d -i key.txt -o data.tar.gz data.tar.gz.age """ stderr = "" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index ce21716c..dc0d8d45 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -67,23 +67,23 @@ criteria = "safe-to-deploy" [[exemptions.anstream]] version = "0.3.2" -criteria = "safe-to-run" +criteria = "safe-to-deploy" [[exemptions.anstyle]] version = "1.0.2" -criteria = "safe-to-run" +criteria = "safe-to-deploy" [[exemptions.anstyle-parse]] version = "0.2.1" -criteria = "safe-to-run" +criteria = "safe-to-deploy" [[exemptions.anstyle-query]] version = "1.0.0" -criteria = "safe-to-run" +criteria = "safe-to-deploy" [[exemptions.anstyle-wincon]] version = "1.0.2" -criteria = "safe-to-run" +criteria = "safe-to-deploy" [[exemptions.arc-swap]] version = "1.6.0" @@ -171,16 +171,24 @@ criteria = "safe-to-deploy" [[exemptions.clap]] version = "4.3.24" -criteria = "safe-to-run" +criteria = "safe-to-deploy" [[exemptions.clap_builder]] version = "4.3.24" -criteria = "safe-to-run" +criteria = "safe-to-deploy" [[exemptions.clap_complete]] version = "4.3.2" criteria = "safe-to-run" +[[exemptions.clap_derive]] +version = "4.3.12" +criteria = "safe-to-deploy" + +[[exemptions.clap_lex]] +version = "0.5.0" +criteria = "safe-to-deploy" + [[exemptions.console]] version = "0.15.7" criteria = "safe-to-deploy" @@ -341,14 +349,6 @@ criteria = "safe-to-deploy" version = "0.28.1" criteria = "safe-to-run" -[[exemptions.gumdrop]] -version = "0.8.1" -criteria = "safe-to-deploy" - -[[exemptions.gumdrop_derive]] -version = "0.8.1" -criteria = "safe-to-deploy" - [[exemptions.hashbrown]] version = "0.14.3" criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 213451db..acd33316 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -344,6 +344,12 @@ criteria = "safe-to-deploy" version = "0.3.27" notes = "Unsafe used to implement a concurrency primitive AtomicWaker. Well-commented and not obviously incorrect. Like my other audits of these concurrency primitives inside the futures family, I couldn't certify that it is correct without formal methods, but that is out of scope for this vetting." +[[audits.bytecode-alliance.audits.heck]] +who = "Alex Crichton " +criteria = "safe-to-deploy" +version = "0.4.0" +notes = "Contains `forbid_unsafe` and only uses `std::fmt` from the standard library. Otherwise only contains string manipulation." + [[audits.bytecode-alliance.audits.iana-time-zone]] who = "Dan Gohman " criteria = "safe-to-deploy" @@ -500,12 +506,6 @@ criteria = "safe-to-run" version = "0.3.67" aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" -[[audits.google.audits.clap_lex]] -who = "George Burgess IV " -criteria = "safe-to-run" -version = "0.4.1" -aggregated-from = "https://chromium.googlesource.com/chromiumos/third_party/rust_crates/+/refs/heads/main/cargo-vet/audits.toml?format=TEXT" - [[audits.google.audits.crossbeam-deque]] who = "George Burgess IV " criteria = "safe-to-run" @@ -682,11 +682,6 @@ who = "David Cook " criteria = "safe-to-deploy" version = "0.9.0" -[[audits.isrg.audits.clap_lex]] -who = "Brandon Pitman " -criteria = "safe-to-run" -delta = "0.4.1 -> 0.5.0" - [[audits.isrg.audits.criterion]] who = "Brandon Pitman " criteria = "safe-to-run" @@ -1198,6 +1193,12 @@ capabilities. """ aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" +[[audits.mozilla.audits.heck]] +who = "Mike Hommey " +criteria = "safe-to-deploy" +delta = "0.4.0 -> 0.4.1" +aggregated-from = "https://hg.mozilla.org/mozilla-central/raw-file/tip/supply-chain/audits.toml" + [[audits.mozilla.audits.hex]] who = "Simon Friedberger " criteria = "safe-to-deploy"