diff --git a/src/comms.rs b/src/comms.rs index db75a30a..9863f75b 100644 --- a/src/comms.rs +++ b/src/comms.rs @@ -5,6 +5,7 @@ use nostr_types::{Event, Id, IdHex, Metadata, PublicKey, PublicKeyHex, RelayUrl, pub enum ToOverlordMessage { AddRelay(RelayUrl), AdvertiseRelayList, + ChangePassphrase(String, String), DeletePub, DeletePriv(String), DropRelay(RelayUrl), diff --git a/src/overlord/mod.rs b/src/overlord/mod.rs index 740c6d6f..24e67c44 100644 --- a/src/overlord/mod.rs +++ b/src/overlord/mod.rs @@ -447,6 +447,11 @@ impl Overlord { ToOverlordMessage::AdvertiseRelayList => { self.advertise_relay_list().await?; } + ToOverlordMessage::ChangePassphrase(mut old, mut new) => { + GLOBALS.signer.change_passphrase(&old, &new)?; + old.zeroize(); + new.zeroize(); + } ToOverlordMessage::DeletePub => { GLOBALS.signer.clear_public_key(); GLOBALS.signer.save_through_settings().await?; diff --git a/src/signer.rs b/src/signer.rs index 1df66dce..e0c101aa 100644 --- a/src/signer.rs +++ b/src/signer.rs @@ -94,6 +94,26 @@ impl Signer { } } + pub fn change_passphrase(&self, old: &str, new: &str) -> Result<(), Error> { + let maybe_encrypted = self.encrypted.read().to_owned(); + match maybe_encrypted { + Some(epk) => { + // Test password + let pk = epk.decrypt(old)?; + let epk = pk.export_encrypted(new, DEFAULT_LOG_N)?; + *self.encrypted.write() = Some(epk); + task::spawn(async move { + if let Err(e) = GLOBALS.signer.save_through_settings().await { + tracing::error!("{}", e); + } + *GLOBALS.status_message.write().await = "Passphrase changed.".to_owned() + }); + Ok(()) + } + _ => Err(Error::NoPrivateKey), + } + } + pub fn generate_private_key(&self, pass: &str) -> Result<(), Error> { let pk = PrivateKey::generate(); *self.encrypted.write() = Some(pk.export_encrypted(pass, DEFAULT_LOG_N)?); @@ -133,7 +153,8 @@ impl Signer { } pub fn export_private_key_bech32(&self, pass: &str) -> Result { - match &*self.encrypted.read() { + let maybe_encrypted = self.encrypted.read().to_owned(); + match maybe_encrypted { Some(epk) => { // Test password let mut pk = epk.decrypt(pass)?; @@ -157,7 +178,8 @@ impl Signer { } pub fn export_private_key_hex(&self, pass: &str) -> Result { - match &*self.encrypted.read() { + let maybe_encrypted = self.encrypted.read().to_owned(); + match maybe_encrypted { Some(epk) => { // Test password let mut pk = epk.decrypt(pass)?; diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 2c8f3375..daf09f5a 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -123,6 +123,7 @@ struct GossipUi { follow_pubkey_at_relay: String, password: String, password2: String, + password3: String, del_password: String, new_metadata_fieldname: String, import_priv: String, @@ -134,6 +135,7 @@ impl Drop for GossipUi { fn drop(&mut self) { self.password.zeroize(); self.password2.zeroize(); + self.password3.zeroize(); self.del_password.zeroize(); } } @@ -250,6 +252,7 @@ impl GossipUi { follow_pubkey_at_relay: "".to_owned(), password: "".to_owned(), password2: "".to_owned(), + password3: "".to_owned(), del_password: "".to_owned(), new_metadata_fieldname: String::new(), import_priv: "".to_owned(), diff --git a/src/ui/you/mod.rs b/src/ui/you/mod.rs index 24a13061..4e7684ec 100644 --- a/src/ui/you/mod.rs +++ b/src/ui/you/mod.rs @@ -62,6 +62,12 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, _frame: &mut eframe::Fra ui.separator(); ui.add_space(10.0); + offer_change_password(app, ui); + + ui.add_space(10.0); + ui.separator(); + ui.add_space(10.0); + offer_export_priv_key(app, ui); ui.add_space(10.0); @@ -211,6 +217,51 @@ fn show_priv_key_detail(_app: &mut GossipUi, ui: &mut Ui) { } } +fn offer_change_password(app: &mut GossipUi, ui: &mut Ui) { + ui.heading("Change Passphrase"); + + ui.horizontal(|ui| { + ui.add_space(10.0); + ui.label("Enter Existing Passphrase: "); + ui.add(TextEdit::singleline(&mut app.password).password(true)); + }); + + ui.horizontal(|ui| { + ui.add_space(10.0); + ui.label("Enter New Passphrase: "); + ui.add(TextEdit::singleline(&mut app.password2).password(true)); + }); + + ui.horizontal(|ui| { + ui.add_space(10.0); + ui.label("Repeat New Passphrase: "); + ui.add(TextEdit::singleline(&mut app.password3).password(true)); + }); + + if ui.button("Change Passphrase").clicked() { + if app.password2 != app.password3 { + *GLOBALS.status_message.blocking_write() = "Passphrases do not match.".to_owned(); + app.password2.zeroize(); + app.password2 = "".to_owned(); + app.password3.zeroize(); + app.password3 = "".to_owned(); + } else { + let _ = GLOBALS + .to_overlord + .send(ToOverlordMessage::ChangePassphrase( + app.password.clone(), + app.password2.clone(), + )); + app.password.zeroize(); + app.password = "".to_owned(); + app.password2.zeroize(); + app.password2 = "".to_owned(); + app.password3.zeroize(); + app.password3 = "".to_owned(); + } + } +} + fn offer_export_priv_key(app: &mut GossipUi, ui: &mut Ui) { let key_security = GLOBALS.signer.key_security().unwrap();