mirror of
https://github.com/mikedilger/gossip.git
synced 2024-09-19 19:46:50 +00:00
Public key import (and delete) [if you don't have a private key setup]
This commit is contained in:
parent
6b7be372da
commit
70a78551aa
@ -408,7 +408,11 @@ impl Overlord {
|
|||||||
}
|
}
|
||||||
"generate_private_key" => {
|
"generate_private_key" => {
|
||||||
let mut password: String = serde_json::from_str(&bus_message.json_payload)?;
|
let mut password: String = serde_json::from_str(&bus_message.json_payload)?;
|
||||||
GLOBALS.signer.write().await.generate_private_key(&password)?;
|
GLOBALS
|
||||||
|
.signer
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.generate_private_key(&password)?;
|
||||||
password.zeroize();
|
password.zeroize();
|
||||||
GLOBALS.signer.read().await.save_through_settings().await?;
|
GLOBALS.signer.read().await.save_through_settings().await?;
|
||||||
}
|
}
|
||||||
@ -417,7 +421,11 @@ impl Overlord {
|
|||||||
serde_json::from_str(&bus_message.json_payload)?;
|
serde_json::from_str(&bus_message.json_payload)?;
|
||||||
let pk = PrivateKey::try_from_bech32_string(&import_bech32)?;
|
let pk = PrivateKey::try_from_bech32_string(&import_bech32)?;
|
||||||
import_bech32.zeroize();
|
import_bech32.zeroize();
|
||||||
GLOBALS.signer.write().await.set_private_key(pk, &password)?;
|
GLOBALS
|
||||||
|
.signer
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.set_private_key(pk, &password)?;
|
||||||
password.zeroize();
|
password.zeroize();
|
||||||
GLOBALS.signer.read().await.save_through_settings().await?;
|
GLOBALS.signer.read().await.save_through_settings().await?;
|
||||||
}
|
}
|
||||||
@ -426,10 +434,31 @@ impl Overlord {
|
|||||||
serde_json::from_str(&bus_message.json_payload)?;
|
serde_json::from_str(&bus_message.json_payload)?;
|
||||||
let pk = PrivateKey::try_from_hex_string(&import_hex)?;
|
let pk = PrivateKey::try_from_hex_string(&import_hex)?;
|
||||||
import_hex.zeroize();
|
import_hex.zeroize();
|
||||||
GLOBALS.signer.write().await.set_private_key(pk, &password)?;
|
GLOBALS
|
||||||
|
.signer
|
||||||
|
.write()
|
||||||
|
.await
|
||||||
|
.set_private_key(pk, &password)?;
|
||||||
password.zeroize();
|
password.zeroize();
|
||||||
GLOBALS.signer.read().await.save_through_settings().await?;
|
GLOBALS.signer.read().await.save_through_settings().await?;
|
||||||
}
|
}
|
||||||
|
"import_pub" => {
|
||||||
|
let pubstr: String = serde_json::from_str(&bus_message.json_payload)?;
|
||||||
|
let maybe_pk1 = PublicKey::try_from_bech32_string(&pubstr);
|
||||||
|
let maybe_pk2 = PublicKey::try_from_hex_string(&pubstr);
|
||||||
|
if maybe_pk1.is_err() && maybe_pk2.is_err() {
|
||||||
|
*GLOBALS.status_message.write().await =
|
||||||
|
"Public key not recognized.".to_owned();
|
||||||
|
} else {
|
||||||
|
let pubkey = maybe_pk1.unwrap_or_else(|_| maybe_pk2.unwrap());
|
||||||
|
GLOBALS.signer.write().await.set_public_key(pubkey);
|
||||||
|
GLOBALS.signer.read().await.save_through_settings().await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"delete_pub" => {
|
||||||
|
GLOBALS.signer.write().await.clear_public_key();
|
||||||
|
GLOBALS.signer.read().await.save_through_settings().await?;
|
||||||
|
}
|
||||||
"save_relays" => {
|
"save_relays" => {
|
||||||
let dirty_relays: Vec<DbRelay> = GLOBALS
|
let dirty_relays: Vec<DbRelay> = GLOBALS
|
||||||
.relays
|
.relays
|
||||||
|
@ -3,35 +3,26 @@ use crate::globals::GLOBALS;
|
|||||||
use nostr_types::{EncryptedPrivateKey, Event, KeySecurity, PreEvent, PrivateKey, PublicKey};
|
use nostr_types::{EncryptedPrivateKey, Event, KeySecurity, PreEvent, PrivateKey, PublicKey};
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Signer {
|
pub struct Signer {
|
||||||
public: Option<PublicKey>,
|
public: Option<PublicKey>,
|
||||||
encrypted: Option<EncryptedPrivateKey>,
|
encrypted: Option<EncryptedPrivateKey>,
|
||||||
private: Option<PrivateKey>,
|
private: Option<PrivateKey>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Signer {
|
|
||||||
fn default() -> Signer {
|
|
||||||
Signer {
|
|
||||||
public: None,
|
|
||||||
encrypted: None,
|
|
||||||
private: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Signer {
|
impl Signer {
|
||||||
pub async fn load_from_settings(&mut self) {
|
pub async fn load_from_settings(&mut self) {
|
||||||
let settings = GLOBALS.settings.read().await;
|
let settings = GLOBALS.settings.read().await;
|
||||||
*self = Signer {
|
*self = Signer {
|
||||||
public: settings.public_key,
|
public: settings.public_key,
|
||||||
encrypted: settings.encrypted_private_key.clone(),
|
encrypted: settings.encrypted_private_key.clone(),
|
||||||
private: None
|
private: None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn save_through_settings(&self) -> Result<(), Error> {
|
pub async fn save_through_settings(&self) -> Result<(), Error> {
|
||||||
let mut settings = GLOBALS.settings.write().await;
|
let mut settings = GLOBALS.settings.write().await;
|
||||||
settings.public_key = self.public.clone();
|
settings.public_key = self.public;
|
||||||
settings.encrypted_private_key = self.encrypted.clone();
|
settings.encrypted_private_key = self.encrypted.clone();
|
||||||
settings.save().await
|
settings.save().await
|
||||||
}
|
}
|
||||||
@ -39,12 +30,23 @@ impl Signer {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn set_public_key(&mut self, pk: PublicKey) {
|
pub fn set_public_key(&mut self, pk: PublicKey) {
|
||||||
if self.private.is_some() {
|
if self.private.is_some() {
|
||||||
*GLOBALS.status_message.blocking_write() = "Ignored setting of public key (private key supercedes)".to_string();
|
*GLOBALS.status_message.blocking_write() =
|
||||||
|
"Ignored setting of public key (private key supercedes)".to_string();
|
||||||
} else {
|
} else {
|
||||||
self.public = Some(pk);
|
self.public = Some(pk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn clear_public_key(&mut self) {
|
||||||
|
if self.private.is_some() {
|
||||||
|
*GLOBALS.status_message.blocking_write() =
|
||||||
|
"Ignored clearing of public key (private key supercedes)".to_string();
|
||||||
|
} else {
|
||||||
|
self.public = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn set_encrypted_private_key(&mut self, epk: EncryptedPrivateKey) {
|
pub fn set_encrypted_private_key(&mut self, epk: EncryptedPrivateKey) {
|
||||||
if self.private.is_some() && self.encrypted.is_some() {
|
if self.private.is_some() && self.encrypted.is_some() {
|
||||||
@ -55,7 +57,7 @@ impl Signer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_private_key(&mut self, pk: PrivateKey, pass: &str) -> Result<(), Error> {
|
pub fn set_private_key(&mut self, pk: PrivateKey, pass: &str) -> Result<(), Error> {
|
||||||
self.encrypted = Some(pk.export_encrypted(&pass)?);
|
self.encrypted = Some(pk.export_encrypted(pass)?);
|
||||||
self.public = Some(pk.public_key());
|
self.public = Some(pk.public_key());
|
||||||
self.private = Some(pk);
|
self.private = Some(pk);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -65,8 +67,7 @@ impl Signer {
|
|||||||
if self.private.is_some() {
|
if self.private.is_some() {
|
||||||
// ignore, already unlocked
|
// ignore, already unlocked
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
} else if let Some(epk) = &self.encrypted {
|
||||||
else if let Some(epk) = &self.encrypted {
|
|
||||||
self.private = Some(epk.decrypt(pass)?);
|
self.private = Some(epk.decrypt(pass)?);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -91,7 +92,7 @@ impl Signer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn public_key(&self) -> Option<PublicKey> {
|
pub fn public_key(&self) -> Option<PublicKey> {
|
||||||
self.public.clone()
|
self.public
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encrypted_private_key(&self) -> Option<EncryptedPrivateKey> {
|
pub fn encrypted_private_key(&self) -> Option<EncryptedPrivateKey> {
|
||||||
@ -99,18 +100,14 @@ impl Signer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn key_security(&self) -> Option<KeySecurity> {
|
pub fn key_security(&self) -> Option<KeySecurity> {
|
||||||
if let Some(pk) = &self.private {
|
self.private.as_ref().map(|pk| pk.key_security())
|
||||||
Some(pk.key_security())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sign_preevent(&self, preevent: PreEvent, pow: Option<u8>) -> Result<Event, Error> {
|
pub fn sign_preevent(&self, preevent: PreEvent, pow: Option<u8>) -> Result<Event, Error> {
|
||||||
match &self.private {
|
match &self.private {
|
||||||
Some(pk) => match pow {
|
Some(pk) => match pow {
|
||||||
Some(pow) => Ok(Event::new_with_pow(preevent, &pk, pow)?),
|
Some(pow) => Ok(Event::new_with_pow(preevent, pk, pow)?),
|
||||||
None => Ok(Event::new(preevent, &pk)?),
|
None => Ok(Event::new(preevent, pk)?),
|
||||||
},
|
},
|
||||||
_ => Err(Error::NoPrivateKey),
|
_ => Err(Error::NoPrivateKey),
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ pub(super) fn update(app: &mut GossipUi, ctx: &Context, frame: &mut eframe::Fram
|
|||||||
let incoming_count: isize = match GLOBALS.incoming_events.try_read() {
|
let incoming_count: isize = match GLOBALS.incoming_events.try_read() {
|
||||||
Ok(v) => v.len() as isize,
|
Ok(v) => v.len() as isize,
|
||||||
Err(_) => -1,
|
Err(_) => -1,
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ui.with_layout(Layout::right_to_left(Align::TOP), |ui| {
|
ui.with_layout(Layout::right_to_left(Align::TOP), |ui| {
|
||||||
@ -586,7 +586,8 @@ fn render_content(app: &mut GossipUi, ui: &mut Ui, tag_re: ®ex::Regex, event:
|
|||||||
}
|
}
|
||||||
Tag::Hashtag(s) => {
|
Tag::Hashtag(s) => {
|
||||||
if ui.link(format!("#{}", s)).clicked() {
|
if ui.link(format!("#{}", s)).clicked() {
|
||||||
*GLOBALS.status_message.blocking_write() = "Gossip doesn't have a hashtag feed yet.".to_owned();
|
*GLOBALS.status_message.blocking_write() =
|
||||||
|
"Gossip doesn't have a hashtag feed yet.".to_owned();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -84,6 +84,7 @@ struct GossipUi {
|
|||||||
password: String,
|
password: String,
|
||||||
import_bech32: String,
|
import_bech32: String,
|
||||||
import_hex: String,
|
import_hex: String,
|
||||||
|
import_pub: String,
|
||||||
replying_to: Option<Id>,
|
replying_to: Option<Id>,
|
||||||
person_view_pubkey: Option<PublicKeyHex>,
|
person_view_pubkey: Option<PublicKeyHex>,
|
||||||
avatars: HashMap<PublicKeyHex, TextureHandle>,
|
avatars: HashMap<PublicKeyHex, TextureHandle>,
|
||||||
@ -154,6 +155,7 @@ impl GossipUi {
|
|||||||
password: "".to_owned(),
|
password: "".to_owned(),
|
||||||
import_bech32: "".to_owned(),
|
import_bech32: "".to_owned(),
|
||||||
import_hex: "".to_owned(),
|
import_hex: "".to_owned(),
|
||||||
|
import_pub: "".to_owned(),
|
||||||
replying_to: None,
|
replying_to: None,
|
||||||
person_view_pubkey: None,
|
person_view_pubkey: None,
|
||||||
avatars: HashMap::new(),
|
avatars: HashMap::new(),
|
||||||
@ -253,7 +255,10 @@ impl eframe::App for GossipUi {
|
|||||||
egui::TopBottomPanel::bottom("status").show(ctx, |ui| {
|
egui::TopBottomPanel::bottom("status").show(ctx, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if ui
|
if ui
|
||||||
.add(Label::new(GLOBALS.status_message.blocking_read().clone()).sense(Sense::click()))
|
.add(
|
||||||
|
Label::new(GLOBALS.status_message.blocking_read().clone())
|
||||||
|
.sense(Sense::click()),
|
||||||
|
)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
*GLOBALS.status_message.blocking_write() = "".to_string();
|
*GLOBALS.status_message.blocking_write() = "".to_string();
|
||||||
|
@ -36,7 +36,8 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr
|
|||||||
&app.new_relay_url
|
&app.new_relay_url
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
*GLOBALS.status_message.blocking_write() = "That's not a valid relay URL.".to_owned();
|
*GLOBALS.status_message.blocking_write() =
|
||||||
|
"That's not a valid relay URL.".to_owned();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -86,8 +86,7 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr
|
|||||||
*GLOBALS.status_message.blocking_write() =
|
*GLOBALS.status_message.blocking_write() =
|
||||||
"Exported key has been printed to the console standard output.".to_owned();
|
"Exported key has been printed to the console standard output.".to_owned();
|
||||||
}
|
}
|
||||||
Err(e) =>
|
Err(e) => *GLOBALS.status_message.blocking_write() = format!("{}", e),
|
||||||
*GLOBALS.status_message.blocking_write() = format!("{}", e),
|
|
||||||
}
|
}
|
||||||
app.password.zeroize();
|
app.password.zeroize();
|
||||||
app.password = "".to_owned();
|
app.password = "".to_owned();
|
||||||
@ -200,9 +199,7 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr
|
|||||||
app.password = "".to_owned();
|
app.password = "".to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.add_space(10.0);
|
ui.add_space(20.0);
|
||||||
ui.separator();
|
|
||||||
ui.add_space(10.0);
|
|
||||||
|
|
||||||
ui.heading("Import a hex private key");
|
ui.heading("Import a hex private key");
|
||||||
|
|
||||||
@ -230,5 +227,54 @@ pub(super) fn update(app: &mut GossipUi, _ctx: &Context, _frame: &mut eframe::Fr
|
|||||||
app.password.zeroize();
|
app.password.zeroize();
|
||||||
app.password = "".to_owned();
|
app.password = "".to_owned();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui.add_space(10.0);
|
||||||
|
ui.separator();
|
||||||
|
ui.add_space(10.0);
|
||||||
|
|
||||||
|
ui.heading("Public Key");
|
||||||
|
ui.add_space(10.0);
|
||||||
|
|
||||||
|
ui.label("You can just import your public key if you only want to view events and don't want to use gossip to create events. This will allow you to (eventually) sync your follow list and follow people on gossip without copying your private key here.");
|
||||||
|
|
||||||
|
if let Some(pk) = GLOBALS.signer.blocking_read().public_key() {
|
||||||
|
let pkhex: PublicKeyHex = pk.into();
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(&format!("Public Key (Hex): {}", pkhex.0));
|
||||||
|
if ui.add(CopyButton {}).clicked() {
|
||||||
|
ui.output().copied_text = pkhex.0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Ok(bech32) = pk.try_as_bech32_string() {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label(&format!("Public Key (bech32): {}", bech32));
|
||||||
|
if ui.add(CopyButton {}).clicked() {
|
||||||
|
ui.output().copied_text = bech32;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ui.button("Delete this public key").clicked() {
|
||||||
|
let _ = GLOBALS.to_overlord.send(BusMessage {
|
||||||
|
target: "overlord".to_string(),
|
||||||
|
kind: "delete_pub".to_string(),
|
||||||
|
json_payload: serde_json::to_string(&app.import_pub).unwrap(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ui.horizontal_wrapped(|ui| {
|
||||||
|
ui.label("Enter your public key");
|
||||||
|
ui.add(TextEdit::singleline(&mut app.import_pub).hint_text("npub1 or hex"));
|
||||||
|
if ui.button("Import a Public Key").clicked() {
|
||||||
|
let _ = GLOBALS.to_overlord.send(BusMessage {
|
||||||
|
target: "overlord".to_string(),
|
||||||
|
kind: "import_pub".to_string(),
|
||||||
|
json_payload: serde_json::to_string(&app.import_pub).unwrap(),
|
||||||
|
});
|
||||||
|
app.import_pub = "".to_owned();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user