chore: fix some gossip and nip4e bugs #23

Merged
reya merged 6 commits from fix-gossip into master 2026-03-18 08:21:40 +00:00
4 changed files with 108 additions and 54 deletions
Showing only changes of commit d53af98feb - Show all commits

View File

@@ -708,8 +708,10 @@ async fn extract_rumor(
async fn try_unwrap(signer: &Arc<CoopSigner>, gift_wrap: &Event) -> Result<UnwrappedGift, Error> { async fn try_unwrap(signer: &Arc<CoopSigner>, gift_wrap: &Event) -> Result<UnwrappedGift, Error> {
// Try with the device signer first // Try with the device signer first
if let Some(signer) = signer.get_encryption_signer().await { if let Some(signer) = signer.get_encryption_signer().await {
log::info!("trying with device signer"); log::info!("trying with encryption key");
return try_unwrap_with(gift_wrap, &signer).await; if let Ok(unwrapped) = try_unwrap_with(gift_wrap, &signer).await {
return Ok(unwrapped);
}
} }
// Fallback to the user's signer // Fallback to the user's signer

View File

@@ -2,7 +2,7 @@ use std::cmp::Ordering;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::time::Duration; use std::time::Duration;
use anyhow::Error; use anyhow::{Error, anyhow};
use common::EventUtils; use common::EventUtils;
use gpui::{App, AppContext, Context, EventEmitter, SharedString, Task}; use gpui::{App, AppContext, Context, EventEmitter, SharedString, Task};
use itertools::Itertools; use itertools::Itertools;
@@ -513,46 +513,46 @@ impl Room {
// Handle encryption signer requirements // Handle encryption signer requirements
if signer_kind.encryption() { if signer_kind.encryption() {
// Receiver didn't set up a decoupled encryption key
if announcement.is_none() { if announcement.is_none() {
reports.push(SendReport::new(public_key).error(NO_DEKEY)); reports.push(SendReport::new(public_key).error(NO_DEKEY));
continue; continue;
} }
// Sender didn't set up a decoupled encryption key
if encryption_signer.is_none() { if encryption_signer.is_none() {
reports.push(SendReport::new(sender.public_key()).error(USER_NO_DEKEY)); reports.push(SendReport::new(sender.public_key()).error(USER_NO_DEKEY));
continue; continue;
} }
} }
// Determine receiver and signer // Determine the signer to use
let (receiver, signer) = match signer_kind { let signer = match signer_kind {
SignerKind::Auto => { SignerKind::Auto => {
if let Some(announcement) = announcement { if announcement.is_some()
if let Some(enc_signer) = encryption_signer.as_ref() { && let Some(encryption_signer) = encryption_signer.clone()
(announcement.public_key(), enc_signer.clone()) {
} else { // Safe to unwrap due to earlier checks
(member.public_key(), user_signer.clone()) encryption_signer
}
} else { } else {
(member.public_key(), user_signer.clone()) user_signer.clone()
} }
} }
SignerKind::Encryption => { SignerKind::Encryption => {
// Safe to unwrap due to earlier checks // Safe to unwrap due to earlier checks
( encryption_signer.as_ref().unwrap().clone()
announcement.unwrap().public_key(),
encryption_signer.as_ref().unwrap().clone(),
)
} }
SignerKind::User => (member.public_key(), user_signer.clone()), SignerKind::User => user_signer.clone(),
}; };
match send_gift_wrap(&client, &signer, relays, &receiver, &rumor, public_key).await // Send the gift wrap event and collect the report
{ match send_gift_wrap(&client, &signer, &member, &rumor, signer_kind, relays).await {
Ok((report, _)) => { Ok(report) => {
reports.push(report); reports.push(report);
sents += 1; sents += 1;
} }
Err(report) => { Err(error) => {
let report = SendReport::new(public_key).error(error.to_string());
reports.push(report); reports.push(report);
} }
} }
@@ -562,12 +562,32 @@ impl Room {
if backup && sents >= 1 { if backup && sents >= 1 {
let public_key = sender.public_key(); let public_key = sender.public_key();
let relays = sender.messaging_relays(); let relays = sender.messaging_relays();
let signer = encryption_signer.as_ref().unwrap_or(&user_signer);
match send_gift_wrap(&client, signer, relays, &public_key, &rumor, public_key).await // Determine the signer to use
{ let signer = match signer_kind {
Ok((report, _)) => reports.push(report), SignerKind::Auto => {
Err(report) => reports.push(report), if sender.announcement().is_some()
&& let Some(encryption_signer) = encryption_signer.clone()
{
// Safe to unwrap due to earlier checks
encryption_signer
} else {
user_signer.clone()
}
}
SignerKind::Encryption => {
// Safe to unwrap due to earlier checks
encryption_signer.as_ref().unwrap().clone()
}
SignerKind::User => user_signer.clone(),
};
match send_gift_wrap(&client, &signer, &sender, &rumor, signer_kind, relays).await {
Ok(report) => reports.push(report),
Err(error) => {
let report = SendReport::new(public_key).error(error.to_string());
reports.push(report);
}
} }
} }
@@ -580,37 +600,56 @@ impl Room {
async fn send_gift_wrap<T>( async fn send_gift_wrap<T>(
client: &Client, client: &Client,
signer: &T, signer: &T,
to: &[RelayUrl], receiver: &Person,
receiver: &PublicKey,
rumor: &UnsignedEvent, rumor: &UnsignedEvent,
public_key: PublicKey, config: &SignerKind,
) -> Result<(SendReport, bool), SendReport> to: &[RelayUrl],
) -> Result<SendReport, Error>
where where
T: NostrSigner + 'static, T: NostrSigner + 'static,
{ {
match EventBuilder::gift_wrap(signer, receiver, rumor.clone(), []).await { let mut extra_tags = vec![];
Ok(event) => {
// Connect to each relay before sending
for url in to.iter() {
client.add_relay(url).and_connect().await.ok();
}
// Send the event to each relay // Determine the receiver public key based on the config
match client let receiver = match config {
.send_event(&event) SignerKind::Auto => {
.to(to) if let Some(announcement) = receiver.announcement().as_ref() {
.ack_policy(AckPolicy::none()) extra_tags.push(Tag::public_key(receiver.public_key()));
.await announcement.public_key()
{ } else {
Ok(output) => Ok(( receiver.public_key()
SendReport::new(public_key)
.gift_wrap_id(event.id)
.output(output),
true,
)),
Err(e) => Err(SendReport::new(public_key).error(e.to_string())),
} }
} }
Err(e) => Err(SendReport::new(public_key).error(e.to_string())), SignerKind::Encryption => {
if let Some(announcement) = receiver.announcement().as_ref() {
extra_tags.push(Tag::public_key(receiver.public_key()));
announcement.public_key()
} else {
return Err(anyhow!("User has no encryption announcement"));
}
}
SignerKind::User => receiver.public_key(),
};
// Construct the gift wrap event
let event = EventBuilder::gift_wrap(signer, &receiver, rumor.clone(), extra_tags).await?;
// Connect to each relay before sending
for url in to.iter() {
client.add_relay(url).and_connect().await.ok();
} }
// Send the gift wrap event and collect the report
let report = client
.send_event(&event)
.to(to)
.ack_policy(AckPolicy::none())
.await
.map(|output| {
SendReport::new(receiver)
.gift_wrap_id(event.id)
.output(output)
})?;
Ok(report)
} }

View File

@@ -36,14 +36,16 @@ pub const NOSTR_CONNECT_RELAY: &str = "wss://relay.nip46.com";
/// Default vertex relays /// Default vertex relays
pub const WOT_RELAYS: [&str; 1] = ["wss://relay.vertexlab.io"]; pub const WOT_RELAYS: [&str; 1] = ["wss://relay.vertexlab.io"];
/// Default search relays
pub const INDEXER_RELAYS: [&str; 1] = ["wss://indexer.coracle.social"];
/// Default search relays /// Default search relays
pub const SEARCH_RELAYS: [&str; 2] = ["wss://antiprimal.net", "wss://search.nos.today"]; pub const SEARCH_RELAYS: [&str; 2] = ["wss://antiprimal.net", "wss://search.nos.today"];
/// Default bootstrap relays /// Default bootstrap relays
pub const BOOTSTRAP_RELAYS: [&str; 4] = [ pub const BOOTSTRAP_RELAYS: [&str; 3] = [
"wss://relay.damus.io", "wss://relay.damus.io",
"wss://relay.primal.net", "wss://relay.primal.net",
"wss://indexer.coracle.social",
"wss://user.kindpag.es", "wss://user.kindpag.es",
]; ];

View File

@@ -188,7 +188,18 @@ impl NostrRegistry {
let task: Task<Result<(), Error>> = cx.background_spawn(async move { let task: Task<Result<(), Error>> = cx.background_spawn(async move {
// Add search relay to the relay pool // Add search relay to the relay pool
for url in SEARCH_RELAYS.into_iter() { for url in SEARCH_RELAYS.into_iter() {
client.add_relay(url).await?; client
.add_relay(url)
.capabilities(RelayCapabilities::READ)
.await?;
}
// Add indexer relay to the relay pool
for url in INDEXER_RELAYS.into_iter() {
client
.add_relay(url)
.capabilities(RelayCapabilities::DISCOVERY)
.await?;
} }
// Add bootstrap relay to the relay pool // Add bootstrap relay to the relay pool