pub struct SsoManager<T, Si, St, E, Pk = NoopProductKeyStore>where
T: SsoTransport + 'static,
Si: SsoSigner,
St: SsoSessionStore + 'static,
E: SsoEventSink + 'static,
Pk: SsoProductKeyStore + 'static,{ /* private fields */ }Expand description
Central coordinator for the SSO pairing lifecycle.
Generic over five injected adapters so hosts provide platform-specific implementations without coupling this crate to any I/O runtime.
The fifth generic Pk defaults to NoopProductKeyStore, so existing
callers constructed via SsoManager::new do not need to change.
All shared fields are wrapped in Arc so the background pairing thread
can update state and notify the sink without requiring Arc<SsoManager>.
Implementations§
Source§impl<T, Si, St, E> SsoManager<T, Si, St, E, NoopProductKeyStore>where
T: SsoTransport + 'static,
Si: SsoSigner,
St: SsoSessionStore + 'static,
E: SsoEventSink + 'static,
impl<T, Si, St, E> SsoManager<T, Si, St, E, NoopProductKeyStore>where
T: SsoTransport + 'static,
Si: SsoSigner,
St: SsoSessionStore + 'static,
E: SsoEventSink + 'static,
Sourcepub fn new(
transport: T,
signer: Si,
store: St,
sink: E,
metadata_url: String,
) -> Self
pub fn new( transport: T, signer: Si, store: St, sink: E, metadata_url: String, ) -> Self
Construct a new manager starting in the Idle state with the default
no-op product key store.
If you need product key caching with persistence, use
SsoManager::with_product_key_store instead.
Source§impl<T, Si, St, E, Pk> SsoManager<T, Si, St, E, Pk>where
T: SsoTransport + 'static,
Si: SsoSigner,
St: SsoSessionStore + 'static,
E: SsoEventSink + 'static,
Pk: SsoProductKeyStore + 'static,
impl<T, Si, St, E, Pk> SsoManager<T, Si, St, E, Pk>where
T: SsoTransport + 'static,
Si: SsoSigner,
St: SsoSessionStore + 'static,
E: SsoEventSink + 'static,
Pk: SsoProductKeyStore + 'static,
Sourcepub fn with_product_key_store(
transport: T,
signer: Si,
store: St,
sink: E,
product_key_store: Pk,
metadata_url: String,
) -> Self
pub fn with_product_key_store( transport: T, signer: Si, store: St, sink: E, product_key_store: Pk, metadata_url: String, ) -> Self
Construct a new manager with a custom product key store.
The manager starts in the Idle state.
Source§impl<T, Si, St, E, Pk> SsoManager<T, Si, St, E, Pk>where
T: SsoTransport + 'static,
Si: SsoSigner,
St: SsoSessionStore + 'static,
E: SsoEventSink + 'static,
Pk: SsoProductKeyStore + 'static,
impl<T, Si, St, E, Pk> SsoManager<T, Si, St, E, Pk>where
T: SsoTransport + 'static,
Si: SsoSigner,
St: SsoSessionStore + 'static,
E: SsoEventSink + 'static,
Pk: SsoProductKeyStore + 'static,
Sourcepub fn pair(&self) -> Result<(), SsoError>
pub fn pair(&self) -> Result<(), SsoError>
Initiate a QR-pairing session in a background thread.
Transitions: Idle / Failed → AwaitingScan (when QR is ready) →
Paired on success, or Failed on error or cancellation.
Returns Err(PairingAlreadyInProgress) if a pairing is already running.
Sourcepub fn unpair(&self) -> Result<(), SsoError>
pub fn unpair(&self) -> Result<(), SsoError>
Clear the current session and return to the Idle state.
If a pairing is in progress it is cancelled before clearing.
Safe to call from any state, including Idle.
Sourcepub fn restore_session(&self) -> Result<(), SsoError>
pub fn restore_session(&self) -> Result<(), SsoError>
Load a previously persisted session from the store.
On success, transitions to Paired. If no session is stored, stays
Idle. Returns Err(Store(_)) if the store call itself fails.
Sourcepub fn handle_pairing_result(
&self,
result: PairingResult,
) -> Result<(), SsoError>
pub fn handle_pairing_result( &self, result: PairingResult, ) -> Result<(), SsoError>
Finalise a completed pairing handshake.
Persists the session metadata, stores sign material for future
request_sign calls, initialises the product key cache with the phone
identity (loading any persisted entries), clears the in-progress guard,
and transitions to Paired. The PairingResult is consumed and its
session_key is zeroized on drop — callers must not use it after this call.
Sourcepub fn request_sign(&self, payload: &[u8]) -> Result<Vec<u8>, SsoError>
pub fn request_sign(&self, payload: &[u8]) -> Result<Vec<u8>, SsoError>
Send a sign request to the paired phone and block until response or timeout.
Must be called from a background thread (blocking I/O). Returns the signature bytes on success.
Returns Err(NotPaired) if no paired session exists, or Err(SignFailed)
if the transport or phone returns an error.
Sourcepub fn request_product_key(
&self,
product_id: &str,
index: u32,
) -> Result<[u8; 32], SsoError>
pub fn request_product_key( &self, product_id: &str, index: u32, ) -> Result<[u8; 32], SsoError>
Request a product public key from the paired phone.
Checks the in-memory cache first (no network round-trip on hit). On a
cache miss, verifies the phone is online before sending a
ProductKeyRequest over the encrypted channel and waiting up to 30
seconds for the phone’s response.
Returns Err(NotPaired) if no paired session exists.
Returns Err(PhoneOffline) if the phone has not sent a heartbeat
within presence::HEARTBEAT_TIMEOUT_SECS (cache misses only).
Returns Err(ProductKeyCapabilityAbsent) if the phone does not advertise
the "product_key" capability.
Returns Err(ProductKeyRejected) if the phone denies the request.
Returns Err(ProductKeyTimeout) if no response arrives within 30 s.
Sourcepub fn is_phone_online(&self) -> bool
pub fn is_phone_online(&self) -> bool
Return true if the phone sent a heartbeat within the presence timeout.
Delegates to presence::is_phone_online using the atomic timestamp so
no mutex is required.
Sourcepub fn cache_remove_and_persist(&self, product_id: &str, index: u32)
pub fn cache_remove_and_persist(&self, product_id: &str, index: u32)
Remove a single entry from the product key cache and persist the snapshot.
No-op if the cache is uninitialised or the entry does not exist.