lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit 05a5160ebedbc3582d7a7f59f9f7d20e00586d3b
parent f64ff2f835036715289d47f828380d0f8e49f829
Author: triesap <tyson@radroots.org>
Date:   Fri, 20 Feb 2026 17:43:41 +0000

app-core: migrate runtime key flows to accounts apis

Diffstat:
MCargo.lock | 1+
Mcrates/app-core/Cargo.toml | 2++
Mcrates/app-core/src/runtime/key_management.rs | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mcrates/app-core/src/runtime/nostr.rs | 2+-
Mcrates/app-core/src/runtime/trade_listing.rs | 5++---
5 files changed, 123 insertions(+), 42 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -2611,6 +2611,7 @@ dependencies = [ "radroots-core", "radroots-events", "radroots-events-codec", + "radroots-identity", "radroots-log", "radroots-net-core", "radroots-nostr", diff --git a/crates/app-core/Cargo.toml b/crates/app-core/Cargo.toml @@ -17,6 +17,7 @@ nostr-client = [ "dep:radroots-core", "dep:radroots-events-codec", "dep:radroots-trade", + "dep:radroots-identity", "dep:radroots-nostr", ] directories = ["radroots-net-core/directories"] @@ -27,6 +28,7 @@ radroots-log = { workspace = true } radroots-events = { workspace = true } radroots-net-core = { workspace = true, features = ["std"] } radroots-core = { workspace = true, optional = true } +radroots-identity = { workspace = true, optional = true, default-features = false, features = ["std"] } radroots-events-codec = { workspace = true, features = ["serde_json"], optional = true } radroots-trade = { workspace = true, features = ["std", "serde", "serde_json"], optional = true } radroots-nostr = { workspace = true, features = ["events"], optional = true } diff --git a/crates/app-core/src/runtime/key_management.rs b/crates/app-core/src/runtime/key_management.rs @@ -1,14 +1,20 @@ use super::RadrootsRuntime; use crate::RadrootsAppError; +use radroots_identity::{RadrootsIdentity, RadrootsIdentityId}; use std::path::PathBuf; #[uniffi::export] impl RadrootsRuntime { - pub fn keys_is_loaded(&self) -> bool { + pub fn accounts_has_selected_signing_identity(&self) -> bool { if let Ok(guard) = self.net.lock() { #[cfg(feature = "nostr-client")] { - return guard.keys.state.loaded; + return guard + .accounts + .selected_signing_identity() + .ok() + .flatten() + .is_some(); } #[cfg(not(feature = "nostr-client"))] { @@ -18,25 +24,60 @@ impl RadrootsRuntime { false } - pub fn keys_npub(&self) -> Option<String> { + pub fn accounts_selected_npub(&self) -> Option<String> { if let Ok(guard) = self.net.lock() { #[cfg(feature = "nostr-client")] { - return guard.keys.npub(); + return guard + .accounts + .selected_public_identity() + .ok() + .flatten() + .map(|identity| identity.public_key_npub); } } None } - pub fn keys_generate_in_memory(&self) -> Result<String, RadrootsAppError> { + pub fn accounts_list_ids(&self) -> Result<Vec<String>, RadrootsAppError> { + let guard = self + .net + .lock() + .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; + #[cfg(feature = "nostr-client")] + { + let accounts = guard + .accounts + .list_accounts() + .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; + return Ok(accounts + .into_iter() + .map(|account| account.account_id.to_string()) + .collect()); + } + #[cfg(not(feature = "nostr-client"))] + { + Err(RadrootsAppError::Msg("nostr disabled".into())) + } + } + + pub fn accounts_generate( + &self, + label: Option<String>, + make_selected: bool, + ) -> Result<String, RadrootsAppError> { let mut guard = self .net .lock() .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; #[cfg(feature = "nostr-client")] { - let k = guard.keys.generate_in_memory(); - return Ok(k.public_key().to_string()); + let account_id = guard + .accounts + .generate_identity(label, make_selected) + .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; + guard.nostr = None; + return Ok(account_id.to_string()); } #[cfg(not(feature = "nostr-client"))] { @@ -44,17 +85,26 @@ impl RadrootsRuntime { } } - pub fn keys_export_secret_hex(&self) -> Result<String, RadrootsAppError> { - let guard = self + pub fn accounts_import_secret( + &self, + secret_key: String, + label: Option<String>, + make_selected: bool, + ) -> Result<String, RadrootsAppError> { + let mut guard = self .net .lock() .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; #[cfg(feature = "nostr-client")] { - return guard - .keys - .export_secret_hex() - .map_err(|e| RadrootsAppError::Msg(format!("{e}"))); + let identity = RadrootsIdentity::from_secret_key_str(secret_key.as_str()) + .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; + let account_id = guard + .accounts + .upsert_identity(&identity, label, make_selected) + .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; + guard.nostr = None; + return Ok(account_id.to_string()); } #[cfg(not(feature = "nostr-client"))] { @@ -62,18 +112,24 @@ impl RadrootsRuntime { } } - pub fn keys_load_hex32(&self, hex: String) -> Result<(), RadrootsAppError> { + pub fn accounts_import_from_path( + &self, + path: String, + label: Option<String>, + make_selected: bool, + ) -> Result<String, RadrootsAppError> { let mut guard = self .net .lock() .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; #[cfg(feature = "nostr-client")] { - guard - .keys - .load_from_hex32(&hex) + let account_id = guard + .accounts + .migrate_legacy_identity_file(PathBuf::from(path), label, make_selected) .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; - Ok(()) + guard.nostr = None; + return Ok(account_id.to_string()); } #[cfg(not(feature = "nostr-client"))] { @@ -81,17 +137,45 @@ impl RadrootsRuntime { } } - pub fn keys_load_from_path_auto(&self, path: String) -> Result<(), RadrootsAppError> { + pub fn accounts_export_selected_secret_hex(&self) -> Result<Option<String>, RadrootsAppError> { + let guard = self + .net + .lock() + .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; + #[cfg(feature = "nostr-client")] + { + let Some(selected_id) = guard + .accounts + .selected_account_id() + .map_err(|e| RadrootsAppError::Msg(format!("{e}")))? + else { + return Ok(None); + }; + return guard + .accounts + .export_secret_hex(&selected_id) + .map_err(|e| RadrootsAppError::Msg(format!("{e}"))); + } + #[cfg(not(feature = "nostr-client"))] + { + Err(RadrootsAppError::Msg("nostr disabled".into())) + } + } + + pub fn accounts_select(&self, account_id: String) -> Result<(), RadrootsAppError> { let mut guard = self .net .lock() .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; #[cfg(feature = "nostr-client")] { + let account_id = RadrootsIdentityId::parse(account_id.as_str()) + .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; guard - .keys - .load_from_path_auto(PathBuf::from(path)) + .accounts + .select_account(&account_id) .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; + guard.nostr = None; Ok(()) } #[cfg(not(feature = "nostr-client"))] @@ -100,30 +184,25 @@ impl RadrootsRuntime { } } - pub fn keys_persist_best_practice(&self) -> Result<String, RadrootsAppError> { - let _guard = self + pub fn accounts_remove(&self, account_id: String) -> Result<(), RadrootsAppError> { + let mut guard = self .net .lock() .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; - #[cfg(all( - feature = "nostr-client", - feature = "directories", - feature = "fs-persistence" - ))] + #[cfg(feature = "nostr-client")] { - let p = _guard - .keys - .persist_best_practice() + let account_id = RadrootsIdentityId::parse(account_id.as_str()) .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; - Ok(p.display().to_string()) + guard + .accounts + .remove_account(&account_id) + .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; + guard.nostr = None; + Ok(()) } - #[cfg(not(all( - feature = "nostr-client", - feature = "directories", - feature = "fs-persistence" - )))] + #[cfg(not(feature = "nostr-client"))] { - Err(RadrootsAppError::Msg("persistence unsupported".into())) + Err(RadrootsAppError::Msg("nostr disabled".into())) } } } diff --git a/crates/app-core/src/runtime/nostr.rs b/crates/app-core/src/runtime/nostr.rs @@ -144,7 +144,7 @@ impl RadrootsRuntime { let guard = self.net.lock().ok()?; #[cfg(feature = "nostr-client")] { - let keys = guard.keys.require().ok()?; + let keys = guard.selected_nostr_keys()?; let pk = keys.public_key(); let mgr = guard.nostr.as_ref()?; let out = mgr.fetch_profile_event_blocking(pk).ok()?; diff --git a/crates/app-core/src/runtime/trade_listing.rs b/crates/app-core/src/runtime/trade_listing.rs @@ -608,9 +608,8 @@ fn current_pubkey_hex(runtime: &RadrootsRuntime) -> Result<String, RadrootsAppEr .lock() .map_err(|e| RadrootsAppError::Msg(format!("{e}")))?; let keys = guard - .keys - .require() - .map_err(|e| RadrootsAppError::Msg(e.to_string()))?; + .selected_nostr_keys() + .ok_or_else(|| RadrootsAppError::Msg("no selected signing identity".into()))?; Ok(keys.public_key().to_hex()) }