From def0148c7e2d96656dd384fe1d4a45b608828b07 Mon Sep 17 00:00:00 2001 From: 8go <> Date: Mon, 5 Dec 2022 16:30:33 +0100 Subject: [PATCH] added --add-contact, --remove-contact and --show-contacts --add-contact Add one or more contacts. Must be used in combination with --alias, --key, --relay. If you want to add N new contacts, use --add-contact and provide exactly N entries in each of the 3 extra arguments. E.g. --add-contact --alias jane joe --key npub1JanesPublicKey npub1JoesPublicKey --relay "wss://janes.relay.org" "wss://joes.relay.org" --remove-contact Remove one or more contacts. Must be used in combination with --alias. For each entry in --alias the corresponding contact will be removed. E.g. --remove-contact --alias jane joe --show-contacts Display current contacts --alias [...] Provide one or multiple aliases (nicknames) for arguments --add-contact and --remove-contact --key [...] Provide one or multiple public keys for argument --add-contact. They have the form 'npub1SomeStrangeString' --relay [...] Provide one or multiple relays for argument --add-contact. They have the form 'wss://some.relay.org' --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 26 +++++++++- VERSION | 2 +- help.txt | 26 +++++++++- src/main.rs | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 192 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 136f4e0..0990313 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -677,7 +677,7 @@ dependencies = [ [[package]] name = "nostr-commander" -version = "0.0.2" +version = "0.0.3" dependencies = [ "anyhow", "clap", diff --git a/Cargo.toml b/Cargo.toml index e26ba33..9f6466e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "nostr-commander" -version = "0.0.2" +version = "0.0.3" edition = "2021" description = "simple but convenient CLI-based Nostr client app for publishing,sending and subscribing" documentation = "https://docs.rs/nostr-commander" diff --git a/README.md b/README.md index feebe22..d05cfc2 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ Options: --publish-pow [...] Publish one or multiple notes with proof-of-work (POW). Use also '--pow-difficulty' to specify difficulty - --dm [...] + --dm [...] Send one or multiple DMs to one given user. DM messages will be encrypted and preserve privacy. The single recipient is specified via its public key, a string in the form of 'npub1...'. The first @@ -156,7 +156,7 @@ Options: --proxy Specify a proxy. Used by --add-relay --show-public-key - Show public key.. + Show public key --show-secret-key Show private, secret key. Protect this key --whoami @@ -186,6 +186,28 @@ Options: Listen to events, notifications and messages. This option listens to events and messages forever. To stop, type Control-C on your keyboard. E.g. this helps you get event ids for published notices + --add-contact + Add one or more contacts. Must be used in combination with --alias, + --key, --relay. If you want to add N new contacts, use --add-contact + and provide exactly N entries in each of the 3 extra arguments. E.g. + --add-contact --alias jane joe --key npub1JanesPublicKey + npub1JoesPublicKey --relay "wss://janes.relay.org" + "wss://joes.relay.org" + --remove-contact + Remove one or more contacts. Must be used in combination with + --alias. For each entry in --alias the corresponding contact will be + removed. E.g. --remove-contact --alias jane joe + --show-contacts + Display current contacts + --alias [...] + Provide one or multiple aliases (nicknames) for arguments + --add-contact and --remove-contact + --key [...] + Provide one or multiple public keys for argument --add-contact. They + have the form 'npub1SomeStrangeString' + --relay [...] + Provide one or multiple relays for argument --add-contact. They have + the form 'wss://some.relay.org' -h, --help Print help information (use `--help` for more detail) ``` diff --git a/VERSION b/VERSION index 4e379d2..bcab45a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.2 +0.0.3 diff --git a/help.txt b/help.txt index c13f611..f748bab 100644 --- a/help.txt +++ b/help.txt @@ -89,7 +89,7 @@ Options: --publish-pow [...] Publish one or multiple notes with proof-of-work (POW). Use also '--pow-difficulty' to specify difficulty - --dm [...] + --dm [...] Send one or multiple DMs to one given user. DM messages will be encrypted and preserve privacy. The single recipient is specified via its public key, a string in the form of 'npub1...'. The first @@ -115,7 +115,7 @@ Options: --proxy Specify a proxy. Used by --add-relay --show-public-key - Show public key.. + Show public key --show-secret-key Show private, secret key. Protect this key --whoami @@ -145,5 +145,27 @@ Options: Listen to events, notifications and messages. This option listens to events and messages forever. To stop, type Control-C on your keyboard. E.g. this helps you get event ids for published notices + --add-contact + Add one or more contacts. Must be used in combination with --alias, + --key, --relay. If you want to add N new contacts, use --add-contact + and provide exactly N entries in each of the 3 extra arguments. E.g. + --add-contact --alias jane joe --key npub1JanesPublicKey + npub1JoesPublicKey --relay "wss://janes.relay.org" + "wss://joes.relay.org" + --remove-contact + Remove one or more contacts. Must be used in combination with + --alias. For each entry in --alias the corresponding contact will be + removed. E.g. --remove-contact --alias jane joe + --show-contacts + Display current contacts + --alias [...] + Provide one or multiple aliases (nicknames) for arguments + --add-contact and --remove-contact + --key [...] + Provide one or multiple public keys for argument --add-contact. They + have the form 'npub1SomeStrangeString' + --relay [...] + Provide one or multiple relays for argument --add-contact. They have + the form 'wss://some.relay.org' -h, --help Print help information (use `--help` for more detail) diff --git a/src/main.rs b/src/main.rs index 658ec2d..cda1964 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,6 +43,7 @@ use update_informer::{registry, Check}; use url::Url; use nostr_sdk::{ + nostr::contact::Contact, nostr::key::{FromBech32, KeyError, Keys, ToBech32}, nostr::message::relay::RelayMessage, // nostr::util::nips::nip04::Error as Nip04Error, @@ -462,7 +463,7 @@ pub struct Args { /// is the recipient key, als further arguments are texts to be /// sent. E.g. '-dm 'npub1SomeStrangeNumbers "First msg" "Second msg"'. // Todo: add '-' to read from stdin or keyboard - #[arg(long, alias = "direct", value_name = "ARGS", num_args(0..), )] + #[arg(long, alias = "direct", value_name = "KEY+MSGS", num_args(0..), )] dm: Vec, /// Add one or multiple relays. A relay is specified via a URI @@ -498,7 +499,7 @@ pub struct Args { #[arg(long)] proxy: Option, - /// Show public key.. + /// Show public key. #[arg(long, default_value_t = false)] show_public_key: bool, @@ -546,6 +547,40 @@ pub struct Args { /// published notices. #[arg(short, long, default_value_t = false)] listen: bool, + + /// Add one or more contacts. Must be used in combination with + /// --alias, --key, --relay. If you want to add N new contacts, + /// use --add-contact and provide exactly N entries in each + /// of the 3 extra arguments. E.g. --add-contact --alias jane joe + /// --key npub1JanesPublicKey npub1JoesPublicKey + /// --relay "wss://janes.relay.org" "wss://joes.relay.org". + #[arg(long, default_value_t = false)] + add_contact: bool, + + /// Remove one or more contacts. Must be used in combination with + /// --alias. For each entry in --alias the corresponding contact will + /// be removed. E.g. --remove-contact --alias jane joe. + #[arg(long, default_value_t = false)] + remove_contact: bool, + + /// Display current contacts. + #[arg(long, default_value_t = false)] + show_contacts: bool, + + /// Provide one or multiple aliases (nicknames) for arguments + /// --add-contact and --remove-contact. + #[arg(long, value_name = "ALIAS", num_args(0..), )] + alias: Vec, + + /// Provide one or multiple public keys for argument + /// --add-contact. They have the form 'npub1SomeStrangeString'. + #[arg(long, value_name = "KEY", num_args(0..), )] + key: Vec, + + /// Provide one or multiple relays for argument + /// --add-contact. They have the form 'wss://some.relay.org'. + #[arg(long, value_name = "RELAY", num_args(0..), )] + relay: Vec, } impl Default for Args { @@ -586,6 +621,12 @@ impl Args { whoami: false, output: Output::default(), listen: false, + add_contact: false, + remove_contact: false, + show_contacts: false, + alias: Vec::new(), + key: Vec::new(), + relay: Vec::new(), } } } @@ -599,6 +640,7 @@ pub struct Credentials { public_key_bech32: String, // npub1... relays: Vec, metadata: Metadata, + contacts: Vec, } impl AsRef for Credentials { @@ -622,6 +664,7 @@ impl Credentials { public_key_bech32: "".to_owned(), relays: Vec::new(), metadata: Metadata::new(), + contacts: Vec::new(), } } @@ -1008,6 +1051,16 @@ pub(crate) fn is_relay_str(relay: &str) -> bool { } } +/// is this syntactically a valid relay string? +pub(crate) fn is_relay_url(relay: &Url) -> bool { + if relay.scheme() != "wss" { + return false; + } else if relay.host_str().is_none() { + return false; + } + true +} + /// Handle the --create_user CLI argument pub(crate) fn cli_create_user(ap: &mut Args) -> Result<(), Error> { if !ap.create_user { @@ -1281,6 +1334,58 @@ pub(crate) async fn cli_dm(client: &Client, ap: &mut Args) -> Result<(), Error> Ok(()) } +/// Handle the --add-conect CLI argument, write contacts from CLI args into creds data structure +pub(crate) async fn cli_add_contact(client: &Client, ap: &mut Args) -> Result<(), Error> { + // Todo + let anum = ap.alias.len(); + let knum = ap.key.len(); + let rnum = ap.relay.len(); + if (anum != knum) || (anum != rnum) || (knum != rnum) { + error!( + "--alias, --key, and --relay must have the same amount of entries. {:?} {:?} {:?} ", + anum, knum, rnum + ); + return Err(Error::MissingCliParameter); + } + + let mut i = 0; + while i < anum { + let key = Keys::from_bech32_public_key(&ap.key[i])?.public_key(); + if ap.alias[i].trim().is_empty() { + error!("Invalid user alias. Cannot be empty. Skipping this contact."); + i += 1; + continue; + } + if !is_relay_url(&ap.relay[i]) { + error!( + "Relay {:?} is not valid. Skipping this contact.", + ap.relay[i] + ); + i += 1; + continue; + } + ap.creds.contacts.push(Contact::new( + key, + ap.relay[i].to_string().clone(), + ap.alias[i].trim().to_string(), + )); + i += 1; + } + Ok(()) +} + +/// Handle the --add-conect CLI argument, write contacts from CLI args into creds data structure +pub(crate) async fn cli_remove_contact(client: &Client, ap: &mut Args) -> Result<(), Error> { + // Todo + let anum = ap.alias.len(); + let mut i = 0; + while i < anum { + ap.creds.contacts.retain(|x| x.alias != ap.alias[i].trim()); + i += 1; + } + Ok(()) +} + /// Utility function to print JSON object as JSON or as plain text pub(crate) fn print_json(json_data: &json::JsonValue, output: Output) { debug!("{:?}", json_data); @@ -1502,6 +1607,40 @@ async fn main() -> Result<(), Error> { } } + // Set contacts, first in local file, second in client + if ap.add_contact { + match crate::cli_add_contact(&client, &mut ap).await { + Ok(()) => { + info!("add_contact successful."); + } + Err(ref e) => { + error!("add_contact failed. Reported error is: {:?}", e); + } + } + } + if ap.remove_contact { + match crate::cli_remove_contact(&client, &mut ap).await { + Ok(()) => { + info!("remove_contact successful."); + } + Err(ref e) => { + error!("remove_contact failed. Reported error is: {:?}", e); + } + } + } + ap.creds.contacts.dedup_by(|a, b| a.alias == b.alias); + match client.set_contact_list(ap.creds.contacts.clone()).await { + Ok(()) => { + info!("set_contact_list successful."); + } + Err(ref e) => { + error!("set_contact_list failed. Reported error is: {:?}", e); + } + } + if ap.show_contacts { + println!("Contacts: {:?}", ap.creds.contacts); + } + // Publish a text note if !ap.publish.is_empty() { match crate::cli_publish(&client, &mut ap).await {