diff --git a/src/commands/agent.rs b/src/commands/agent.rs index 23f4ac1..3ceebc0 100644 --- a/src/commands/agent.rs +++ b/src/commands/agent.rs @@ -1,14 +1,10 @@ +use crate::SyncToken; use anyhow::{anyhow, Result}; -use crate::{ - SyncToken, -}; use stamp_aux::util::UIMessage; -use stamp_core::{ - crypto::base::SecretKey, -}; +use stamp_core::crypto::base::SecretKey; //use stamp_net::Multiaddr; -use tokio::{task, sync::mpsc as channel}; -use tracing::{warn}; +use tokio::{sync::mpsc as channel, task}; +use tracing::warn; /* pub fn run(bind: Multiaddr, sync_token: Option, sync_join: Vec, agent_port: u32, agent_lock_after: u64, net: bool, net_join: Vec) -> Result<()> { diff --git a/src/commands/claim.rs b/src/commands/claim.rs index c5472bd..92417fe 100644 --- a/src/commands/claim.rs +++ b/src/commands/claim.rs @@ -1,26 +1,23 @@ -use anyhow::{anyhow, Result}; use crate::{ commands::{dag, id, stamp}, - config, - db, - util, + config, db, util, }; +use anyhow::{anyhow, Result}; use prettytable::Table; use stamp_aux; use stamp_core::{ crypto::{ - base::{SecretKey, rng}, + base::{rng, SecretKey}, private::MaybePrivate, }, dag::{TransactionID, Transactions}, identity::{ - Identity, - IdentityID, claim::{Claim, ClaimID, ClaimSpec, RelationshipType}, - stamp::{Stamp}, + stamp::Stamp, + Identity, IdentityID, }, - rasn::{Encode, Decode}, - util::{Date, Url, Public, BinaryVec, SerText, Timestamp}, + rasn::{Decode, Encode}, + util::{BinaryVec, Date, Public, SerText, Timestamp, Url}, }; use std::convert::TryFrom; use std::ops::Deref; @@ -39,8 +36,10 @@ pub(crate) fn claim_pre_noval(id: &str) -> Result<(SecretKey, Transactions)> { let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let master_key = util::passphrase_prompt(format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - transactions.test_master_key(&master_key) + let master_key = + util::passphrase_prompt(format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; + transactions + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {:?}", e))?; Ok((master_key, transactions)) } @@ -52,28 +51,28 @@ pub(crate) fn claim_pre(id: &str, prompt: &str) -> Result<(SecretKey, Transactio } fn unwrap_maybe(maybe: &MaybePrivate, masterkey_fn: F) -> Result - where T: Encode + Decode + Clone, - F: FnOnce() -> Result, +where + T: Encode + Decode + Clone, + F: FnOnce() -> Result, { if maybe.has_private() { let master_key = masterkey_fn()?; - maybe.open(&master_key) - .map_err(|e| anyhow!("Unable to open private claim: {}", e)) + maybe.open(&master_key).map_err(|e| anyhow!("Unable to open private claim: {}", e)) } else { let mut rng = rng::chacha20(); - let fake_master_key = SecretKey::new_xchacha20poly1305(&mut rng) - .map_err(|e| anyhow!("Unable to generate key: {}", e))?; - maybe.open(&fake_master_key) - .map_err(|e| anyhow!("Unable to open claim: {}", e)) + let fake_master_key = SecretKey::new_xchacha20poly1305(&mut rng).map_err(|e| anyhow!("Unable to generate key: {}", e))?; + maybe.open(&fake_master_key).map_err(|e| anyhow!("Unable to open claim: {}", e)) } } pub fn check(claim_id: &str) -> Result<()> { - let transactions = db::find_identity_by_prefix("claim", claim_id)? - .ok_or(anyhow!("Identity with claim id {} was not found", claim_id))?; + let transactions = + db::find_identity_by_prefix("claim", claim_id)?.ok_or(anyhow!("Identity with claim id {} was not found", claim_id))?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let claim = identity.claims().iter() + let claim = identity + .claims() + .iter() .find(|x| id_str!(x.id()).map(|x| x.starts_with(claim_id)).ok() == Some(true)) .ok_or(anyhow!("Couldn't find the claim {} in identity {}", claim_id, IdentityID::short(&id_str)))?; let claim_id_str = id_str!(claim.id())?; @@ -81,7 +80,14 @@ pub fn check(claim_id: &str) -> Result<()> { Ok(url) => { let green = dialoguer::console::Style::new().green(); println!("\nThe claim {} has been {}!\n", ClaimID::short(&claim_id_str), green.apply_to("verified")); - println!("{}", util::text_wrap(&format!("It is very likely that the identity {} owns the resource {}", IdentityID::short(&id_str), url))); + println!( + "{}", + util::text_wrap(&format!( + "It is very likely that the identity {} owns the resource {}", + IdentityID::short(&id_str), + url + )) + ); Ok(()) } Err(err) => { @@ -110,8 +116,10 @@ pub fn view(id: &str, claim_id: &str, output: &str) -> Result<()> { let id_str = id_str!(identity.id())?; let masterkey_fn = || { - let master_key = util::passphrase_prompt(format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - identity.test_master_key(&master_key) + let master_key = + util::passphrase_prompt(format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; + identity + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {:?}", e))?; Ok(master_key) }; @@ -164,19 +172,23 @@ pub fn list(id: &str, private: bool, verbose: bool) -> Result<()> { let identity = util::build_identity(&transactions)?; let master_key_maybe = if private { let id_str = id_str!(identity.id())?; - let master_key = util::passphrase_prompt(format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - identity.test_master_key(&master_key) + let master_key = + util::passphrase_prompt(format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; + identity + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {:?}", e))?; Some(master_key) } else { None }; - let ts_fake = Timestamp::from_str("0000-01-01T00:00:00.000Z") - .map_err(|e| anyhow!("Error creating fake timestamp: {:?}", e))?; - let claim_list = identity.claims().iter() + let ts_fake = Timestamp::from_str("0000-01-01T00:00:00.000Z").map_err(|e| anyhow!("Error creating fake timestamp: {:?}", e))?; + let claim_list = identity + .claims() + .iter() .map(|claim| { let claim_id: TransactionID = claim.id().deref().clone(); - let ts = transactions.iter() + let ts = transactions + .iter() .find(|t| t.id() == &claim_id) .map(|t| t.entry().created().clone()) .unwrap_or_else(|| ts_fake.clone()); @@ -191,33 +203,35 @@ pub fn stamp_list(id: &str, claim_id_or_name: &str, verbose: bool) -> Result<()> let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let claim = identity.claims().iter() + let claim = identity + .claims() + .iter() .find(|x| { - x.name().as_ref().map(|y| y == claim_id_or_name).unwrap_or(false) || - id_str!(x.id()).unwrap_or("".into()).starts_with(claim_id_or_name) + x.name().as_ref().map(|y| y == claim_id_or_name).unwrap_or(false) + || id_str!(x.id()).unwrap_or("".into()).starts_with(claim_id_or_name) }) .ok_or_else(|| anyhow!("Could not find claim {} in identity {}.", claim_id_or_name, id_str))?; - let stamps = claim.stamps().iter() - .collect::>(); + let stamps = claim.stamps().iter().collect::>(); stamp::print_stamps_table(&stamps, verbose, false)?; Ok(()) } fn find_stamp_by_id<'a>(identity: &'a Identity, stamp_id: &str) -> Option<&'a Stamp> { - identity.claims().iter() - .find_map(|c| { - c.stamps().iter() - .find(|s| id_str!(s.id()).unwrap_or("".into()).starts_with(stamp_id)) - }) + identity.claims().iter().find_map(|c| { + c.stamps() + .iter() + .find(|s| id_str!(s.id()).unwrap_or("".into()).starts_with(stamp_id)) + }) } pub fn stamp_view(id: &str, stamp_id: &str) -> Result<()> { let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let stamp = find_stamp_by_id(&identity, stamp_id) - .ok_or_else(|| anyhow!("Could not find stamp {} in identity {}.", stamp_id, id_str))?; - let stamp_text = stamp.serialize_text() + let stamp = + find_stamp_by_id(&identity, stamp_id).ok_or_else(|| anyhow!("Could not find stamp {} in identity {}.", stamp_id, id_str))?; + let stamp_text = stamp + .serialize_text() .map_err(|e| anyhow!("Problem serializing stamp transaction: {:?}", e))?; println!("{}", stamp_text); Ok(()) @@ -228,9 +242,10 @@ pub fn stamp_delete(id: &str, stamp_id: &str, stage: bool, sign_with: Option<&st let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let stamp = find_stamp_by_id(&identity, stamp_id) - .ok_or_else(|| anyhow!("Could not find stamp {} in identity {}.", stamp_id, id_str))?; - let stamp_text = stamp.serialize_text() + let stamp = + find_stamp_by_id(&identity, stamp_id).ok_or_else(|| anyhow!("Could not find stamp {} in identity {}.", stamp_id, id_str))?; + let stamp_text = stamp + .serialize_text() .map_err(|e| anyhow!("Problem serializing stamp transaction: {:?}", e))?; println!("{}", stamp_text); println!("----------"); @@ -238,9 +253,13 @@ pub fn stamp_delete(id: &str, stamp_id: &str, stage: bool, sign_with: Option<&st println!("Aborted."); return Ok(()); } - let trans = transactions.delete_stamp(&hash_with, Timestamp::now(), stamp.id().clone()) + let trans = transactions + .delete_stamp(&hash_with, Timestamp::now(), stamp.id().clone()) .map_err(|e| anyhow!("Problem creating stamp delete transaction: {:?}", e))?; - let master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; + let master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity.created(), + )?; let signed = util::sign_helper(&identity, trans, &master_key, stage, sign_with)?; dag::save_or_stage(transactions, signed, stage)?; Ok(()) @@ -256,7 +275,8 @@ pub fn print_claims_table(claims: &Vec<(Claim, Timestamp)>, master_key_maybe: Op macro_rules! extract_str { ($maybe:expr, $tostr:expr) => { if let Some(master_key) = master_key_maybe.as_ref() { - $maybe.open(master_key) + $maybe + .open(master_key) .map(|val| { let strval = $tostr(val); if $maybe.has_private() { @@ -269,9 +289,7 @@ pub fn print_claims_table(claims: &Vec<(Claim, Timestamp)>, master_key_maybe: Op .unwrap_or_else(|e| format!("Decryption error: {}", e)) } else { match $maybe { - MaybePrivate::Public(val) => { - $tostr(val.clone()) - } + MaybePrivate::Public(val) => $tostr(val.clone()), MaybePrivate::Private { .. } => { let red = dialoguer::console::Style::new().red(); format!("{}", red.apply_to("")) @@ -285,10 +303,17 @@ pub fn print_claims_table(claims: &Vec<(Claim, Timestamp)>, master_key_maybe: Op } let name = claim.name().as_ref().map(|x| x.clone()).unwrap_or("-".into()); let (ty, val) = match claim.spec() { - ClaimSpec::Identity(id) => ("identity", extract_str!(id, |x: IdentityID| { - let (id_full, id_short) = id_str_split!(&x); - if verbose { id_full } else { id_short } - })), + ClaimSpec::Identity(id) => ( + "identity", + extract_str!(id, |x: IdentityID| { + let (id_full, id_short) = id_str_split!(&x); + if verbose { + id_full + } else { + id_short + } + }), + ), ClaimSpec::Name(name) => ("name", extract_str!(name)), ClaimSpec::Birthday(birthday) => ("birthday", extract_str!(birthday, |x: Date| x.to_string())), ClaimSpec::Email(email) => ("email", extract_str!(email)), @@ -327,4 +352,3 @@ pub fn print_claims_table(claims: &Vec<(Claim, Timestamp)>, master_key_maybe: Op } table.printstd(); } - diff --git a/src/commands/config.rs b/src/commands/config.rs index 867e6ad..3f6e7e1 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -1,19 +1,12 @@ +use crate::{commands, config, db, util}; use anyhow::{anyhow, Result}; -use crate::{ - commands, - config, - db, - util, -}; use std::convert::TryFrom; pub fn set_default(search: &str) -> Result<()> { let mut conf = config::load()?; let identities = db::list_local_identities(Some(search))?; if identities.len() > 1 { - let identities_vec = identities.iter() - .map(|x| util::build_identity(x)) - .collect::>>()?; + let identities_vec = identities.iter().map(|x| util::build_identity(x)).collect::>>()?; commands::id::print_identities_table(&identities_vec, false); Err(anyhow!("Multiple identities matched that search"))?; } else if identities.len() == 0 { @@ -26,4 +19,3 @@ pub fn set_default(search: &str) -> Result<()> { conf.default_identity = Some(id_str); config::save(&conf) } - diff --git a/src/commands/dag.rs b/src/commands/dag.rs index d3dd3bc..69f2716 100644 --- a/src/commands/dag.rs +++ b/src/commands/dag.rs @@ -1,25 +1,14 @@ +use crate::{commands::id, db, util}; use anyhow::{anyhow, Result}; -use crate::{ - commands::id, - db, - util, -}; use prettytable::Table; use stamp_aux::db::stage_transaction; use stamp_core::{ - crypto::{ - base::KeyID, - private::MaybePrivate, - }, - dag::{TransactionBody, Transaction, Transactions}, - identity::{ - IdentityID, - claim::ClaimSpec, - keychain::Key, - }, - util::{SerdeBinary, base64_encode}, + crypto::{base::KeyID, private::MaybePrivate}, + dag::{Transaction, TransactionBody, Transactions}, + identity::{claim::ClaimSpec, keychain::Key, IdentityID}, + util::{base64_encode, SerdeBinary}, }; -use std::convert::{TryFrom, From}; +use std::convert::{From, TryFrom}; use std::ops::Deref; pub fn list(id: &str) -> Result<()> { @@ -32,10 +21,14 @@ pub fn reset(id: &str, txid: &str) -> Result<()> { let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let trans = transactions.transactions().iter() + let trans = transactions + .transactions() + .iter() .find(|x| id_str!(x.id()).map(|id| id.starts_with(txid)).unwrap_or(false)) .ok_or(anyhow!("Transaction {} not found for identity {}", txid, IdentityID::short(&id_str)))?; - let transactions_reset = transactions.clone().reset(trans.id()) + let transactions_reset = transactions + .clone() + .reset(trans.id()) .map_err(|e| anyhow!("Problem resetting transactions: {}", e))?; let removed = transactions.transactions().len() - transactions_reset.transactions().len(); println!("Removed {} transactions from identity {}", removed, IdentityID::short(&id_str)); @@ -47,10 +40,13 @@ pub fn export(id: &str, txid: &str, output: &str, base64: bool) -> Result<()> { let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let trans = transactions.transactions().iter() + let trans = transactions + .transactions() + .iter() .find(|x| id_str!(x.id()).map(|id| id.starts_with(txid)).unwrap_or(false)) .ok_or(anyhow!("Transaction {} not found for identity {}", txid, IdentityID::short(&id_str)))?; - let serialized = trans.serialize_binary() + let serialized = trans + .serialize_binary() .map_err(|e| anyhow!("Problem serializing transaction: {:?}", e))?; if base64 { let serialized_str = base64_encode(serialized.as_slice()); @@ -93,9 +89,13 @@ pub fn post_save(transactions: &Transactions, transaction: &Transaction, stage: match spec { ClaimSpec::Domain(MaybePrivate::Public(domain)) => { let claim_id: stamp_core::identity::claim::ClaimID = transaction.id().clone().into(); - let claim = identity.claims().iter().find(|c| c.id() == &claim_id) + let claim = identity + .claims() + .iter() + .find(|c| c.id() == &claim_id) .ok_or_else(|| anyhow!("Unable to find created claim"))?; - let instant_values = claim.instant_verify_allowed_values(identity.id()) + let instant_values = claim + .instant_verify_allowed_values(identity.id()) .map_err(|e| anyhow!("Problem grabbing allowed claim values: {}", e))?; format!( "{}\n {}\n {}\n", @@ -106,9 +106,13 @@ pub fn post_save(transactions: &Transactions, transaction: &Transaction, stage: } ClaimSpec::Url(MaybePrivate::Public(url)) => { let claim_id: stamp_core::identity::claim::ClaimID = transaction.id().clone().into(); - let claim = identity.claims().iter().find(|c| c.id() == &claim_id) + let claim = identity + .claims() + .iter() + .find(|c| c.id() == &claim_id) .ok_or_else(|| anyhow!("Unable to find created claim"))?; - let instant_values = claim.instant_verify_allowed_values(identity.id()) + let instant_values = claim + .instant_verify_allowed_values(identity.id()) .map_err(|e| anyhow!("Problem grabbing allowed claim values: {}", e))?; format!( "{}\n {}\n {}\n {}\n {}\n", @@ -120,7 +124,8 @@ pub fn post_save(transactions: &Transactions, transaction: &Transaction, stage: ) } _ => { - let name_format = name.as_ref() + let name_format = name + .as_ref() .map(|x| format!(" with name {}", x)) .unwrap_or_else(|| String::from("")); format!("Claim{} added.", name_format) @@ -212,21 +217,20 @@ pub fn post_save(transactions: &Transactions, transaction: &Transaction, stage: return Ok(None); } } - _ => { return Ok(None) } + _ => return Ok(None), }; Ok(Some(msg)) } pub fn save_or_stage(transactions: Transactions, transaction: Transaction, stage: bool) -> Result { - let identity_id = transactions.identity_id() - .ok_or(anyhow!("Unable to generate identity id"))?; + let identity_id = transactions.identity_id().ok_or(anyhow!("Unable to generate identity id"))?; let trans_clone = transaction.clone(); let transactions = if stage { - stage_transaction(&identity_id, transaction) - .map_err(|e| anyhow!("Error staging transaction: {:?}", e))?; + stage_transaction(&identity_id, transaction).map_err(|e| anyhow!("Error staging transaction: {:?}", e))?; transactions } else { - let transactions_mod = transactions.push_transaction(transaction) + let transactions_mod = transactions + .push_transaction(transaction) .map_err(|e| anyhow!("Error saving transaction: {:?}", e))?; db::save_identity(transactions_mod)? }; @@ -271,17 +275,10 @@ pub fn print_transactions_table(transactions: &Vec) { table.set_titles(row!["ID", "Type", "Signatures", "Created"]); for trans in transactions { let ty = transaction_to_string(trans); - let id = id_str!(trans.id()) - .unwrap_or_else(|e| format!("", trans.id(), e)); + let id = id_str!(trans.id()).unwrap_or_else(|e| format!("", trans.id(), e)); let created = trans.entry().created().local().format("%b %e, %Y %H:%M:%S"); let num_sig = trans.signatures().len(); - table.add_row(row![ - id, - ty, - num_sig, - created, - ]); + table.add_row(row![id, ty, num_sig, created,]); } table.printstd(); } - diff --git a/src/commands/debug.rs b/src/commands/debug.rs index e3879ed..6122493 100644 --- a/src/commands/debug.rs +++ b/src/commands/debug.rs @@ -1,9 +1,5 @@ +use crate::{commands::id, db, util}; use anyhow::{anyhow, Result}; -use crate::{ - commands::id, - db, - util, -}; #[cfg(feature = "yaml-export")] use stamp_core::{ dag::Transactions, @@ -38,8 +34,7 @@ pub fn export(id: &str) -> Result<()> { #[cfg(feature = "yaml-export")] pub fn import(export_file: &str) -> Result<()> { let yaml = util::read_file(export_file)?; - let yaml_string = String::from_utf8(yaml) - .map_err(|e| anyhow!("Error reading YAML file: {}", e))?; + let yaml_string = String::from_utf8(yaml).map_err(|e| anyhow!("Error reading YAML file: {}", e))?; let identity: Transactions = text_import(&yaml_string)?; let identity_id = identity.identity_id() // panics are fine and kewl if you are building debug commands... @@ -48,4 +43,3 @@ pub fn import(export_file: &str) -> Result<()> { println!("Identity {} imported.", identity_id); Ok(()) } - diff --git a/src/commands/id.rs b/src/commands/id.rs index 3c54d21..faaebd2 100644 --- a/src/commands/id.rs +++ b/src/commands/id.rs @@ -1,19 +1,13 @@ +use crate::{config, db, util}; use anyhow::{anyhow, Result}; -use crate::{ - config, - db, - util, -}; use indicatif::{ProgressBar, ProgressStyle}; use prettytable::Table; -use stamp_aux::{ - db::stage_transaction, -}; +use stamp_aux::db::stage_transaction; use stamp_core::{ - crypto::base::{SecretKey}, + crypto::base::SecretKey, dag::Transactions, - identity::{IdentityID, Identity}, - util::{Timestamp, SerdeBinary, SerText}, + identity::{Identity, IdentityID}, + util::{SerText, SerdeBinary, Timestamp}, }; use std::convert::TryFrom; @@ -56,9 +50,7 @@ pub(crate) fn post_create(transactions: &Transactions) -> Result<()> { pub(crate) fn try_load_single_identity(id: &str) -> Result { let identities = db::load_identities_by_prefix(id)?; if identities.len() > 1 { - let identities = identities.iter() - .map(|x| util::build_identity(x)) - .collect::>>()?; + let identities = identities.iter().map(|x| util::build_identity(x)).collect::>>()?; print_identities_table(&identities, false); Err(anyhow!("Multiple identities matched ID {}", id))?; } else if identities.len() == 0 { @@ -67,28 +59,24 @@ pub(crate) fn try_load_single_identity(id: &str) -> Result { Ok(identities[0].clone()) } -pub(crate) fn create_vanity(regex: Option<&str>, contains: Vec<&str>, prefix: Option<&str>) -> Result<(SecretKey, Transactions, Timestamp)> { +pub(crate) fn create_vanity( + regex: Option<&str>, + contains: Vec<&str>, + prefix: Option<&str>, +) -> Result<(SecretKey, Transactions, Timestamp)> { let hash_with = config::hash_algo(None); let spinner = ProgressBar::new_spinner(); spinner.enable_steady_tick(250); spinner.set_style( ProgressStyle::default_spinner() - .tick_strings(&[ - " ", - "* ", - " * ", - " * ", - " * ", - " * ", - " *", - " *", - ]) - .template("[{spinner:.green}] {msg}") + .tick_strings(&[" ", "* ", " * ", " * ", " * ", " * ", " *", " *"]) + .template("[{spinner:.green}] {msg}"), ); spinner.set_message("Starting vanity ID search, this might take a while."); let (tmp_master_key, transactions, now) = stamp_aux::id::create_personal_vanity(&hash_with, regex, contains, prefix, |counter| { spinner.set_message(&format!("Searched {} IDs", counter)); - }).map_err(|e| anyhow!("Error generating vanity id: {}", e))?; + }) + .map_err(|e| anyhow!("Error generating vanity id: {}", e))?; spinner.finish(); let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; @@ -102,25 +90,28 @@ pub fn publish(id: &str, stage: bool, sign_with: Option<&str>) -> Result let transactions = try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let master_key = util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; + let master_key = + util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; let now = Timestamp::now(); - let transaction = transactions.publish(&hash_with, now) + let transaction = transactions + .publish(&hash_with, now) .map_err(|e| anyhow!("Error creating publish transaction: {:?}", e))?; let signed = util::sign_helper(&identity, transaction, &master_key, stage, sign_with)?; if stage { - let transaction = stage_transaction(identity.id(), signed) - .map_err(|e| anyhow!("Error staging transaction: {:?}", e))?; + let transaction = stage_transaction(identity.id(), signed).map_err(|e| anyhow!("Error staging transaction: {:?}", e))?; id_str!(transaction.id()) } else { - signed.serialize_text() + signed + .serialize_text() .map_err(|e| anyhow!("Error serializing transaction: {:?}", e)) } } pub fn export_private(id: &str) -> Result> { let identity = try_load_single_identity(id)?; - let serialized = identity.serialize_binary() + let serialized = identity + .serialize_binary() .map_err(|e| anyhow!("There was a problem serializing the identity: {:?}", e))?; Ok(serialized) } @@ -130,7 +121,8 @@ pub fn delete(search: &str, skip_confirm: bool, verbose: bool) -> Result<()> { if identities.len() == 0 { Err(anyhow!("No identities match that search"))?; } - let identities = identities.into_iter() + let identities = identities + .into_iter() .map(|x| util::build_identity(&x)) .collect::>>()?; print_identities_table(&identities, verbose); @@ -152,9 +144,7 @@ pub fn delete(search: &str, skip_confirm: bool, verbose: bool) -> Result<()> { pub fn view(search: &str) -> Result { let identities = db::list_local_identities(Some(search))?; if identities.len() > 1 { - let identities = identities.iter() - .map(|x| util::build_identity(x)) - .collect::>>()?; + let identities = identities.iter().map(|x| util::build_identity(x)).collect::>>()?; print_identities_table(&identities, false); Err(anyhow!("Multiple identities matched that search"))?; } else if identities.len() == 0 { @@ -162,21 +152,18 @@ pub fn view(search: &str) -> Result { } let transactions = identities[0].clone(); let identity = util::build_identity(&transactions)?; - let serialized = identity.serialize_text() + let serialized = identity + .serialize_text() .map_err(|e| anyhow!("Problem serializing identity: {:?}", e))?; Ok(serialized) } pub fn fingerprint(id: &str, format: FingerprintFormat) -> Result { let transactions = try_load_single_identity(id)?; - let identity_id = transactions.identity_id() - .ok_or_else(|| anyhow!("Identity {} not found", id))?; - let fingerprint = stamp_aux::id::fingerprint(&identity_id) - .map_err(|e| anyhow!("Problem generating fingerprint: {:?}", e))?; + let identity_id = transactions.identity_id().ok_or_else(|| anyhow!("Identity {} not found", id))?; + let fingerprint = stamp_aux::id::fingerprint(&identity_id).map_err(|e| anyhow!("Problem generating fingerprint: {:?}", e))?; match format { - FingerprintFormat::Svg => { - Ok(stamp_aux::id::fingerprint_to_svg(&fingerprint)) - } + FingerprintFormat::Svg => Ok(stamp_aux::id::fingerprint_to_svg(&fingerprint)), FingerprintFormat::Term => { let print_char = "██"; let black = dialoguer::console::Style::new().color256(0); @@ -188,10 +175,7 @@ pub fn fingerprint(id: &str, format: FingerprintFormat) -> Result { let block = format!("{}", color.apply_to(print_char)); out[y as usize][x as usize] = block; } - Ok(out.into_iter() - .map(|row| row.join("")) - .collect::>() - .join("\n")) + Ok(out.into_iter().map(|row| row.join("")).collect::>().join("\n")) } } } @@ -208,83 +192,33 @@ pub(crate) fn print_identities_table(identities: &Vec, verbose: bool) let email = identity.emails().get(0).map(|x| x.clone()).unwrap_or_else(|| String::from("")); let created = identity.created().local().format("%b %d, %Y").to_string(); let owned = if identity.is_owned() { "x" } else { "" }; - table.add_row(row![ - owned, - if verbose { &id_full } else { &id_short }, - name, - email, - created, - ]); + table.add_row(row![owned, if verbose { &id_full } else { &id_short }, name, email, created,]); } table.printstd(); } fn rgb_to_256(rgb: [u8; 3]) -> u8 { let mapping: [u32; 256] = [ - 0x000000, 0x800000, 0x008000, 0x808000, - 0x000080, 0x800080, 0x008080, 0xc0c0c0, - 0x808080, 0xff0000, 0x00ff00, 0xffff00, - 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff, - 0x000000, 0x00005f, 0x000087, 0x0000af, - 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f, - 0x005f87, 0x005faf, 0x005fd7, 0x005fff, - 0x008700, 0x00875f, 0x008787, 0x0087af, - 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, - 0x00af87, 0x00afaf, 0x00afd7, 0x00afff, - 0x00d700, 0x00d75f, 0x00d787, 0x00d7af, - 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f, - 0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, - 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af, - 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, - 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff, - 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, - 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f, - 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, - 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af, - 0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, - 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff, - 0x870000, 0x87005f, 0x870087, 0x8700af, - 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f, - 0x875f87, 0x875faf, 0x875fd7, 0x875fff, - 0x878700, 0x87875f, 0x878787, 0x8787af, - 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, - 0x87af87, 0x87afaf, 0x87afd7, 0x87afff, - 0x87d700, 0x87d75f, 0x87d787, 0x87d7af, - 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f, - 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, - 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af, - 0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, - 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff, - 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, - 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f, - 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, - 0xafd700, 0xafd75f, 0xafd787, 0xafd7af, - 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, - 0xafff87, 0xafffaf, 0xafffd7, 0xafffff, - 0xd70000, 0xd7005f, 0xd70087, 0xd700af, - 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f, - 0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, - 0xd78700, 0xd7875f, 0xd78787, 0xd787af, - 0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, - 0xd7af87, 0xd7afaf, 0xd7afd7, 0xd7afff, - 0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, - 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f, - 0xd7ff87, 0xd7ffaf, 0xd7ffd7, 0xd7ffff, - 0xff0000, 0xff005f, 0xff0087, 0xff00af, - 0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, - 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff, - 0xff8700, 0xff875f, 0xff8787, 0xff87af, - 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f, - 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, - 0xffd700, 0xffd75f, 0xffd787, 0xffd7af, - 0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, - 0xffff87, 0xffffaf, 0xffffd7, 0xffffff, - 0x080808, 0x121212, 0x1c1c1c, 0x262626, - 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e, - 0x585858, 0x626262, 0x6c6c6c, 0x767676, - 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e, - 0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, - 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee, + 0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xc0c0c0, 0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, + 0xff00ff, 0x00ffff, 0xffffff, 0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f, 0x005f87, 0x005faf, + 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af, 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, + 0x00afff, 0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f, 0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, + 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af, 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff, 0x5f8700, + 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f, 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, + 0x5fd787, 0x5fd7af, 0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff, 0x870000, 0x87005f, 0x870087, + 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f, 0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af, + 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff, 0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, + 0x87d7ff, 0x87ff00, 0x87ff5f, 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af, 0xaf00d7, 0xaf00ff, + 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff, 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, + 0xafaf5f, 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af, 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, + 0xafff87, 0xafffaf, 0xafffd7, 0xafffff, 0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f, 0xd75f87, + 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af, 0xd787d7, 0xd787ff, 0xd7af00, 0xd7af5f, 0xd7af87, 0xd7afaf, + 0xd7afd7, 0xd7afff, 0xd7d700, 0xd7d75f, 0xd7d787, 0xd7d7af, 0xd7d7d7, 0xd7d7ff, 0xd7ff00, 0xd7ff5f, 0xd7ff87, 0xd7ffaf, 0xd7ffd7, + 0xd7ffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af, 0xff00d7, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fd7, 0xff5fff, + 0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87d7, 0xff87ff, 0xffaf00, 0xffaf5f, 0xffaf87, 0xffafaf, 0xffafd7, 0xffafff, 0xffd700, + 0xffd75f, 0xffd787, 0xffd7af, 0xffd7d7, 0xffd7ff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffd7, 0xffffff, 0x080808, 0x121212, + 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e, 0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, + 0x9e9e9e, 0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee, ]; let mut lowest_dist = (f32::MAX, 0u8); @@ -299,9 +233,7 @@ fn rgb_to_256(rgb: [u8; 3]) -> u8 { let d_g = rgb1[1] as f32 - rgb2[1] as f32; let d_b = rgb1[2] as f32 - rgb2[2] as f32; f32::sqrt( - ((((512.0 + rmean) * d_r * d_r) as i32 >> 8) + - (4.0 * d_g * d_g) as i32 + - (((767.0 - rmean) * d_b * d_b) as i32 >> 8)) as f32 + ((((512.0 + rmean) * d_r * d_r) as i32 >> 8) + (4.0 * d_g * d_g) as i32 + (((767.0 - rmean) * d_b * d_b) as i32 >> 8)) as f32, ) } for i in 0..mapping.len() { @@ -317,4 +249,3 @@ fn rgb_to_256(rgb: [u8; 3]) -> u8 { } lowest_dist.1 } - diff --git a/src/commands/keychain.rs b/src/commands/keychain.rs index 5a1890d..b25e259 100644 --- a/src/commands/keychain.rs +++ b/src/commands/keychain.rs @@ -1,26 +1,20 @@ -use anyhow::{anyhow, Result}; use crate::{ - commands::{ - id, dag, - claim::claim_pre_noval, - }, - config, - db, - util, + commands::{claim::claim_pre_noval, dag, id}, + config, db, util, }; +use anyhow::{anyhow, Result}; use prettytable::Table; use stamp_core::{ crypto::{ self, - base::{KeyID, SecretKey, rng}, + base::{rng, KeyID, SecretKey}, private::PrivateWithHmac, }, identity::{ - Identity, - IdentityID, keychain::{AdminKey, AdminKeypair, ExtendKeypair, Key, RevocationReason, Subkey}, + Identity, IdentityID, }, - util::{Timestamp, Public, base64_encode, base64_decode}, + util::{base64_decode, base64_encode, Public, Timestamp}, }; use std::convert::{TryFrom, TryInto}; @@ -70,15 +64,19 @@ pub fn new(id: &str, ty: &str, name: &str, desc: Option<&str>, stage: bool, sign let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; let hash_with = config::hash_algo(Some(&id_str)); - let master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - identity.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity.created(), + )?; + identity + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {:?}", e))?; let transaction = match ty { "admin" => { - let admin_keypair = AdminKeypair::new_ed25519(&mut rng, &master_key) - .map_err(|e| anyhow!("Error generating key: {:?}", e))?; + let admin_keypair = AdminKeypair::new_ed25519(&mut rng, &master_key).map_err(|e| anyhow!("Error generating key: {:?}", e))?; let admin_key = AdminKey::new(admin_keypair, name, desc); - transactions.add_admin_key(&hash_with, Timestamp::now(), admin_key) + transactions + .add_admin_key(&hash_with, Timestamp::now(), admin_key) .map_err(|e| anyhow!("Problem adding key to identity: {:?}", e))? } "sign" | "crypto" | "secret" => { @@ -94,15 +92,16 @@ pub fn new(id: &str, ty: &str, name: &str, desc: Option<&str>, stage: bool, sign Key::new_crypto(new_key) } "secret" => { - let rand_key = crypto::base::SecretKey::new_xchacha20poly1305(&mut rng) - .map_err(|e| anyhow!("Unable to generate key: {}", e))?; - let new_key = PrivateWithHmac::seal(&mut rng, &master_key, rand_key) - .map_err(|e| anyhow!("Error generating key: {:?}", e))?; + let rand_key = + crypto::base::SecretKey::new_xchacha20poly1305(&mut rng).map_err(|e| anyhow!("Unable to generate key: {}", e))?; + let new_key = + PrivateWithHmac::seal(&mut rng, &master_key, rand_key).map_err(|e| anyhow!("Error generating key: {:?}", e))?; Key::new_secret(new_key) } _ => Err(anyhow!("Invalid key type: {}", ty))?, }; - transactions.add_subkey(&hash_with, Timestamp::now(), key, name, desc) + transactions + .add_subkey(&hash_with, Timestamp::now(), key, name, desc) .map_err(|e| anyhow!("Problem adding key to identity: {:?}", e))? } _ => Err(anyhow!("Invalid key type: {}", ty))?, @@ -161,27 +160,37 @@ pub fn update(id: &str, search: &str, name: Option<&str>, desc: Option { - let trans = transactions.edit_admin_key(&hash_with, Timestamp::now(), admin.key_id(), name, desc) + let trans = transactions + .edit_admin_key(&hash_with, Timestamp::now(), admin.key_id(), name, desc) .map_err(|e| anyhow!("Error updating admin key: {:?}", e))?; (trans, admin.key().key_id()) } (_, Some(subkey)) => { - let trans = transactions.edit_subkey(&hash_with, Timestamp::now(), subkey.key_id(), name, desc) + let trans = transactions + .edit_subkey(&hash_with, Timestamp::now(), subkey.key_id(), name, desc) .map_err(|e| anyhow!("Error updating subkey: {:?}", e))?; (trans, subkey.key_id()) } @@ -197,17 +206,25 @@ pub fn revoke(id: &str, search: &str, reason: &str, stage: bool, sign_with: Opti let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let key_admin = identity.keychain().admin_key_by_name(search) + let key_admin = identity + .keychain() + .admin_key_by_name(search) .or_else(|| identity.keychain().admin_key_by_keyid_str(search)); - let key_subkey = identity.keychain().subkey_by_name(search) + let key_subkey = identity + .keychain() + .subkey_by_name(search) .or_else(|| identity.keychain().subkey_by_keyid_str(search)); if key_admin.is_none() && key_subkey.is_none() { Err(anyhow!("Cannot find key {} in identity {}", search, IdentityID::short(&id_str)))?; } - let master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - transactions.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity.created(), + )?; + transactions + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {:?}", e))?; let rev_reason = match reason { @@ -218,12 +235,14 @@ pub fn revoke(id: &str, search: &str, reason: &str, stage: bool, sign_with: Opti }; let (transaction, _key_id) = match (key_admin, key_subkey) { (Some(admin), _) => { - let trans = transactions.revoke_admin_key(&hash_with, Timestamp::now(), admin.key_id(), rev_reason, None::) + let trans = transactions + .revoke_admin_key(&hash_with, Timestamp::now(), admin.key_id(), rev_reason, None::) .map_err(|e| anyhow!("Error revoking admin key: {:?}", e))?; (trans, admin.key().key_id()) } (_, Some(subkey)) => { - let trans = transactions.revoke_subkey(&hash_with, Timestamp::now(), subkey.key_id(), rev_reason, None::) + let trans = transactions + .revoke_subkey(&hash_with, Timestamp::now(), subkey.key_id(), rev_reason, None::) .map_err(|e| anyhow!("Error revoking subkey: {:?}", e))?; (trans, subkey.key_id()) } @@ -239,15 +258,12 @@ pub fn delete_subkey(id: &str, search: &str, stage: bool, sign_with: Option<&str let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let key = identity.keychain().subkeys().iter() + let key = identity + .keychain() + .subkeys() + .iter() .rev() - .find_map(|x| { - if x.name() == search { - Some(x) - } else { - None - } - }) + .find_map(|x| if x.name() == search { Some(x) } else { None }) .ok_or(anyhow!("Cannot find key {} in identity {}", search, IdentityID::short(&id_str)))? .clone(); match key.key() { @@ -259,10 +275,15 @@ pub fn delete_subkey(id: &str, search: &str, stage: bool, sign_with: Option<&str } } } - let master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - transactions.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity.created(), + )?; + transactions + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {:?}", e))?; - let transaction = transactions.delete_subkey(&hash_with, Timestamp::now(), key.key_id()) + let transaction = transactions + .delete_subkey(&hash_with, Timestamp::now(), key.key_id()) .map_err(|e| anyhow!("Problem deleting subkey from keychain: {:?}", e))?; let signed = util::sign_helper(&identity, transaction, &master_key, stage, sign_with)?; dag::save_or_stage(transactions, signed, stage)?; @@ -275,15 +296,11 @@ pub fn passwd(id: &str, keyfile: Option<&str>, keyparts: Vec<&str>) -> Result<() let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; fn master_key_from_base64_shamir_parts(parts: &Vec<&str>) -> Result { - let keyfile_parts = parts.iter() + let keyfile_parts = parts + .iter() + .map(|part| base64_decode(part.trim()).map_err(|e| anyhow!("Problem reading key part: {:?}", e))) .map(|part| { - base64_decode(part.trim()).map_err(|e| anyhow!("Problem reading key part: {:?}", e)) - }) - .map(|part| { - part.and_then(|x| { - sharks::Share::try_from(x.as_slice()) - .map_err(|e| anyhow!("Problem deserializing key part: {:?}", e)) - }) + part.and_then(|x| sharks::Share::try_from(x.as_slice()).map_err(|e| anyhow!("Problem deserializing key part: {:?}", e))) }) .collect::>>()?; let mut key_bytes = None; @@ -308,31 +325,39 @@ pub fn passwd(id: &str, keyfile: Option<&str>, keyparts: Vec<&str>) -> Result<() let master_key = if let Some(keyfile) = keyfile { let keyfile_contents = util::read_file(keyfile)?; - let keyfile_string = String::from_utf8(keyfile_contents) - .map_err(|_| anyhow!("Invalid keyfile format."))?; + let keyfile_string = String::from_utf8(keyfile_contents).map_err(|_| anyhow!("Invalid keyfile format."))?; let keyfile_parts = keyfile_string.split("\n").collect::>(); let master_key = master_key_from_base64_shamir_parts(&keyfile_parts)?; - identity.test_master_key(&master_key) + identity + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect master key: {}", e))?; util::print_wrapped("Successfully recovered master key from keyfile!\n"); master_key } else if keyparts.len() > 0 { let master_key = master_key_from_base64_shamir_parts(&keyparts)?; - identity.test_master_key(&master_key) + identity + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect master key: {}", e))?; util::print_wrapped("Successfully recovered master key from key parts!\n"); master_key } else { - let master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - identity.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity.created(), + )?; + identity + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {}", e))?; master_key }; - let (_, new_master_key) = util::with_new_passphrase("Your new master passphrase", |_master_key, _now| { Ok(()) }, Some(identity.created().clone()))?; - let transactions_reencrypted = transactions.reencrypt(&mut rng, &master_key, &new_master_key) + let (_, new_master_key) = + util::with_new_passphrase("Your new master passphrase", |_master_key, _now| Ok(()), Some(identity.created().clone()))?; + let transactions_reencrypted = transactions + .reencrypt(&mut rng, &master_key, &new_master_key) .map_err(|e| anyhow!("Password change failed: {}", e))?; // make sure it actually works before we save it... - transactions_reencrypted.test_master_key(&new_master_key) + transactions_reencrypted + .test_master_key(&new_master_key) .map_err(|e| anyhow!("Password change failed: {}", e))?; db::save_identity(transactions_reencrypted)?; println!("Identity re-encrypted with new passphrase!"); @@ -377,11 +402,13 @@ pub(crate) fn sync_token(id: &str, blind: bool, stage: bool, sign_with: Option<& pub fn keyfile(id: &str, shamir: &str, output: &str) -> Result<()> { let mut shamir_parts = shamir.split("/"); - let min_shares: u8 = shamir_parts.next() + let min_shares: u8 = shamir_parts + .next() .ok_or(anyhow!("Invalid shamir format (must be \"M/S\")"))? .parse() .map_err(|_| anyhow!("Invalid shamir format (must be \"M/S\")"))?; - let num_shares: u8 = shamir_parts.next() + let num_shares: u8 = shamir_parts + .next() .ok_or(anyhow!("Invalid shamir format (must be \"M/S\")"))? .parse() .map_err(|_| anyhow!("Invalid shamir format (must be \"M/S\")"))?; @@ -391,12 +418,17 @@ pub fn keyfile(id: &str, shamir: &str, output: &str) -> Result<()> { let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - transactions.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity.created(), + )?; + transactions + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {}", e))?; let sharks = sharks::Sharks(min_shares); let dealer = sharks.dealer(master_key.as_ref()); - let shares: Vec = dealer.take(num_shares as usize) + let shares: Vec = dealer + .take(num_shares as usize) .map(|x| base64_encode(Vec::from(&x).as_slice())) .collect::>(); util::write_file(output, shares.join("\n").as_bytes()) @@ -441,7 +473,8 @@ pub fn print_keys_table(keys: &Vec, choice: bool, show_revoked: bo } pub fn find_keys_by_search_or_prompt(identity: &Identity, key_search: Option<&str>, key_type: &str, key_filter: F) -> Result - where F: Fn(&Subkey) -> Option<&T>, +where + F: Fn(&Subkey) -> Option<&T>, { #[derive(Debug)] enum FoundOne { @@ -465,7 +498,10 @@ pub fn find_keys_by_search_or_prompt(identity: &Identity, key_search: Opti match identity.keychain().subkey_by_name(key_search) { Some(key) => FoundOne::One(key.clone()), None => { - let keys_from_id = identity.keychain().subkeys().iter() + let keys_from_id = identity + .keychain() + .subkeys() + .iter() .filter_map(|x| { key_filter(x)?; if x.key_id().as_string().starts_with(key_search) { @@ -498,7 +534,10 @@ pub fn find_keys_by_search_or_prompt(identity: &Identity, key_search: Opti .ok_or(anyhow!("The key you chose isn't an option"))? } FoundOne::None => { - let keys_as_ref = identity.keychain().subkeys().iter() + let keys_as_ref = identity + .keychain() + .subkeys() + .iter() .filter_map(|sub| { key_filter(sub)?; Some(sub) @@ -517,4 +556,3 @@ pub fn find_keys_by_search_or_prompt(identity: &Identity, key_search: Opti }; Ok(key) } - diff --git a/src/commands/message.rs b/src/commands/message.rs index 37d3939..af795b4 100644 --- a/src/commands/message.rs +++ b/src/commands/message.rs @@ -1,28 +1,33 @@ -use anyhow::{anyhow, Result}; use crate::{ commands::{id, keychain}, - db, - util, + db, util, }; +use anyhow::{anyhow, Result}; use stamp_core::{ crypto::{ base::rng, message::{self, Message}, }, identity::IdentityID, - util::{base64_encode, base64_decode, SerdeBinary}, + util::{base64_decode, base64_encode, SerdeBinary}, }; use std::convert::TryFrom; -pub fn send(id_from: &str, key_search_from: Option<&str>, key_search_to: Option<&str>, input: &str, output: &str, search_to: &str, base64: bool) -> Result<()> { +pub fn send( + id_from: &str, + key_search_from: Option<&str>, + key_search_to: Option<&str>, + input: &str, + output: &str, + search_to: &str, + base64: bool, +) -> Result<()> { let mut rng = rng::chacha20(); let transactions_from = id::try_load_single_identity(id_from)?; let identity_from = util::build_identity(&transactions_from)?; let identities = db::list_local_identities(Some(search_to))?; if identities.len() > 1 { - let identities_vec = identities.iter() - .map(|x| util::build_identity(x)) - .collect::>>()?; + let identities_vec = identities.iter().map(|x| util::build_identity(x)).collect::>>()?; id::print_identities_table(&identities_vec, false); Err(anyhow!("Multiple identities matched that search"))?; } else if identities.len() == 0 { @@ -35,12 +40,17 @@ pub fn send(id_from: &str, key_search_from: Option<&str>, key_search_to: Option< let msg_bytes = util::read_file(input)?; let id_str = id_str!(identity_from.id())?; - let master_key_from = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity_from.created())?; - transactions_from.test_master_key(&master_key_from) + let master_key_from = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity_from.created(), + )?; + transactions_from + .test_master_key(&master_key_from) .map_err(|e| anyhow!("Incorrect passphrase: {}", e))?; let sealed = message::send(&mut rng, &master_key_from, identity_from.id(), &key_from, &key_to, msg_bytes.as_slice()) .map_err(|e| anyhow!("Problem sealing the message: {}", e))?; - let serialized = sealed.serialize_binary() + let serialized = sealed + .serialize_binary() .map_err(|e| anyhow!("Problem serializing the sealed message: {}", e))?; if base64 { let base64 = base64_encode(serialized.as_slice()); @@ -55,9 +65,7 @@ pub fn send_anonymous(key_search_to: Option<&str>, input: &str, output: &str, se let mut rng = rng::chacha20(); let identities = db::list_local_identities(Some(search_to))?; if identities.len() > 1 { - let identities_vec = identities.iter() - .map(|x| util::build_identity(x)) - .collect::>>()?; + let identities_vec = identities.iter().map(|x| util::build_identity(x)).collect::>>()?; id::print_identities_table(&identities_vec, false); Err(anyhow!("Multiple identities matched that search"))?; } else if identities.len() == 0 { @@ -68,9 +76,10 @@ pub fn send_anonymous(key_search_to: Option<&str>, input: &str, output: &str, se let key_to = keychain::find_keys_by_search_or_prompt(&identity_to, key_search_to, "crypto", |sub| sub.key().as_cryptokey())?; let msg_bytes = util::read_file(input)?; - let sealed = message::send_anonymous(&mut rng, &key_to, msg_bytes.as_slice()) - .map_err(|e| anyhow!("Problem sealing the message: {}", e))?; - let serialized = sealed.serialize_binary() + let sealed = + message::send_anonymous(&mut rng, &key_to, msg_bytes.as_slice()).map_err(|e| anyhow!("Problem sealing the message: {}", e))?; + let serialized = sealed + .serialize_binary() .map_err(|e| anyhow!("Problem serializing the sealed message: {}", e))?; if base64 { let base64 = base64_encode(serialized.as_slice()); @@ -86,35 +95,39 @@ pub fn open(id_to: &str, key_search_open: Option<&str>, input: &str, output: &st let identity_to = util::build_identity(&transactions_to)?; let sealed_bytes = util::read_file(input)?; let sealed_message = Message::deserialize_binary(sealed_bytes.as_slice()) - .or_else(|_| { - Message::deserialize_binary(&base64_decode(sealed_bytes.as_slice())?) - }) + .or_else(|_| Message::deserialize_binary(&base64_decode(sealed_bytes.as_slice())?)) .map_err(|e| anyhow!("Error reading sealed message: {}", e))?; macro_rules! dry { ({$master_key:ident, $key_to:ident, $sealed_message:ident } $opener:expr) => { let $key_to = keychain::find_keys_by_search_or_prompt(&identity_to, key_search_open, "crypto", |sub| sub.key().as_cryptokey())?; let id_str = id_str!(identity_to.id())?; - let $master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity_to.created())?; - identity_to.test_master_key(&$master_key) + let $master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity_to.created(), + )?; + identity_to + .test_master_key(&$master_key) .map_err(|e| anyhow!("Incorrect passphrase: {}", e))?; - $opener - .map_err(|e| anyhow!("Problem opening message: {}", e))? - } + $opener.map_err(|e| anyhow!("Problem opening message: {}", e))? + }; } let opened = match &sealed_message { Message::Anonymous(_) => { - dry!{ + dry! { { master_key_to, key_to, bytes } message::open_anonymous(&master_key_to, &key_to, &sealed_message) } } Message::Signed(signed_msg) => { - let transactions_from = db::load_identity(signed_msg.signed_by_identity())? - .ok_or(anyhow!("The identity that sent this message has not been imported, see the `stamp id import` command"))?; + let transactions_from = db::load_identity(signed_msg.signed_by_identity())?.ok_or(anyhow!( + "The identity that sent this message has not been imported, see the `stamp id import` command" + ))?; let identity_from = util::build_identity(&transactions_from)?; - let key_from = identity_from.keychain().subkey_by_keyid(&signed_msg.signed_by_key()) + let key_from = identity_from + .keychain() + .subkey_by_keyid(&signed_msg.signed_by_key()) .ok_or(anyhow!("The identity that send this message is missing the key used to sign the message"))?; - dry!{ + dry! { { master_key_to, key_to, bytes } message::open(&master_key_to, &key_to, &key_from, &sealed_message) } @@ -123,4 +136,3 @@ pub fn open(id_to: &str, key_search_open: Option<&str>, input: &str, output: &st util::write_file(output, opened.as_slice())?; Ok(()) } - diff --git a/src/commands/mod.rs b/src/commands/mod.rs index e718a1e..32cf2ee 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -7,6 +7,5 @@ pub mod id; pub mod keychain; pub mod message; pub mod sign; -pub mod stamp; pub mod stage; - +pub mod stamp; diff --git a/src/commands/sign.rs b/src/commands/sign.rs index 9b52b77..dddf976 100644 --- a/src/commands/sign.rs +++ b/src/commands/sign.rs @@ -1,10 +1,8 @@ -use anyhow::{anyhow, Result}; use crate::{ commands::{dag, id, keychain}, - config, - db, - util, + config, db, util, }; +use anyhow::{anyhow, Result}; use stamp_aux::db::stage_transaction; use stamp_core::{ crypto::{ @@ -12,33 +10,36 @@ use stamp_core::{ sign::{self, Signature}, }, dag::{Transaction, TransactionBody}, - identity::{IdentityID}, - util::{base64_encode, base64_decode, SerdeBinary, Timestamp}, + identity::IdentityID, + util::{base64_decode, base64_encode, SerdeBinary, Timestamp}, }; use std::convert::TryFrom; pub fn sign_id(id_sign: &str, input: &str, output: &str, base64: bool, stage: bool, sign_with: Option<&str>) -> Result<()> { let hash_with = config::hash_algo(Some(&id_sign)); let transactions = id::try_load_single_identity(id_sign)?; - let identity_id = transactions.identity_id() - .ok_or(anyhow!("Unable to generate identity id"))?; + let identity_id = transactions.identity_id().ok_or(anyhow!("Unable to generate identity id"))?; let identity = util::build_identity(&transactions)?; let msg_bytes = util::read_file(input)?; let id_str = id_str!(identity.id())?; - let master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - transactions.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity.created(), + )?; + transactions + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {}", e))?; let transaction = transactions.sign(&hash_with, Timestamp::now(), &hash_with, msg_bytes.as_slice())?; let signed = util::sign_helper(&identity, transaction, &master_key, stage, sign_with)?; if stage { let msg = dag::post_save(&transactions, &signed, stage)?; - stage_transaction(&identity_id, signed) - .map_err(|e| anyhow!("Error staging transaction: {:?}", e))?; + stage_transaction(&identity_id, signed).map_err(|e| anyhow!("Error staging transaction: {:?}", e))?; if let Some(msg) = msg { println!("{}", msg); } } else { - let serialized = signed.serialize_binary() + let serialized = signed + .serialize_binary() .map_err(|e| anyhow!("Problem serializing the signature: {}", e))?; if base64 { let base64 = base64_encode(serialized.as_slice()); @@ -57,17 +58,21 @@ pub fn sign_subkey(id_sign: &str, key_search_sign: Option<&str>, input: &str, ou let msg_bytes = util::read_file(input)?; let id_str = id_str!(identity.id())?; - let master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - transactions.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity.created(), + )?; + transactions + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {}", e))?; let signature = if attached { sign::sign_attached(&master_key, identity.id(), &key_sign, msg_bytes.as_slice()) .map_err(|e| anyhow!("Problem creating signature: {}", e))? } else { - sign::sign(&master_key, identity.id(), &key_sign, msg_bytes.as_slice()) - .map_err(|e| anyhow!("Problem creating signature: {}", e))? + sign::sign(&master_key, identity.id(), &key_sign, msg_bytes.as_slice()).map_err(|e| anyhow!("Problem creating signature: {}", e))? }; - let serialized = signature.serialize_binary() + let serialized = signature + .serialize_binary() .map_err(|e| anyhow!("Problem serializing the signature: {}", e))?; if base64 { let base64 = base64_encode(serialized.as_slice()); @@ -85,32 +90,28 @@ pub fn verify(input_signature: &str, input_message: Option<&str>) -> Result<()> Subkey(Signature), } let signature = Transaction::deserialize_binary(sig_bytes.as_slice()) - .or_else(|_| { - Transaction::deserialize_binary(&base64_decode(sig_bytes.as_slice())?) - }) + .or_else(|_| Transaction::deserialize_binary(&base64_decode(sig_bytes.as_slice())?)) .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| PolicyOrSub::Subkey(x)) + .or_else(|_| Signature::deserialize_binary(&base64_decode(sig_bytes.as_slice())?)) + .map(|x| PolicyOrSub::Subkey(x)) }) .map_err(|e| anyhow!("Error reading signature: {}", e))?; let res = match &signature { PolicyOrSub::Policy(transaction) => { - let input_message = input_message - .ok_or(anyhow!("A MESSAGE argument must be give when verifying an policy signature."))?; + let input_message = input_message.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?", id_str))?; + let creator_transactions = + db::load_identity(&creator)?.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)) + transaction + .verify(Some(&creator_identity)) .map_err(|e| anyhow!("Policy signature invalid: {}", e))?; match body_hash { Hash::Blake3(..) => { @@ -134,23 +135,21 @@ pub fn verify(input_signature: &str, input_message: Option<&str>) -> Result<()> let identity_id = sig.signed_by_identity(); 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?", id_str))?; + let transactions = db::load_identity(identity_id)?.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)))?; + 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) + ))?; match signature { Signature::Detached { .. } => { - let input_message = input_message - .ok_or(anyhow!("A MESSAGE argument must be give when verifying a detached signature."))?; + let input_message = + input_message.ok_or(anyhow!("A MESSAGE argument must be give when verifying a detached signature."))?; let message_bytes = util::read_file(&input_message)?; - sign::verify(&subkey, signature, message_bytes.as_slice()) - .map_err(|e| anyhow!("{}", e)) - } - Signature::Attached { .. } => { - sign::verify_attached(&subkey, signature) - .map_err(|e| anyhow!("{}", e)) + sign::verify(&subkey, signature, message_bytes.as_slice()).map_err(|e| anyhow!("{}", e)) } + Signature::Attached { .. } => sign::verify_attached(&subkey, signature).map_err(|e| anyhow!("{}", e)), } } }; @@ -161,17 +160,28 @@ pub fn verify(input_signature: &str, input_message: Option<&str>) -> Result<()> 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."))?, + _ => 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); + 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()); + 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() + ); } } } @@ -182,4 +192,3 @@ pub fn verify(input_signature: &str, input_message: Option<&str>) -> Result<()> } Ok(()) } - diff --git a/src/commands/stage.rs b/src/commands/stage.rs index 67ae977..6d687c6 100644 --- a/src/commands/stage.rs +++ b/src/commands/stage.rs @@ -1,21 +1,15 @@ -use anyhow::{anyhow, Result}; use crate::{ - commands::{ - id, - dag, - }, - db, - util, + commands::{dag, id}, + db, util, }; +use anyhow::{anyhow, Result}; use prettytable::Table; -use stamp_aux::{ - db::{delete_staged_transaction, find_staged_transactions, load_staged_transaction, stage_transaction}, -}; +use stamp_aux::db::{delete_staged_transaction, find_staged_transactions, load_staged_transaction, stage_transaction}; use stamp_core::{ crypto::base::rng, - dag::{TransactionID, Transaction}, + dag::{Transaction, TransactionID}, identity::{Identity, IdentityID}, - util::{base64_encode, base64_decode, Public, SerdeBinary, SerText, Timestamp}, + util::{base64_decode, base64_encode, Public, SerText, SerdeBinary, Timestamp}, }; use std::convert::TryFrom; use std::str::FromStr; @@ -23,27 +17,25 @@ use std::str::FromStr; pub fn list(id: &str) -> Result<()> { let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; - let transactions = find_staged_transactions(identity.id()) - .map_err(|e| anyhow!("Error loading staged transactions: {:?}", e))?; + let transactions = find_staged_transactions(identity.id()).map_err(|e| anyhow!("Error loading staged transactions: {:?}", e))?; print_transactions_table(Some(&identity), &transactions); Ok(()) } pub fn view(txid: &str) -> Result<()> { - let transaction_id = TransactionID::try_from(txid) - .map_err(|e| anyhow!("Error loading transaction id: {:?}", e))?; + let transaction_id = TransactionID::try_from(txid).map_err(|e| anyhow!("Error loading transaction id: {:?}", e))?; let (_, transaction) = load_staged_transaction(&transaction_id) .map_err(|e| anyhow!("Error loading staged transaction: {:?}", e))? .ok_or_else(|| anyhow!("Transaction {} not found", txid))?; - let serialized = transaction.serialize_text() + let serialized = transaction + .serialize_text() .map_err(|e| anyhow!("Error serializing staged transaction: {:?}", e))?; println!("{}", serialized); Ok(()) } pub fn export(txid: &str, output: &str, base64: bool) -> Result<()> { - let transaction_id = TransactionID::try_from(txid) - .map_err(|e| anyhow!("Error loading transaction id: {:?}", e))?; + let transaction_id = TransactionID::try_from(txid).map_err(|e| anyhow!("Error loading transaction id: {:?}", e))?; let (identity_id, transaction) = load_staged_transaction(&transaction_id) .map_err(|e| anyhow!("Error loading staged transaction: {:?}", e))? .ok_or_else(|| anyhow!("Transaction {} not found", txid))?; @@ -53,14 +45,18 @@ pub fn export(txid: &str, output: &str, base64: bool) -> Result<()> { let id_str = id_str!(&identity_id)?; let transactions = id::try_load_single_identity(&id_str)?; let identity = util::build_identity(&transactions)?; - let master_key = util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - let (_, new_key) = util::with_new_passphrase("Your new passphrase to encrypt this transaction", |master_key, _now| { Ok(()) }, Some(now))?; - transaction.reencrypt(&mut rng, &master_key, &new_key) + let master_key = + util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; + let (_, new_key) = + util::with_new_passphrase("Your new passphrase to encrypt this transaction", |master_key, _now| Ok(()), Some(now))?; + transaction + .reencrypt(&mut rng, &master_key, &new_key) .map_err(|e| anyhow!("Error re-encrypting transaction: {}", e))? } else { transaction }; - let serialized = transaction.serialize_binary() + let serialized = transaction + .serialize_binary() .map_err(|e| anyhow!("Error serializing transaction: {}", e))?; if base64 { let base64 = base64_encode(serialized.as_slice()); @@ -77,9 +73,7 @@ pub fn import(id: &str, input: &str) -> Result<()> { let id_str = id_str!(identity.id())?; let trans_bytes = util::read_file(input)?; let transaction = Transaction::deserialize_binary(trans_bytes.as_slice()) - .or_else(|_| { - Transaction::deserialize_binary(&base64_decode(trans_bytes.as_slice())?) - }) + .or_else(|_| Transaction::deserialize_binary(&base64_decode(trans_bytes.as_slice())?)) .map_err(|e| anyhow!("Error reading transaction: {}", e))?; let transaction = if transaction.has_private() { let now = Timestamp::from_str("2020-12-29T07:04:27.000Z").unwrap(); @@ -87,39 +81,38 @@ pub fn import(id: &str, input: &str) -> Result<()> { let transactions = id::try_load_single_identity(&id_str)?; let identity = util::build_identity(&transactions)?; let new_key = util::passphrase_prompt(&format!("The encryption passphrase for this transaction"), &now)?; - let master_key = util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - identity.test_master_key(&master_key) + let master_key = + util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; + identity + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect master passphrase: {:?}", e))?; - transaction.reencrypt(&mut rng, &new_key, &master_key) + transaction + .reencrypt(&mut rng, &new_key, &master_key) .map_err(|e| anyhow!("Error re-encrypting transaction: {}", e))? } else { transaction }; let txid = transaction.id().clone(); - stage_transaction(identity.id(), transaction) - .map_err(|e| anyhow!("Error staging transaction: {:?}", e))?; + stage_transaction(identity.id(), transaction).map_err(|e| anyhow!("Error staging transaction: {:?}", e))?; println!("Staged transaction {} import into identity {}", txid, IdentityID::short(&id_str)); Ok(()) } pub fn delete(txid: &str) -> Result<()> { - let transaction_id = TransactionID::try_from(txid) - .map_err(|e| anyhow!("Error loading transaction id: {:?}", e))?; + let transaction_id = TransactionID::try_from(txid).map_err(|e| anyhow!("Error loading transaction id: {:?}", e))?; load_staged_transaction(&transaction_id) .map_err(|e| anyhow!("Error loading staged transaction: {:?}", e))? .ok_or_else(|| anyhow!("Transaction {} not found", txid))?; if !util::yesno_prompt("Do you really want to delete this staged transaction?) [y/N]", "N")? { return Ok(()); } - delete_staged_transaction(&transaction_id) - .map_err(|e| anyhow!("Error deleting staged transaction: {:?}", e))?; + delete_staged_transaction(&transaction_id).map_err(|e| anyhow!("Error deleting staged transaction: {:?}", e))?; println!("Staged transaction {} deleted!", txid); Ok(()) } pub fn sign(txid: &str, sign_with: &str) -> Result<()> { - let transaction_id = TransactionID::try_from(txid) - .map_err(|e| anyhow!("Error loading transaction id: {:?}", e))?; + let transaction_id = TransactionID::try_from(txid).map_err(|e| anyhow!("Error loading transaction id: {:?}", e))?; let (identity_id, transaction) = load_staged_transaction(&transaction_id) .map_err(|e| anyhow!("Error loading staged transaction: {:?}", e))? .ok_or_else(|| anyhow!("Transaction {} not found", txid))?; @@ -127,46 +120,59 @@ pub fn sign(txid: &str, sign_with: &str) -> Result<()> { let id_str = id_str!(&identity_id)?; let transactions = id::try_load_single_identity(&id_str)?; let identity = util::build_identity(&transactions)?; - let master_key = util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; + let master_key = + util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; let signed = util::sign_helper(&identity, transaction, &master_key, true, Some(sign_with))?; // TODO: do a match here and untangle the various error conditions. for now, // we'll just reduce this to a binary. let ready = signed.verify(Some(&identity)).is_ok(); // save it back into staging - stage_transaction(identity.id(), signed) - .map_err(|e| anyhow!("Error saving staged transaction: {:?}", e))?; + stage_transaction(identity.id(), signed).map_err(|e| anyhow!("Error saving staged transaction: {:?}", e))?; if ready { let green = dialoguer::console::Style::new().green(); - println!("Transaction signed and saved! {} and the transaction can be applied with:", green.apply_to("All required signatures are present")); + println!( + "Transaction signed and saved! {} and the transaction can be applied with:", + green.apply_to("All required signatures are present") + ); println!(" stamp stage apply {}", txid); } else { let yellow = dialoguer::console::Style::new().yellow(); - println!("Transaction signed and saved! {}", yellow.apply_to("This transaction requires more signatures to be valid.")); + println!( + "Transaction signed and saved! {}", + yellow.apply_to("This transaction requires more signatures to be valid.") + ); } Ok(()) } pub fn apply(txid: &str) -> Result<()> { - let transaction_id = TransactionID::try_from(txid) - .map_err(|e| anyhow!("Error loading transaction id: {:?}", e))?; + let transaction_id = TransactionID::try_from(txid).map_err(|e| anyhow!("Error loading transaction id: {:?}", e))?; let (identity_id, transaction) = load_staged_transaction(&transaction_id) .map_err(|e| anyhow!("Error loading staged transaction: {:?}", e))? .ok_or_else(|| anyhow!("Transaction {} not found", txid))?; let id_str = id_str!(&identity_id)?; let transactions = id::try_load_single_identity(&id_str)?; - let transactions_mod = transactions.push_transaction(transaction) + let transactions_mod = transactions + .push_transaction(transaction) .map_err(|e| anyhow!("Problem saving staged transaction to identity: {:?}", e))?; let transactions_mod = db::save_identity(transactions_mod)?; println!("Transaction {} has been applied to the identity {}", transaction_id, IdentityID::short(&id_str)); - let trans = transactions_mod.transactions().iter().find(|t| t.id() == &transaction_id) + let trans = transactions_mod + .transactions() + .iter() + .find(|t| t.id() == &transaction_id) .ok_or_else(|| anyhow!("Unable to find saved transaction {}", transaction_id))?; let post_save_msg = dag::post_save(&transactions_mod, trans, false)?; if let Some(msg) = post_save_msg { println!("{}", msg); } - delete_staged_transaction(&transaction_id) - .map_err(|_| anyhow!("Problem removing staged transaction. The transaction was applied and can be safely removed with:\n stamp stage delete {}", transaction_id))?; + delete_staged_transaction(&transaction_id).map_err(|_| { + anyhow!( + "Problem removing staged transaction. The transaction was applied and can be safely removed with:\n stamp stage delete {}", + transaction_id + ) + })?; Ok(()) } @@ -176,19 +182,11 @@ pub fn print_transactions_table(identity: Option<&Identity>, transactions: &Vec< table.set_titles(row!["ID", "Type", "Signatures", "Ready", "Created"]); for trans in transactions { let ty = dag::transaction_to_string(trans); - let id = id_str!(trans.id()) - .unwrap_or_else(|e| format!("", trans.id(), e)); + let id = id_str!(trans.id()).unwrap_or_else(|e| format!("", trans.id(), e)); let ready = if trans.verify(identity).is_ok() { "x" } else { "" }; let created = trans.entry().created().local().format("%b %e, %Y %H:%M:%S"); let num_sig = trans.signatures().len(); - table.add_row(row![ - id, - ty, - num_sig, - ready, - created, - ]); + table.add_row(row![id, ty, num_sig, ready, created,]); } table.printstd(); } - diff --git a/src/commands/stamp.rs b/src/commands/stamp.rs index 1db84c7..34e2d34 100644 --- a/src/commands/stamp.rs +++ b/src/commands/stamp.rs @@ -1,31 +1,29 @@ -use anyhow::{anyhow, Result}; use crate::{ commands::{dag, id}, - config, - db, - util, + config, db, util, }; +use anyhow::{anyhow, Result}; use prettytable::Table; use stamp_core::{ crypto::{ - base::{SecretKey, rng}, - message::{Message}, + base::{rng, SecretKey}, + message::Message, }, - dag::{Transaction}, + dag::Transaction, identity::{ - IdentityID, - claim::{ClaimID}, + claim::ClaimID, stamp::{Confidence, RevocationReason, Stamp, StampEntry, StampRequest}, + IdentityID, }, - util::{Timestamp, SerdeBinary, SerText, base64_decode}, + util::{base64_decode, SerText, SerdeBinary, Timestamp}, }; use std::convert::TryFrom; pub fn new(our_identity_id: &str, claim_id: &str, stage: bool, sign_with: Option<&str>) -> Result<()> { let hash_with = config::hash_algo(Some(&our_identity_id)); let our_transactions = id::try_load_single_identity(our_identity_id)?; - let their_transactions = db::find_identity_by_prefix("claim", claim_id)? - .ok_or(anyhow!("Identity with claim {} not found", claim_id))?; + let their_transactions = + db::find_identity_by_prefix("claim", claim_id)?.ok_or(anyhow!("Identity with claim {} not found", claim_id))?; let our_identity = util::build_identity(&our_transactions)?; let their_identity = util::build_identity(&their_transactions)?; let claim = their_identity.claims() @@ -40,16 +38,31 @@ pub fn new(our_identity_id: &str, claim_id: &str, stage: bool, sign_with: Option .ok_or(anyhow!("Claim {} not found in identity {}", claim_id, id_str!(their_identity.id())?))?; let their_id_str = id_str!(their_identity.id())?; let claim_id_str = id_str!(claim.id())?; - util::print_wrapped(&format!("You are about to stamp the claim {} made by the identity {}.\n", ClaimID::short(&claim_id_str), IdentityID::short(&their_id_str))); - util::print_wrapped("Effectively, you are vouching for them and that their claim is true. You can specify your confidence in the claim:\n"); + util::print_wrapped(&format!( + "You are about to stamp the claim {} made by the identity {}.\n", + ClaimID::short(&claim_id_str), + IdentityID::short(&their_id_str) + )); + util::print_wrapped( + "Effectively, you are vouching for them and that their claim is true. You can specify your confidence in the claim:\n", + ); util::print_wrapped(" negative\n"); - util::print_wrapped_indent("you are certain this claim is false and you are creating this stamp as a warning to others\n", " "); + util::print_wrapped_indent( + "you are certain this claim is false and you are creating this stamp as a warning to others\n", + " ", + ); util::print_wrapped(" low\n"); util::print_wrapped_indent("you have done a quick and dirty verification of the claim\n", " "); util::print_wrapped(" medium\n"); - util::print_wrapped_indent("you're doing a decent amount of verification, such as having them click a verification link in email\n", " "); + util::print_wrapped_indent( + "you're doing a decent amount of verification, such as having them click a verification link in email\n", + " ", + ); util::print_wrapped(" high\n"); - util::print_wrapped_indent("you have verified the claim extensively (birth certificates, retinal scans, fingerprint matching, etc)\n", " "); + util::print_wrapped_indent( + "you have verified the claim extensively (birth certificates, retinal scans, fingerprint matching, etc)\n", + " ", + ); util::print_wrapped(" extreme\n"); util::print_wrapped_indent("you have known this person for the last 50 years and can be absolutely certain that the claim they are making is correct and they are not a hologram or an android imposter\n", " "); let confidence_val = util::value_prompt("\nHow confident are you in this claim?")?; @@ -59,61 +72,79 @@ pub fn new(our_identity_id: &str, claim_id: &str, stage: bool, sign_with: Option "medium" => Confidence::Medium, "high" => Confidence::High, "extreme" => Confidence::Extreme, - _ => Err(anyhow!("Invalid confidence value: {}", confidence_val))?, + _ => Err(anyhow!("Invalid confidence value: {}", confidence_val))?, }; let expires: Option = if util::yesno_prompt("Would you like your stamp to expire on a certain date? [y/N]", "n")? { let expire_val = util::value_prompt("What date would you like it to expire? [ex 2024-10-13T12:00:00Z]")?; - let ts: Timestamp = expire_val.parse() + let ts: Timestamp = expire_val + .parse() .map_err(|e| anyhow!("Error parsing time: {}: {}", expire_val, e))?; Some(ts) } else { None }; let our_id = id_str!(our_identity.id())?; - let master_key = util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&our_id)), our_identity.created())?; - our_transactions.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your master passphrase for identity {}", IdentityID::short(&our_id)), + our_identity.created(), + )?; + our_transactions + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {}", e))?; let stamp_entry = StampEntry::new(our_identity.id().clone(), their_identity.id().clone(), claim.id().clone(), confidence, expires); - let transaction = our_transactions.make_stamp(&hash_with, Timestamp::now(), stamp_entry) + let transaction = our_transactions + .make_stamp(&hash_with, Timestamp::now(), stamp_entry) .map_err(|e| anyhow!("Error making stamp: {}", e))?; let signed = util::sign_helper(&our_identity, transaction, &master_key, stage, sign_with)?; dag::save_or_stage(our_transactions, signed, stage)?; Ok(()) } -pub fn request(our_identity_id: &str, claim_search: &str, our_crypto_subkey_search: &str, stamper_identity_id: &str, stamper_crypto_subkey_search: &str) -> Result> { +pub fn request( + our_identity_id: &str, + claim_search: &str, + our_crypto_subkey_search: &str, + stamper_identity_id: &str, + stamper_crypto_subkey_search: &str, +) -> Result> { let mut rng = rng::chacha20(); let our_transactions = id::try_load_single_identity(our_identity_id)?; let stamper_transactions = id::try_load_single_identity(stamper_identity_id)?; let our_identity = util::build_identity(&our_transactions)?; let our_id = id_str!(our_identity.id())?; let stamper_identity = util::build_identity(&stamper_transactions)?; - let key_from = our_identity.keychain().subkeys().iter() - .find(|k| { - k.key_id().as_string().starts_with(our_crypto_subkey_search) || - k.name() == our_crypto_subkey_search - }) + let key_from = our_identity + .keychain() + .subkeys() + .iter() + .find(|k| k.key_id().as_string().starts_with(our_crypto_subkey_search) || k.name() == our_crypto_subkey_search) .ok_or_else(|| anyhow!("Cannot find `from` key {}", our_crypto_subkey_search))?; - let key_to = stamper_identity.keychain().subkeys().iter() - .find(|k| { - k.key_id().as_string().starts_with(stamper_crypto_subkey_search) || - k.name() == stamper_crypto_subkey_search - }) + let key_to = stamper_identity + .keychain() + .subkeys() + .iter() + .find(|k| k.key_id().as_string().starts_with(stamper_crypto_subkey_search) || k.name() == stamper_crypto_subkey_search) .ok_or_else(|| anyhow!("Cannot find `to` key {}", our_crypto_subkey_search))?; - let claim = our_identity.claims().iter() + let claim = our_identity + .claims() + .iter() .find(|x| { let claim_id = String::try_from(x.id()).unwrap_or("".into()); - claim_id.starts_with(claim_search) || - x.name().as_ref().map(|x| x == claim_search).unwrap_or(false) + claim_id.starts_with(claim_search) || x.name().as_ref().map(|x| x == claim_search).unwrap_or(false) }) .ok_or_else(|| anyhow!("Cannot find claim {}", claim_search))?; - let master_key = util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&our_id)), our_identity.created())?; - our_transactions.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your master passphrase for identity {}", IdentityID::short(&our_id)), + our_identity.created(), + )?; + our_transactions + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {:?}", e))?; let sk_tmp = SecretKey::new_xchacha20poly1305(&mut rng)?; let req_message = StampRequest::new_message(&mut rng, &master_key, our_identity.id(), &key_from, &key_to, claim, sk_tmp) .map_err(|e| anyhow!("Problem creating stamp request: {:?}", e))?; - let bytes = req_message.serialize_binary() + let bytes = req_message + .serialize_binary() .map_err(|e| anyhow!("Problem serializing stamp request: {:?}", e))?; Ok(bytes) } @@ -122,34 +153,36 @@ pub fn open_request(our_identity_id: &str, our_crypto_subkey_search: &str, req: let our_transactions = id::try_load_single_identity(our_identity_id)?; let our_identity = util::build_identity(&our_transactions)?; let our_id = id_str!(our_identity.id())?; - let key_to = our_identity.keychain().subkeys().iter() - .find(|k| { - k.key_id().as_string().starts_with(our_crypto_subkey_search) || - k.name() == our_crypto_subkey_search - }) + let key_to = our_identity + .keychain() + .subkeys() + .iter() + .find(|k| k.key_id().as_string().starts_with(our_crypto_subkey_search) || k.name() == our_crypto_subkey_search) .ok_or_else(|| anyhow!("Cannot find `to` key {}", our_crypto_subkey_search))?; let sealed_bytes = util::read_file(req)?; let sealed_message = Message::deserialize_binary(sealed_bytes.as_slice()) - .or_else(|_| { - Message::deserialize_binary(&base64_decode(sealed_bytes.as_slice())?) - }) + .or_else(|_| Message::deserialize_binary(&base64_decode(sealed_bytes.as_slice())?)) .map_err(|e| anyhow!("Error reading sealed message: {}", e))?; - let signed_message = sealed_message.signed() - .ok_or_else(|| anyhow!("Invalid stemp request message"))?; + let signed_message = sealed_message.signed().ok_or_else(|| anyhow!("Invalid stemp request message"))?; let stampee_identity_id = signed_message.signed_by_identity(); let stampee_key_id = signed_message.signed_by_key(); let stampee_identity_id_str = id_str!(stampee_identity_id)?; let stampee_transactions = id::try_load_single_identity(&stampee_identity_id_str)?; let stampee_identity = util::build_identity(&stampee_transactions)?; - let key_from = stampee_identity.keychain().subkey_by_keyid(stampee_key_id) + let key_from = stampee_identity + .keychain() + .subkey_by_keyid(stampee_key_id) .ok_or_else(|| anyhow!("Cannot find `from` key {:?}", stampee_key_id))?; - let master_key = util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&our_id)), our_identity.created())?; - our_transactions.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your master passphrase for identity {}", IdentityID::short(&our_id)), + our_identity.created(), + )?; + our_transactions + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {:?}", e))?; let claim = StampRequest::open(&master_key, &key_to, &key_from, &sealed_message) .map_err(|e| anyhow!("Problem opening stamp request: {:?}", e))?; - let claim_str = claim.serialize_text() - .map_err(|e| anyhow!("Problem serializing claim: {:?}", e))?; + let claim_str = claim.serialize_text().map_err(|e| anyhow!("Problem serializing claim: {:?}", e))?; println!("{}", claim_str); Ok(()) } @@ -157,14 +190,10 @@ pub fn open_request(our_identity_id: &str, our_crypto_subkey_search: &str, req: pub fn list(id: &str, revoked: bool, verbose: bool) -> Result<()> { let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; - let stamps = identity.stamps().iter() - .filter(|x| { - if revoked { - true - } else { - x.revocation().is_none() - } - }) + let stamps = identity + .stamps() + .iter() + .filter(|x| if revoked { true } else { x.revocation().is_none() }) .collect::>(); print_stamps_table(&stamps, verbose, revoked)?; Ok(()) @@ -177,11 +206,10 @@ pub fn accept(id: &str, location: &str, stage: bool, sign_with: Option<&str>) -> let id_str = id_str!(identity.id())?; let stamp_bytes = util::read_file(location)?; let stamp = Transaction::deserialize_binary(stamp_bytes.as_slice()) - .or_else(|_| { - Transaction::deserialize_binary(&base64_decode(stamp_bytes.as_slice())?) - }) + .or_else(|_| Transaction::deserialize_binary(&base64_decode(stamp_bytes.as_slice())?)) .map_err(|e| anyhow!("Error deserializing stamp transaction: {:?}", e))?; - let stamp_text = stamp.serialize_text() + let stamp_text = stamp + .serialize_text() .map_err(|e| anyhow!("Problem serializing stamp transaction: {:?}", e))?; println!("{}", stamp_text); println!("----------"); @@ -189,9 +217,13 @@ pub fn accept(id: &str, location: &str, stage: bool, sign_with: Option<&str>) -> println!("Aborted."); return Ok(()); } - let trans = transactions.accept_stamp(&hash_with, Timestamp::now(), stamp) + let trans = transactions + .accept_stamp(&hash_with, Timestamp::now(), stamp) .map_err(|e| anyhow!("Problem creating acceptance transaction: {:?}", e))?; - let master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; + let master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity.created(), + )?; let signed = util::sign_helper(&identity, trans, &master_key, stage, sign_with)?; dag::save_or_stage(transactions, signed, stage)?; Ok(()) @@ -202,7 +234,9 @@ pub fn revoke(id: &str, stamp_search: &str, reason: &str, stage: bool, sign_with let transactions = id::try_load_single_identity(id)?; let identity = util::build_identity(&transactions)?; let id_str = id_str!(identity.id())?; - let stamp = identity.stamps().iter() + let stamp = identity + .stamps() + .iter() .find(|x| { let id_str = String::try_from(x.id()).unwrap_or_else(|_| "".into()); id_str.starts_with(stamp_search) @@ -211,8 +245,12 @@ pub fn revoke(id: &str, stamp_search: &str, reason: &str, stage: bool, sign_with if stamp.revocation().is_some() { Err(anyhow!("The stamp {} is already revoked", stamp.id()))?; } - let master_key = util::passphrase_prompt(&format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), identity.created())?; - transactions.test_master_key(&master_key) + let master_key = util::passphrase_prompt( + &format!("Your current master passphrase for identity {}", IdentityID::short(&id_str)), + identity.created(), + )?; + transactions + .test_master_key(&master_key) .map_err(|e| anyhow!("Incorrect passphrase: {:?}", e))?; let rev_reason = match reason { "superseded" => RevocationReason::Superseded, @@ -220,7 +258,8 @@ pub fn revoke(id: &str, stamp_search: &str, reason: &str, stage: bool, sign_with "invalid" => RevocationReason::Invalid, _ => RevocationReason::Unspecified, }; - let trans = transactions.revoke_stamp(&hash_with, Timestamp::now(), stamp.id().clone(), rev_reason) + let trans = transactions + .revoke_stamp(&hash_with, Timestamp::now(), stamp.id().clone(), rev_reason) .map_err(|e| anyhow!("Problem creating revocation transaction: {:?}", e))?; let signed = util::sign_helper(&identity, trans, &master_key, stage, sign_with)?; dag::save_or_stage(transactions, signed, stage)?; @@ -250,7 +289,10 @@ pub fn print_stamps_table(stamps: &Vec<&Stamp>, verbose: bool, show_revoked: boo let (id_full, id_short) = id_str_split!(stamp.id()); let (claim_id_full, claim_id_short) = id_str_split!(stamp.entry().claim_id()); let (stampee_full, stampee_short) = id_str_split!(stamp.entry().stampee()); - let expires = stamp.entry().expires().as_ref() + let expires = stamp + .entry() + .expires() + .as_ref() .map(|x| x.local().format("%b %d, %Y").to_string()) .unwrap_or_else(|| String::from("-")); let created = stamp.created().local().format("%b %d, %Y").to_string(); @@ -274,7 +316,6 @@ pub fn print_stamps_table(stamps: &Vec<&Stamp>, verbose: bool, show_revoked: boo cols.push(prettytable::Cell::new(if revoked { "x" } else { "" })); } table.add_row(prettytable::Row::new(cols)); - } table.printstd(); Ok(()) diff --git a/src/config.rs b/src/config.rs index ce0ee46..34f54e8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -3,16 +3,13 @@ pub use stamp_aux::config::Config; use stamp_core::crypto::base::HashAlgo; pub fn load() -> Result { - stamp_aux::config::load() - .map_err(|e| anyhow!("Problem loading config: {}", e)) + stamp_aux::config::load().map_err(|e| anyhow!("Problem loading config: {}", e)) } pub fn save(config: &Config) -> Result<()> { - stamp_aux::config::save(config) - .map_err(|e| anyhow!("Problem saving config: {}", e)) + stamp_aux::config::save(config).map_err(|e| anyhow!("Problem saving config: {}", e)) } pub fn hash_algo(_identity_id: Option<&str>) -> HashAlgo { HashAlgo::Blake3 } - diff --git a/src/db.rs b/src/db.rs index f59c63f..926faa4 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,46 +1,35 @@ use anyhow::{anyhow, Result}; use stamp_aux::db; -use stamp_core::{ - dag::Transactions, - identity::IdentityID, -}; +use stamp_core::{dag::Transactions, identity::IdentityID}; pub fn ensure_schema() -> Result<()> { - db::ensure_schema() - .map_err(|e| anyhow!("Error initializing database: {}", e)) + db::ensure_schema().map_err(|e| anyhow!("Error initializing database: {}", e)) } pub fn save_identity(transactions: Transactions) -> Result { - db::save_identity(transactions) - .map_err(|e| anyhow!("Problem saving identity: {}", e)) + db::save_identity(transactions).map_err(|e| anyhow!("Problem saving identity: {}", e)) } /// Load an identity by ID. pub fn load_identity(id: &IdentityID) -> Result> { - db::load_identity(id) - .map_err(|e| anyhow!("Problem loading identity: {}", e)) + db::load_identity(id).map_err(|e| anyhow!("Problem loading identity: {}", e)) } /// Load an identity by ID. pub fn load_identities_by_prefix(id_prefix: &str) -> Result> { - db::load_identities_by_prefix(id_prefix) - .map_err(|e| anyhow!("Problem loading identities: {}", e)) + db::load_identities_by_prefix(id_prefix).map_err(|e| anyhow!("Problem loading identities: {}", e)) } /// List identities stored locally. pub fn list_local_identities(search: Option<&str>) -> Result> { - db::list_local_identities(search) - .map_err(|e| anyhow!("Problem listing identities: {}", e)) + db::list_local_identities(search).map_err(|e| anyhow!("Problem listing identities: {}", e)) } pub fn find_identity_by_prefix(ty: &str, id_prefix: &str) -> Result> { - db::find_identity_by_prefix(ty, id_prefix) - .map_err(|e| anyhow!("Problem finding identity by prefix: {}", e)) + db::find_identity_by_prefix(ty, id_prefix).map_err(|e| anyhow!("Problem finding identity by prefix: {}", e)) } /// Delete a local identity by id. pub fn delete_identity(id: &str) -> Result<()> { - db::delete_identity(id) - .map_err(|e| anyhow!("Problem deleting identity: {}", e)) + db::delete_identity(id).map_err(|e| anyhow!("Problem deleting identity: {}", e)) } - diff --git a/src/log.rs b/src/log.rs index e1a48db..b76c625 100644 --- a/src/log.rs +++ b/src/log.rs @@ -1,5 +1,5 @@ use anyhow::{anyhow, Result}; -use tracing_subscriber::{EnvFilter, fmt, prelude::*}; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; pub fn init() -> Result<()> { tracing_subscriber::registry() @@ -7,7 +7,7 @@ pub fn init() -> Result<()> { .with( EnvFilter::try_from_default_env() .or_else(|_| EnvFilter::try_new("info")) - .map_err(|e| anyhow!("Error setting up logging/tracing: {:?}", e))? + .map_err(|e| anyhow!("Error setting up logging/tracing: {:?}", e))?, ) .init(); Ok(()) diff --git a/src/main.rs b/src/main.rs index 7e8fd17..1666ffe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ -#[macro_use] extern crate prettytable; -#[macro_use] mod util; +#[macro_use] +extern crate prettytable; +#[macro_use] +mod util; mod commands; mod config; mod db; @@ -8,15 +10,11 @@ mod log; use anyhow::{anyhow, Result}; use clap::{ builder::{Command, TypedValueParser}, - Arg, ArgAction, ArgGroup, ArgMatches, - value_parser, + value_parser, Arg, ArgAction, ArgGroup, ArgMatches, }; use stamp_core::{ crypto::base::rng, - identity::{ - IdentityID, - claim::RelationshipType, - }, + identity::{claim::RelationshipType, IdentityID}, }; //use stamp_net::{Multiaddr}; use std::convert::TryFrom; @@ -54,14 +52,20 @@ pub struct SyncToken { impl SyncToken { /// Create a new `SyncToken` pub fn new(identity_id: String, channel: String, shared_key: Option) -> Self { - Self { identity_id, channel, shared_key } + Self { + identity_id, + channel, + shared_key, + } } } #[derive(Debug, Clone)] struct SyncTokenParser {} impl SyncTokenParser { - fn new() -> Self { Self {} } + fn new() -> Self { + Self {} + } } impl TypedValueParser for SyncTokenParser { @@ -70,9 +74,11 @@ impl TypedValueParser for SyncTokenParser { fn parse_ref(&self, _cmd: &Command, _arg: Option<&Arg>, value: &OsStr) -> core::result::Result { let converted = value.to_string_lossy(); let parts = converted.split(':').collect::>(); - let identity_id = parts.get(0) + let identity_id = parts + .get(0) .ok_or(clap::Error::raw(clap::error::ErrorKind::InvalidValue, "Invalid token given"))?; - let channel = parts.get(1) + let channel = parts + .get(1) .ok_or(clap::Error::raw(clap::error::ErrorKind::InvalidValue, "Invalid token given"))?; let shared_key = parts.get(2).map(|x| String::from(*x)); Ok(Self::Value::new(String::from(*identity_id), String::from(*channel), shared_key)) @@ -84,10 +90,7 @@ fn run() -> Result<()> { log::init()?; db::ensure_schema()?; let id_arg = |help: &'static str| -> Arg { - let arg = Arg::new("identity") - .long("id") - .value_name("identity id") - .help(help); + let arg = Arg::new("identity").long("id").value_name("identity id").help(help); arg }; @@ -1139,134 +1142,132 @@ fn run() -> Result<()> { ); let args = app.get_matches(); match args.subcommand() { - Some(("id", args)) => { - match args.subcommand() { - Some(("new", _)) => { - let hash_with = config::hash_algo(None); - crate::commands::id::passphrase_note(); - let (transactions, master_key) = util::with_new_passphrase("Your master passphrase", |master_key, now| { + Some(("id", args)) => match args.subcommand() { + Some(("new", _)) => { + let hash_with = config::hash_algo(None); + crate::commands::id::passphrase_note(); + let (transactions, master_key) = util::with_new_passphrase( + "Your master passphrase", + |master_key, now| { stamp_aux::id::create_personal_random(&master_key, &hash_with, now) .map_err(|e| anyhow!("Error creating identity: {}", e)) - }, None)?; - println!(""); - let identity = util::build_identity(&transactions) - .map_err(|err| anyhow!("Failed to build identity: {:?}", err))?; - let id_str = id_str!(identity.id())?; - println!("Generated a new identity with the ID {}", id_str); - println!(""); - let (name, email) = crate::commands::id::prompt_name_email()?; - let transactions = stamp_aux::id::post_new_personal_id(&master_key, transactions, &hash_with, name, email) - .map_err(|e| anyhow!("Error finalizing identity: {}", e))?; - crate::commands::id::post_create(&transactions)?; + }, + None, + )?; + println!(""); + let identity = util::build_identity(&transactions).map_err(|err| anyhow!("Failed to build identity: {:?}", err))?; + let id_str = id_str!(identity.id())?; + println!("Generated a new identity with the ID {}", id_str); + println!(""); + let (name, email) = crate::commands::id::prompt_name_email()?; + let transactions = stamp_aux::id::post_new_personal_id(&master_key, transactions, &hash_with, name, email) + .map_err(|e| anyhow!("Error finalizing identity: {}", e))?; + crate::commands::id::post_create(&transactions)?; + } + Some(("vanity", args)) => { + let mut rng = rng::chacha20(); + let regex = args.get_one::("regex").map(|x| x.as_str()); + let contains: Vec<&str> = args + .get_many::("contains") + .unwrap_or_default() + .map(|v| v.as_str()) + .collect(); + let prefix = args.get_one::("prefix").map(|x| x.as_str()); + if regex.is_none() && contains.len() == 0 && prefix.is_none() { + println!("Please specify --regex, --contains, or --prefix"); + return Ok(()); } - Some(("vanity", args)) => { - let mut rng = rng::chacha20(); - let regex = args.get_one::("regex").map(|x| x.as_str()); - let contains: Vec<&str> = args.get_many::("contains") - .unwrap_or_default() - .map(|v| v.as_str()) - .collect(); - let prefix = args.get_one::("prefix").map(|x| x.as_str()); - if regex.is_none() && contains.len() == 0 && prefix.is_none() { - println!("Please specify --regex, --contains, or --prefix"); - return Ok(()); - } - let hash_with = config::hash_algo(None); + let hash_with = config::hash_algo(None); - let (tmp_master_key, transactions, now) = commands::id::create_vanity(regex, contains, prefix)?; - crate::commands::id::passphrase_note(); - let (_, master_key) = util::with_new_passphrase("Your master passphrase", |_master_key, _now| { Ok(()) }, Some(now.clone()))?; - let transactions = transactions.reencrypt(&mut rng, &tmp_master_key, &master_key) - .map_err(|err| anyhow!("Failed to create identity: {}", err))?; - let (name, email) = crate::commands::id::prompt_name_email()?; - let transactions = stamp_aux::id::post_new_personal_id(&master_key, transactions, &hash_with, name, email) - .map_err(|e| anyhow!("Error finalizing identity: {}", e))?; - crate::commands::id::post_create(&transactions)?; - } - Some(("list", args)) => { - let search = args.get_one::("SEARCH").map(|x| x.as_str()); - let verbose = args.get_flag("verbose"); + let (tmp_master_key, transactions, now) = commands::id::create_vanity(regex, contains, prefix)?; + crate::commands::id::passphrase_note(); + let (_, master_key) = util::with_new_passphrase("Your master passphrase", |_master_key, _now| Ok(()), Some(now.clone()))?; + let transactions = transactions + .reencrypt(&mut rng, &tmp_master_key, &master_key) + .map_err(|err| anyhow!("Failed to create identity: {}", err))?; + let (name, email) = crate::commands::id::prompt_name_email()?; + let transactions = stamp_aux::id::post_new_personal_id(&master_key, transactions, &hash_with, name, email) + .map_err(|e| anyhow!("Error finalizing identity: {}", e))?; + crate::commands::id::post_create(&transactions)?; + } + Some(("list", args)) => { + let search = args.get_one::("SEARCH").map(|x| x.as_str()); + let verbose = args.get_flag("verbose"); - let identities = db::list_local_identities(search)? - .iter() - .map(|x| util::build_identity(x)) - .collect::>>()?; - crate::commands::id::print_identities_table(&identities, verbose); - } - Some(("import", args)) => { - let location = args.get_one::("LOCATION") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a location value"))?; + let identities = db::list_local_identities(search)? + .iter() + .map(|x| util::build_identity(x)) + .collect::>>()?; + crate::commands::id::print_identities_table(&identities, verbose); + } + Some(("import", args)) => { + let location = args + .get_one::("LOCATION") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a location value"))?; - let contents = util::load_file(location)?; - let (transactions, existing) = stamp_aux::id::import_pre(contents.as_slice()) - .map_err(|e| anyhow!("Error importing identity: {}", e))?; - let identity = util::build_identity(&transactions)?; - if existing.is_some() { - if !util::yesno_prompt("The identity you're importing already exists locally. Overwrite? [y/N]", "n")? { - return Ok(()); - } - } - let id_str = id_str!(identity.id())?; - db::save_identity(transactions)?; - println!("Imported identity {}", id_str); - } - Some(("publish", args)) => { - let id = id_val(args)?; - let stage = args.get_flag("stage"); - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let published = commands::id::publish(&id, stage, sign_with)?; - if stage { - println!("Publish transaction staged! To view:\n stamp stage view {}", published); - } else { - util::write_file(output, published.as_bytes())?; + let contents = util::load_file(location)?; + let (transactions, existing) = + stamp_aux::id::import_pre(contents.as_slice()).map_err(|e| anyhow!("Error importing identity: {}", e))?; + let identity = util::build_identity(&transactions)?; + if existing.is_some() { + if !util::yesno_prompt("The identity you're importing already exists locally. Overwrite? [y/N]", "n")? { + return Ok(()); } } - Some(("export-private", args)) => { - let id = id_val(args)?; - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let serialized = commands::id::export_private(&id)?; - util::write_file(output, serialized.as_slice())?; - } - Some(("delete", args)) => { - let search = args.get_one::("SEARCH") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a search value"))?; - let skip_confirm = args.get_flag("yes"); - let verbose = args.get_flag("verbose"); - commands::id::delete(search, skip_confirm, verbose)? - } - Some(("view", args)) => { - let search = args.get_one::("SEARCH") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a search value"))?; - let identity = commands::id::view(search)?; - println!("{}", identity); + let id_str = id_str!(identity.id())?; + db::save_identity(transactions)?; + println!("Imported identity {}", id_str); + } + Some(("publish", args)) => { + let id = id_val(args)?; + let stage = args.get_flag("stage"); + let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let published = commands::id::publish(&id, stage, sign_with)?; + if stage { + println!("Publish transaction staged! To view:\n stamp stage view {}", published); + } else { + util::write_file(output, published.as_bytes())?; } - Some(("fingerprint", args)) => { - let id = id_val(args)?; - let format = args.get_one::("format") - .map(|x| x.as_str()) - .unwrap_or("term"); - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); + } + Some(("export-private", args)) => { + let id = id_val(args)?; + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let serialized = commands::id::export_private(&id)?; + util::write_file(output, serialized.as_slice())?; + } + Some(("delete", args)) => { + let search = args + .get_one::("SEARCH") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a search value"))?; + let skip_confirm = args.get_flag("yes"); + let verbose = args.get_flag("verbose"); + commands::id::delete(search, skip_confirm, verbose)? + } + Some(("view", args)) => { + let search = args + .get_one::("SEARCH") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a search value"))?; + let identity = commands::id::view(search)?; + println!("{}", identity); + } + Some(("fingerprint", args)) => { + let id = id_val(args)?; + let format = args.get_one::("format").map(|x| x.as_str()).unwrap_or("term"); + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); - let fp_format = match format { - "svg" => commands::id::FingerprintFormat::Svg, - _ => commands::id::FingerprintFormat::Term, - }; - let fingerprint = commands::id::fingerprint(&id, fp_format)?; - util::write_file(output, fingerprint.as_bytes())?; - } - _ => unreachable!("Unknown command") + let fp_format = match format { + "svg" => commands::id::FingerprintFormat::Svg, + _ => commands::id::FingerprintFormat::Term, + }; + let fingerprint = commands::id::fingerprint(&id, fp_format)?; + util::write_file(output, fingerprint.as_bytes())?; } - } + _ => unreachable!("Unknown command"), + }, Some(("claim", args)) => { macro_rules! claim_args { ($args:ident) => {{ @@ -1276,19 +1277,19 @@ fn run() -> Result<()> { let stage = $args.get_flag("stage"); let sign_with = $args.get_one::("admin-key").map(|x| x.as_str()); (id, private, name, stage, sign_with) - }} + }}; } macro_rules! aux_op { ($op:expr) => { $op.map_err(|e| anyhow!("Problem adding claim: {}", e)) - } + }; } macro_rules! save_trans { ($transactions:ident, $master_key:ident, $transaction:ident, $stage:ident, $sign_with:ident) => { let identity = util::build_identity(&$transactions)?; let signed = util::sign_helper(&identity, $transaction, &$master_key, $stage, $sign_with)?; commands::dag::save_or_stage($transactions, signed, $stage)? - } + }; } macro_rules! easy_claim { ($args:ident, $fn:ident, $prompt:expr) => { @@ -1297,82 +1298,96 @@ fn run() -> Result<()> { let (master_key, transactions, value) = commands::claim::claim_pre(&id, $prompt)?; let trans = aux_op!(stamp_aux::claim::$fn(&master_key, &transactions, &hash_with, value, private, name))?; save_trans!(transactions, master_key, trans, stage, sign_with); - } + }; } match args.subcommand() { - Some(("new", args)) => { - match args.subcommand() { - Some(("identity", args)) => { - easy_claim! { args, new_id, "Enter the ID of your other identity" } - } - Some(("name", args)) => { - easy_claim! { args, new_name, "Enter your name" } - } - Some(("birthday", args)) => { - easy_claim! { args, new_birthday, "Enter your date of birth (eg 1987-11-23)" } - } - Some(("email", args)) => { - easy_claim! { args, new_email, "Enter your email" } - } - Some(("photo", args)) => { - let (id, private, name, stage, sign_with) = claim_args!(args); - let photofile = args.get_one::("PHOTO-FILE") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a photo"))?; - let hash_with = config::hash_algo(Some(&id)); + Some(("new", args)) => match args.subcommand() { + Some(("identity", args)) => { + easy_claim! { args, new_id, "Enter the ID of your other identity" } + } + Some(("name", args)) => { + easy_claim! { args, new_name, "Enter your name" } + } + Some(("birthday", args)) => { + easy_claim! { args, new_birthday, "Enter your date of birth (eg 1987-11-23)" } + } + Some(("email", args)) => { + easy_claim! { args, new_email, "Enter your email" } + } + Some(("photo", args)) => { + let (id, private, name, stage, sign_with) = claim_args!(args); + let photofile = args + .get_one::("PHOTO-FILE") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a photo"))?; + let hash_with = config::hash_algo(Some(&id)); - let photo_bytes = util::read_file(photofile)?; - if photo_bytes.len() > stamp_aux::claim::MAX_PHOTO_BYTES { - Err(anyhow!("Please choose a photo smaller than {} bytes (given photo is {} bytes)", stamp_aux::claim::MAX_PHOTO_BYTES, photo_bytes.len()))?; - } - let (master_key, transactions) = commands::claim::claim_pre_noval(&id)?; - let trans = aux_op!(stamp_aux::claim::new_photo(&master_key, &transactions, &hash_with, photo_bytes, private, name))?; - save_trans!(transactions, master_key, trans, stage, sign_with); - } - Some(("pgp", args)) => { - easy_claim! { args, new_pgp, "Enter your PGP ID" } - } - Some(("domain", args)) => { - easy_claim! { args, new_domain, "Enter your domain name" } - } - Some(("url", args)) => { - easy_claim! { args, new_url, "Enter the URL you own" } - } - Some(("address", args)) => { - easy_claim! { args, new_address, "Enter your address" } - } - Some(("phone", args)) => { - easy_claim! { args, new_phone, "Enter your phone number" } + let photo_bytes = util::read_file(photofile)?; + if photo_bytes.len() > stamp_aux::claim::MAX_PHOTO_BYTES { + Err(anyhow!( + "Please choose a photo smaller than {} bytes (given photo is {} bytes)", + stamp_aux::claim::MAX_PHOTO_BYTES, + photo_bytes.len() + ))?; } - Some(("relation", args)) => { - let (id, private, name, stage, sign_with) = claim_args!(args); - let ty = args.get_one::("TYPE") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a relationship type"))?; - let hash_with = config::hash_algo(Some(&id)); - let reltype = match ty { - "org" => RelationshipType::OrganizationMember, - _ => Err(anyhow!("Invalid relationship type: {}", ty))?, - }; - let (master_key, transactions, value) = commands::claim::claim_pre(&id, "Enter the full Stamp identity id for the entity you are related to")?; - let trans = aux_op!(stamp_aux::claim::new_relation(&master_key, &transactions, &hash_with, reltype, value, private, name))?; - save_trans!(transactions, master_key, trans, stage, sign_with); - } - _ => unreachable!("Unknown command"), + let (master_key, transactions) = commands::claim::claim_pre_noval(&id)?; + let trans = + aux_op!(stamp_aux::claim::new_photo(&master_key, &transactions, &hash_with, photo_bytes, private, name))?; + save_trans!(transactions, master_key, trans, stage, sign_with); } - } + Some(("pgp", args)) => { + easy_claim! { args, new_pgp, "Enter your PGP ID" } + } + Some(("domain", args)) => { + easy_claim! { args, new_domain, "Enter your domain name" } + } + Some(("url", args)) => { + easy_claim! { args, new_url, "Enter the URL you own" } + } + Some(("address", args)) => { + easy_claim! { args, new_address, "Enter your address" } + } + Some(("phone", args)) => { + easy_claim! { args, new_phone, "Enter your phone number" } + } + Some(("relation", args)) => { + let (id, private, name, stage, sign_with) = claim_args!(args); + let ty = args + .get_one::("TYPE") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a relationship type"))?; + let hash_with = config::hash_algo(Some(&id)); + let reltype = match ty { + "org" => RelationshipType::OrganizationMember, + _ => Err(anyhow!("Invalid relationship type: {}", ty))?, + }; + let (master_key, transactions, value) = + commands::claim::claim_pre(&id, "Enter the full Stamp identity id for the entity you are related to")?; + let trans = aux_op!(stamp_aux::claim::new_relation( + &master_key, + &transactions, + &hash_with, + reltype, + value, + private, + name + ))?; + save_trans!(transactions, master_key, trans, stage, sign_with); + } + _ => unreachable!("Unknown command"), + }, Some(("check", args)) => { - let claim_id = args.get_one::("CLAIM") + let claim_id = args + .get_one::("CLAIM") .map(|x| x.as_str()) .ok_or(anyhow!("Must specify a claim ID"))?; commands::claim::check(claim_id)?; } Some(("view", args)) => { let id = id_val(args)?; - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let claim_id = args.get_one::("CLAIM") + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let claim_id = args + .get_one::("CLAIM") .map(|x| x.as_str()) .ok_or(anyhow!("Must specify a claim ID"))?; commands::claim::view(&id, claim_id, output)?; @@ -1387,55 +1402,62 @@ fn run() -> Result<()> { let id = id_val(args)?; let stage = args.get_flag("stage"); let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - let claim_id = args.get_one::("CLAIM") + let claim_id = args + .get_one::("CLAIM") .map(|x| x.as_str()) .ok_or(anyhow!("Must specify a CLAIM id"))?; - let name = args.get_one::("NAME") + let name = args + .get_one::("NAME") .map(|x| x.as_str()) .map(|x| if x == "-" { None } else { Some(x) }) .ok_or(anyhow!("Must specify a name"))?; let hash_with = config::hash_algo(Some(&id)); let transactions = commands::id::try_load_single_identity(&id)?; let identity = util::build_identity(&transactions)?; - let master_key = util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&id)), identity.created())?; + let master_key = util::passphrase_prompt( + &format!("Your master passphrase for identity {}", IdentityID::short(&id)), + identity.created(), + )?; let trans = stamp_aux::claim::rename(&transactions, &hash_with, &claim_id, name) .map_err(|e| anyhow!("Problem renaming claim: {}", e))?; save_trans!(transactions, master_key, trans, stage, sign_with); } - Some(("stamp", args)) => { - match args.subcommand() { - Some(("list", args)) => { - let id = id_val(args)?; - let claim = args.get_one::("CLAIM") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a CLAIM"))?; - let verbose = args.get_flag("verbose"); - commands::claim::stamp_list(&id, claim, verbose)?; - } - Some(("view", args)) => { - let id = id_val(args)?; - let stamp_id = args.get_one::("STAMP") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a STAMP id"))?; - commands::claim::stamp_view(&id, stamp_id)?; - } - Some(("delete", args)) => { - let id = id_val(args)?; - let stage = args.get_flag("stage"); - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - let stamp_id = args.get_one::("STAMP") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a STAMP id"))?; - commands::claim::stamp_delete(&id, stamp_id, stage, sign_with)?; - } - _ => unreachable!("Unknown command"), + Some(("stamp", args)) => match args.subcommand() { + Some(("list", args)) => { + let id = id_val(args)?; + let claim = args + .get_one::("CLAIM") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a CLAIM"))?; + let verbose = args.get_flag("verbose"); + commands::claim::stamp_list(&id, claim, verbose)?; } - } + Some(("view", args)) => { + let id = id_val(args)?; + let stamp_id = args + .get_one::("STAMP") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a STAMP id"))?; + commands::claim::stamp_view(&id, stamp_id)?; + } + Some(("delete", args)) => { + let id = id_val(args)?; + let stage = args.get_flag("stage"); + let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); + let stamp_id = args + .get_one::("STAMP") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a STAMP id"))?; + commands::claim::stamp_delete(&id, stamp_id, stage, sign_with)?; + } + _ => unreachable!("Unknown command"), + }, Some(("delete", args)) => { let id = id_val(args)?; let stage = args.get_flag("stage"); let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - let claim_id = args.get_one::("CLAIM") + let claim_id = args + .get_one::("CLAIM") .map(|x| x.as_str()) .ok_or(anyhow!("Must specify a claim ID"))?; let hash_with = config::hash_algo(Some(&id)); @@ -1444,407 +1466,370 @@ fn run() -> Result<()> { if !util::yesno_prompt(&format!("Really delete the claim {} and all of its stamps? [y/N]", claim_id), "n")? { return Ok(()); } - let master_key = util::passphrase_prompt(&format!("Your master passphrase for identity {}", IdentityID::short(&id)), identity.created())?; + let master_key = util::passphrase_prompt( + &format!("Your master passphrase for identity {}", IdentityID::short(&id)), + identity.created(), + )?; let trans = stamp_aux::claim::delete(&transactions, &hash_with, &claim_id) .map_err(|e| anyhow!("Problem deleting claim: {}", e))?; save_trans!(transactions, master_key, trans, stage, sign_with); } - _ => unreachable!("Unknown command") + _ => unreachable!("Unknown command"), } } - Some(("stamp", args)) => { - match args.subcommand() { - Some(("new", args)) => { - let our_identity_id = id_val(args)?; - let claim_id = args.get_one::("CLAIM") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a claim"))?; - let stage = args.get_flag("stage"); - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - commands::stamp::new(&our_identity_id, claim_id, stage, sign_with)?; - } - Some(("req", args)) => { - let id = id_val(args)?; - let key_from = args.get_one::("key-from") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify the from key"))?; - let stamper_id = args.get_one::("stamper-identity-id") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify the stamper's identity id"))?; - let key_to = args.get_one::("key-to") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify the to key"))?; - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let base64 = args.get_flag("base64"); - let claim = args.get_one::("CLAIM") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a claim"))?; - let req = commands::stamp::request(&id, claim, key_from, stamper_id, key_to)?; - if base64 { - util::write_file(output, stamp_core::util::base64_encode(req.as_slice()).as_bytes())?; - } else { - util::write_file(output, req.as_slice())?; - } - } - Some(("open-req", args)) => { - let id = id_val(args)?; - let key_to = args.get_one::("key-to") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify the to key"))?; - let req = args.get_one::("ENCRYPTED") - .map(|x| x.as_str()) - .unwrap_or("-"); - commands::stamp::open_request(&id, &key_to, req)?; - } - Some(("list", args)) => { - let id = id_val(args)?; - let revoked = args.get_flag("revoked"); - let verbose = args.get_flag("verbose"); - commands::stamp::list(&id, revoked, verbose)?; - } - Some(("export", args)) => { - let id = id_val(args)?; - let stamp = args.get_one::("STAMP") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a STAMP id"))?; - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let base64 = args.get_flag("base64"); - commands::dag::export(&id, stamp, output, base64)?; - } - Some(("accept", args)) => { - let id = id_val(args)?; - let location = args.get_one::("LOCATION") - .map(|x| x.as_str()) - .ok_or_else(|| anyhow!("Must specify a LOCATION value"))?; - let stage = args.get_flag("stage"); - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - commands::stamp::accept(&id, location, stage, sign_with)?; - } - Some(("revoke", args)) => { - let id = id_val(args)?; - let stamp_search = args.get_one::("STAMP") - .map(|x| x.as_str()) - .ok_or_else(|| anyhow!("Must specify a STAMP value"))?; - let reason = args.get_one::("reason") - .map(|x| x.as_str()) - .unwrap_or("unspecified"); - let stage = args.get_flag("stage"); - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - commands::stamp::revoke(&id, stamp_search, reason, stage, sign_with)?; + Some(("stamp", args)) => match args.subcommand() { + Some(("new", args)) => { + let our_identity_id = id_val(args)?; + let claim_id = args + .get_one::("CLAIM") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a claim"))?; + let stage = args.get_flag("stage"); + let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); + commands::stamp::new(&our_identity_id, claim_id, stage, sign_with)?; + } + Some(("req", args)) => { + let id = id_val(args)?; + let key_from = args + .get_one::("key-from") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify the from key"))?; + let stamper_id = args + .get_one::("stamper-identity-id") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify the stamper's identity id"))?; + let key_to = args + .get_one::("key-to") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify the to key"))?; + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let base64 = args.get_flag("base64"); + let claim = args + .get_one::("CLAIM") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a claim"))?; + let req = commands::stamp::request(&id, claim, key_from, stamper_id, key_to)?; + if base64 { + util::write_file(output, stamp_core::util::base64_encode(req.as_slice()).as_bytes())?; + } else { + util::write_file(output, req.as_slice())?; } - _ => unreachable!("Unknown command") } - } - Some(("keychain", args)) => { - match args.subcommand() { - Some(("new", args)) => { - macro_rules! parse_new_key_args { - ($args:ident) => {{ - let id = id_val($args)?; - let name = $args.get_one::("NAME") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a name"))?; - let desc = $args.get_one::("description") - .map(|x| x.as_str()); - let stage = $args.get_flag("stage"); - let sign_with = $args.get_one::("admin-key").map(|x| x.as_str()); - (id, name, desc, stage, sign_with) - }} + Some(("open-req", args)) => { + let id = id_val(args)?; + let key_to = args + .get_one::("key-to") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify the to key"))?; + let req = args.get_one::("ENCRYPTED").map(|x| x.as_str()).unwrap_or("-"); + commands::stamp::open_request(&id, &key_to, req)?; + } + Some(("list", args)) => { + let id = id_val(args)?; + let revoked = args.get_flag("revoked"); + let verbose = args.get_flag("verbose"); + commands::stamp::list(&id, revoked, verbose)?; + } + Some(("export", args)) => { + let id = id_val(args)?; + let stamp = args + .get_one::("STAMP") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a STAMP id"))?; + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let base64 = args.get_flag("base64"); + commands::dag::export(&id, stamp, output, base64)?; + } + Some(("accept", args)) => { + let id = id_val(args)?; + let location = args + .get_one::("LOCATION") + .map(|x| x.as_str()) + .ok_or_else(|| anyhow!("Must specify a LOCATION value"))?; + let stage = args.get_flag("stage"); + let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); + commands::stamp::accept(&id, location, stage, sign_with)?; + } + Some(("revoke", args)) => { + let id = id_val(args)?; + let stamp_search = args + .get_one::("STAMP") + .map(|x| x.as_str()) + .ok_or_else(|| anyhow!("Must specify a STAMP value"))?; + let reason = args.get_one::("reason").map(|x| x.as_str()).unwrap_or("unspecified"); + let stage = args.get_flag("stage"); + let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); + commands::stamp::revoke(&id, stamp_search, reason, stage, sign_with)?; + } + _ => unreachable!("Unknown command"), + }, + Some(("keychain", args)) => match args.subcommand() { + Some(("new", args)) => { + macro_rules! parse_new_key_args { + ($args:ident) => {{ + let id = id_val($args)?; + let name = $args + .get_one::("NAME") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a name"))?; + let desc = $args.get_one::("description").map(|x| x.as_str()); + let stage = $args.get_flag("stage"); + let sign_with = $args.get_one::("admin-key").map(|x| x.as_str()); + (id, name, desc, stage, sign_with) + }}; + } + match args.subcommand() { + Some(("admin", args)) => { + let (id, name, desc, stage, sign_with) = parse_new_key_args!(args); + commands::keychain::new(&id, "admin", name, desc, stage, sign_with)?; } - match args.subcommand() { - Some(("admin", args)) => { - let (id, name, desc, stage, sign_with) = parse_new_key_args!(args); - commands::keychain::new(&id, "admin", name, desc, stage, sign_with)?; - } - Some(("sign", args)) => { - let (id, name, desc, stage, sign_with) = parse_new_key_args!(args); - commands::keychain::new(&id, "sign", name, desc, stage, sign_with)?; - } - Some(("crypto", args)) => { - let (id, name, desc, stage, sign_with) = parse_new_key_args!(args); - commands::keychain::new(&id, "crypto", name, desc, stage, sign_with)?; - } - Some(("secret", args)) => { - let (id, name, desc, stage, sign_with) = parse_new_key_args!(args); - commands::keychain::new(&id, "secret", name, desc, stage, sign_with)?; - } - _ => unreachable!("Unknown command") + Some(("sign", args)) => { + let (id, name, desc, stage, sign_with) = parse_new_key_args!(args); + commands::keychain::new(&id, "sign", name, desc, stage, sign_with)?; } + Some(("crypto", args)) => { + let (id, name, desc, stage, sign_with) = parse_new_key_args!(args); + commands::keychain::new(&id, "crypto", name, desc, stage, sign_with)?; + } + Some(("secret", args)) => { + let (id, name, desc, stage, sign_with) = parse_new_key_args!(args); + commands::keychain::new(&id, "secret", name, desc, stage, sign_with)?; + } + _ => unreachable!("Unknown command"), } - Some(("list", args)) => { - let id = id_val(args)?; - let ty = args.get_one::("type") - .map(|x| x.as_str()); - let revoked = args.get_flag("revoked"); - let search = args.get_one::("SEARCH") - .map(|x| x.as_str()); - commands::keychain::list(&id, ty, revoked, search)?; - } - Some(("update", args)) => { - let id = id_val(args)?; - let search = args.get_one::("SEARCH") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a key id or name"))?; - let name = args.get_one::("name") - .map(|x| x.as_str()); - let desc = args.get_one::("description") - .map(|x| x.as_str()) - .map(|x| if x == "-" { None } else { Some(x) }); - let stage = args.get_flag("stage"); - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - commands::keychain::update(&id, search, name, desc, stage, sign_with)?; - } - Some(("revoke", args)) => { - let id = id_val(args)?; - let stage = args.get_flag("stage"); - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - let reason = args.get_one::("reason") - .map(|x| x.as_str()) - .unwrap_or("unspecified"); - let search = args.get_one::("SEARCH") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a key id or name"))?; - commands::keychain::revoke(&id, search, reason, stage, sign_with)?; - } - Some(("delete-subkey", args)) => { - let id = id_val(args)?; - let stage = args.get_flag("stage"); - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - let search = args.get_one::("SEARCH") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a key id or name"))?; - commands::keychain::delete_subkey(&id, search, stage, sign_with)?; - } - Some(("passwd", args)) => { - let id = id_val(args)?; - let keyfile = args.get_one::("keyfile") - .map(|x| x.as_str()); - let keyparts: Vec<&str> = args.get_many::("KEYPARTS") - .unwrap_or_default() - .map(|v| v.as_str()) - .collect(); - commands::keychain::passwd(&id, keyfile, keyparts)?; - } - Some(("sync-token", args)) => { - let id = id_val(args)?; - let stage = args.get_flag("stage"); - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - let blind = args.get_flag("blind"); - commands::keychain::sync_token(&id, blind, stage, sign_with)?; - } - Some(("keyfile", args)) => { - let id = id_val(args)?; - let shamir = args.get_one::("shamir") - .map(|x| x.as_str()) - .unwrap_or("1/1"); - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - commands::keychain::keyfile(&id, shamir, output)?; - } - _ => unreachable!("Unknown command") } - } - Some(("message", args)) => { - match args.subcommand() { - Some(("send", args)) => { - let from_id = id_val(args)?; - let key_from_search = args.get_one::("key-from") - .map(|x| x.as_str()); - let key_to_search = args.get_one::("key-to") - .map(|x| x.as_str()); - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let search = args.get_one::("SEARCH") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a search value"))?; - let input = args.get_one::("MESSAGE") - .map(|x| x.as_str()) - .unwrap_or("-"); - let base64 = args.get_flag("base64"); - commands::message::send(&from_id, key_from_search, key_to_search, input, output, search, base64)?; - } - Some(("send-anonymous", args)) => { - let key_to_search = args.get_one::("key-to") - .map(|x| x.as_str()); - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let search = args.get_one::("SEARCH") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a search value"))?; - let input = args.get_one::("MESSAGE") - .map(|x| x.as_str()) - .unwrap_or("-"); - let base64 = args.get_flag("base64"); - commands::message::send_anonymous(key_to_search, input, output, search, base64)?; - } - Some(("open", args)) => { - let to_id = id_val(args)?; - let key_open = args.get_one::("key-open") - .map(|x| x.as_str()); - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let input = args.get_one::("ENCRYPTED") - .map(|x| x.as_str()) - .unwrap_or("-"); - commands::message::open(&to_id, key_open, input, output)?; - } - _ => unreachable!("Unknown command") + Some(("list", args)) => { + let id = id_val(args)?; + let ty = args.get_one::("type").map(|x| x.as_str()); + let revoked = args.get_flag("revoked"); + let search = args.get_one::("SEARCH").map(|x| x.as_str()); + commands::keychain::list(&id, ty, revoked, search)?; } - } - Some(("sign", args)) => { - match args.subcommand() { - Some(("id", args)) => { - let sign_id = id_val(args)?; - let stage = args.get_flag("stage"); - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let input = args.get_one::("MESSAGE") - .map(|x| x.as_str()) - .unwrap_or("-"); - let base64 = args.get_flag("base64"); - commands::sign::sign_id(&sign_id, input, output, base64, stage, sign_with)?; - } - Some(("subkey", args)) => { - let sign_id = id_val(args)?; - let key_sign_search = args.get_one::("key-sign") - .map(|x| x.as_str()); - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let input = args.get_one::("MESSAGE") - .map(|x| x.as_str()) - .unwrap_or("-"); - let attached = args.get_flag("attached"); - let base64 = args.get_flag("base64"); - commands::sign::sign_subkey(&sign_id, key_sign_search, input, output, attached, base64)?; - } - Some(("verify", args)) => { - let signature = args.get_one::("SIGNATURE") - .map(|x| x.as_str()) - .unwrap_or("-"); - let input = args.get_one::("MESSAGE") - .map(|x| x.as_str()); - commands::sign::verify(signature, input)?; - } - _ => unreachable!("Unknown command") + Some(("update", args)) => { + let id = id_val(args)?; + let search = args + .get_one::("SEARCH") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a key id or name"))?; + let name = args.get_one::("name").map(|x| x.as_str()); + let desc = args + .get_one::("description") + .map(|x| x.as_str()) + .map(|x| if x == "-" { None } else { Some(x) }); + let stage = args.get_flag("stage"); + let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); + commands::keychain::update(&id, search, name, desc, stage, sign_with)?; } - } - Some(("config", args)) => { - match args.subcommand() { - Some(("set-default", args)) => { - let search = args.get_one::("SEARCH") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a search value"))?; - commands::config::set_default(search)?; - } - _ => unreachable!("Unknown command") + Some(("revoke", args)) => { + let id = id_val(args)?; + let stage = args.get_flag("stage"); + let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); + let reason = args.get_one::("reason").map(|x| x.as_str()).unwrap_or("unspecified"); + let search = args + .get_one::("SEARCH") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a key id or name"))?; + commands::keychain::revoke(&id, search, reason, stage, sign_with)?; } - } - Some(("dag", args)) => { - match args.subcommand() { - Some(("list", args)) => { - let id = id_val(args)?; - commands::dag::list(&id)?; - } - Some(("reset", args)) => { - let id = id_val(args)?; - let txid = args.get_one::("TXID") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a TXID"))?; - commands::dag::reset(&id, txid)?; - } - _ => unreachable!("Unknown command") + Some(("delete-subkey", args)) => { + let id = id_val(args)?; + let stage = args.get_flag("stage"); + let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); + let search = args + .get_one::("SEARCH") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a key id or name"))?; + commands::keychain::delete_subkey(&id, search, stage, sign_with)?; } - } + Some(("passwd", args)) => { + let id = id_val(args)?; + let keyfile = args.get_one::("keyfile").map(|x| x.as_str()); + let keyparts: Vec<&str> = args + .get_many::("KEYPARTS") + .unwrap_or_default() + .map(|v| v.as_str()) + .collect(); + commands::keychain::passwd(&id, keyfile, keyparts)?; + } + Some(("sync-token", args)) => { + let id = id_val(args)?; + let stage = args.get_flag("stage"); + let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); + let blind = args.get_flag("blind"); + commands::keychain::sync_token(&id, blind, stage, sign_with)?; + } + Some(("keyfile", args)) => { + let id = id_val(args)?; + let shamir = args.get_one::("shamir").map(|x| x.as_str()).unwrap_or("1/1"); + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + commands::keychain::keyfile(&id, shamir, output)?; + } + _ => unreachable!("Unknown command"), + }, + Some(("message", args)) => match args.subcommand() { + Some(("send", args)) => { + let from_id = id_val(args)?; + let key_from_search = args.get_one::("key-from").map(|x| x.as_str()); + let key_to_search = args.get_one::("key-to").map(|x| x.as_str()); + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let search = args + .get_one::("SEARCH") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a search value"))?; + let input = args.get_one::("MESSAGE").map(|x| x.as_str()).unwrap_or("-"); + let base64 = args.get_flag("base64"); + commands::message::send(&from_id, key_from_search, key_to_search, input, output, search, base64)?; + } + Some(("send-anonymous", args)) => { + let key_to_search = args.get_one::("key-to").map(|x| x.as_str()); + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let search = args + .get_one::("SEARCH") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a search value"))?; + let input = args.get_one::("MESSAGE").map(|x| x.as_str()).unwrap_or("-"); + let base64 = args.get_flag("base64"); + commands::message::send_anonymous(key_to_search, input, output, search, base64)?; + } + Some(("open", args)) => { + let to_id = id_val(args)?; + let key_open = args.get_one::("key-open").map(|x| x.as_str()); + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let input = args.get_one::("ENCRYPTED").map(|x| x.as_str()).unwrap_or("-"); + commands::message::open(&to_id, key_open, input, output)?; + } + _ => unreachable!("Unknown command"), + }, + Some(("sign", args)) => match args.subcommand() { + Some(("id", args)) => { + let sign_id = id_val(args)?; + let stage = args.get_flag("stage"); + let sign_with = args.get_one::("admin-key").map(|x| x.as_str()); + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let input = args.get_one::("MESSAGE").map(|x| x.as_str()).unwrap_or("-"); + let base64 = args.get_flag("base64"); + commands::sign::sign_id(&sign_id, input, output, base64, stage, sign_with)?; + } + Some(("subkey", args)) => { + let sign_id = id_val(args)?; + let key_sign_search = args.get_one::("key-sign").map(|x| x.as_str()); + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let input = args.get_one::("MESSAGE").map(|x| x.as_str()).unwrap_or("-"); + let attached = args.get_flag("attached"); + let base64 = args.get_flag("base64"); + commands::sign::sign_subkey(&sign_id, key_sign_search, input, output, attached, base64)?; + } + Some(("verify", args)) => { + let signature = args.get_one::("SIGNATURE").map(|x| x.as_str()).unwrap_or("-"); + let input = args.get_one::("MESSAGE").map(|x| x.as_str()); + commands::sign::verify(signature, input)?; + } + _ => unreachable!("Unknown command"), + }, + Some(("config", args)) => match args.subcommand() { + Some(("set-default", args)) => { + let search = args + .get_one::("SEARCH") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a search value"))?; + commands::config::set_default(search)?; + } + _ => unreachable!("Unknown command"), + }, + Some(("dag", args)) => match args.subcommand() { + Some(("list", args)) => { + let id = id_val(args)?; + commands::dag::list(&id)?; + } + Some(("reset", args)) => { + let id = id_val(args)?; + let txid = args + .get_one::("TXID") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a TXID"))?; + commands::dag::reset(&id, txid)?; + } + _ => unreachable!("Unknown command"), + }, Some(("debug", args)) => { match args.subcommand() { Some(("resave", args)) => { // no default here, debug commands should be explicit - let id = args.get_one::("identity") + let id = args + .get_one::("identity") .map(|x| x.as_str()) .ok_or(anyhow!("Must specify an ID"))?; commands::debug::resave(id)?; } Some(("export", args)) => { // no default here, debug commands should be explicit - let id = args.get_one::("identity") + let id = args + .get_one::("identity") .map(|x| x.as_str()) .ok_or(anyhow!("Must specify an ID"))?; commands::debug::export(id)?; } Some(("import", args)) => { // no default here, debug commands should be explicit - let input = args.get_one::("EXPORT-PATH") - .map(|x| x.as_str()) - .unwrap_or("-"); + let input = args.get_one::("EXPORT-PATH").map(|x| x.as_str()).unwrap_or("-"); commands::debug::import(input)?; } - _ => unreachable!("Unknown command") + _ => unreachable!("Unknown command"), } } - Some(("stage", args)) => { - match args.subcommand() { - Some(("list", args)) => { - let id = id_val(args)?; - commands::stage::list(&id)?; - } - Some(("view", args)) => { - let txid = args.get_one::("TXID") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a join token"))?; - commands::stage::view(txid)?; - } - Some(("export", args)) => { - let output = args.get_one::("output") - .map(|x| x.as_str()) - .unwrap_or("-"); - let base64 = args.get_flag("base64"); - let txid = args.get_one::("TXID") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a join token"))?; - commands::stage::export(txid, output, base64)?; - } - Some(("import", args)) => { - let id = args.get_one::("identity") - .ok_or(anyhow!("Must specify an ID"))?; - let input = args.get_one::("TRANSACTION") - .map(|x| x.as_str()) - .unwrap_or("-"); - commands::stage::import(id, input)?; - } - Some(("delete", args)) => { - let txid = args.get_one::("TXID") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a join token"))?; - commands::stage::delete(txid)?; - } - Some(("sign", args)) => { - let txid = args.get_one::("TXID") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a join token"))?; - let sign_with = args.get_one::("admin-key").map(|x| x.as_str()) - .ok_or(anyhow!("Must specify an admin key to sign with"))?; - commands::stage::sign(txid, sign_with)?; - } - Some(("apply", args)) => { - let txid = args.get_one::("TXID") - .map(|x| x.as_str()) - .ok_or(anyhow!("Must specify a join token"))?; - commands::stage::apply(txid)?; - } - _ => unreachable!("Unknown command") + Some(("stage", args)) => match args.subcommand() { + Some(("list", args)) => { + let id = id_val(args)?; + commands::stage::list(&id)?; } - } + Some(("view", args)) => { + let txid = args + .get_one::("TXID") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a join token"))?; + commands::stage::view(txid)?; + } + Some(("export", args)) => { + let output = args.get_one::("output").map(|x| x.as_str()).unwrap_or("-"); + let base64 = args.get_flag("base64"); + let txid = args + .get_one::("TXID") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a join token"))?; + commands::stage::export(txid, output, base64)?; + } + Some(("import", args)) => { + let id = args.get_one::("identity").ok_or(anyhow!("Must specify an ID"))?; + let input = args.get_one::("TRANSACTION").map(|x| x.as_str()).unwrap_or("-"); + commands::stage::import(id, input)?; + } + Some(("delete", args)) => { + let txid = args + .get_one::("TXID") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a join token"))?; + commands::stage::delete(txid)?; + } + Some(("sign", args)) => { + let txid = args + .get_one::("TXID") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a join token"))?; + let sign_with = args + .get_one::("admin-key") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify an admin key to sign with"))?; + commands::stage::sign(txid, sign_with)?; + } + Some(("apply", args)) => { + let txid = args + .get_one::("TXID") + .map(|x| x.as_str()) + .ok_or(anyhow!("Must specify a join token"))?; + commands::stage::apply(txid)?; + } + _ => unreachable!("Unknown command"), + }, /* Some(("agent", args)) => { let bind = args.get_one::("bind") @@ -1874,7 +1859,7 @@ fn run() -> Result<()> { //commands::agent::run(bind, sync_token, sync_join, agent_port, agent_lock_after, net_bind, net_join)?; } */ - _ => unreachable!("Unknown command") + _ => unreachable!("Unknown command"), } Ok(()) } @@ -1888,4 +1873,3 @@ fn main() { } } } - diff --git a/src/util.rs b/src/util.rs index 066071d..9b3f1e7 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,18 +1,18 @@ use anyhow::{anyhow, Result}; -use stamp_aux::{ - id::sign_with_optimal_key, -}; +use stamp_aux::id::sign_with_optimal_key; use stamp_core::{ - crypto::base::{KDF_OPS_INTERACTIVE, KDF_OPS_MODERATE, KDF_MEM_INTERACTIVE, KDF_MEM_MODERATE, SecretKey}, + crypto::base::{SecretKey, KDF_MEM_INTERACTIVE, KDF_MEM_MODERATE, KDF_OPS_INTERACTIVE, KDF_OPS_MODERATE}, dag::{Transaction, Transactions}, identity::Identity, }; use std::fs::File; use std::io::{BufReader, Read, Write}; use textwrap; -use tracing::{warn}; +use tracing::warn; -pub(crate) fn term_maxwidth() -> usize { 120 } +pub(crate) fn term_maxwidth() -> usize { + 120 +} pub(crate) fn yesno_prompt(prompt: &str, default: &str) -> Result { let yesno: String = dialoguer::Input::new() @@ -39,9 +39,8 @@ pub(crate) fn value_prompt(prompt: &str) -> Result { macro_rules! id_str { ($id:expr) => { - String::try_from($id) - .map_err(|e| anyhow::anyhow!("There was a problem converting the id {:?} to a string: {:?}", $id, e)) - } + String::try_from($id).map_err(|e| anyhow::anyhow!("There was a problem converting the id {:?} to a string: {:?}", $id, e)) + }; } macro_rules! id_str_split { @@ -50,41 +49,49 @@ macro_rules! id_str_split { Ok(id_full) => { let id_short = stamp_core::identity::IdentityID::short(&id_full); (id_full, id_short) - } + } Err(..) => (String::from(""), String::from("")), } - } + }; } -pub(crate) fn sign_helper(identity: &Identity, transaction: Transaction, master_key: &SecretKey, stage: bool, sign_with: Option<&str>) -> Result { +pub(crate) fn sign_helper( + identity: &Identity, + transaction: Transaction, + master_key: &SecretKey, + stage: bool, + sign_with: Option<&str>, +) -> Result { match (stage, sign_with) { (true, Some(key_str)) => { - let admin = identity.keychain().admin_key_by_keyid_str(key_str) + let admin = identity + .keychain() + .admin_key_by_keyid_str(key_str) .or_else(|| identity.keychain().admin_key_by_name(key_str)) .ok_or_else(|| anyhow!("Admin key not found"))?; - let transaction = transaction.sign(master_key, admin) + let transaction = transaction + .sign(master_key, admin) .map_err(|e| anyhow!("Error signing transaction: {:?}", e))?; Ok(transaction) } _ => { - let transaction = sign_with_optimal_key(&identity, &master_key, transaction) - .map_err(|e| anyhow!("Error signing transaction: {:?}", e))?; + let transaction = + sign_with_optimal_key(&identity, &master_key, transaction).map_err(|e| anyhow!("Error signing transaction: {:?}", e))?; Ok(transaction) } } } pub(crate) fn build_identity(transactions: &Transactions) -> Result { - transactions.build_identity() + transactions + .build_identity() .map_err(|e| anyhow!("Problem building identity: {}", e)) } fn derive_master(passphrase: &str, now: &stamp_core::util::Timestamp) -> Result { let salt_bytes = stamp_core::crypto::base::Hash::new_blake3(format!("{}", now.format("%+")).as_bytes()) .map_err(|err| anyhow!("Error deriving master key salt: {:?}", err))?; - let quick = std::env::var("STAMP_KDF_QUICK") - .map(|x| x == "1") - .unwrap_or(false); + let quick = std::env::var("STAMP_KDF_QUICK").map(|x| x == "1").unwrap_or(false); if quick { warn!("Using quick KDF parameters. This is only ok for dev/testing."); } @@ -97,17 +104,24 @@ fn derive_master(passphrase: &str, now: &stamp_core::util::Timestamp) -> Result< /// Grab a password and use it along with a timestamp to generate a master key. pub(crate) fn passphrase_prompt>(prompt: T, now: &stamp_core::util::Timestamp) -> Result { - let passphrase = dialoguer::Password::new().with_prompt(prompt).interact() + let passphrase = dialoguer::Password::new() + .with_prompt(prompt) + .interact() .map_err(|err| anyhow!("There was an error grabbing your passphrase: {:?}", err))?; derive_master(&passphrase, now) } pub(crate) fn with_new_passphrase(prompt: &str, gen_fn: F, now: Option) -> Result<(T, SecretKey)> - where F: FnOnce(&stamp_core::crypto::base::SecretKey, stamp_core::util::Timestamp) -> Result, +where + F: FnOnce(&stamp_core::crypto::base::SecretKey, stamp_core::util::Timestamp) -> Result, { - let passphrase = dialoguer::Password::new().with_prompt(prompt).interact() + let passphrase = dialoguer::Password::new() + .with_prompt(prompt) + .interact() .map_err(|err| anyhow!("There was an error grabbing your passphrase: {:?}", err))?; - let confirm = dialoguer::Password::new().with_prompt("Confirm passphrase").interact() + let confirm = dialoguer::Password::new() + .with_prompt("Confirm passphrase") + .interact() .map_err(|err| anyhow!("There was an error grabbing your confirmation: {:?}", err))?; if passphrase != confirm { if yesno_prompt("Passphrase and confirmation do not match. Try again? [Y/n]", "y")? { @@ -127,13 +141,15 @@ pub fn read_file(filename: &str) -> Result> { let mut contents = String::new(); let stdin = std::io::stdin(); eprintln!("{}", text_wrap("Enter your message and hit enter/return:")); - stdin.read_line(&mut contents) + stdin + .read_line(&mut contents) .map_err(|e| anyhow!("Problem reading file: {}: {:?}", filename, e))?; Ok(Vec::from(contents.trim_end_matches('\n').trim_end_matches('\r').as_bytes())) } else { let mut contents = Vec::new(); let mut stdin = std::io::stdin(); - stdin.read_to_end(&mut contents) + stdin + .read_to_end(&mut contents) .map_err(|e| anyhow!("Problem reading file: {}: {:?}", filename, e))?; Ok(contents) } @@ -153,20 +169,20 @@ pub fn write_file(filename: &str, bytes: &[u8]) -> Result<()> { .map_err(|e| anyhow!("There was a problem outputting the identity: {:?}", e))?; println!(""); } else { - let mut handle = File::create(&filename) - .map_err(|e| anyhow!("Error opening file: {}: {:?}", filename, e))?; - handle.write_all(bytes) + let mut handle = File::create(&filename).map_err(|e| anyhow!("Error opening file: {}: {:?}", filename, e))?; + handle + .write_all(bytes) .map_err(|e| anyhow!("Error writing to identity file: {}: {:?}", filename, e))?; } Ok(()) } pub fn load_file(filename: &str) -> Result> { - let file = File::open(filename) - .map_err(|e| anyhow!("Unable to open file: {}: {:?}", filename, e))?; + let file = File::open(filename).map_err(|e| anyhow!("Unable to open file: {}: {:?}", filename, e))?; let mut reader = BufReader::new(file); let mut contents = Vec::new(); - reader.read_to_end(&mut contents) + reader + .read_to_end(&mut contents) .map_err(|e| anyhow!("Problem reading file: {}: {:?}", filename, e))?; Ok(contents) } @@ -185,4 +201,3 @@ pub fn print_wrapped_indent(text: &str, indent: &str) { let indented = textwrap::indent(lines.as_str(), indent); print!("{}", indented); } -