pub struct SqliteDeviceStore { /* private fields */ }device and sqlite only.Expand description
SQLite-backed DeviceStore.
Wrap an existing SqlitePool and call
init_schema once at startup. The store is
Clone (cheap: wraps Arcs); share across handlers / tasks.
§Encryption
The primary constructor new requires a
SessionCrypto envelope key. The bindings column is encrypted
before storage and decrypted on load. Use
plaintext only for local development and
testing.
Implementations§
Source§impl SqliteDeviceStore
impl SqliteDeviceStore
Sourcepub fn new(pool: SqlitePool, crypto: SessionCrypto) -> Self
pub fn new(pool: SqlitePool, crypto: SessionCrypto) -> Self
Create an encrypted store (recommended for production).
Sourcepub fn plaintext(pool: SqlitePool) -> Self
pub fn plaintext(pool: SqlitePool) -> Self
Create a plaintext store (development/testing only). Logs a warning so production builds don’t accidentally pick this path.
Sourcepub fn with_clock(self, clock: Arc<dyn Clock>) -> Self
pub fn with_clock(self, clock: Arc<dyn Clock>) -> Self
Inject a Clock for deterministic-simulation testing. The
clock is read on every record_sighting / set_trust_level
call where the caller did not supply an explicit now.
Sourcepub fn with_sweep_config(self, config: SweepConfig) -> Self
pub fn with_sweep_config(self, config: SweepConfig) -> Self
Override the SweepConfig driving the retention ladder.
Sourcepub async fn init_schema(&self) -> Result<(), Error>
pub async fn init_schema(&self) -> Result<(), Error>
Create the devices and device_bindings_refresh tables and
supporting indexes. Idempotent: safe to call on every startup.
Trait Implementations§
Source§impl Clone for SqliteDeviceStore
impl Clone for SqliteDeviceStore
Source§fn clone(&self) -> SqliteDeviceStore
fn clone(&self) -> SqliteDeviceStore
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl DeviceStore for SqliteDeviceStore
impl DeviceStore for SqliteDeviceStore
Source§type Error = SqlDeviceStoreError
type Error = SqlDeviceStoreError
Source§fn load(
&self,
tenant_id: &TenantId,
id: &DeviceId,
) -> impl Future<Output = Result<Option<Device>, Self::Error>> + Send
fn load( &self, tenant_id: &TenantId, id: &DeviceId, ) -> impl Future<Output = Result<Option<Device>, Self::Error>> + Send
None if absent.Source§fn find_by_fingerprint(
&self,
tenant_id: &TenantId,
hash: &FingerprintHash,
) -> impl Future<Output = Result<Option<Device>, Self::Error>> + Send
fn find_by_fingerprint( &self, tenant_id: &TenantId, hash: &FingerprintHash, ) -> impl Future<Output = Result<Option<Device>, Self::Error>> + Send
device_id cookie is
present yet. Collisions must be vanishingly rare given a
per-tenant HMAC key, but implementations MUST scope the query by
tenant_id to prevent cross-tenant correlation.Source§fn find_for_user(
&self,
tenant_id: &TenantId,
user_id: &UserId,
limit: usize,
) -> impl Future<Output = Result<Vec<Device>, Self::Error>> + Send
fn find_for_user( &self, tenant_id: &TenantId, user_id: &UserId, limit: usize, ) -> impl Future<Output = Result<Vec<Device>, Self::Error>> + Send
limit caps
the result so a high-cardinality user doesn’t blow up
device-management UIs. Read moreSource§fn find_by_refresh_family(
&self,
tenant_id: &TenantId,
family_id: &str,
) -> impl Future<Output = Result<Vec<Device>, Self::Error>> + Send
fn find_by_refresh_family( &self, tenant_id: &TenantId, family_id: &str, ) -> impl Future<Output = Result<Vec<Device>, Self::Error>> + Send
tenant carrying a
DeviceBinding::Refresh { family_id }
matching the supplied family_id. Used by the refresh-cascade
path to convert “this refresh-token family was compromised”
into the list of Devices to revoke. Read moreSource§fn save(
&self,
device: &Device,
) -> impl Future<Output = Result<(), Self::Error>> + Send
fn save( &self, device: &Device, ) -> impl Future<Output = Result<(), Self::Error>> + Send
Source§fn record_sighting(
&self,
tenant_id: &TenantId,
id: &DeviceId,
now: DateTime<Utc>,
) -> impl Future<Output = Result<(), Self::Error>> + Send
fn record_sighting( &self, tenant_id: &TenantId, id: &DeviceId, now: DateTime<Utc>, ) -> impl Future<Output = Result<(), Self::Error>> + Send
last_seen_at timestamp for the given device.
Implementations SHOULD perform this as a single UPDATE rather than
a load-modify-save round trip.Source§fn set_trust_level(
&self,
tenant_id: &TenantId,
id: &DeviceId,
level: DeviceTrustLevel,
now: DateTime<Utc>,
) -> impl Future<Output = Result<(), Self::Error>> + Send
fn set_trust_level( &self, tenant_id: &TenantId, id: &DeviceId, level: DeviceTrustLevel, now: DateTime<Utc>, ) -> impl Future<Output = Result<(), Self::Error>> + Send
DeviceTrustLevel ladder. Setting to
DeviceTrustLevel::Revoked also stamps revoked_at = now.Source§fn delete(
&self,
tenant_id: &TenantId,
id: &DeviceId,
) -> impl Future<Output = Result<(), Self::Error>> + Send
fn delete( &self, tenant_id: &TenantId, id: &DeviceId, ) -> impl Future<Output = Result<(), Self::Error>> + Send
Revoked device has aged out of the configured grace window, and
by Art 17 erasure cascades.Source§fn sweep(
&self,
tenant_id: &TenantId,
now: DateTime<Utc>,
) -> impl Future<Output = Result<SweepCounts, Self::Error>> + Send
fn sweep( &self, tenant_id: &TenantId, now: DateTime<Utc>, ) -> impl Future<Output = Result<SweepCounts, Self::Error>> + Send
Source§fn find_active_for_user(
&self,
tenant_id: &TenantId,
user_id: &UserId,
limit: usize,
) -> impl Future<Output = Result<Vec<Device>, Self::Error>> + Send
fn find_active_for_user( &self, tenant_id: &TenantId, user_id: &UserId, limit: usize, ) -> impl Future<Output = Result<Vec<Device>, Self::Error>> + Send
find_for_user but excludes
Revoked rows. Default implementation filters in-memory after a
full find_for_user call; SQL backends SHOULD override with a
WHERE trust_level != 'Revoked' clause that the optimiser can
use against the trust-level index.Source§impl HealthCheck for SqliteDeviceStore
impl HealthCheck for SqliteDeviceStore
Auto Trait Implementations§
impl Freeze for SqliteDeviceStore
impl !RefUnwindSafe for SqliteDeviceStore
impl Send for SqliteDeviceStore
impl Sync for SqliteDeviceStore
impl Unpin for SqliteDeviceStore
impl UnsafeUnpin for SqliteDeviceStore
impl !UnwindSafe for SqliteDeviceStore
Blanket Implementations§
Source§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
Source§type ArchivedMetadata = ()
type ArchivedMetadata = ()
Source§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
Source§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>
Source§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
Source§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
Source§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out indicating that a T is niched.