Reject gift wraps whose rumor pubkey doesn’t match the seal signer (#190)

* Verify seal sender before caching rumors

* Test rumor sender verification logic

---------

Co-authored-by: alltheseas <alltheseas@users.noreply.github.com>
This commit is contained in:
alltheseas
2025-10-24 04:30:25 -05:00
committed by GitHub
parent ac0b233089
commit 47abd2909b

View File

@@ -728,8 +728,17 @@ impl AppState {
if let Ok(event) = self.get_rumor(gift_wrap.id).await { if let Ok(event) = self.get_rumor(gift_wrap.id).await {
rumor = Some(event); rumor = Some(event);
} else if let Ok(unwrapped) = self.client.unwrap_gift_wrap(gift_wrap).await { } else if let Ok(unwrapped) = self.client.unwrap_gift_wrap(gift_wrap).await {
// Sign the unwrapped event with a RANDOM KEYS let sender = unwrapped.sender;
if let Ok(event) = unwrapped.rumor.sign_with_keys(&Keys::generate()) { let rumor_unsigned = unwrapped.rumor;
if !Self::verify_rumor_sender(sender, &rumor_unsigned) {
log::warn!(
"Ignoring gift wrap {}: seal pubkey {} mismatches rumor pubkey {}",
gift_wrap.id,
sender,
rumor_unsigned.pubkey
);
} else if let Ok(event) = rumor_unsigned.clone().sign_with_keys(&Keys::generate()) {
// Save this event to the database for future use. // Save this event to the database for future use.
if let Err(e) = self.set_rumor(gift_wrap.id, &event).await { if let Err(e) = self.set_rumor(gift_wrap.id, &event).await {
log::warn!("Failed to cache unwrapped event: {e}") log::warn!("Failed to cache unwrapped event: {e}")
@@ -759,4 +768,32 @@ impl AppState {
} }
} }
} }
fn verify_rumor_sender(sender: PublicKey, rumor: &UnsignedEvent) -> bool {
rumor.pubkey == sender
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_rumor_sender_accepts_matching_sender() {
let keys = Keys::generate();
let public_key = keys.public_key();
let rumor = EventBuilder::text_note("hello").build(public_key);
assert!(AppState::verify_rumor_sender(public_key, &rumor));
}
#[test]
fn verify_rumor_sender_rejects_mismatched_sender() {
let sender_keys = Keys::generate();
let rumor_keys = Keys::generate();
let rumor = EventBuilder::text_note("spoof").build(rumor_keys.public_key());
assert!(!AppState::verify_rumor_sender(
sender_keys.public_key(),
&rumor
));
}
} }