Skip to main content

SessionManager

Struct SessionManager 

Source
pub struct SessionManager<K: NostrKeypair> { /* private fields */ }
Expand description

Routes double-ratchet sessions across many peers and devices.

Generic over the in-process keypair K exactly like Session, so it works with the production K256Keypair and any test signer alike.

§Inbound routing index

A naive router trial-decrypts an inbound event against every held session — O(sessions) Schnorr verifies per event, which a stranger can weaponise. Instead we keep sender_index: a map from each peer DH key a session will accept (see Session::accepted_senders) to that session’s (peer, device). Because DH ephemeral keys are globally unique, the map is an exact index — a message’s sender routes to at most one session in O(log n), and a foreign sender misses instantly. The index is refreshed from a session’s accepted set whenever it is installed or advances on receive.

Implementations§

Source§

impl<K: NostrKeypair> SessionManager<K>

Source

pub fn new(identity: K) -> Self

Create a manager owning our long-term identity keypair (used to authenticate invite handshakes).

Source

pub fn our_pubkey(&self) -> &str

Our identity public key (x-only hex).

Source

pub fn has_session(&self, peer: &str) -> bool

Whether we currently hold at least one session with peer.

Source

pub fn peers(&self) -> impl Iterator<Item = &String>

The peers (owner pubkeys) we hold sessions with, sorted.

Source

pub fn devices(&self, peer: &str) -> Vec<String>

The device ids we hold sessions with for peer, sorted.

Source

pub fn session_count(&self) -> usize

Total number of sessions across all peers and devices.

Source

pub fn install_session( &mut self, peer: &str, device_id: &str, session: Session<K>, )

Install (or replace) a session for (peer, device_id) directly — for restoring persisted state or wiring an externally-bootstrapped session.

Source

pub fn sessions(&self) -> impl Iterator<Item = ((&str, &str), &SessionState)>

Enumerate every held session as ((peer, device_id), &SessionState), in sorted (peer, device) order — the inverse of [install_session].

Exposed for persistence: a caller can snapshot each session’s [SessionState] (all-public, Session::from_state-restorable) and later replay them through [install_session] to revive the manager.

Source

pub fn accept_invite( &mut self, invite: &Invite, owner_pubkey: Option<&str>, created_at: i64, ) -> Result<NostrNote, Nip104Error>

Invitee side. Accept invite, install the resulting initiator session (keyed under the inviter), and return the signed invite-response event to publish back.

owner_pubkey is our optional multi-device owner key.

§Errors

Propagates Invite::accept crypto/signing failures.

Source

pub fn receive_invite_response( &mut self, invite: &Invite, event: &NostrNote, ) -> Result<String, Nip104Error>

Inviter side. Consume an invite-response event, install the mirror responder session, and return the peer (owner) pubkey we now have a session with.

The session is keyed under the invitee’s owner pubkey when supplied (so all of a multi-device peer’s devices group together), else under their identity; the device id is always the invitee’s identity pubkey.

§Errors

Propagates Invite::receive failures (bad signature, wrong kind, missing ephemeral secret, crypto).

Source

pub fn process_event(&mut self, event: &NostrNote) -> Option<ReceivedMessage>

Route an inbound kind-MESSAGE_EVENT_KIND event to the session that accepts its sender, commit that session’s ratchet advance, and return the decrypted message.

Routing is O(log n) via the sender_index: the event’s pubkey (the sender’s current DH key) is looked up directly, so a foreign or forged event misses without touching any ratchet. Returns None if the event is not a message event, names a sender we don’t hold, or fails to decrypt (replay/tamper — the codec verifies the signature).

Source

pub fn send( &mut self, peer: &str, payload: &[u8], created_at: i64, ) -> Result<Vec<NostrNote>, Nip104Error>

Fan out: encrypt payload to every device session held for peer, committing each ratchet advance, and return one signed kind-1060 event per device ready to publish.

Devices that cannot send yet (their first inbound message hasn’t arrived) are skipped. The returned order follows sorted device id.

§Errors

Nip104Error::UnknownPeer if we hold no sessions for peer; plus any per-session send failure.

Trait Implementations§

Source§

impl<K: Clone + NostrKeypair> Clone for SessionManager<K>

Source§

fn clone(&self) -> SessionManager<K>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<K: Debug + NostrKeypair> Debug for SessionManager<K>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<K> Freeze for SessionManager<K>
where K: Freeze,

§

impl<K> RefUnwindSafe for SessionManager<K>
where K: RefUnwindSafe,

§

impl<K> Send for SessionManager<K>
where K: Send,

§

impl<K> Sync for SessionManager<K>
where K: Sync,

§

impl<K> Unpin for SessionManager<K>
where K: Unpin,

§

impl<K> UnsafeUnpin for SessionManager<K>
where K: UnsafeUnpin,

§

impl<K> UnwindSafe for SessionManager<K>
where K: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.