|
|
|
|
@@ -15,7 +15,6 @@ use crate::constants::{
|
|
|
|
|
BOOTSTRAP_RELAYS, METADATA_BATCH_LIMIT, METADATA_BATCH_TIMEOUT, QUERY_TIMEOUT, SEARCH_RELAYS,
|
|
|
|
|
};
|
|
|
|
|
use crate::paths::config_dir;
|
|
|
|
|
use crate::state::device::Device;
|
|
|
|
|
use crate::state::ingester::Ingester;
|
|
|
|
|
use crate::state::tracker::EventTracker;
|
|
|
|
|
|
|
|
|
|
@@ -24,6 +23,7 @@ mod ingester;
|
|
|
|
|
mod signal;
|
|
|
|
|
mod tracker;
|
|
|
|
|
|
|
|
|
|
pub use device::*;
|
|
|
|
|
pub use signal::*;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
@@ -43,6 +43,9 @@ pub struct AppState {
|
|
|
|
|
/// Cache of messaging relays for each public key
|
|
|
|
|
pub relay_cache: RwLock<HashMap<PublicKey, HashSet<RelayUrl>>>,
|
|
|
|
|
|
|
|
|
|
/// Cache of device announcement for each public key
|
|
|
|
|
pub announcement_cache: RwLock<HashMap<PublicKey, Option<Announcement>>>,
|
|
|
|
|
|
|
|
|
|
/// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
|
|
|
|
|
pub device: RwLock<Device>,
|
|
|
|
|
|
|
|
|
|
@@ -83,6 +86,7 @@ impl AppState {
|
|
|
|
|
let device = RwLock::new(Device::default());
|
|
|
|
|
let event_tracker = RwLock::new(EventTracker::default());
|
|
|
|
|
let relay_cache = RwLock::new(HashMap::default());
|
|
|
|
|
let announcement_cache = RwLock::new(HashMap::default());
|
|
|
|
|
|
|
|
|
|
let signal = Signal::default();
|
|
|
|
|
let ingester = Ingester::default();
|
|
|
|
|
@@ -92,6 +96,7 @@ impl AppState {
|
|
|
|
|
device,
|
|
|
|
|
event_tracker,
|
|
|
|
|
relay_cache,
|
|
|
|
|
announcement_cache,
|
|
|
|
|
signal,
|
|
|
|
|
ingester,
|
|
|
|
|
initialized_at: Timestamp::now(),
|
|
|
|
|
@@ -138,6 +143,9 @@ impl AppState {
|
|
|
|
|
// Get user's gossip relays
|
|
|
|
|
self.get_nip65(pk).await.ok();
|
|
|
|
|
|
|
|
|
|
// Initialize the relay and announcement caches
|
|
|
|
|
self.init_cache().await.ok();
|
|
|
|
|
|
|
|
|
|
// Initialize client keys
|
|
|
|
|
self.init_client_keys().await.ok();
|
|
|
|
|
|
|
|
|
|
@@ -236,12 +244,16 @@ impl AppState {
|
|
|
|
|
match event.kind {
|
|
|
|
|
// Encryption Keys announcement event
|
|
|
|
|
Kind::Custom(10044) => {
|
|
|
|
|
if let Ok(true) = self.is_self_authored(&event).await {
|
|
|
|
|
if let Ok(announcement) = self.extract_announcement(&event) {
|
|
|
|
|
if let Ok(announcement) = self.extract_announcement(&event) {
|
|
|
|
|
if let Ok(true) = self.is_self_authored(&event).await {
|
|
|
|
|
self.signal
|
|
|
|
|
.send(SignalKind::EncryptionSet(announcement))
|
|
|
|
|
.send(SignalKind::EncryptionSet(announcement.clone()))
|
|
|
|
|
.await;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cache the announcement for further queries
|
|
|
|
|
let mut announcement_cache = self.announcement_cache.write().await;
|
|
|
|
|
announcement_cache.insert(event.pubkey, Some(announcement));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Encryption Keys request event
|
|
|
|
|
@@ -572,6 +584,33 @@ impl AppState {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Initialize the relay and announcement caches with events from the local database
|
|
|
|
|
pub async fn init_cache(&self) -> Result<(), Error> {
|
|
|
|
|
let filter = Filter::new().kind(Kind::InboxRelays);
|
|
|
|
|
let events = self.client.database().query(filter).await?;
|
|
|
|
|
let mut relay_cache = self.relay_cache.write().await;
|
|
|
|
|
|
|
|
|
|
for event in events.into_iter() {
|
|
|
|
|
let relays: Vec<RelayUrl> =
|
|
|
|
|
nip17::extract_relay_list(&event).take(3).cloned().collect();
|
|
|
|
|
|
|
|
|
|
// Push all relays to the relay cache
|
|
|
|
|
relay_cache.entry(event.pubkey).or_default().extend(relays);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let filter = Filter::new().kind(Kind::Custom(10044));
|
|
|
|
|
let events = self.client.database().query(filter).await?;
|
|
|
|
|
let mut announcement_cache = self.announcement_cache.write().await;
|
|
|
|
|
|
|
|
|
|
for event in events.into_iter() {
|
|
|
|
|
if let Ok(announcement) = self.extract_announcement(&event) {
|
|
|
|
|
announcement_cache.insert(event.pubkey, Some(announcement));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Initialize the client keys to communicate between clients
|
|
|
|
|
///
|
|
|
|
|
/// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
|
|
|
|
|
@@ -961,7 +1000,7 @@ impl AppState {
|
|
|
|
|
|
|
|
|
|
// Subscribe to gift wrap events
|
|
|
|
|
self.client
|
|
|
|
|
.subscribe_with_id_to(urls, id, filter, None)
|
|
|
|
|
.subscribe_with_id_to(&urls, id, filter, None)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
@@ -1037,22 +1076,22 @@ impl AppState {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try to unwrap with the available signer
|
|
|
|
|
if let Ok(unwrapped) = self.try_unwrap_gift_wrap(gift_wrap).await {
|
|
|
|
|
let sender = unwrapped.sender;
|
|
|
|
|
let mut rumor_unsigned = unwrapped.rumor;
|
|
|
|
|
let unwrapped = self.try_unwrap_gift_wrap(gift_wrap).await?;
|
|
|
|
|
let sender = unwrapped.sender;
|
|
|
|
|
let mut rumor_unsigned = unwrapped.rumor;
|
|
|
|
|
|
|
|
|
|
if !self.verify_sender(sender, &rumor_unsigned).await {
|
|
|
|
|
return Err(anyhow!("Invalid rumor"));
|
|
|
|
|
};
|
|
|
|
|
if !self.verify_sender(sender, &rumor_unsigned).await {
|
|
|
|
|
return Err(anyhow!("Invalid rumor"));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Generate event id for the rumor if it doesn't have one
|
|
|
|
|
rumor_unsigned.ensure_id();
|
|
|
|
|
// Generate event id for the rumor if it doesn't have one
|
|
|
|
|
rumor_unsigned.ensure_id();
|
|
|
|
|
|
|
|
|
|
self.set_rumor(gift_wrap.id, &rumor_unsigned).await?;
|
|
|
|
|
self.process_rumor(gift_wrap.id, rumor_unsigned).await?;
|
|
|
|
|
// Cache the rumor
|
|
|
|
|
self.set_rumor(gift_wrap.id, &rumor_unsigned).await?;
|
|
|
|
|
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
// Process the rumor
|
|
|
|
|
self.process_rumor(gift_wrap.id, rumor_unsigned).await?;
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
@@ -1062,20 +1101,21 @@ impl AppState {
|
|
|
|
|
// Try to unwrap with the device's encryption keys first
|
|
|
|
|
// NIP-4e: https://github.com/nostr-protocol/nips/blob/per-device-keys/4e.md
|
|
|
|
|
if let Some(signer) = self.device.read().await.encryption.as_ref() {
|
|
|
|
|
if let Ok(unwrapped) = UnwrappedGift::from_gift_wrap(signer, gift_wrap).await {
|
|
|
|
|
return Ok(unwrapped);
|
|
|
|
|
match UnwrappedGift::from_gift_wrap(signer, gift_wrap).await {
|
|
|
|
|
Ok(unwrapped) => {
|
|
|
|
|
return Ok(unwrapped);
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
|
|
|
|
log::error!("Failed to unwrap with the encryption key: {e}")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get user's signer
|
|
|
|
|
let signer = self.client.signer().await?;
|
|
|
|
|
|
|
|
|
|
// Try to unwrap with the user's signer
|
|
|
|
|
if let Ok(unwrapped) = UnwrappedGift::from_gift_wrap(&signer, gift_wrap).await {
|
|
|
|
|
return Ok(unwrapped);
|
|
|
|
|
}
|
|
|
|
|
let signer = self.client.signer().await?;
|
|
|
|
|
let unwrapped = UnwrappedGift::from_gift_wrap(&signer, gift_wrap).await?;
|
|
|
|
|
|
|
|
|
|
Err(anyhow!("No signer available"))
|
|
|
|
|
Ok(unwrapped)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Process a rumor event.
|
|
|
|
|
|