1use std::{borrow::Cow, fmt};
4
5use as_variant::as_variant;
6use ruma_common::{
7 OwnedClientSecret, OwnedSessionId, OwnedUserId, serde::JsonObject, thirdparty::Medium,
8};
9use serde::{Deserialize, Serialize, de::DeserializeOwned};
10use serde_json::Value as JsonValue;
11
12mod data_serde;
13
14use super::AuthType;
15use crate::PrivOwnedStr;
16
17#[derive(Clone, Serialize)]
19#[non_exhaustive]
20#[serde(untagged)]
21pub enum AuthData {
22 Password(Password),
24
25 ReCaptcha(ReCaptcha),
27
28 EmailIdentity(EmailIdentity),
30
31 Msisdn(Msisdn),
33
34 Dummy(Dummy),
36
37 RegistrationToken(RegistrationToken),
39
40 FallbackAcknowledgement(FallbackAcknowledgement),
42
43 Terms(Terms),
47
48 OAuth(OAuth),
53
54 #[doc(hidden)]
56 _Custom(CustomAuthData),
57}
58
59impl AuthData {
60 pub fn new(
71 auth_type: &str,
72 session: Option<String>,
73 data: JsonObject,
74 ) -> serde_json::Result<Self> {
75 fn deserialize_variant<T: DeserializeOwned>(
76 session: Option<String>,
77 mut obj: JsonObject,
78 ) -> serde_json::Result<T> {
79 if let Some(session) = session {
80 obj.insert("session".into(), session.into());
81 }
82 serde_json::from_value(JsonValue::Object(obj))
83 }
84
85 Ok(match auth_type {
86 "m.login.password" => Self::Password(deserialize_variant(session, data)?),
87 "m.login.recaptcha" => Self::ReCaptcha(deserialize_variant(session, data)?),
88 "m.login.email.identity" => Self::EmailIdentity(deserialize_variant(session, data)?),
89 "m.login.msisdn" => Self::Msisdn(deserialize_variant(session, data)?),
90 "m.login.dummy" => Self::Dummy(deserialize_variant(session, data)?),
91 "m.registration_token" => Self::RegistrationToken(deserialize_variant(session, data)?),
92 "m.login.terms" => Self::Terms(deserialize_variant(session, data)?),
93 "m.oauth" | "org.matrix.cross_signing_reset" => {
94 Self::OAuth(deserialize_variant(session, data)?)
95 }
96 _ => {
97 Self::_Custom(CustomAuthData { auth_type: auth_type.into(), session, extra: data })
98 }
99 })
100 }
101
102 pub fn fallback_acknowledgement(session: String) -> Self {
104 Self::FallbackAcknowledgement(FallbackAcknowledgement::new(session))
105 }
106
107 pub fn auth_type(&self) -> Option<AuthType> {
109 match self {
110 Self::Password(_) => Some(AuthType::Password),
111 Self::ReCaptcha(_) => Some(AuthType::ReCaptcha),
112 Self::EmailIdentity(_) => Some(AuthType::EmailIdentity),
113 Self::Msisdn(_) => Some(AuthType::Msisdn),
114 Self::Dummy(_) => Some(AuthType::Dummy),
115 Self::RegistrationToken(_) => Some(AuthType::RegistrationToken),
116 Self::FallbackAcknowledgement(_) => None,
117 Self::Terms(_) => Some(AuthType::Terms),
118 Self::OAuth(_) => Some(AuthType::OAuth),
119 Self::_Custom(c) => Some(AuthType::_Custom(PrivOwnedStr(c.auth_type.as_str().into()))),
120 }
121 }
122
123 pub fn session(&self) -> Option<&str> {
125 match self {
126 Self::Password(x) => x.session.as_deref(),
127 Self::ReCaptcha(x) => x.session.as_deref(),
128 Self::EmailIdentity(x) => x.session.as_deref(),
129 Self::Msisdn(x) => x.session.as_deref(),
130 Self::Dummy(x) => x.session.as_deref(),
131 Self::RegistrationToken(x) => x.session.as_deref(),
132 Self::FallbackAcknowledgement(x) => Some(&x.session),
133 Self::Terms(x) => x.session.as_deref(),
134 Self::OAuth(x) => x.session.as_deref(),
135 Self::_Custom(x) => x.session.as_deref(),
136 }
137 }
138
139 pub fn data(&self) -> Cow<'_, JsonObject> {
147 fn serialize<T: Serialize>(obj: T) -> JsonObject {
148 match serde_json::to_value(obj).expect("auth data serialization to succeed") {
149 JsonValue::Object(obj) => obj,
150 _ => panic!("all auth data variants must serialize to objects"),
151 }
152 }
153
154 match self {
155 Self::Password(x) => Cow::Owned(serialize(Password {
156 identifier: x.identifier.clone(),
157 password: x.password.clone(),
158 session: None,
159 })),
160 Self::ReCaptcha(x) => {
161 Cow::Owned(serialize(ReCaptcha { response: x.response.clone(), session: None }))
162 }
163 Self::EmailIdentity(x) => Cow::Owned(serialize(EmailIdentity {
164 thirdparty_id_creds: x.thirdparty_id_creds.clone(),
165 session: None,
166 })),
167 Self::Msisdn(x) => Cow::Owned(serialize(Msisdn {
168 thirdparty_id_creds: x.thirdparty_id_creds.clone(),
169 session: None,
170 })),
171 Self::RegistrationToken(x) => {
172 Cow::Owned(serialize(RegistrationToken { token: x.token.clone(), session: None }))
173 }
174 Self::Dummy(_) | Self::FallbackAcknowledgement(_) | Self::Terms(_) | Self::OAuth(_) => {
176 Cow::Owned(JsonObject::default())
177 }
178 Self::_Custom(c) => Cow::Borrowed(&c.extra),
179 }
180 }
181}
182
183impl fmt::Debug for AuthData {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 match self {
187 Self::Password(inner) => inner.fmt(f),
188 Self::ReCaptcha(inner) => inner.fmt(f),
189 Self::EmailIdentity(inner) => inner.fmt(f),
190 Self::Msisdn(inner) => inner.fmt(f),
191 Self::Dummy(inner) => inner.fmt(f),
192 Self::RegistrationToken(inner) => inner.fmt(f),
193 Self::FallbackAcknowledgement(inner) => inner.fmt(f),
194 Self::Terms(inner) => inner.fmt(f),
195 Self::OAuth(inner) => inner.fmt(f),
196 Self::_Custom(inner) => inner.fmt(f),
197 }
198 }
199}
200
201#[derive(Clone, Deserialize, Serialize)]
207#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
208#[serde(tag = "type", rename = "m.login.password")]
209pub struct Password {
210 pub identifier: UserIdentifier,
212
213 pub password: String,
215
216 pub session: Option<String>,
218}
219
220impl Password {
221 pub fn new(identifier: UserIdentifier, password: String) -> Self {
223 Self { identifier, password, session: None }
224 }
225}
226
227impl fmt::Debug for Password {
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 let Self { identifier, password: _, session } = self;
230 f.debug_struct("Password")
231 .field("identifier", identifier)
232 .field("session", session)
233 .finish_non_exhaustive()
234 }
235}
236
237#[derive(Clone, Deserialize, Serialize)]
243#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
244#[serde(tag = "type", rename = "m.login.recaptcha")]
245pub struct ReCaptcha {
246 pub response: String,
248
249 pub session: Option<String>,
251}
252
253impl ReCaptcha {
254 pub fn new(response: String) -> Self {
256 Self { response, session: None }
257 }
258}
259
260impl fmt::Debug for ReCaptcha {
261 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262 let Self { response: _, session } = self;
263 f.debug_struct("ReCaptcha").field("session", session).finish_non_exhaustive()
264 }
265}
266
267#[derive(Clone, Debug, Deserialize, Serialize)]
273#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
274#[serde(tag = "type", rename = "m.login.email.identity")]
275pub struct EmailIdentity {
276 #[serde(rename = "threepid_creds")]
278 pub thirdparty_id_creds: ThirdpartyIdCredentials,
279
280 pub session: Option<String>,
282}
283
284#[derive(Clone, Debug, Deserialize, Serialize)]
290#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
291#[serde(tag = "type", rename = "m.login.msisdn")]
292pub struct Msisdn {
293 #[serde(rename = "threepid_creds")]
295 pub thirdparty_id_creds: ThirdpartyIdCredentials,
296
297 pub session: Option<String>,
299}
300
301#[derive(Clone, Debug, Default, Deserialize, Serialize)]
307#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
308#[serde(tag = "type", rename = "m.login.dummy")]
309pub struct Dummy {
310 pub session: Option<String>,
312}
313
314impl Dummy {
315 pub fn new() -> Self {
317 Self::default()
318 }
319}
320
321#[derive(Clone, Deserialize, Serialize)]
327#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
328#[serde(tag = "type", rename = "m.login.registration_token")]
329pub struct RegistrationToken {
330 pub token: String,
332
333 pub session: Option<String>,
335}
336
337impl RegistrationToken {
338 pub fn new(token: String) -> Self {
340 Self { token, session: None }
341 }
342}
343
344impl fmt::Debug for RegistrationToken {
345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346 let Self { token: _, session } = self;
347 f.debug_struct("RegistrationToken").field("session", session).finish_non_exhaustive()
348 }
349}
350
351#[derive(Clone, Debug, Deserialize, Serialize)]
357#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
358pub struct FallbackAcknowledgement {
359 pub session: String,
361}
362
363impl FallbackAcknowledgement {
364 pub fn new(session: String) -> Self {
366 Self { session }
367 }
368}
369
370#[derive(Clone, Debug, Default, Deserialize, Serialize)]
378#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
379#[serde(tag = "type", rename = "m.login.terms")]
380pub struct Terms {
381 pub session: Option<String>,
383}
384
385impl Terms {
386 pub fn new() -> Self {
388 Self::default()
389 }
390}
391
392#[derive(Clone, Debug, Default, Deserialize, Serialize)]
396#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
397#[serde(tag = "type", rename = "m.oauth")]
398pub struct OAuth {
399 pub session: Option<String>,
401}
402
403impl OAuth {
404 pub fn new() -> Self {
406 Self::default()
407 }
408}
409
410#[doc(hidden)]
412#[derive(Clone, Deserialize, Serialize)]
413#[non_exhaustive]
414pub struct CustomAuthData {
415 #[serde(rename = "type")]
417 auth_type: String,
418
419 session: Option<String>,
421
422 #[serde(flatten)]
424 extra: JsonObject,
425}
426
427impl fmt::Debug for CustomAuthData {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429 let Self { auth_type, session, extra: _ } = self;
430 f.debug_struct("CustomAuthData")
431 .field("auth_type", auth_type)
432 .field("session", session)
433 .finish_non_exhaustive()
434 }
435}
436
437#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
439#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
440#[serde(untagged)]
441pub enum UserIdentifier {
442 Matrix(MatrixUserIdentifier),
444
445 Email(EmailUserIdentifier),
447
448 Msisdn(MsisdnUserIdentifier),
450
451 PhoneNumber(PhoneNumberUserIdentifier),
453
454 #[doc(hidden)]
456 _CustomThirdParty(CustomThirdPartyUserIdentifier),
457
458 #[doc(hidden)]
460 _Custom(CustomUserIdentifier),
461}
462
463impl UserIdentifier {
464 pub fn identifier_type(&self) -> &str {
466 match self {
467 Self::Matrix(_) => "m.id.user",
468 Self::Email(_) => "m.id.thirdparty",
469 Self::Msisdn(_) => "m.id.thirdparty",
470 Self::PhoneNumber(_) => "m.id.phone",
471 Self::_CustomThirdParty(_) => "m.id.thirdparty",
472 Self::_Custom(CustomUserIdentifier { identifier_type, .. }) => identifier_type,
473 }
474 }
475
476 pub fn third_party_id(medium: Medium, address: String) -> Self {
478 match medium {
479 Medium::Email => Self::Email(EmailUserIdentifier { address }),
480 Medium::Msisdn => Self::Msisdn(MsisdnUserIdentifier { number: address }),
481 _ => Self::_CustomThirdParty(CustomThirdPartyUserIdentifier { medium, address }),
482 }
483 }
484
485 pub fn as_third_party_id(&self) -> Option<(&Medium, &str)> {
487 match self {
488 Self::Email(EmailUserIdentifier { address }) => Some((&Medium::Email, address)),
489 Self::Msisdn(MsisdnUserIdentifier { number }) => Some((&Medium::Msisdn, number)),
490 Self::_CustomThirdParty(CustomThirdPartyUserIdentifier { medium, address }) => {
491 Some((medium, address))
492 }
493 _ => None,
494 }
495 }
496
497 pub fn custom_identifier_data(&self) -> Option<&JsonObject> {
502 as_variant!(self, Self::_Custom).map(|id| &id.data)
503 }
504}
505
506impl From<OwnedUserId> for UserIdentifier {
507 fn from(id: OwnedUserId) -> Self {
508 Self::Matrix(id.into())
509 }
510}
511
512impl From<&OwnedUserId> for UserIdentifier {
513 fn from(id: &OwnedUserId) -> Self {
514 Self::Matrix(id.into())
515 }
516}
517
518impl From<MatrixUserIdentifier> for UserIdentifier {
519 fn from(id: MatrixUserIdentifier) -> Self {
520 Self::Matrix(id)
521 }
522}
523
524impl From<EmailUserIdentifier> for UserIdentifier {
525 fn from(id: EmailUserIdentifier) -> Self {
526 Self::Email(id)
527 }
528}
529
530impl From<MsisdnUserIdentifier> for UserIdentifier {
531 fn from(id: MsisdnUserIdentifier) -> Self {
532 Self::Msisdn(id)
533 }
534}
535
536impl From<PhoneNumberUserIdentifier> for UserIdentifier {
537 fn from(id: PhoneNumberUserIdentifier) -> Self {
538 Self::PhoneNumber(id)
539 }
540}
541
542#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
544#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
545#[serde(tag = "type", rename = "m.id.user")]
546pub struct MatrixUserIdentifier {
547 pub user: String,
549}
550
551impl MatrixUserIdentifier {
552 pub fn new(user: String) -> Self {
554 Self { user }
555 }
556}
557
558impl From<OwnedUserId> for MatrixUserIdentifier {
559 fn from(id: OwnedUserId) -> Self {
560 Self::new(id.into())
561 }
562}
563
564impl From<&OwnedUserId> for MatrixUserIdentifier {
565 fn from(id: &OwnedUserId) -> Self {
566 Self::new(id.as_str().to_owned())
567 }
568}
569
570#[derive(Clone, Debug, PartialEq, Eq)]
572#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
573pub struct EmailUserIdentifier {
574 pub address: String,
576}
577
578impl EmailUserIdentifier {
579 pub fn new(address: String) -> Self {
581 Self { address }
582 }
583}
584
585#[derive(Clone, Debug, PartialEq, Eq)]
587#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
588pub struct MsisdnUserIdentifier {
589 pub number: String,
593}
594
595impl MsisdnUserIdentifier {
596 pub fn new(number: String) -> Self {
598 Self { number }
599 }
600}
601
602#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
606#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
607#[serde(tag = "type", rename = "m.id.phone")]
608pub struct PhoneNumberUserIdentifier {
609 pub country: String,
615
616 pub phone: String,
618}
619
620impl PhoneNumberUserIdentifier {
621 pub fn new(country: String, phone: String) -> Self {
623 Self { country, phone }
624 }
625}
626
627#[doc(hidden)]
629#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
630#[serde(tag = "type", rename = "m.id.thirdparty")]
631pub struct CustomThirdPartyUserIdentifier {
632 medium: Medium,
634
635 address: String,
637}
638
639#[doc(hidden)]
641#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
642pub struct CustomUserIdentifier {
643 #[serde(rename = "type")]
645 identifier_type: String,
646
647 #[serde(flatten)]
649 data: JsonObject,
650}
651
652#[derive(Clone, Deserialize, Serialize)]
654#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
655pub struct ThirdpartyIdCredentials {
656 pub sid: OwnedSessionId,
658
659 pub client_secret: OwnedClientSecret,
661
662 #[serde(skip_serializing_if = "Option::is_none")]
664 pub id_server: Option<String>,
665
666 #[serde(skip_serializing_if = "Option::is_none")]
668 pub id_access_token: Option<String>,
669}
670
671impl ThirdpartyIdCredentials {
672 pub fn new(sid: OwnedSessionId, client_secret: OwnedClientSecret) -> Self {
674 Self { sid, client_secret, id_server: None, id_access_token: None }
675 }
676}
677
678impl fmt::Debug for ThirdpartyIdCredentials {
679 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
680 let Self { sid, client_secret: _, id_server, id_access_token } = self;
681 f.debug_struct("ThirdpartyIdCredentials")
682 .field("sid", sid)
683 .field("id_server", id_server)
684 .field("id_access_token", id_access_token)
685 .finish_non_exhaustive()
686 }
687}