use super::*;
pub(in crate::core) fn is_private_transport_event(event: &Event) -> bool {
matches!(
event.kind.as_u16() as u32,
MESSAGE_EVENT_KIND | INVITE_RESPONSE_KIND | 21_111
)
}
fn recipient_device_target(event: &Event) -> BTreeSet<String> {
let recipients = event.tags.public_keys().copied().collect::<Vec<_>>();
let [recipient] = recipients.as_slice() else {
return BTreeSet::new();
};
fips_peer_from_hex(&recipient.to_hex())
.map(|peer| BTreeSet::from([peer.npub()]))
.unwrap_or_default()
}
#[cfg(test)]
pub(super) fn encoded_private_targets(payload: &[u8]) -> Option<BTreeSet<String>> {
let FipsNearbyPacket::Event { event_json, .. } = FipsNearbyPacket::decode(payload)? else {
return None;
};
let event = serde_json::from_str::<Event>(&event_json).ok()?;
if !is_private_transport_event(&event) {
return None;
}
Some(if event.kind.as_u16() as u32 == INVITE_RESPONSE_KIND {
BTreeSet::new()
} else {
recipient_device_target(&event)
})
}
impl AppCore {
pub(in crate::core) fn accepts_private_nearby_event(&self, event: &Event) -> bool {
if !is_private_transport_event(event) {
return true;
}
let recipients = event.tags.public_keys().copied().collect::<Vec<_>>();
let [recipient] = recipients.as_slice() else {
return false;
};
if event.kind.as_u16() as u32 == INVITE_RESPONSE_KIND {
let Some(local) = &self.logged_in else {
return false;
};
if *recipient == local.owner_pubkey || *recipient == local.device_keys.public_key() {
return false;
}
return self
.protocol_engine
.as_ref()
.and_then(ProtocolEngine::local_invite_response_pubkey)
== Some(*recipient)
|| self.private_chat_invites.values().any(|invite| {
invite.metadata_privacy_version
== nostr_double_ratchet::METADATA_PRIVACY_VERSION
&& invite.inviter_ephemeral_private_key.is_some()
&& invite.inviter_device_pubkey.to_nostr().ok()
== Some(local.device_keys.public_key())
&& invite.inviter_ephemeral_public_key.to_nostr().ok() == Some(*recipient)
});
}
self.logged_in
.as_ref()
.is_some_and(|local| *recipient == local.device_keys.public_key())
}
pub(in crate::core) fn private_nearby_targets(
&self,
event: &Event,
) -> Option<BTreeSet<String>> {
if !is_private_transport_event(event) {
return None;
}
if event.kind.as_u16() as u32 != INVITE_RESPONSE_KIND {
return Some(recipient_device_target(event));
}
let recipients = event.tags.public_keys().collect::<Vec<_>>();
let [recipient] = recipients.as_slice() else {
return Some(BTreeSet::new());
};
let ephemeral = recipient.to_hex();
let targets = self
.protocol_engine
.as_ref()
.map(ProtocolEngine::session_manager_snapshot)
.into_iter()
.flat_map(|snapshot| snapshot.users)
.flat_map(|user| user.devices)
.filter(|device| {
device.public_invite.as_ref().is_some_and(|invite| {
invite.inviter_ephemeral_public_key.to_string() == ephemeral
})
})
.filter_map(|device| fips_peer_from_hex(&device.device_pubkey.to_string()))
.map(|device| device.npub())
.collect();
Some(targets)
}
}