feat: nip4e (#188)

* encryption keys

* .

* .

* move nip4e to device crate

* .

* .

* use i18n for device crate

* refactor

* refactor

* .

* add reset button

* send message with encryption keys

* clean up

* .

* choose signer

* fix

* update i18n

* fix sending
This commit is contained in:
reya
2025-10-26 18:10:40 +07:00
committed by GitHub
parent 83687e5448
commit 15bbe82a87
29 changed files with 1856 additions and 851 deletions
+10 -76
View File
@@ -1,6 +1,5 @@
use std::cmp::Reverse;
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, LazyLock};
use anyhow::Error;
use common::event::EventUtils;
@@ -14,19 +13,12 @@ use room::RoomKind;
use settings::AppSettings;
use smallvec::{smallvec, SmallVec};
use states::app_state;
use states::constants::KEYRING_URL;
use states::state::UnwrappingStatus;
use crate::keystore::{FileProvider, KeyStore, KeyringProvider};
use crate::room::Room;
pub mod keystore;
pub mod message;
pub mod room;
pub static DISABLE_KEYRING: LazyLock<bool> =
LazyLock::new(|| std::env::var("DISABLE_KEYRING").is_ok_and(|value| !value.is_empty()));
pub fn init(cx: &mut App) {
Registry::set_global(cx.new(Registry::new), cx);
}
@@ -49,14 +41,8 @@ pub struct Registry {
/// Collection of all persons (user profiles)
pub persons: HashMap<PublicKey, Entity<Profile>>,
/// Status of the unwrapping process
pub unwrapping_status: Entity<UnwrappingStatus>,
/// Key Store for storing credentials
pub keystore: Arc<dyn KeyStore>,
/// Whether the keystore has been initialized
pub initialized_keystore: bool,
/// Loading status of the registry
pub loading: bool,
/// Public Key of the currently activated signer
signer_pubkey: Option<PublicKey>,
@@ -85,39 +71,8 @@ impl Registry {
/// Create a new registry instance
pub(crate) fn new(cx: &mut Context<Self>) -> Self {
let unwrapping_status = cx.new(|_| UnwrappingStatus::default());
let read_credential = cx.read_credentials(KEYRING_URL);
let initialized_keystore = cfg!(debug_assertions) || *DISABLE_KEYRING;
let keystore: Arc<dyn KeyStore> = if cfg!(debug_assertions) || *DISABLE_KEYRING {
Arc::new(FileProvider::default())
} else {
Arc::new(KeyringProvider)
};
let mut tasks = smallvec![];
if !(cfg!(debug_assertions) || *DISABLE_KEYRING) {
tasks.push(
// Verify the keyring access
cx.spawn(async move |this, cx| {
let result = read_credential.await;
this.update(cx, |this, cx| {
if let Err(e) = result {
log::error!("Keyring error: {e}");
// For Linux:
// The user has not installed secret service on their system
// Fall back to the file provider
this.keystore = Arc::new(FileProvider::default());
}
this.initialized_keystore = true;
cx.notify();
})
.ok();
}),
);
}
tasks.push(
// Load all user profiles from the database
cx.spawn(async move |this, cx| {
@@ -136,12 +91,10 @@ impl Registry {
);
Self {
unwrapping_status,
keystore,
initialized_keystore,
rooms: vec![],
persons: HashMap::new(),
signer_pubkey: None,
loading: true,
_tasks: tasks,
}
}
@@ -165,16 +118,6 @@ impl Registry {
})
}
/// Returns the keystore.
pub fn keystore(&self) -> Arc<dyn KeyStore> {
Arc::clone(&self.keystore)
}
/// Returns true if the keystore is a file keystore.
pub fn is_using_file_keystore(&self) -> bool {
self.keystore.name() == "file"
}
/// Returns the public key of the currently activated signer.
pub fn signer_pubkey(&self) -> Option<PublicKey> {
self.signer_pubkey
@@ -233,6 +176,11 @@ impl Registry {
}
}
pub fn set_loading(&mut self, loading: bool, cx: &mut Context<Self>) {
self.loading = loading;
cx.notify();
}
/// Get a room by its ID.
pub fn room(&self, id: &u64, cx: &App) -> Option<Entity<Room>> {
self.rooms
@@ -297,24 +245,13 @@ impl Registry {
pub fn search_by_public_key(&self, public_key: PublicKey, cx: &App) -> Vec<Entity<Room>> {
self.rooms
.iter()
.filter(|room| room.read(cx).members.contains(&public_key))
.filter(|room| room.read(cx).members.contains_key(&public_key))
.cloned()
.collect()
}
/// Set the loading status of the registry.
pub fn set_unwrapping_status(&mut self, status: UnwrappingStatus, cx: &mut Context<Self>) {
self.unwrapping_status.update(cx, |this, cx| {
*this = status;
cx.notify();
});
}
/// Reset the registry.
pub fn reset(&mut self, cx: &mut Context<Self>) {
// Reset the unwrapping status
self.set_unwrapping_status(UnwrappingStatus::default(), cx);
// Clear the current identity
self.signer_pubkey = None;
@@ -339,10 +276,7 @@ impl Registry {
let authored_filter = Filter::new()
.kind(Kind::ApplicationSpecificData)
.custom_tag(
SingleLetterTag::lowercase(Alphabet::A),
public_key.to_hex(),
);
.custom_tag(SingleLetterTag::lowercase(Alphabet::A), public_key);
let addressed_filter = Filter::new()
.kind(Kind::ApplicationSpecificData)