pub struct EncryptingUserStore { /* private fields */ }Expand description
A UserStore decorator that keeps email/phone encrypted at rest while
preserving equality lookup via a keyed blind index (HMAC-SHA256).
The wrapped store never sees plaintext PII: on write, the real address is
AES-encrypted into the identity’s attributes and the indexed email field
is replaced by its blind index; on read, the plaintext is transparently
restored. find_by_email hashes the query with the same key, so exact-match
lookup still works without exposing PII — closing the “plaintext PII in the
store” gap while remaining GDPR-shreddable (drop the subject’s key in the
vault and the ciphertext is unrecoverable).
Storing the index in the email field is intrinsic to decorating an opaque
UserStore (whose find_by_email matches on that field). To make the value
unmistakably not a plaintext address — for anyone inspecting the backing
store — the blind index is prefixed with BLIND_INDEX_PREFIX
("bi$"), which no real email can contain in that position.
Implementations§
Trait Implementations§
Source§impl UserStore for EncryptingUserStore
impl UserStore for EncryptingUserStore
fn find_by_id<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Identity>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn find_by_email<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
tenant: Option<&'life1 str>,
email: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<Identity>>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Source§fn insert<'life0, 'life1, 'async_trait>(
&'life0 self,
identity: &'life1 Identity,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn insert<'life0, 'life1, 'async_trait>(
&'life0 self,
identity: &'life1 Identity,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
IdentityError::AlreadyExists on a
tenant+email collision.Source§fn update<'life0, 'life1, 'async_trait>(
&'life0 self,
identity: &'life1 Identity,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn update<'life0, 'life1, 'async_trait>(
&'life0 self,
identity: &'life1 Identity,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn set_status<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
status: AccountStatus,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_status<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
status: AccountStatus,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn set_mfa<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
mfa: MfaState,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_mfa<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 str,
mfa: MfaState,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Auto Trait Implementations§
impl !RefUnwindSafe for EncryptingUserStore
impl !UnwindSafe for EncryptingUserStore
impl Freeze for EncryptingUserStore
impl Send for EncryptingUserStore
impl Sync for EncryptingUserStore
impl Unpin for EncryptingUserStore
impl UnsafeUnpin for EncryptingUserStore
Blanket Implementations§
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
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> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request