From 7dd428421df1c0e168ed368f91d6c5b49bed7d33 Mon Sep 17 00:00:00 2001 From: Andrew Danger Lyon Date: Mon, 19 Feb 2024 22:00:58 -0800 Subject: [PATCH] rename identity sig -> policy sig. update error strings for missing identities when verifying sigs to include FULL identity id, not the short one. --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- src/commands/dag.rs | 2 +- src/commands/sign.rs | 48 +++++++++++++++++++++++++++----------------- src/main.rs | 16 ++++++++------- 5 files changed, 48 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94a1fb8..9c88700 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ hottest fireee Stamp CLI changes *allowed by law*. +## v0.1.4 // TBD + +### Features + +- Changing signature verification messages to be more clear. +- Rename "Identity signature" to "Policy signature." I believe it's less ambiguous. + ## v0.1.3 // 2024-02-19 Fixing subkey signatures, adding identity signatures, and updating staged transaction interface. diff --git a/Cargo.lock b/Cargo.lock index 55c33bb..0d3953e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2532,7 +2532,7 @@ dependencies = [ [[package]] name = "stamp-cli" -version = "0.1.2" +version = "0.1.3" dependencies = [ "anyhow", "atty", diff --git a/src/commands/dag.rs b/src/commands/dag.rs index 7586ebd..d3dd3bc 100644 --- a/src/commands/dag.rs +++ b/src/commands/dag.rs @@ -206,7 +206,7 @@ pub fn post_save(transactions: &Transactions, transaction: &Transaction, stage: } TransactionBody::SignV1 { creator, body_hash } => { if stage { - format!("Identity signature with hash {} created. {}", body_hash, view_staged()) + format!("Policy signature with hash {} created. {}", body_hash, view_staged()) } else { // weird, should never get here. return Ok(None); diff --git a/src/commands/sign.rs b/src/commands/sign.rs index d263e1a..9b52b77 100644 --- a/src/commands/sign.rs +++ b/src/commands/sign.rs @@ -80,53 +80,53 @@ pub fn sign_subkey(id_sign: &str, key_search_sign: Option<&str>, input: &str, ou pub fn verify(input_signature: &str, input_message: Option<&str>) -> Result<()> { let sig_bytes = util::read_file(input_signature)?; - enum IdOrSub { - Id(Transaction), - Sub(Signature), + enum PolicyOrSub { + Policy(Transaction), + Subkey(Signature), } let signature = Transaction::deserialize_binary(sig_bytes.as_slice()) .or_else(|_| { Transaction::deserialize_binary(&base64_decode(sig_bytes.as_slice())?) }) - .map(|x| IdOrSub::Id(x)) + .map(|x| PolicyOrSub::Policy(x)) .or_else(|_| { Signature::deserialize_binary(sig_bytes.as_slice()) .or_else(|_| { Signature::deserialize_binary(&base64_decode(sig_bytes.as_slice())?) }) - .map(|x| IdOrSub::Sub(x)) + .map(|x| PolicyOrSub::Subkey(x)) }) .map_err(|e| anyhow!("Error reading signature: {}", e))?; let res = match &signature { - IdOrSub::Id(transaction) => { + PolicyOrSub::Policy(transaction) => { let input_message = input_message - .ok_or(anyhow!("A MESSAGE argument must be give when verifying an identity signature."))?; + .ok_or(anyhow!("A MESSAGE argument must be give when verifying an policy signature."))?; let message_bytes = util::read_file(&input_message)?; match transaction.entry().body() { TransactionBody::SignV1 { creator, body_hash } => { let id_str = format!("{}", creator); let creator_transactions = db::load_identity(&creator)? - .ok_or(anyhow!("Identity {} not found. Have you imported it?", IdentityID::short(&id_str)))?; + .ok_or(anyhow!("Identity {} not found. Have you imported it?", id_str))?; let creator_identity = util::build_identity(&creator_transactions)?; // TODO: verify against past version of creator_transactions if verification // fails and we have a non-empty previous_transactions. see issue #41 transaction.verify(Some(&creator_identity)) - .map_err(|e| anyhow!("Identity signature invalid: {}", e))?; + .map_err(|e| anyhow!("Policy signature invalid: {}", e))?; match body_hash { Hash::Blake3(..) => { let compare = Hash::new_blake3(message_bytes.as_slice())?; if &compare == body_hash { Ok(()) } else { - Err(anyhow!("Identity signature hash ({}) does not match message hash ({})", body_hash, compare)) + Err(anyhow!("Policy signature hash ({}) does not match message hash ({})", body_hash, compare)) } } } } - _ => Err(anyhow!("Invalid identity signature"))?, + _ => Err(anyhow!("Invalid policy signature: invalid transaction type (expected `Sign` transaction)"))?, } } - IdOrSub::Sub(signature) => { + PolicyOrSub::Subkey(signature) => { let sig = match signature { Signature::Detached { sig } => sig, Signature::Attached { sig, .. } => sig, @@ -135,7 +135,7 @@ pub fn verify(input_signature: &str, input_message: Option<&str>) -> Result<()> let key_id = sig.signed_by_key(); let id_str = id_str!(identity_id)?; let transactions = db::load_identity(identity_id)? - .ok_or(anyhow!("Identity {} not found. Have you imported it?", IdentityID::short(&id_str)))?; + .ok_or(anyhow!("Identity {} not found. Have you imported it?", id_str))?; let identity = util::build_identity(&transactions)?; let subkey = identity.keychain().subkey_by_keyid(&key_id) .ok_or(anyhow!("Signing key {} not found in identity {}", key_id.as_string(), IdentityID::short(&id_str)))?; @@ -156,12 +156,24 @@ pub fn verify(input_signature: &str, input_message: Option<&str>) -> Result<()> }; match res { Ok(..) => { - let sigtype = match signature { - IdOrSub::Id(..) => "identity", - IdOrSub::Sub(..) => "subkey", - }; let green = dialoguer::console::Style::new().green(); - println!("The {} signature is {}!", sigtype, green.apply_to("valid")); + match signature { + PolicyOrSub::Policy(trans) => { + let identity_id = match trans.entry().body() { + TransactionBody::SignV1 { creator, .. } => creator, + _ => Err(anyhow!("Problem pulling signature `creator` field from policy signature. Perhaps it is not a Sign transaction."))?, + }; + let id_str_creator = id_str!(identity_id)?; + println!("This signature is {}! It is a policy signature made by the identity {}.", green.apply_to("valid"), id_str_creator); + } + PolicyOrSub::Subkey(sig) => { + let signed_obj = match sig { + Signature::Detached { sig } => sig, + Signature::Attached { sig, .. } => sig, + }; + println!("This signature is {}! It is a subkey signature made by the identity {} with the key {}.", green.apply_to("valid"), signed_obj.signed_by_identity(), signed_obj.signed_by_key()); + } + } } Err(e) => { let red = dialoguer::console::Style::new().red(); diff --git a/src/main.rs b/src/main.rs index 8bdd5a4..7e8fd17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -891,9 +891,10 @@ fn run() -> Result<()> { .subcommand_required(true) .arg_required_else_help(true) .subcommand( - Command::new("id") - .about("Create an identity signature. This type of signature is a transaction validated by the policy system, meaning the correct admin key signatures need to be present for it to be considered valid. Use this for creating official signatures.") - .alias("new") + Command::new("policy") + .about("Create a policy signature. This type of signature is a transaction validated by the policy system, meaning the correct admin key signatures need to be present for it to be considered valid. Use this for creating official signatures representative of your identity (for instance if signing a legal document).") + .alias("identity") + .alias("id") .arg(id_arg("The ID of the identity we want to sign from. This overrides the configured default identity.")) .arg(stage_arg()) .arg(signwith_arg()) @@ -909,12 +910,13 @@ fn run() -> Result<()> { .arg(Arg::new("MESSAGE") .index(1) .required(false) - .help("The input file to read the plaintext message from. You can leave blank or use the value '-' to signify STDIN.")) + .help("The input file to read the data from. You can leave blank or use the value '-' to signify STDIN.")) ) .subcommand( Command::new("subkey") - .about("Sign a message or document with one of your `sign` subkeys. This type of signature carries less weight than an `id` signature and only proves you have access to one of the identity's subkeys.") + .about("Sign a message or document with one of your `sign` subkeys. This type of signature carries less weight than a `policy` signature and only proves you have access to one of the identity's subkeys. Use this for less official signatures.") .alias("sub") + .alias("key") .arg(Arg::new("key-sign") .short('k') .long("key-sign") @@ -937,11 +939,11 @@ fn run() -> Result<()> { .arg(Arg::new("MESSAGE") .index(1) .required(false) - .help("The input file to read the plaintext message from. You can leave blank or use the value '-' to signify STDIN.")) + .help("The input file to read the data from. You can leave blank or use the value '-' to signify STDIN.")) ) .subcommand( Command::new("verify") - .about("Verify a signature. This can verify both identity and subkey signatures. This requires having the signing identity imported.") + .about("Verify a signature. This can verify both policy and subkey signatures. This requires having the signing identity imported.") .arg(Arg::new("SIGNATURE") .index(1) .required(true)