pub struct Service {
db: Data,
pending_mutex: MutexMap<String, ()>,
claim_mutex: MutexMap<UiaaKey, ()>,
ip_ratelimiter: Mutex<HashMap<IpAddr, (Instant, f64)>>,
address_ratelimiter: Mutex<HashMap<SmallString<[u8; 48]>, (Instant, f64)>>,
}Expand description
Manages email threepid bindings, verification sessions, and request limits.
Persistent maps provide lookups from user to email and email to user.
In-memory token buckets limit requestToken calls by caller IP and
canonical address.
Fields§
§db: Data§pending_mutex: MutexMap<String, ()>§claim_mutex: MutexMap<UiaaKey, ()>§ip_ratelimiter: Mutex<HashMap<IpAddr, (Instant, f64)>>§address_ratelimiter: Mutex<HashMap<SmallString<[u8; 48]>, (Instant, f64)>>Implementations§
Source§impl Service
impl Service
Sourcepub async fn put_binding(
&self,
user_id: &UserId,
email_canon: &str,
medium: Medium,
validated_at: MilliSecondsSinceUnixEpoch,
added_at: MilliSecondsSinceUnixEpoch,
)
pub async fn put_binding( &self, user_id: &UserId, email_canon: &str, medium: Medium, validated_at: MilliSecondsSinceUnixEpoch, added_at: MilliSecondsSinceUnixEpoch, )
Persists a canonical email binding in both index directions.
The forward row stores the medium and timestamps, while the reverse row stores the owning user. These are separate map writes, so callers must not treat the two rows as one atomic snapshot.
Source§impl Service
impl Service
Sourcepub fn get_bindings<'a>(
&'a self,
user_id: &'a UserId,
) -> impl Stream<Item = ThirdPartyIdentifier> + Send + 'a
pub fn get_bindings<'a>( &'a self, user_id: &'a UserId, ) -> impl Stream<Item = ThirdPartyIdentifier> + Send + 'a
Streams all third-party identifiers bound to user_id.
Entries are decoded lazily from the user’s forward-index prefix. Storage or decoding failures are skipped, and each yielded identifier owns its data.
Source§impl Service
impl Service
Sourcepub async fn del_binding(&self, user_id: &UserId, email_canon: &str)
pub async fn del_binding(&self, user_id: &UserId, email_canon: &str)
Removes a canonical email binding from both index directions.
The forward row is deleted even when absent. The reverse row is removed only when a successful lookup still names this user, so a read failure or a different owner leaves that row untouched.
Source§impl Service
impl Service
Sourcepub async fn bound_elsewhere(
&self,
user_id: &UserId,
email_canon: &str,
) -> Result<bool>
pub async fn bound_elsewhere( &self, user_id: &UserId, email_canon: &str, ) -> Result<bool>
Whether a canonical email address is bound to an account other than this one.
No binding or a binding to user_id returns false. Storage and decoding
failures from the reverse lookup are propagated.
Source§impl Service
impl Service
Sourcepub async fn user_id_for_email(
&self,
email_canon: &str,
) -> Result<Option<OwnedUserId>>
pub async fn user_id_for_email( &self, email_canon: &str, ) -> Result<Option<OwnedUserId>>
Returns the user bound to a canonical email address.
An absent reverse row returns None. Storage and user-ID decoding failures
are propagated.
Source§impl Service
impl Service
Sourcepub async fn address_in_use(&self, email_canon: &str) -> bool
pub async fn address_in_use(&self, email_canon: &str) -> bool
Tests whether a canonical email address has a readable reverse row.
Any successful raw lookup returns true without decoding the stored user.
Absence and all storage failures are both collapsed to false.
Source§impl Service
impl Service
Sourcepub async fn create_or_reuse_pending(
&self,
client_secret: &str,
medium: Medium,
address: &str,
send_attempt: u64,
ttl: Duration,
) -> Result<PendingOutcome>
pub async fn create_or_reuse_pending( &self, client_secret: &str, medium: Medium, address: &str, send_attempt: u64, ttl: Duration, ) -> Result<PendingOutcome>
Opens or reuses a pending verification for one request identity.
The session identifier is derived from the medium, address, and client secret. A live unvalidated session with no greater send attempt is reused without minting another token; other accepted attempts replace the pending proof and restart its expiry.
Source§impl Service
impl Service
Sourcepub async fn validate_pending_token(
&self,
sid: &str,
client_secret: &str,
token: &str,
) -> Result<()>
pub async fn validate_pending_token( &self, sid: &str, client_secret: &str, token: &str, ) -> Result<()>
Validates a submitted secret and token against a pending session.
Each mismatch increments the durable attempt count, and the fifth mismatch deletes the session. Failure responses avoid distinguishing the secret from the token, while expired and already-used sessions remain separate errors.
Source§impl Service
impl Service
Sourcepub async fn claim_validated(
&self,
sid: &str,
client_secret: &str,
claim: UiaaKey,
) -> Result<bool>
pub async fn claim_validated( &self, sid: &str, client_secret: &str, claim: UiaaKey, ) -> Result<bool>
Exclusively claim a validated pending session for one UIAA transaction.
Invalid or unavailable proofs return false; storage and decoding failures
remain errors so registration cannot silently continue through them.
Repeating the same claim is accepted, while a different owner or existing
session for that claim is rejected.
Source§impl Service
impl Service
Sourcepub async fn refresh_claim(&self, claim: &UiaaKey) -> Result<bool>
pub async fn refresh_claim(&self, claim: &UiaaKey) -> Result<bool>
Refresh a claim that is still owned by one UIAA transaction.
Rewriting both rows keeps their persistence lifetime aligned with later
successful stages that refresh the owning UIAA session.
Missing, expired, or inconsistent rows return false after stale indexes
are removed where possible.
Source§impl Service
impl Service
Sourcepub async fn redeem_claim(&self, claim: &UiaaKey) -> Result<Association>
pub async fn redeem_claim(&self, claim: &UiaaKey) -> Result<Association>
Spends the validated threepid owned by one UIAA transaction.
Redemption atomically records the pending proof as spent and removes the claim index, so retries cannot yield the association again. Expired, missing, changed, or differently owned claims return an error.
Source§impl Service
impl Service
Sourcepub async fn redeem_validated(
&self,
sid: &str,
client_secret: &str,
) -> Result<Association>
pub async fn redeem_validated( &self, sid: &str, client_secret: &str, ) -> Result<Association>
Spends an unclaimed validated session directly, returning its association.
The pending row remains as a spent tombstone so replayed requests fail closed
instead of reusing a previously accepted proof. An expiry-aware later
operation removes the tombstone after observing expiry; passage of time alone
does not delete it.
Claimed sessions must instead be consumed through Service::redeem_claim.
Source§impl Service
impl Service
Sourcepub async fn session_validated(&self, sid: &str, client_secret: &str) -> bool
pub async fn session_validated(&self, sid: &str, client_secret: &str) -> bool
Reports whether an unclaimed pending session is ready for UIAA.
This non-consuming gate maps wrong secrets, expired or unknown sessions,
spent proofs, and storage failures to false, revealing no extra liveness.
It does not refresh, claim, redeem, or delete the pending row.
Trait Implementations§
Source§impl Service for Service
impl Service for Service
Source§fn build(args: &Args<'_>) -> Result<Arc<Self>>
fn build(args: &Args<'_>) -> Result<Arc<Self>>
Source§fn name(&self) -> &str
fn name(&self) -> &str
crate::service::make_name(std::module_path!())Source§fn worker<'async_trait>(
self: Arc<Self>,
) -> Pin<Box<dyn Future<Output = Result> + Send + 'async_trait>>where
Self: 'async_trait,
fn worker<'async_trait>(
self: Arc<Self>,
) -> Pin<Box<dyn Future<Output = Result> + Send + 'async_trait>>where
Self: 'async_trait,
Source§fn interrupt<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn interrupt<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn clear_cache<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn clear_cache<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Source§fn memory_usage<'life0, 'life1, 'async_trait>(
&'life0 self,
_out: &'life1 mut (dyn Write + Send),
) -> Pin<Box<dyn Future<Output = Result> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn memory_usage<'life0, 'life1, 'async_trait>(
&'life0 self,
_out: &'life1 mut (dyn Write + Send),
) -> Pin<Box<dyn Future<Output = Result> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Source§fn unconstrained(&self) -> bool
fn unconstrained(&self) -> bool
Auto Trait Implementations§
impl !Freeze for Service
impl !RefUnwindSafe for Service
impl !UnwindSafe for Service
impl Send for Service
impl Sync for Service
impl Unpin for Service
impl UnsafeUnpin for Service
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
Source§impl<T> ExpectInto for T
impl<T> ExpectInto for T
Source§impl<T> Expected for T
impl<T> Expected for T
Source§fn expected_add(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedAdd,
fn expected_add(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedAdd,
rhs with an expectation that the operation is valid. Read moreSource§fn expected_sub(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedSub,
fn expected_sub(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedSub,
rhs with an expectation that the operation is valid. Read moreSource§fn expected_mul(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedMul,
fn expected_mul(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedMul,
rhs with an expectation that the operation is valid. Read moreSource§fn expected_div(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedDiv,
fn expected_div(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedDiv,
rhs with an expectation that the operation is valid. Read moreSource§fn expected_rem(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedRem,
fn expected_rem(self, rhs: Self) -> Selfwhere
Self: Sized + CheckedRem,
§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> 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 moreimpl<T> JsonCastable<CanonicalJsonValue> for T
impl<T> JsonCastable<Value> for T
§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling [Attribute] value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi [Quirk] value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the [Condition] value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
§impl<T> ServiceExt for T
impl<T> ServiceExt for T
§fn add_extension<T>(self, value: T) -> AddExtension<Self, T>where
Self: Sized,
fn add_extension<T>(self, value: T) -> AddExtension<Self, T>where
Self: Sized,
§fn compression(self) -> Compression<Self>where
Self: Sized,
fn compression(self) -> Compression<Self>where
Self: Sized,
§fn decompression(self) -> Decompression<Self>where
Self: Sized,
fn decompression(self) -> Decompression<Self>where
Self: Sized,
§fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>where
Self: Sized,
fn trace_for_http(self) -> Trace<Self, SharedClassifier<ServerErrorsAsFailures>>where
Self: Sized,
§fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>where
Self: Sized,
fn trace_for_grpc(self) -> Trace<Self, SharedClassifier<GrpcErrorsAsFailures>>where
Self: Sized,
§fn follow_redirects(self) -> FollowRedirect<Self>where
Self: Sized,
fn follow_redirects(self) -> FollowRedirect<Self>where
Self: Sized,
§fn sensitive_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveRequestHeaders<SetSensitiveResponseHeaders<Self>>where
Self: Sized,
fn sensitive_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveRequestHeaders<SetSensitiveResponseHeaders<Self>>where
Self: Sized,
§fn sensitive_request_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveRequestHeaders<Self>where
Self: Sized,
fn sensitive_request_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveRequestHeaders<Self>where
Self: Sized,
§fn sensitive_response_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveResponseHeaders<Self>where
Self: Sized,
fn sensitive_response_headers(
self,
headers: impl IntoIterator<Item = HeaderName>,
) -> SetSensitiveResponseHeaders<Self>where
Self: Sized,
§fn override_request_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
fn override_request_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
§fn append_request_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
fn append_request_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
§fn insert_request_header_if_not_present<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
fn insert_request_header_if_not_present<M>(
self,
header_name: HeaderName,
make: M,
) -> SetRequestHeader<Self, M>where
Self: Sized,
§fn override_response_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
fn override_response_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
§fn append_response_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
fn append_response_header<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
§fn insert_response_header_if_not_present<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
fn insert_response_header_if_not_present<M>(
self,
header_name: HeaderName,
make: M,
) -> SetResponseHeader<Self, M>where
Self: Sized,
§fn catch_panic(self) -> CatchPanic<Self, DefaultResponseForPanic>where
Self: Sized,
fn catch_panic(self) -> CatchPanic<Self, DefaultResponseForPanic>where
Self: Sized,
500 Internal Server responses. Read moreSource§impl<T> Tried for T
impl<T> Tried for T
Source§fn try_add(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedAdd,
fn try_add(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedAdd,
rhs with checked arithmetic. Read moreSource§fn try_sub(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedSub,
fn try_sub(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedSub,
rhs with checked arithmetic. Read moreSource§fn try_mul(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedMul,
fn try_mul(self, rhs: Self) -> Result<Self, Error>where
Self: Sized + CheckedMul,
rhs with checked arithmetic. Read more