Skip to main content

tuwunel_service/threepid/
mod.rs

1mod binding;
2mod canonical;
3mod pending;
4mod ratelimit;
5
6use std::{
7	collections::HashMap,
8	net::IpAddr,
9	sync::{Arc, Mutex},
10	time::Instant,
11};
12
13use ruma::{MilliSecondsSinceUnixEpoch, thirdparty::Medium};
14use serde::{Deserialize, Serialize};
15use tuwunel_core::{Result, smallstr::SmallString};
16use tuwunel_database::Map;
17
18pub use self::{canonical::canonicalize_email, pending::PendingOutcome};
19
20/// Token-bucket table keyed on a throttle axis: last-refill instant and
21/// remaining tokens per key.
22type Ratelimiter<K> = Mutex<HashMap<K, (Instant, f64)>>;
23
24/// Stack-string key for the per-address throttle bucket; the modal email
25/// canonical address fits inline.
26type EmailKey = SmallString<[u8; 48]>;
27
28/// Third-party identifier (email) storage and the requestToken throttle. Holds
29/// the forward `(user, email)` bindings, the reverse `email -> user` lookup,
30/// the pending email verification sessions, and the per-IP and per-address
31/// token buckets.
32pub struct Service {
33	db: Data,
34	ip_ratelimiter: Ratelimiter<IpAddr>,
35	address_ratelimiter: Ratelimiter<EmailKey>,
36}
37
38struct Data {
39	userid_email: Arc<Map>,
40	email_userid: Arc<Map>,
41	threepidsid_pending: Arc<Map>,
42}
43
44/// CBOR value of a `userid_email` row: the per-binding metadata, with the
45/// address carried in the composite key.
46#[derive(Clone, Debug, Deserialize, Serialize)]
47struct Binding {
48	medium: Medium,
49	validated_at: MilliSecondsSinceUnixEpoch,
50	added_at: MilliSecondsSinceUnixEpoch,
51}
52
53/// Validated `(medium, address)` pair handed back when a pending verification
54/// is consumed by the add flow.
55#[derive(Clone, Debug)]
56pub struct Association {
57	pub medium: Medium,
58	pub address: String,
59}
60
61impl crate::Service for Service {
62	fn build(args: &crate::Args<'_>) -> Result<Arc<Self>> {
63		Ok(Arc::new(Self {
64			db: Data {
65				userid_email: args.db["userid_email"].clone(),
66				email_userid: args.db["email_userid"].clone(),
67				threepidsid_pending: args.db["threepidsid_pending"].clone(),
68			},
69			ip_ratelimiter: Mutex::new(HashMap::new()),
70			address_ratelimiter: Mutex::new(HashMap::new()),
71		}))
72	}
73
74	fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
75}