simplify key storage

Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
kernelkind
2025-03-15 15:06:40 -04:00
parent 69b651bbc5
commit 1e05fa551d
6 changed files with 67 additions and 146 deletions

View File

@@ -1,8 +1,7 @@
use tracing::{debug, error, info};
use crate::{
KeyStorageResponse, KeyStorageType, MuteFun, Muted, RelaySpec, SingleUnkIdAction, UnknownIds,
UserAccount,
FileKeyStorage, MuteFun, Muted, RelaySpec, SingleUnkIdAction, UnknownIds, UserAccount,
};
use enostr::{ClientMessage, FilledKeypair, Keypair, RelayPool};
use nostrdb::{Filter, Ndb, Note, NoteBuilder, NoteKey, Subscription, Transaction};
@@ -309,7 +308,7 @@ pub struct AccountData {
pub struct Accounts {
currently_selected_account: Option<usize>,
accounts: Vec<UserAccount>,
key_store: KeyStorageType,
key_store: Option<FileKeyStorage>,
account_data: BTreeMap<[u8; 32], AccountData>,
forced_relays: BTreeSet<RelaySpec>,
bootstrap_relays: BTreeSet<RelaySpec>,
@@ -317,14 +316,24 @@ pub struct Accounts {
}
impl Accounts {
pub fn new(key_store: KeyStorageType, forced_relays: Vec<String>) -> Self {
let accounts = if let KeyStorageResponse::ReceivedResult(res) = key_store.get_keys() {
res.unwrap_or_default()
} else {
Vec::new()
pub fn new(key_store: Option<FileKeyStorage>, forced_relays: Vec<String>) -> Self {
let accounts = match &key_store {
Some(keystore) => match keystore.get_keys() {
Ok(k) => k,
Err(e) => {
tracing::error!("could not get keys: {e}");
Vec::new()
}
},
None => Vec::new(),
};
let currently_selected_account = if let Some(key_store) = &key_store {
get_selected_index(&accounts, key_store)
} else {
None
};
let currently_selected_account = get_selected_index(&accounts, &key_store);
let account_data = BTreeMap::new();
let forced_relays: BTreeSet<RelaySpec> = forced_relays
.into_iter()
@@ -367,7 +376,12 @@ impl Accounts {
pub fn remove_account(&mut self, index: usize) {
if let Some(account) = self.accounts.get(index) {
let _ = self.key_store.remove_key(account);
if let Some(key_store) = &self.key_store {
if let Err(e) = key_store.remove_key(account) {
tracing::error!("Could not remove account at index {index}: {e}");
}
}
self.accounts.remove(index);
if let Some(selected_index) = self.currently_selected_account {
@@ -426,7 +440,12 @@ impl Accounts {
"user provided nsec, but we already have npub {}. Upgrading to nsec",
pubkey
);
let _ = self.key_store.add_key(&account);
if let Some(key_store) = &self.key_store {
if let Err(e) = key_store.add_key(&account) {
tracing::error!("Could not add key for {:?}: {e}", account.pubkey);
}
}
self.accounts[contains_acc.index] = account;
} else {
@@ -435,7 +454,11 @@ impl Accounts {
contains_acc.index
} else {
info!("adding new account {}", pubkey);
let _ = self.key_store.add_key(&account);
if let Some(key_store) = &self.key_store {
if let Err(e) = key_store.add_key(&account) {
tracing::error!("Could not add key for {:?}: {e}", account.pubkey);
}
}
self.accounts.push(account);
self.accounts.len() - 1
};
@@ -493,13 +516,21 @@ impl Accounts {
pub fn select_account(&mut self, index: usize) {
if let Some(account) = self.accounts.get(index) {
self.currently_selected_account = Some(index);
self.key_store.select_key(Some(account.pubkey));
if let Some(key_store) = &self.key_store {
if let Err(e) = key_store.select_key(Some(account.pubkey)) {
tracing::error!("Could not select key {:?}: {e}", account.pubkey);
}
}
}
}
pub fn clear_selected_account(&mut self) {
self.currently_selected_account = None;
self.key_store.select_key(None);
if let Some(key_store) = &self.key_store {
if let Err(e) = key_store.select_key(None) {
tracing::error!("Could not select None key: {e}");
}
}
}
pub fn mutefun(&self) -> Box<MuteFun> {
@@ -794,14 +825,13 @@ enum RelayAction {
Remove,
}
fn get_selected_index(accounts: &[UserAccount], keystore: &KeyStorageType) -> Option<usize> {
fn get_selected_index(accounts: &[UserAccount], keystore: &FileKeyStorage) -> Option<usize> {
match keystore.get_selected_key() {
KeyStorageResponse::ReceivedResult(Ok(Some(pubkey))) => {
Ok(Some(pubkey)) => {
return accounts.iter().position(|account| account.pubkey == pubkey);
}
KeyStorageResponse::ReceivedResult(Err(e)) => error!("Error getting selected key: {}", e),
KeyStorageResponse::Waiting | KeyStorageResponse::ReceivedResult(Ok(None)) => {}
Ok(None) => {}
Err(e) => error!("Error getting selected key: {}", e),
};
None

View File

@@ -1,7 +1,7 @@
use crate::persist::{AppSizeHandler, ZoomHandler};
use crate::{
Accounts, AppContext, Args, DataPath, DataPathType, Directory, FileKeyStorage, Images,
KeyStorageType, NoteCache, RelayDebugView, ThemeHandler, UnknownIds,
NoteCache, RelayDebugView, ThemeHandler, UnknownIds,
};
use egui::ThemePreference;
use egui_winit::clipboard::Clipboard;
@@ -149,12 +149,12 @@ impl Notedeck {
let keystore = if parsed_args.use_keystore {
let keys_path = path.path(DataPathType::Keys);
let selected_key_path = path.path(DataPathType::SelectedKey);
KeyStorageType::FileSystem(FileKeyStorage::new(
Some(FileKeyStorage::new(
Directory::new(keys_path),
Directory::new(selected_key_path),
))
} else {
KeyStorageType::None
None
};
let mut accounts = Accounts::new(keystore, parsed_args.relays.clone());

View File

@@ -44,9 +44,7 @@ pub use persist::*;
pub use relay_debug::RelayDebugView;
pub use relayspec::RelaySpec;
pub use result::Result;
pub use storage::{
DataPath, DataPathType, Directory, FileKeyStorage, KeyStorageResponse, KeyStorageType,
};
pub use storage::{DataPath, DataPathType, Directory, FileKeyStorage};
pub use style::NotedeckTextStyle;
pub use theme::ColorTheme;
pub use time::time_ago_since;

View File

@@ -1,10 +1,7 @@
use crate::Result;
use enostr::{Keypair, Pubkey, SerializableKeypair};
use super::{
file_storage::{delete_file, write_file, Directory},
key_storage_impl::KeyStorageResponse,
};
use super::file_storage::{delete_file, write_file, Directory};
static SELECTED_PUBKEY_FILE_NAME: &str = "selected_pubkey";
@@ -23,7 +20,7 @@ impl FileKeyStorage {
}
}
fn add_key_internal(&self, key: &Keypair) -> Result<()> {
pub fn add_key(&self, key: &Keypair) -> Result<()> {
write_file(
&self.keys_directory.file_path,
key.pubkey.hex(),
@@ -31,7 +28,7 @@ impl FileKeyStorage {
)
}
fn get_keys_internal(&self) -> Result<Vec<Keypair>> {
pub fn get_keys(&self) -> Result<Vec<Keypair>> {
let keys = self
.keys_directory
.get_files()?
@@ -42,11 +39,11 @@ impl FileKeyStorage {
Ok(keys)
}
fn remove_key_internal(&self, key: &Keypair) -> Result<()> {
pub fn remove_key(&self, key: &Keypair) -> Result<()> {
delete_file(&self.keys_directory.file_path, key.pubkey.hex())
}
fn get_selected_pubkey(&self) -> Result<Option<Pubkey>> {
pub fn get_selected_key(&self) -> Result<Option<Pubkey>> {
match self
.selected_key_directory
.get_file(SELECTED_PUBKEY_FILE_NAME.to_owned())
@@ -57,7 +54,7 @@ impl FileKeyStorage {
}
}
fn select_pubkey(&self, pubkey: Option<Pubkey>) -> Result<()> {
pub fn select_key(&self, pubkey: Option<Pubkey>) -> Result<()> {
if let Some(pubkey) = pubkey {
write_file(
&self.selected_key_directory.file_path,
@@ -80,28 +77,6 @@ impl FileKeyStorage {
}
}
impl FileKeyStorage {
pub fn get_keys(&self) -> KeyStorageResponse<Vec<enostr::Keypair>> {
KeyStorageResponse::ReceivedResult(self.get_keys_internal())
}
pub fn add_key(&self, key: &enostr::Keypair) -> KeyStorageResponse<()> {
KeyStorageResponse::ReceivedResult(self.add_key_internal(key))
}
pub fn remove_key(&self, key: &enostr::Keypair) -> KeyStorageResponse<()> {
KeyStorageResponse::ReceivedResult(self.remove_key_internal(key))
}
pub fn get_selected_key(&self) -> KeyStorageResponse<Option<Pubkey>> {
KeyStorageResponse::ReceivedResult(self.get_selected_pubkey())
}
pub fn select_key(&self, key: Option<Pubkey>) -> KeyStorageResponse<()> {
KeyStorageResponse::ReceivedResult(self.select_pubkey(key))
}
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
@@ -128,27 +103,21 @@ mod tests {
let storage = FileKeyStorage::mock().unwrap();
let resp = storage.add_key(&kp);
assert_eq!(resp, KeyStorageResponse::ReceivedResult(Ok(())));
assert!(resp.is_ok());
assert_num_storage(&storage.get_keys(), 1);
assert_eq!(
storage.remove_key(&kp),
KeyStorageResponse::ReceivedResult(Ok(()))
);
assert!(storage.remove_key(&kp).is_ok());
assert_num_storage(&storage.get_keys(), 0);
}
fn assert_num_storage(keys_response: &KeyStorageResponse<Vec<Keypair>>, n: usize) {
fn assert_num_storage(keys_response: &Result<Vec<Keypair>>, n: usize) {
match keys_response {
KeyStorageResponse::ReceivedResult(Ok(keys)) => {
Ok(keys) => {
assert_eq!(keys.len(), n);
}
KeyStorageResponse::ReceivedResult(Err(_e)) => {
Err(_e) => {
panic!("could not get keys");
}
KeyStorageResponse::Waiting => {
panic!("did not receive result");
}
}
}
@@ -160,10 +129,10 @@ mod tests {
let _ = storage.add_key(&kp);
assert_num_storage(&storage.get_keys(), 1);
let resp = storage.select_pubkey(Some(kp.pubkey));
let resp = storage.select_key(Some(kp.pubkey));
assert!(resp.is_ok());
let resp = storage.get_selected_pubkey();
let resp = storage.get_selected_key();
assert!(resp.is_ok());
}
@@ -174,7 +143,7 @@ mod tests {
// Should return Ok(None) when no key has been selected
match storage.get_selected_key() {
KeyStorageResponse::ReceivedResult(Ok(None)) => (), // This is what we expect
Ok(None) => (), // This is what we expect
other => panic!("Expected Ok(None), got {:?}", other),
}
}

View File

@@ -1,73 +0,0 @@
use enostr::{Keypair, Pubkey};
use super::file_key_storage::FileKeyStorage;
use crate::Result;
#[derive(Debug, PartialEq)]
pub enum KeyStorageType {
None,
FileSystem(FileKeyStorage),
}
#[allow(dead_code)]
#[derive(Debug)]
pub enum KeyStorageResponse<R> {
Waiting,
ReceivedResult(Result<R>),
}
impl<R: PartialEq> PartialEq for KeyStorageResponse<R> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(KeyStorageResponse::Waiting, KeyStorageResponse::Waiting) => true,
(
KeyStorageResponse::ReceivedResult(Ok(r1)),
KeyStorageResponse::ReceivedResult(Ok(r2)),
) => r1 == r2,
(
KeyStorageResponse::ReceivedResult(Err(_)),
KeyStorageResponse::ReceivedResult(Err(_)),
) => true,
_ => false,
}
}
}
impl KeyStorageType {
pub fn get_keys(&self) -> KeyStorageResponse<Vec<Keypair>> {
match self {
Self::None => KeyStorageResponse::ReceivedResult(Ok(Vec::new())),
Self::FileSystem(f) => f.get_keys(),
}
}
pub fn add_key(&self, key: &Keypair) -> KeyStorageResponse<()> {
let _ = key;
match self {
Self::None => KeyStorageResponse::ReceivedResult(Ok(())),
Self::FileSystem(f) => f.add_key(key),
}
}
pub fn remove_key(&self, key: &Keypair) -> KeyStorageResponse<()> {
let _ = key;
match self {
Self::None => KeyStorageResponse::ReceivedResult(Ok(())),
Self::FileSystem(f) => f.remove_key(key),
}
}
pub fn get_selected_key(&self) -> KeyStorageResponse<Option<Pubkey>> {
match self {
Self::None => KeyStorageResponse::ReceivedResult(Ok(None)),
Self::FileSystem(f) => f.get_selected_key(),
}
}
pub fn select_key(&self, key: Option<Pubkey>) -> KeyStorageResponse<()> {
match self {
Self::None => KeyStorageResponse::ReceivedResult(Ok(())),
Self::FileSystem(f) => f.select_key(key),
}
}
}

View File

@@ -3,6 +3,3 @@ mod file_storage;
pub use file_key_storage::FileKeyStorage;
pub use file_storage::{delete_file, write_file, DataPath, DataPathType, Directory};
pub mod key_storage_impl;
pub use key_storage_impl::{KeyStorageResponse, KeyStorageType};