notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit 536f7579a90042871772801566032fe4f59bc336
parent 12743b446932bbc67e0d81e6345cbfb7e3bc6e6e
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 27 Nov 2024 09:19:34 -0800

Merge: user can upgrade their npub -> nsec #485

William Casarin (2):
      refactor: make LoginAction a bit safer

kernelkind (1):
      user can upgrade their npub -> nsec

Diffstat:
Msrc/accounts/mod.rs | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 59 insertions(+), 18 deletions(-)

diff --git a/src/accounts/mod.rs b/src/accounts/mod.rs @@ -1,7 +1,7 @@ use std::cmp::Ordering; use enostr::{FilledKeypair, FullKeypair, Keypair}; -use nostrdb::Ndb; +use nostrdb::{Ndb, Transaction}; use crate::{ column::Columns, @@ -14,6 +14,7 @@ use crate::{ accounts::{AccountsView, AccountsViewResponse}, }, unknowns::SingleUnkIdAction, + unknowns::UnknownIds, user_account::UserAccount, }; use tracing::{error, info}; @@ -138,27 +139,45 @@ impl Accounts { } } - pub fn has_account_pubkey(&self, pubkey: &[u8; 32]) -> bool { - for account in &self.accounts { - if account.pubkey.bytes() == pubkey { - return true; + fn contains_account(&self, pubkey: &[u8; 32]) -> Option<ContainsAccount> { + for (index, account) in self.accounts.iter().enumerate() { + let has_pubkey = account.pubkey.bytes() == pubkey; + let has_nsec = account.secret_key.is_some(); + if has_pubkey { + return Some(ContainsAccount { has_nsec, index }); } } - false + None } #[must_use = "UnknownIdAction's must be handled. Use .process_unknown_id_action()"] - pub fn add_account(&mut self, account: Keypair) -> SingleUnkIdAction { - if self.has_account_pubkey(account.pubkey.bytes()) { - info!("already have account, not adding {}", account.pubkey); - return SingleUnkIdAction::pubkey(account.pubkey); - } + pub fn add_account(&mut self, account: Keypair) -> LoginAction { + let pubkey = account.pubkey; + let switch_to_index = if let Some(contains_acc) = self.contains_account(pubkey.bytes()) { + if account.secret_key.is_some() && !contains_acc.has_nsec { + info!( + "user provided nsec, but we already have npub {}. Upgrading to nsec", + pubkey + ); + let _ = self.key_store.add_key(&account); - let _ = self.key_store.add_key(&account); - let pk = account.pubkey; - self.accounts.push(account); - SingleUnkIdAction::pubkey(pk) + self.accounts[contains_acc.index] = account; + } else { + info!("already have account, not adding {}", pubkey); + } + contains_acc.index + } else { + info!("adding new account {}", pubkey); + let _ = self.key_store.add_key(&account); + self.accounts.push(account); + self.accounts.len() - 1 + }; + + LoginAction { + unk: SingleUnkIdAction::pubkey(pubkey), + switch_to_index, + } } pub fn num_accounts(&self) -> usize { @@ -217,12 +236,34 @@ pub fn process_login_view_response( manager: &mut Accounts, response: AccountLoginResponse, ) -> SingleUnkIdAction { - let r = match response { + let login_action = match response { AccountLoginResponse::CreateNew => { manager.add_account(FullKeypair::generate().to_keypair()) } AccountLoginResponse::LoginWith(keypair) => manager.add_account(keypair), }; - manager.select_account(manager.num_accounts() - 1); - r + manager.select_account(login_action.switch_to_index); + login_action.unk +} + +#[must_use = "You must call process_login_action on this to handle unknown ids"] +pub struct LoginAction { + unk: SingleUnkIdAction, + pub switch_to_index: usize, +} + +impl LoginAction { + // Simple wrapper around processing the unknown action to expose too + // much internal logic. This allows us to have a must_use on our + // LoginAction type, otherwise the SingleUnkIdAction's must_use will + // be lost when returned in the login action + pub fn process_action(&mut self, ids: &mut UnknownIds, ndb: &Ndb, txn: &Transaction) { + self.unk.process_action(ids, ndb, txn); + } +} + +#[derive(Default)] +struct ContainsAccount { + pub has_nsec: bool, + pub index: usize, }