1use std::{borrow::Cow, fmt};
4
5use ruma_common::{
6 OwnedClientSecret, OwnedSessionId, OwnedUserId, serde::JsonObject, thirdparty::Medium,
7};
8use serde::{Deserialize, Serialize, de::DeserializeOwned};
9use serde_json::Value as JsonValue;
10
11mod data_serde;
12
13use super::AuthType;
14use crate::PrivOwnedStr;
15
16#[derive(Clone, Serialize)]
18#[non_exhaustive]
19#[serde(untagged)]
20pub enum AuthData {
21 Password(Password),
23
24 ReCaptcha(ReCaptcha),
26
27 EmailIdentity(EmailIdentity),
29
30 Msisdn(Msisdn),
32
33 Dummy(Dummy),
35
36 RegistrationToken(RegistrationToken),
38
39 FallbackAcknowledgement(FallbackAcknowledgement),
41
42 Terms(Terms),
46
47 OAuth(OAuth),
52
53 #[doc(hidden)]
55 _Custom(CustomAuthData),
56}
57
58impl AuthData {
59 pub fn new(
70 auth_type: &str,
71 session: Option<String>,
72 data: JsonObject,
73 ) -> serde_json::Result<Self> {
74 fn deserialize_variant<T: DeserializeOwned>(
75 session: Option<String>,
76 mut obj: JsonObject,
77 ) -> serde_json::Result<T> {
78 if let Some(session) = session {
79 obj.insert("session".into(), session.into());
80 }
81 serde_json::from_value(JsonValue::Object(obj))
82 }
83
84 Ok(match auth_type {
85 "m.login.password" => Self::Password(deserialize_variant(session, data)?),
86 "m.login.recaptcha" => Self::ReCaptcha(deserialize_variant(session, data)?),
87 "m.login.email.identity" => Self::EmailIdentity(deserialize_variant(session, data)?),
88 "m.login.msisdn" => Self::Msisdn(deserialize_variant(session, data)?),
89 "m.login.dummy" => Self::Dummy(deserialize_variant(session, data)?),
90 "m.registration_token" => Self::RegistrationToken(deserialize_variant(session, data)?),
91 "m.login.terms" => Self::Terms(deserialize_variant(session, data)?),
92 "m.oauth" | "org.matrix.cross_signing_reset" => {
93 Self::OAuth(deserialize_variant(session, data)?)
94 }
95 _ => Self::_Custom(CustomAuthData { auth_type: auth_type.into(), session, data }),
96 })
97 }
98
99 pub fn fallback_acknowledgement(session: String) -> Self {
101 Self::FallbackAcknowledgement(FallbackAcknowledgement::new(session))
102 }
103
104 pub fn auth_type(&self) -> Option<AuthType> {
106 match self {
107 Self::Password(_) => Some(AuthType::Password),
108 Self::ReCaptcha(_) => Some(AuthType::ReCaptcha),
109 Self::EmailIdentity(_) => Some(AuthType::EmailIdentity),
110 Self::Msisdn(_) => Some(AuthType::Msisdn),
111 Self::Dummy(_) => Some(AuthType::Dummy),
112 Self::RegistrationToken(_) => Some(AuthType::RegistrationToken),
113 Self::FallbackAcknowledgement(_) => None,
114 Self::Terms(_) => Some(AuthType::Terms),
115 Self::OAuth(_) => Some(AuthType::OAuth),
116 Self::_Custom(c) => Some(AuthType::_Custom(PrivOwnedStr(c.auth_type.as_str().into()))),
117 }
118 }
119
120 pub fn session(&self) -> Option<&str> {
122 match self {
123 Self::Password(x) => x.session.as_deref(),
124 Self::ReCaptcha(x) => x.session.as_deref(),
125 Self::EmailIdentity(x) => x.session.as_deref(),
126 Self::Msisdn(x) => x.session.as_deref(),
127 Self::Dummy(x) => x.session.as_deref(),
128 Self::RegistrationToken(x) => x.session.as_deref(),
129 Self::FallbackAcknowledgement(x) => Some(&x.session),
130 Self::Terms(x) => x.session.as_deref(),
131 Self::OAuth(x) => x.session.as_deref(),
132 Self::_Custom(x) => x.session.as_deref(),
133 }
134 }
135
136 pub fn data(&self) -> Cow<'_, JsonObject> {
144 fn serialize<T: Serialize>(obj: T) -> JsonObject {
145 match serde_json::to_value(obj).expect("auth data serialization to succeed") {
146 JsonValue::Object(obj) => obj,
147 _ => panic!("all auth data variants must serialize to objects"),
148 }
149 }
150
151 match self {
152 Self::Password(x) => Cow::Owned(serialize(Password {
153 identifier: x.identifier.clone(),
154 password: x.password.clone(),
155 session: None,
156 })),
157 Self::ReCaptcha(x) => {
158 Cow::Owned(serialize(ReCaptcha { response: x.response.clone(), session: None }))
159 }
160 Self::EmailIdentity(x) => Cow::Owned(serialize(EmailIdentity {
161 thirdparty_id_creds: x.thirdparty_id_creds.clone(),
162 session: None,
163 })),
164 Self::Msisdn(x) => Cow::Owned(serialize(Msisdn {
165 thirdparty_id_creds: x.thirdparty_id_creds.clone(),
166 session: None,
167 })),
168 Self::RegistrationToken(x) => {
169 Cow::Owned(serialize(RegistrationToken { token: x.token.clone(), session: None }))
170 }
171 Self::Dummy(_) | Self::FallbackAcknowledgement(_) | Self::Terms(_) | Self::OAuth(_) => {
173 Cow::Owned(JsonObject::default())
174 }
175 Self::_Custom(c) => Cow::Borrowed(&c.data),
176 }
177 }
178}
179
180impl fmt::Debug for AuthData {
181 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
182 match self {
184 Self::Password(inner) => inner.fmt(f),
185 Self::ReCaptcha(inner) => inner.fmt(f),
186 Self::EmailIdentity(inner) => inner.fmt(f),
187 Self::Msisdn(inner) => inner.fmt(f),
188 Self::Dummy(inner) => inner.fmt(f),
189 Self::RegistrationToken(inner) => inner.fmt(f),
190 Self::FallbackAcknowledgement(inner) => inner.fmt(f),
191 Self::Terms(inner) => inner.fmt(f),
192 Self::OAuth(inner) => inner.fmt(f),
193 Self::_Custom(inner) => inner.fmt(f),
194 }
195 }
196}
197
198#[derive(Clone, Deserialize, Serialize)]
204#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
205#[serde(tag = "type", rename = "m.login.password")]
206pub struct Password {
207 pub identifier: UserIdentifier,
209
210 pub password: String,
212
213 pub session: Option<String>,
215}
216
217impl Password {
218 pub fn new(identifier: UserIdentifier, password: String) -> Self {
220 Self { identifier, password, session: None }
221 }
222}
223
224impl fmt::Debug for Password {
225 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
226 let Self { identifier, password: _, session } = self;
227 f.debug_struct("Password")
228 .field("identifier", identifier)
229 .field("session", session)
230 .finish_non_exhaustive()
231 }
232}
233
234#[derive(Clone, Deserialize, Serialize)]
240#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
241#[serde(tag = "type", rename = "m.login.recaptcha")]
242pub struct ReCaptcha {
243 pub response: String,
245
246 pub session: Option<String>,
248}
249
250impl ReCaptcha {
251 pub fn new(response: String) -> Self {
253 Self { response, session: None }
254 }
255}
256
257impl fmt::Debug for ReCaptcha {
258 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259 let Self { response: _, session } = self;
260 f.debug_struct("ReCaptcha").field("session", session).finish_non_exhaustive()
261 }
262}
263
264#[derive(Clone, Debug, Deserialize, Serialize)]
270#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
271#[serde(tag = "type", rename = "m.login.email.identity")]
272pub struct EmailIdentity {
273 #[serde(rename = "threepid_creds")]
275 pub thirdparty_id_creds: ThirdpartyIdCredentials,
276
277 pub session: Option<String>,
279}
280
281#[derive(Clone, Debug, Deserialize, Serialize)]
287#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
288#[serde(tag = "type", rename = "m.login.msisdn")]
289pub struct Msisdn {
290 #[serde(rename = "threepid_creds")]
292 pub thirdparty_id_creds: ThirdpartyIdCredentials,
293
294 pub session: Option<String>,
296}
297
298#[derive(Clone, Debug, Default, Deserialize, Serialize)]
304#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
305#[serde(tag = "type", rename = "m.login.dummy")]
306pub struct Dummy {
307 pub session: Option<String>,
309}
310
311impl Dummy {
312 pub fn new() -> Self {
314 Self::default()
315 }
316}
317
318#[derive(Clone, Deserialize, Serialize)]
324#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
325#[serde(tag = "type", rename = "m.login.registration_token")]
326pub struct RegistrationToken {
327 pub token: String,
329
330 pub session: Option<String>,
332}
333
334impl RegistrationToken {
335 pub fn new(token: String) -> Self {
337 Self { token, session: None }
338 }
339}
340
341impl fmt::Debug for RegistrationToken {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 let Self { token: _, session } = self;
344 f.debug_struct("RegistrationToken").field("session", session).finish_non_exhaustive()
345 }
346}
347
348#[derive(Clone, Debug, Deserialize, Serialize)]
354#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
355pub struct FallbackAcknowledgement {
356 pub session: String,
358}
359
360impl FallbackAcknowledgement {
361 pub fn new(session: String) -> Self {
363 Self { session }
364 }
365}
366
367#[derive(Clone, Debug, Default, Deserialize, Serialize)]
375#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
376#[serde(tag = "type", rename = "m.login.terms")]
377pub struct Terms {
378 pub session: Option<String>,
380}
381
382impl Terms {
383 pub fn new() -> Self {
385 Self::default()
386 }
387}
388
389#[derive(Clone, Debug, Default, Deserialize, Serialize)]
393#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
394#[serde(tag = "type", rename = "m.oauth")]
395pub struct OAuth {
396 pub session: Option<String>,
398}
399
400impl OAuth {
401 pub fn new() -> Self {
403 Self::default()
404 }
405}
406
407#[doc(hidden)]
409#[derive(Clone, Serialize)]
410#[non_exhaustive]
411pub struct CustomAuthData {
412 #[serde(rename = "type")]
414 auth_type: String,
415
416 session: Option<String>,
418
419 #[serde(flatten)]
421 data: JsonObject,
422}
423
424impl fmt::Debug for CustomAuthData {
425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
426 let Self { auth_type, session, data: _ } = self;
427 f.debug_struct("CustomAuthData")
428 .field("auth_type", auth_type)
429 .field("session", session)
430 .finish_non_exhaustive()
431 }
432}
433
434#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
436#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
437#[serde(untagged)]
438pub enum UserIdentifier {
439 Matrix(MatrixUserIdentifier),
441
442 Email(EmailUserIdentifier),
444
445 Msisdn(MsisdnUserIdentifier),
447
448 PhoneNumber(PhoneNumberUserIdentifier),
450
451 #[doc(hidden)]
453 _CustomThirdParty(CustomThirdPartyUserIdentifier),
454
455 #[doc(hidden)]
457 _Custom(CustomUserIdentifier),
458}
459
460impl UserIdentifier {
461 pub fn identifier_type(&self) -> &str {
463 match self {
464 Self::Matrix(_) => "m.id.user",
465 Self::Email(_) => "m.id.thirdparty",
466 Self::Msisdn(_) => "m.id.thirdparty",
467 Self::PhoneNumber(_) => "m.id.phone",
468 Self::_CustomThirdParty(_) => "m.id.thirdparty",
469 Self::_Custom(CustomUserIdentifier { identifier_type, .. }) => identifier_type,
470 }
471 }
472
473 pub fn third_party_id(medium: Medium, address: String) -> Self {
475 match medium {
476 Medium::Email => Self::Email(EmailUserIdentifier { address }),
477 Medium::Msisdn => Self::Msisdn(MsisdnUserIdentifier { number: address }),
478 _ => Self::_CustomThirdParty(CustomThirdPartyUserIdentifier { medium, address }),
479 }
480 }
481
482 pub fn as_third_party_id(&self) -> Option<(&Medium, &str)> {
484 match self {
485 Self::Email(EmailUserIdentifier { address }) => Some((&Medium::Email, address)),
486 Self::Msisdn(MsisdnUserIdentifier { number }) => Some((&Medium::Msisdn, number)),
487 Self::_CustomThirdParty(CustomThirdPartyUserIdentifier { medium, address }) => {
488 Some((medium, address))
489 }
490 _ => None,
491 }
492 }
493
494 pub fn data(&self) -> Cow<'_, JsonObject> {
502 fn serialize<T: Serialize>(obj: &T) -> JsonObject {
503 match serde_json::to_value(obj).expect("user identifier serialization to succeed") {
504 JsonValue::Object(mut obj) => {
505 obj.remove("type");
506 obj
507 }
508 _ => panic!("all user identifiers must serialize to objects"),
509 }
510 }
511
512 match self {
513 Self::Matrix(i) => Cow::Owned(serialize(i)),
514 Self::Email(i) => Cow::Owned(serialize(i)),
515 Self::Msisdn(i) => Cow::Owned(serialize(i)),
516 Self::PhoneNumber(i) => Cow::Owned(serialize(i)),
517 Self::_CustomThirdParty(i) => Cow::Owned(serialize(i)),
518 Self::_Custom(i) => Cow::Borrowed(&i.data),
519 }
520 }
521}
522
523impl From<OwnedUserId> for UserIdentifier {
524 fn from(id: OwnedUserId) -> Self {
525 Self::Matrix(id.into())
526 }
527}
528
529impl From<&OwnedUserId> for UserIdentifier {
530 fn from(id: &OwnedUserId) -> Self {
531 Self::Matrix(id.into())
532 }
533}
534
535impl From<MatrixUserIdentifier> for UserIdentifier {
536 fn from(id: MatrixUserIdentifier) -> Self {
537 Self::Matrix(id)
538 }
539}
540
541impl From<EmailUserIdentifier> for UserIdentifier {
542 fn from(id: EmailUserIdentifier) -> Self {
543 Self::Email(id)
544 }
545}
546
547impl From<MsisdnUserIdentifier> for UserIdentifier {
548 fn from(id: MsisdnUserIdentifier) -> Self {
549 Self::Msisdn(id)
550 }
551}
552
553impl From<PhoneNumberUserIdentifier> for UserIdentifier {
554 fn from(id: PhoneNumberUserIdentifier) -> Self {
555 Self::PhoneNumber(id)
556 }
557}
558
559#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
561#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
562#[serde(tag = "type", rename = "m.id.user")]
563pub struct MatrixUserIdentifier {
564 pub user: String,
566}
567
568impl MatrixUserIdentifier {
569 pub fn new(user: String) -> Self {
571 Self { user }
572 }
573}
574
575impl From<OwnedUserId> for MatrixUserIdentifier {
576 fn from(id: OwnedUserId) -> Self {
577 Self::new(id.into())
578 }
579}
580
581impl From<&OwnedUserId> for MatrixUserIdentifier {
582 fn from(id: &OwnedUserId) -> Self {
583 Self::new(id.as_str().to_owned())
584 }
585}
586
587#[derive(Clone, Debug, PartialEq, Eq)]
589#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
590pub struct EmailUserIdentifier {
591 pub address: String,
593}
594
595impl EmailUserIdentifier {
596 pub fn new(address: String) -> Self {
598 Self { address }
599 }
600}
601
602#[derive(Clone, Debug, PartialEq, Eq)]
604#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
605pub struct MsisdnUserIdentifier {
606 pub number: String,
610}
611
612impl MsisdnUserIdentifier {
613 pub fn new(number: String) -> Self {
615 Self { number }
616 }
617}
618
619#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
623#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
624#[serde(tag = "type", rename = "m.id.phone")]
625pub struct PhoneNumberUserIdentifier {
626 pub country: String,
632
633 pub phone: String,
635}
636
637impl PhoneNumberUserIdentifier {
638 pub fn new(country: String, phone: String) -> Self {
640 Self { country, phone }
641 }
642}
643
644#[doc(hidden)]
646#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
647#[serde(tag = "type", rename = "m.id.thirdparty")]
648pub struct CustomThirdPartyUserIdentifier {
649 medium: Medium,
651
652 address: String,
654}
655
656#[doc(hidden)]
658#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
659pub struct CustomUserIdentifier {
660 #[serde(rename = "type")]
662 identifier_type: String,
663
664 #[serde(flatten)]
666 data: JsonObject,
667}
668
669#[derive(Clone, Deserialize, Serialize)]
671#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
672pub struct ThirdpartyIdCredentials {
673 pub sid: OwnedSessionId,
675
676 pub client_secret: OwnedClientSecret,
678
679 #[serde(skip_serializing_if = "Option::is_none")]
681 pub id_server: Option<String>,
682
683 #[serde(skip_serializing_if = "Option::is_none")]
685 pub id_access_token: Option<String>,
686}
687
688impl ThirdpartyIdCredentials {
689 pub fn new(sid: OwnedSessionId, client_secret: OwnedClientSecret) -> Self {
691 Self { sid, client_secret, id_server: None, id_access_token: None }
692 }
693}
694
695impl fmt::Debug for ThirdpartyIdCredentials {
696 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
697 let Self { sid, client_secret: _, id_server, id_access_token } = self;
698 f.debug_struct("ThirdpartyIdCredentials")
699 .field("sid", sid)
700 .field("id_server", id_server)
701 .field("id_access_token", id_access_token)
702 .finish_non_exhaustive()
703 }
704}