mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-19 01:24:21 +01:00
@@ -1,8 +1,7 @@
|
|||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
KeyStorageResponse, KeyStorageType, MuteFun, Muted, RelaySpec, SingleUnkIdAction, UnknownIds,
|
FileKeyStorage, MuteFun, Muted, RelaySpec, SingleUnkIdAction, UnknownIds, UserAccount,
|
||||||
UserAccount,
|
|
||||||
};
|
};
|
||||||
use enostr::{ClientMessage, FilledKeypair, Keypair, RelayPool};
|
use enostr::{ClientMessage, FilledKeypair, Keypair, RelayPool};
|
||||||
use nostrdb::{Filter, Ndb, Note, NoteBuilder, NoteKey, Subscription, Transaction};
|
use nostrdb::{Filter, Ndb, Note, NoteBuilder, NoteKey, Subscription, Transaction};
|
||||||
@@ -309,7 +308,7 @@ pub struct AccountData {
|
|||||||
pub struct Accounts {
|
pub struct Accounts {
|
||||||
currently_selected_account: Option<usize>,
|
currently_selected_account: Option<usize>,
|
||||||
accounts: Vec<UserAccount>,
|
accounts: Vec<UserAccount>,
|
||||||
key_store: KeyStorageType,
|
key_store: Option<FileKeyStorage>,
|
||||||
account_data: BTreeMap<[u8; 32], AccountData>,
|
account_data: BTreeMap<[u8; 32], AccountData>,
|
||||||
forced_relays: BTreeSet<RelaySpec>,
|
forced_relays: BTreeSet<RelaySpec>,
|
||||||
bootstrap_relays: BTreeSet<RelaySpec>,
|
bootstrap_relays: BTreeSet<RelaySpec>,
|
||||||
@@ -317,14 +316,24 @@ pub struct Accounts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Accounts {
|
impl Accounts {
|
||||||
pub fn new(key_store: KeyStorageType, forced_relays: Vec<String>) -> Self {
|
pub fn new(key_store: Option<FileKeyStorage>, forced_relays: Vec<String>) -> Self {
|
||||||
let accounts = if let KeyStorageResponse::ReceivedResult(res) = key_store.get_keys() {
|
let accounts = match &key_store {
|
||||||
res.unwrap_or_default()
|
Some(keystore) => match keystore.get_keys() {
|
||||||
} else {
|
Ok(k) => k,
|
||||||
Vec::new()
|
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 account_data = BTreeMap::new();
|
||||||
let forced_relays: BTreeSet<RelaySpec> = forced_relays
|
let forced_relays: BTreeSet<RelaySpec> = forced_relays
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -367,7 +376,12 @@ impl Accounts {
|
|||||||
|
|
||||||
pub fn remove_account(&mut self, index: usize) {
|
pub fn remove_account(&mut self, index: usize) {
|
||||||
if let Some(account) = self.accounts.get(index) {
|
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);
|
self.accounts.remove(index);
|
||||||
|
|
||||||
if let Some(selected_index) = self.currently_selected_account {
|
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",
|
"user provided nsec, but we already have npub {}. Upgrading to nsec",
|
||||||
pubkey
|
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;
|
self.accounts[contains_acc.index] = account;
|
||||||
} else {
|
} else {
|
||||||
@@ -435,7 +454,11 @@ impl Accounts {
|
|||||||
contains_acc.index
|
contains_acc.index
|
||||||
} else {
|
} else {
|
||||||
info!("adding new account {}", pubkey);
|
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.push(account);
|
||||||
self.accounts.len() - 1
|
self.accounts.len() - 1
|
||||||
};
|
};
|
||||||
@@ -493,13 +516,21 @@ impl Accounts {
|
|||||||
pub fn select_account(&mut self, index: usize) {
|
pub fn select_account(&mut self, index: usize) {
|
||||||
if let Some(account) = self.accounts.get(index) {
|
if let Some(account) = self.accounts.get(index) {
|
||||||
self.currently_selected_account = Some(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) {
|
pub fn clear_selected_account(&mut self) {
|
||||||
self.currently_selected_account = None;
|
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> {
|
pub fn mutefun(&self) -> Box<MuteFun> {
|
||||||
@@ -794,14 +825,13 @@ enum RelayAction {
|
|||||||
Remove,
|
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() {
|
match keystore.get_selected_key() {
|
||||||
KeyStorageResponse::ReceivedResult(Ok(Some(pubkey))) => {
|
Ok(Some(pubkey)) => {
|
||||||
return accounts.iter().position(|account| account.pubkey == pubkey);
|
return accounts.iter().position(|account| account.pubkey == pubkey);
|
||||||
}
|
}
|
||||||
|
Ok(None) => {}
|
||||||
KeyStorageResponse::ReceivedResult(Err(e)) => error!("Error getting selected key: {}", e),
|
Err(e) => error!("Error getting selected key: {}", e),
|
||||||
KeyStorageResponse::Waiting | KeyStorageResponse::ReceivedResult(Ok(None)) => {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::persist::{AppSizeHandler, ZoomHandler};
|
use crate::persist::{AppSizeHandler, ZoomHandler};
|
||||||
use crate::{
|
use crate::{
|
||||||
Accounts, AppContext, Args, DataPath, DataPathType, Directory, FileKeyStorage, Images,
|
Accounts, AppContext, Args, DataPath, DataPathType, Directory, FileKeyStorage, Images,
|
||||||
KeyStorageType, NoteCache, RelayDebugView, ThemeHandler, UnknownIds,
|
NoteCache, RelayDebugView, ThemeHandler, UnknownIds,
|
||||||
};
|
};
|
||||||
use egui::ThemePreference;
|
use egui::ThemePreference;
|
||||||
use egui_winit::clipboard::Clipboard;
|
use egui_winit::clipboard::Clipboard;
|
||||||
@@ -149,12 +149,12 @@ impl Notedeck {
|
|||||||
let keystore = if parsed_args.use_keystore {
|
let keystore = if parsed_args.use_keystore {
|
||||||
let keys_path = path.path(DataPathType::Keys);
|
let keys_path = path.path(DataPathType::Keys);
|
||||||
let selected_key_path = path.path(DataPathType::SelectedKey);
|
let selected_key_path = path.path(DataPathType::SelectedKey);
|
||||||
KeyStorageType::FileSystem(FileKeyStorage::new(
|
Some(FileKeyStorage::new(
|
||||||
Directory::new(keys_path),
|
Directory::new(keys_path),
|
||||||
Directory::new(selected_key_path),
|
Directory::new(selected_key_path),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
KeyStorageType::None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut accounts = Accounts::new(keystore, parsed_args.relays.clone());
|
let mut accounts = Accounts::new(keystore, parsed_args.relays.clone());
|
||||||
|
|||||||
@@ -44,9 +44,7 @@ pub use persist::*;
|
|||||||
pub use relay_debug::RelayDebugView;
|
pub use relay_debug::RelayDebugView;
|
||||||
pub use relayspec::RelaySpec;
|
pub use relayspec::RelaySpec;
|
||||||
pub use result::Result;
|
pub use result::Result;
|
||||||
pub use storage::{
|
pub use storage::{DataPath, DataPathType, Directory, FileKeyStorage};
|
||||||
DataPath, DataPathType, Directory, FileKeyStorage, KeyStorageResponse, KeyStorageType,
|
|
||||||
};
|
|
||||||
pub use style::NotedeckTextStyle;
|
pub use style::NotedeckTextStyle;
|
||||||
pub use theme::ColorTheme;
|
pub use theme::ColorTheme;
|
||||||
pub use time::time_ago_since;
|
pub use time::time_ago_since;
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
use crate::Result;
|
use crate::Result;
|
||||||
use enostr::{Keypair, Pubkey, SerializableKeypair};
|
use enostr::{Keypair, Pubkey, SerializableKeypair};
|
||||||
|
|
||||||
use super::{
|
use super::file_storage::{delete_file, write_file, Directory};
|
||||||
file_storage::{delete_file, write_file, Directory},
|
|
||||||
key_storage_impl::KeyStorageResponse,
|
|
||||||
};
|
|
||||||
|
|
||||||
static SELECTED_PUBKEY_FILE_NAME: &str = "selected_pubkey";
|
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(
|
write_file(
|
||||||
&self.keys_directory.file_path,
|
&self.keys_directory.file_path,
|
||||||
key.pubkey.hex(),
|
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
|
let keys = self
|
||||||
.keys_directory
|
.keys_directory
|
||||||
.get_files()?
|
.get_files()?
|
||||||
@@ -42,11 +39,11 @@ impl FileKeyStorage {
|
|||||||
Ok(keys)
|
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())
|
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
|
match self
|
||||||
.selected_key_directory
|
.selected_key_directory
|
||||||
.get_file(SELECTED_PUBKEY_FILE_NAME.to_owned())
|
.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 {
|
if let Some(pubkey) = pubkey {
|
||||||
write_file(
|
write_file(
|
||||||
&self.selected_key_directory.file_path,
|
&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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@@ -128,27 +103,21 @@ mod tests {
|
|||||||
let storage = FileKeyStorage::mock().unwrap();
|
let storage = FileKeyStorage::mock().unwrap();
|
||||||
let resp = storage.add_key(&kp);
|
let resp = storage.add_key(&kp);
|
||||||
|
|
||||||
assert_eq!(resp, KeyStorageResponse::ReceivedResult(Ok(())));
|
assert!(resp.is_ok());
|
||||||
assert_num_storage(&storage.get_keys(), 1);
|
assert_num_storage(&storage.get_keys(), 1);
|
||||||
|
|
||||||
assert_eq!(
|
assert!(storage.remove_key(&kp).is_ok());
|
||||||
storage.remove_key(&kp),
|
|
||||||
KeyStorageResponse::ReceivedResult(Ok(()))
|
|
||||||
);
|
|
||||||
assert_num_storage(&storage.get_keys(), 0);
|
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 {
|
match keys_response {
|
||||||
KeyStorageResponse::ReceivedResult(Ok(keys)) => {
|
Ok(keys) => {
|
||||||
assert_eq!(keys.len(), n);
|
assert_eq!(keys.len(), n);
|
||||||
}
|
}
|
||||||
KeyStorageResponse::ReceivedResult(Err(_e)) => {
|
Err(_e) => {
|
||||||
panic!("could not get keys");
|
panic!("could not get keys");
|
||||||
}
|
}
|
||||||
KeyStorageResponse::Waiting => {
|
|
||||||
panic!("did not receive result");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,10 +129,10 @@ mod tests {
|
|||||||
let _ = storage.add_key(&kp);
|
let _ = storage.add_key(&kp);
|
||||||
assert_num_storage(&storage.get_keys(), 1);
|
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());
|
assert!(resp.is_ok());
|
||||||
|
|
||||||
let resp = storage.get_selected_pubkey();
|
let resp = storage.get_selected_key();
|
||||||
|
|
||||||
assert!(resp.is_ok());
|
assert!(resp.is_ok());
|
||||||
}
|
}
|
||||||
@@ -174,7 +143,7 @@ mod tests {
|
|||||||
|
|
||||||
// Should return Ok(None) when no key has been selected
|
// Should return Ok(None) when no key has been selected
|
||||||
match storage.get_selected_key() {
|
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),
|
other => panic!("Expected Ok(None), got {:?}", other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,3 @@ mod file_storage;
|
|||||||
|
|
||||||
pub use file_key_storage::FileKeyStorage;
|
pub use file_key_storage::FileKeyStorage;
|
||||||
pub use file_storage::{delete_file, write_file, DataPath, DataPathType, Directory};
|
pub use file_storage::{delete_file, write_file, DataPath, DataPathType, Directory};
|
||||||
|
|
||||||
pub mod key_storage_impl;
|
|
||||||
pub use key_storage_impl::{KeyStorageResponse, KeyStorageType};
|
|
||||||
|
|||||||
Reference in New Issue
Block a user