From 6b7be372daefd85f7820f17ff6bbc316888be7f1 Mon Sep 17 00:00:00 2001 From: Mike Dilger Date: Thu, 5 Jan 2023 21:43:16 +1300 Subject: [PATCH] Rewrite of Signer --- src/overlord/mod.rs | 63 +++---------------- src/signer.rs | 147 +++++++++++++++++++++++++++----------------- 2 files changed, 98 insertions(+), 112 deletions(-) diff --git a/src/overlord/mod.rs b/src/overlord/mod.rs index cc9f9dd3..a796a601 100644 --- a/src/overlord/mod.rs +++ b/src/overlord/mod.rs @@ -78,17 +78,8 @@ impl Overlord { } pub async fn run_inner(&mut self) -> Result<(), Error> { - // Load Signer (we cannot unlock yet, UI will have to drive that after - // prompting for a password) - if let Some(epk) = GLOBALS - .settings - .read() - .await - .encrypted_private_key - .to_owned() - { - GLOBALS.signer.write().await.load_encrypted_private_key(epk); - } + // Load signer from settings + GLOBALS.signer.write().await.load_from_settings().await; // FIXME - if this needs doing, it should be done dynamically as // new people are encountered, not batch-style on startup. @@ -417,65 +408,27 @@ impl Overlord { } "generate_private_key" => { let mut password: String = serde_json::from_str(&bus_message.json_payload)?; - let epk = GLOBALS - .signer - .write() - .await - .generate_private_key(&password)?; + GLOBALS.signer.write().await.generate_private_key(&password)?; password.zeroize(); - - // Export and save private key - let public_key = GLOBALS.signer.read().await.public_key().unwrap(); - { - let mut settings = GLOBALS.settings.write().await; - settings.encrypted_private_key = Some(epk); - settings.public_key = Some(public_key); - settings.save().await?; - } + GLOBALS.signer.read().await.save_through_settings().await?; } "import_bech32" => { let (mut import_bech32, mut password): (String, String) = serde_json::from_str(&bus_message.json_payload)?; let pk = PrivateKey::try_from_bech32_string(&import_bech32)?; import_bech32.zeroize(); - let epk = pk.export_encrypted(&password)?; - { - let mut signer = GLOBALS.signer.write().await; - signer.load_encrypted_private_key(epk.clone()); - signer.unlock_encrypted_private_key(&password)?; - } + GLOBALS.signer.write().await.set_private_key(pk, &password)?; password.zeroize(); - - // Save - let public_key = GLOBALS.signer.read().await.public_key().unwrap(); - { - let mut settings = GLOBALS.settings.write().await; - settings.encrypted_private_key = Some(epk); - settings.public_key = Some(public_key); - settings.save().await?; - } + GLOBALS.signer.read().await.save_through_settings().await?; } "import_hex" => { let (mut import_hex, mut password): (String, String) = serde_json::from_str(&bus_message.json_payload)?; let pk = PrivateKey::try_from_hex_string(&import_hex)?; import_hex.zeroize(); - let epk = pk.export_encrypted(&password)?; - { - let mut signer = GLOBALS.signer.write().await; - signer.load_encrypted_private_key(epk.clone()); - signer.unlock_encrypted_private_key(&password)?; - } + GLOBALS.signer.write().await.set_private_key(pk, &password)?; password.zeroize(); - - // Save - let public_key = GLOBALS.signer.read().await.public_key().unwrap(); - { - let mut settings = GLOBALS.settings.write().await; - settings.encrypted_private_key = Some(epk); - settings.public_key = Some(public_key); - settings.save().await?; - } + GLOBALS.signer.read().await.save_through_settings().await?; } "save_relays" => { let dirty_relays: Vec = GLOBALS diff --git a/src/signer.rs b/src/signer.rs index 9e05721f..4dc59d9a 100644 --- a/src/signer.rs +++ b/src/signer.rs @@ -3,65 +3,103 @@ use crate::globals::GLOBALS; use nostr_types::{EncryptedPrivateKey, Event, KeySecurity, PreEvent, PrivateKey, PublicKey}; use tokio::task; -pub enum Signer { - Fresh, - Encrypted(EncryptedPrivateKey), - Ready(PrivateKey, EncryptedPrivateKey), +pub struct Signer { + public: Option, + encrypted: Option, + private: Option, } impl Default for Signer { fn default() -> Signer { - Signer::Fresh + Signer { + public: None, + encrypted: None, + private: None, + } } } impl Signer { - pub fn load_encrypted_private_key(&mut self, epk: EncryptedPrivateKey) { - *self = Signer::Encrypted(epk); + pub async fn load_from_settings(&mut self) { + let settings = GLOBALS.settings.read().await; + *self = Signer { + public: settings.public_key, + encrypted: settings.encrypted_private_key.clone(), + private: None + }; + } + + pub async fn save_through_settings(&self) -> Result<(), Error> { + let mut settings = GLOBALS.settings.write().await; + settings.public_key = self.public.clone(); + settings.encrypted_private_key = self.encrypted.clone(); + settings.save().await + } + + #[allow(dead_code)] + pub fn set_public_key(&mut self, pk: PublicKey) { + if self.private.is_some() { + *GLOBALS.status_message.blocking_write() = "Ignored setting of public key (private key supercedes)".to_string(); + } else { + self.public = Some(pk); + } + } + + #[allow(dead_code)] + pub fn set_encrypted_private_key(&mut self, epk: EncryptedPrivateKey) { + if self.private.is_some() && self.encrypted.is_some() { + // ignore, epk supercedes + } else { + self.encrypted = Some(epk); + } + } + + pub fn set_private_key(&mut self, pk: PrivateKey, pass: &str) -> Result<(), Error> { + self.encrypted = Some(pk.export_encrypted(&pass)?); + self.public = Some(pk.public_key()); + self.private = Some(pk); + Ok(()) } pub fn unlock_encrypted_private_key(&mut self, pass: &str) -> Result<(), Error> { - if let Signer::Encrypted(epk) = self { - *self = Signer::Ready(epk.decrypt(pass)?, epk.clone()); + if self.private.is_some() { + // ignore, already unlocked + Ok(()) + } + else if let Some(epk) = &self.encrypted { + self.private = Some(epk.decrypt(pass)?); Ok(()) } else { Err(Error::NoPrivateKey) } } - pub fn generate_private_key(&mut self, pass: &str) -> Result { + pub fn generate_private_key(&mut self, pass: &str) -> Result<(), Error> { let pk = PrivateKey::generate(); - let epk = pk.export_encrypted(pass)?; - *self = Signer::Ready(pk, epk.clone()); - Ok(epk) + self.encrypted = Some(pk.export_encrypted(pass)?); + self.public = Some(pk.public_key()); + self.private = Some(pk); + Ok(()) } pub fn is_loaded(&self) -> bool { - matches!(self, Signer::Encrypted(_)) || matches!(self, Signer::Ready(_, _)) + self.encrypted.is_some() || self.private.is_some() } pub fn is_ready(&self) -> bool { - matches!(self, Signer::Ready(_, _)) + self.private.is_some() } pub fn public_key(&self) -> Option { - if let Signer::Ready(pk, _) = self { - Some(pk.public_key()) - } else { - None - } + self.public.clone() } pub fn encrypted_private_key(&self) -> Option { - if let Signer::Ready(_, epk) = self { - Some(epk.clone()) - } else { - None - } + self.encrypted.clone() } pub fn key_security(&self) -> Option { - if let Signer::Ready(pk, _) = self { + if let Some(pk) = &self.private { Some(pk.key_security()) } else { None @@ -69,35 +107,33 @@ impl Signer { } pub fn sign_preevent(&self, preevent: PreEvent, pow: Option) -> Result { - match self { - Signer::Ready(pk, _) => match pow { - Some(pow) => Ok(Event::new_with_pow(preevent, pk, pow)?), - None => Ok(Event::new(preevent, pk)?), + match &self.private { + Some(pk) => match pow { + Some(pow) => Ok(Event::new_with_pow(preevent, &pk, pow)?), + None => Ok(Event::new(preevent, &pk)?), }, _ => Err(Error::NoPrivateKey), } } pub fn export_private_key_bech32(&mut self, pass: &str) -> Result { - match self { - Signer::Ready(_, epk) => { + match &self.encrypted { + Some(epk) => { + // Test password let mut pk = epk.decrypt(pass)?; + let output = pk.try_as_bech32_string()?; // We have to regenerate encrypted private key because it may have fallen from - // medium to weak security. + // medium to weak security. And then we need to save that let epk = pk.export_encrypted(pass)?; - - // And then we have to save that - let mut settings = GLOBALS.settings.blocking_write(); - settings.encrypted_private_key = Some(epk.clone()); + self.encrypted = Some(epk); + self.private = Some(pk); task::spawn(async move { - if let Err(e) = settings.save().await { + if let Err(e) = GLOBALS.signer.read().await.save_through_settings().await { tracing::error!("{}", e); } }); - - *self = Signer::Ready(pk, epk); Ok(output) } _ => Err(Error::NoPrivateKey), @@ -105,25 +141,23 @@ impl Signer { } pub fn export_private_key_hex(&mut self, pass: &str) -> Result { - match self { - Signer::Ready(_, epk) => { + match &self.encrypted { + Some(epk) => { + // Test password let mut pk = epk.decrypt(pass)?; + let output = pk.as_hex_string(); // We have to regenerate encrypted private key because it may have fallen from - // medium to weak security. + // medium to weak security. And then we need to save that let epk = pk.export_encrypted(pass)?; - - // And then we have to save that - let mut settings = GLOBALS.settings.blocking_write(); - settings.encrypted_private_key = Some(epk.clone()); + self.encrypted = Some(epk); + self.private = Some(pk); task::spawn(async move { - if let Err(e) = settings.save().await { + if let Err(e) = GLOBALS.signer.read().await.save_through_settings().await { tracing::error!("{}", e); } }); - - *self = Signer::Ready(pk, epk); Ok(output) } _ => Err(Error::NoPrivateKey), @@ -131,20 +165,19 @@ impl Signer { } pub fn delete_identity(&mut self, pass: &str) -> Result<(), Error> { - match self { - Signer::Ready(_, epk) => { + match &self.encrypted { + Some(epk) => { // Verify their password let _pk = epk.decrypt(pass)?; - // Delete from database - let mut settings = GLOBALS.settings.blocking_write(); - settings.encrypted_private_key = None; + self.private = None; + self.encrypted = None; + self.public = None; task::spawn(async move { - if let Err(e) = settings.save().await { + if let Err(e) = GLOBALS.signer.read().await.save_through_settings().await { tracing::error!("{}", e); } }); - *self = Signer::Fresh; Ok(()) } _ => Err(Error::NoPrivateKey),