diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2021-01-04 16:44:00 +0100 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2021-01-04 16:47:11 +0100 |
commit | 426e5d38ef0113961a8e1b5ca76d9cf575ac5aee (patch) | |
tree | bb1f63946c4efc23789f14ed2006c3f57eceaae4 | |
parent | 8117d594fb75fc32b2b2b26cf46fde6758be2203 (diff) |
sop: Move to https://gitlab.com/sequoia-pgp/sequoia-sop
- From this point on, the crate sequoia-sop will be maintained in
its own repository.
-rw-r--r-- | Cargo.lock | 74 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | doc/release-checklist.md | 1 | ||||
-rw-r--r-- | sop/Cargo.toml | 38 | ||||
-rw-r--r-- | sop/Makefile | 25 | ||||
-rw-r--r-- | sop/README.md | 33 | ||||
-rw-r--r-- | sop/src/cli.rs | 334 | ||||
-rw-r--r-- | sop/src/dates.rs | 95 | ||||
-rw-r--r-- | sop/src/errors.rs | 101 | ||||
-rw-r--r-- | sop/src/main.rs | 786 |
11 files changed, 0 insertions, 1490 deletions
@@ -1022,15 +1022,6 @@ dependencies = [ ] [[package]] -name = "heck" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -dependencies = [ - "unicode-segmentation", -] - -[[package]] name = "hermit-abi" version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1685,30 +1676,6 @@ dependencies = [ ] [[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check 0.9.2", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check 0.9.2", -] - -[[package]] name = "proc-macro-hack" version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2082,17 +2049,6 @@ dependencies = [ ] [[package]] -name = "sequoia-sop" -version = "0.22.0" -dependencies = [ - "anyhow", - "chrono", - "sequoia-openpgp", - "structopt", - "thiserror", -] - -[[package]] name = "sequoia-sq" version = "0.22.0" dependencies = [ @@ -2298,30 +2254,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" [[package]] -name = "structopt" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] name = "subtle" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2573,12 +2505,6 @@ dependencies = [ ] [[package]] -name = "unicode-segmentation" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" - -[[package]] name = "unicode-width" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -10,7 +10,6 @@ members = [ "net", "openpgp", "openpgp-ffi", - "sop", "sq", "sqv", "store", @@ -101,7 +101,6 @@ build-release: $(MAKE) -Cffi build-release $(MAKE) -Csq build-release $(MAKE) -Csqv build-release - $(MAKE) -Csop build-release .PHONY: install install: build-release @@ -109,7 +108,6 @@ install: build-release $(MAKE) -Cffi install $(MAKE) -Csq install $(MAKE) -Csqv install - $(MAKE) -Csop install # Infrastructure for creating source distributions. .PHONY: dist diff --git a/doc/release-checklist.md b/doc/release-checklist.md index ad8e5404..e8243b20 100644 --- a/doc/release-checklist.md +++ b/doc/release-checklist.md @@ -26,7 +26,6 @@ This is a checklist for doing Sequoia releases. publish': - buffered-reader - openpgp - - sop - sqv 10. In case of errors, correct them, and go back to 6. 11. Merge the branch to master by merging the merge request created in diff --git a/sop/Cargo.toml b/sop/Cargo.toml deleted file mode 100644 index 931799d9..00000000 --- a/sop/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -name = "sequoia-sop" -description = "An implementation of the Stateless OpenPGP Command Line Interface using Sequoia" -version = "0.22.0" -authors = [ - "Justus Winter <justus@sequoia-pgp.org>", -] -documentation = "https://docs.sequoia-pgp.org/0.21.0/sop" -homepage = "https://sequoia-pgp.org/" -repository = "https://gitlab.com/sequoia-pgp/sequoia" -readme = "README.md" -keywords = ["cryptography", "openpgp", "pgp", "sop", "stateless-openpgp"] -categories = ["cryptography", "command-line-utilities"] -license = "GPL-2.0-or-later" -edition = "2018" - -[badges] -gitlab = { repository = "sequoia-pgp/sequoia" } -maintenance = { status = "actively-developed" } - -[dependencies] -sequoia-openpgp = { path = "../openpgp", version = "1.0.0", default-features = false } -anyhow = "1.0.18" -chrono = "0.4.10" -structopt = { version = "0.3.11", default-features = false } -thiserror = "1.0.2" - -[[bin]] -name = "sqop" -path = "src/main.rs" - -[features] -default = ["sequoia-openpgp/default"] -crypto-nettle = ["sequoia-openpgp/crypto-nettle"] -crypto-cng = ["sequoia-openpgp/crypto-cng"] -compression = ["sequoia-openpgp/compression"] -compression-deflate = ["sequoia-openpgp/compression-deflate"] -compression-bzip2 = ["sequoia-openpgp/compression-bzip2"] diff --git a/sop/Makefile b/sop/Makefile deleted file mode 100644 index c9827d56..00000000 --- a/sop/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Configuration. -CARGO_TARGET_DIR ?= $(shell pwd)/../target -# We currently only support absolute paths. -CARGO_TARGET_DIR := $(abspath $(CARGO_TARGET_DIR)) -SOP ?= $(CARGO_TARGET_DIR)/debug/sqop - -# Tools. -CARGO ?= cargo - -ifneq ($(filter Darwin %BSD,$(shell uname -s)),) - INSTALL ?= ginstall -else - INSTALL ?= install -endif - -# Installation. -.PHONY: build-release -build-release: - CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) \ - $(CARGO) build $(CARGO_FLAGS) --release --package sequoia-sop - -.PHONY: install -install: build-release - $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -t $(DESTDIR)$(PREFIX)/bin $(CARGO_TARGET_DIR)/release/sqop diff --git a/sop/README.md b/sop/README.md deleted file mode 100644 index e16e4076..00000000 --- a/sop/README.md +++ /dev/null @@ -1,33 +0,0 @@ -An implementation of the Stateless OpenPGP Command Line Interface -using Sequoia. - -This implements a subset of the [Stateless OpenPGP Command Line -Interface] (SOP) using the Sequoia OpenPGP implementation. While SOP -is not intended for daily use, it is a good way to interact with and -explore OpenPGP implementations. SOP is primarily used as abstraction -in the [OpenPGP interoperability test suite]. - - [Stateless OpenPGP Command Line Interface]: https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/ - [OpenPGP interoperability test suite]: https://tests.sequoia-pgp.org/ - -# SOP primer - -To demonstrate SOP, let's generate a key, and encrypt and decrypt a -message: - -```sh -$ sqop generate-key julia@example.org > julia.secret.pgp -$ sqop extract-cert < julia.secret.pgp > julia.public.pgp -``` - -First, we generate a key for `julia@example.org`. Next, we extract -the certificate, i.e. the key without the secret key material. - -```sh -$ echo "a message" | sqop encrypt julia.public.pgp > message.pgp -$ sqop decrypt julia.secret.pgp < message.pgp -a message -``` - -Here, we encrypt a message with Julia's certificate, and decrypt it -with her key. diff --git a/sop/src/cli.rs b/sop/src/cli.rs deleted file mode 100644 index 202dd5dd..00000000 --- a/sop/src/cli.rs +++ /dev/null @@ -1,334 +0,0 @@ -use std::fmt; -use std::path::Path; - -use anyhow::Context; -use chrono::{DateTime, offset::Utc}; -use structopt::StructOpt; - -use sequoia_openpgp as openpgp; -use openpgp::{ - cert::{ - Cert, - CertParser, - }, - crypto::{ - Password, - }, - types::{ - SignatureType, - DataFormat, - }, - parse::Parse, -}; - -use super::{ - dates, - Error, - Result, -}; - -#[derive(StructOpt)] -#[structopt(about = "An implementation of the \ - Stateless OpenPGP Command Line Interface \ - using Sequoia")] -pub enum SOP { - /// Prints version information. - Version { - }, - /// Generates a Secret Key. - GenerateKey { - /// Don't ASCII-armor output. - #[structopt(long)] - no_armor: bool, - /// UserIDs for the generated key. - userids: Vec<String>, - }, - /// Extracts a Certificate from a Secret Key. - ExtractCert { - /// Don't ASCII-armor output. - #[structopt(long)] - no_armor: bool, - }, - /// Creates Detached Signatures. - Sign { - /// Don't ASCII-armor output. - #[structopt(long)] - no_armor: bool, - /// Sign binary data or UTF-8 text. - #[structopt(default_value = "binary", long = "as")] - as_: SignAs, - /// Keys for signing. - keys: Vec<String>, - }, - /// Verifies Detached Signatures. - Verify { - /// Consider signatures before this date invalid. - #[structopt(long, parse(try_from_str = dates::parse_bound_round_down))] - not_before: Option<DateTime<Utc>>, - /// Consider signatures after this date invalid. - #[structopt(long, parse(try_from_str = dates::parse_bound_round_up))] - not_after: Option<DateTime<Utc>>, - /// Signatures to verify. - signatures: String, - /// Certs for verification. - certs: Vec<String>, - }, - /// Encrypts a Message. - Encrypt { - /// Don't ASCII-armor output. - #[structopt(long)] - no_armor: bool, - /// Encrypt binary data, UTF-8 text, or MIME data. - #[structopt(default_value = "binary", long = "as")] - as_: EncryptAs, - /// Encrypt with passwords. - #[structopt(long)] - with_password: Vec<String>, - /// Keys for signing. - #[structopt(long)] - sign_with: Vec<String>, - /// Encrypt for these certs. - certs: Vec<String>, - }, - /// Decrypts a Message. - Decrypt { - /// Write the session key here. - #[structopt(long)] - session_key_out: Option<String>, - /// Try to decrypt with this session key. - #[structopt(long)] - with_session_key: Vec<String>, - /// Try to decrypt with this password. - #[structopt(long)] - with_password: Vec<String>, - /// Write verification result here. - #[structopt(long)] - verify_out: Option<String>, - /// Certs for verification. - #[structopt(long)] - verify_with: Vec<String>, - /// Consider signatures before this date invalid. - #[structopt(long, parse(try_from_str = dates::parse_bound_round_down))] - verify_not_before: Option<DateTime<Utc>>, - /// Consider signatures after this date invalid. - #[structopt(long, parse(try_from_str = dates::parse_bound_round_up))] - verify_not_after: Option<DateTime<Utc>>, - /// Try to decrypt with this key. - key: Vec<String>, - }, - /// Converts binary OpenPGP data to ASCII - Armor { - /// Indicates the kind of data - #[structopt(long, default_value = "auto")] - label: ArmorKind, - }, - /// Converts ASCII OpenPGP data to binary - Dearmor { - }, - /// Unsupported subcommand. - #[structopt(external_subcommand)] - Unsupported(Vec<String>), -} - -#[derive(Clone, Copy)] -pub enum SignAs { - Binary, - Text, -} - -impl std::str::FromStr for SignAs { - type Err = anyhow::Error; - fn from_str(s: &str) -> openpgp::Result<Self> { - match s { - "binary" => Ok(SignAs::Binary), - "text" => Ok(SignAs::Text), - _ => Err(anyhow::anyhow!( - "{:?}, expected one of {{binary|text}}", s)), - } - } -} - -impl fmt::Display for SignAs { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - SignAs::Binary => f.write_str("binary"), - SignAs::Text => f.write_str("text"), - } - } -} - -impl From<SignAs> for SignatureType { - fn from(a: SignAs) -> Self { - match a { - SignAs::Binary => SignatureType::Binary, - SignAs::Text => SignatureType::Text, - } - } -} - -#[derive(Clone, Copy)] -pub enum EncryptAs { - Binary, - Text, - MIME, -} - -impl std::str::FromStr for EncryptAs { - type Err = anyhow::Error; - fn from_str(s: &str) -> openpgp::Result<Self> { - match s { - "binary" => Ok(EncryptAs::Binary), - "text" => Ok(EncryptAs::Text), - "mime" => Ok(EncryptAs::MIME), - _ => Err(anyhow::anyhow!( - "{}, expected one of {{binary|text|mime}}", s)), - } - } -} - -impl fmt::Display for EncryptAs { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - EncryptAs::Binary => f.write_str("binary"), - EncryptAs::Text => f.write_str("text"), - EncryptAs::MIME => f.write_str("mime"), - } - } -} - -impl From<EncryptAs> for SignatureType { - fn from(a: EncryptAs) -> Self { - match a { - EncryptAs::Binary => SignatureType::Binary, - EncryptAs::Text => SignatureType::Text, - // XXX: We should inspect the serialized MIME structure - // and use Text if it is UTF-8, Binary otherwise. But, we - // cannot be bothered at this point. - EncryptAs::MIME => SignatureType::Binary, - } - } -} - -impl From<EncryptAs> for DataFormat { - fn from(a: EncryptAs) -> Self { - match a { - EncryptAs::Binary => DataFormat::Binary, - EncryptAs::Text => DataFormat::Text, - EncryptAs::MIME => DataFormat::MIME, - } - } -} - -#[derive(Clone, Copy)] -pub enum ArmorKind { - Auto, - Sig, - Key, - Cert, - Message, -} - -impl std::str::FromStr for ArmorKind { - type Err = anyhow::Error; - fn from_str(s: &str) -> openpgp::Result<Self> { - match s { - "auto" => Ok(ArmorKind::Auto), - "sig" => Ok(ArmorKind::Sig), - "key" => Ok(ArmorKind::Key), - "cert" => Ok(ArmorKind::Cert), - "message" => Ok(ArmorKind::Message), - _ => Err(anyhow::anyhow!( - "{:?}, expected one of \ - {{auto|sig|key|cert|message}}", s)), - } - } -} - -impl fmt::Display for ArmorKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - ArmorKind::Auto => f.write_str("auto"), - ArmorKind::Sig => f.write_str("sig"), - ArmorKind::Key => f.write_str("key"), - ArmorKind::Cert => f.write_str("cert"), - ArmorKind::Message => f.write_str("message"), - } - } -} - - -fn is_special_designator<S: AsRef<str>>(file: S) -> bool { - file.as_ref().starts_with("@") -} - -/// Loads the given (special) file. -pub fn load_file<S: AsRef<str>>(file: S) -> Result<std::fs::File> { - let f = file.as_ref(); - - if is_special_designator(f) { - if Path::new(f).exists() { - return Err(anyhow::Error::from(Error::AmbiguousInput)) - .context(format!("File {:?} exists", f)); - } - - return Err(anyhow::Error::from(Error::UnsupportedSpecialPrefix)); - } - - std::fs::File::open(f).map_err(|_| Error::MissingInput) - .context(format!("Failed to open file {:?}", f)) -} - -/// Creates the given (special) file. -pub fn create_file<S: AsRef<str>>(file: S) -> Result<std::fs::File> { - let f = file.as_ref(); - - if is_special_designator(f) { - if Path::new(f).exists() { - return Err(anyhow::Error::from(Error::AmbiguousInput)) - .context(format!("File {:?} exists", f)); - } - - return Err(anyhow::Error::from(Error::UnsupportedSpecialPrefix)); - } - - if Path::new(f).exists() { - return Err(anyhow::Error::from(Error::OutputExists)) - .context(format!("File {:?} exists", f)); - } - - std::fs::File::create(f).map_err(|_| Error::MissingInput) // XXX - .context(format!("Failed to create file {:?}", f)) -} - -/// Loads the certs given by the (special) files. -pub fn load_certs(files: Vec<String>) -> Result<Vec<Cert>> { - let mut certs = vec![]; - for f in files { - let r = load_file(&f)?; - for cert in CertParser::from_reader(r).map_err(|_| Error::BadData) - .context(format!("Failed to load CERTS from file {:?}", f))? - { - certs.push( - cert.context(format!("Malformed certificate in file {:?}", f))? - ); - } - } - Ok(certs) -} - -/// Loads the KEY given by the (special) files. -pub fn load_keys(files: Vec<String>) -> Result<Vec<Cert>> { - let mut keys = vec![]; - for f in files { - let r = load_file(&f)?; - keys.push(Cert::from_reader(r).map_err(|_| Error::BadData) - .context(format!("Failed to load KEY from file {:?}", f))?); - } - Ok(keys) -} - -/// Frobnicates the strings and converts them to passwords. -pub fn frob_passwords(p: Vec<String>) -> Result<Vec<Password>> { - // XXX: Maybe do additional checks. - Ok(p.iter().map(|p| p.trim_end().into()).collect()) -} diff --git a/sop/src/dates.rs b/sop/src/dates.rs deleted file mode 100644 index b76fe1fc..00000000 --- a/sop/src/dates.rs +++ /dev/null @@ -1,95 +0,0 @@ -use chrono::{DateTime, offset::Utc}; - -use crate::Result; - -/// Parses the given string depicting a ISO 8601 timestamp, rounding down. -pub fn parse_bound_round_down(s: &str) -> Result<DateTime<Utc>> { - match s { - // XXX: parse "-" to None once we figure out how to do that - // with structopt. - "now" => Ok(Utc::now()), - _ => parse_iso8601(s, chrono::NaiveTime::from_hms(0, 0, 0)), - } -} - -/// Parses the given string depicting a ISO 8601 timestamp, rounding up. -pub fn parse_bound_round_up(s: &str) -> Result<DateTime<Utc>> { - match s { - // XXX: parse "-" to None once we figure out how to do that - // with structopt. - "now" => Ok(Utc::now()), - _ => parse_iso8601(s, chrono::NaiveTime::from_hms(23, 59, 59)), - } -} - -/// Parses the given string depicting a ISO 8601 timestamp. -fn parse_iso8601(s: &str, pad_date_with: chrono::NaiveTime) - -> 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)) -} - -#[test] -fn test_parse_iso8601() { - let z = chrono::NaiveTime::from_hms(0, 0, 0); - parse_iso8601("2017-03-04T13:25:35Z", z).unwrap(); - parse_iso8601("2017-03-04T13:25:35+08:30", z).unwrap(); - parse_iso8601("2017-03-04T13:25:35", z).unwrap(); - parse_iso8601("2017-03-04T13:25Z", z).unwrap(); - parse_iso8601("2017-03-04T13:25", z).unwrap(); - // parse_iso8601("2017-03-04T13Z", z).unwrap(); // XXX: chrono doesn't like - // parse_iso8601("2017-03-04T13", z).unwrap(); // ditto - parse_iso8601("2017-03-04", z).unwrap(); - // parse_iso8601("2017-03", z).unwrap(); // ditto - parse_iso8601("2017-031", z).unwrap(); - parse_iso8601("20170304T132535Z", z).unwrap(); - parse_iso8601("20170304T132535+0830", z).unwrap(); - parse_iso8601("20170304T132535", z).unwrap(); - parse_iso8601("20170304T1325Z", z).unwrap(); - parse_iso8601("20170304T1325", z).unwrap(); - // parse_iso8601("20170304T13Z", z).unwrap(); // ditto - // parse_iso8601("20170304T13", z).unwrap(); // ditto - parse_iso8601("20170304", z).unwrap(); - // parse_iso8601("201703", z).unwrap(); // ditto - parse_iso8601("2017031", z).unwrap(); - // parse_iso8601("2017", z).unwrap(); // ditto -} diff --git a/sop/src/errors.rs b/sop/src/errors.rs deleted file mode 100644 index 0eae86b7..00000000 --- a/sop/src/errors.rs +++ /dev/null @@ -1,101 +0,0 @@ -/// Errors defined by the Stateless OpenPGP Protocol. -#[derive(thiserror::Error, Debug, Clone)] -pub enum Error { - /// No acceptable signatures found ("sop verify"). - #[error("No acceptable signatures found")] - NoSignature, - - /// Asymmetric algorithm unsupported ("sop encrypt"). - #[error("Asymmetric algorithm unsupported")] - UnsupportedAsymmetricAlgo, - - /// Certificate not encryption-capable (e.g., expired, revoked, - /// unacceptable usage flags) ("sop encrypt"). - #[error("Certificate not encryption-capable")] - CertCannotEncrypt, - - /// Missing required argument. - #[error("Missing required argument")] - MissingArg, - - /// Incomplete verification instructions ("sop decrypt"). - #[error("Incomplete verification instructions")] - IncompleteVerification, - - /// Unable to decrypt ("sop decrypt"). - #[error("Unable to decrypt")] - CannotDecrypt, - - /// Non-"UTF-8" or otherwise unreliable password ("sop encrypt"). - #[error("Non-UTF-8 or otherwise unreliable password")] - PasswordNotHumanReadable, - - /// Unsupported option. - #[error("Unsupported option")] - UnsupportedOption, - - /// Invalid data type (no secret key where "KEY" expected, etc). - #[error("Invalid data type")] - BadData, - - /// Non-text input where text expected. - #[error("Non-text input where text expected")] - ExpectedText, - - /// Output file already exists. - #[error("Output file already exists")] - OutputExists, - - /// Input file does not exist. - #[error("Input file does not exist")] - MissingInput, - - /// A "KEY" input is protected (locked) with a password, and "sop" cannot - /// unlock it. - #[error("A KEY input is protected with a password")] - KeyIsProtected, - - /// Unsupported subcommand. - #[error("Unsupported subcommand")] - UnsupportedSubcommand, - - /// An indirect parameter is a special designator (it starts with "@") but - /// "sop" does not know how to handle the prefix. - #[error("An indirect parameter is a special designator with unknown prefix")] - UnsupportedSpecialPrefix, - - /// A indirect input parameter is a special designator (it starts with - /// "@"), and a filename matching the designator is actually present. - #[error("A indirect input parameter is a special designator matches file")] - AmbiguousInput, -} - -impl From<Error> for i32 { - fn from(e: Error) -> Self { - use Error::*; - match e { - NoSignature => 3, - UnsupportedAsymmetricAlgo => 13, - CertCannotEncrypt => 17, - MissingArg => 19, - IncompleteVerification => 23, - CannotDecrypt => 29, - PasswordNotHumanReadable => 31, - UnsupportedOption => 37, - BadData => 41, - ExpectedText => 53, - OutputExists => 59, - MissingInput => 61, - KeyIsProtected => 67, - UnsupportedSubcommand => 69, - UnsupportedSpecialPrefix => 71, - AmbiguousInput => 73, - } - } -} - -/// Prints the error and causes, if any. |