Skip to main content

ruma_identity_service_api/invitation/
store_invitation.rs

1//! `POST /_matrix/identity/*/store-invite`
2//!
3//! Store pending invitations to a user's third-party ID.
4
5pub mod v2 {
6    //! `/v2/` ([spec])
7    //!
8    //! [spec]: https://spec.matrix.org/v1.19/identity-service-api/#post_matrixidentityv2store-invite
9
10    use ruma_common::{
11        OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, OwnedUserId,
12        api::{request, response},
13        metadata,
14        room::RoomType,
15        third_party_invite::IdentityServerBase64PublicKey,
16        thirdparty::Medium,
17    };
18    use ruma_events::room::third_party_invite::RoomThirdPartyInviteEventContent;
19    use serde::{Deserialize, Serialize, ser::SerializeSeq};
20
21    use crate::IdentityServiceToken;
22
23    metadata! {
24        method: POST,
25        rate_limited: false,
26        authentication: IdentityServiceToken,
27        history: {
28            1.0 => "/_matrix/identity/v2/store-invite",
29        }
30    }
31
32    /// Request type for the `store_invitation` endpoint.
33    #[request]
34    pub struct Request {
35        /// The type of the third party identifier for the invited user.
36        ///
37        /// Currently, only `Medium::Email` is supported.
38        pub medium: Medium,
39
40        /// The email address of the invited user.
41        pub address: String,
42
43        /// The Matrix room ID to which the user is invited.
44        pub room_id: OwnedRoomId,
45
46        /// The Matrix user ID of the inviting user.
47        pub sender: OwnedUserId,
48
49        /// The Matrix room alias for the room to which the user is invited.
50        ///
51        /// This should be retrieved from the `m.room.canonical` state event.
52        #[serde(skip_serializing_if = "Option::is_none")]
53        pub room_alias: Option<OwnedRoomAliasId>,
54
55        /// The Content URI for the room to which the user is invited.
56        ///
57        /// This should be retrieved from the `m.room.avatar` state event.
58        #[serde(skip_serializing_if = "Option::is_none")]
59        pub room_avatar_url: Option<OwnedMxcUri>,
60
61        /// The `join_rule` for the room to which the user is invited.
62        ///
63        /// This should be retrieved from the `m.room.join_rules` state event.
64        #[serde(skip_serializing_if = "Option::is_none")]
65        pub room_join_rules: Option<String>,
66
67        /// The name of the room to which the user is invited.
68        ///
69        /// This should be retrieved from the `m.room.name` state event.
70        #[serde(skip_serializing_if = "Option::is_none")]
71        pub room_name: Option<String>,
72
73        /// The type of the room to which the user is invited.
74        ///
75        /// This should be retrieved from the `m.room.create` state event.
76        #[serde(skip_serializing_if = "Option::is_none")]
77        pub room_type: Option<RoomType>,
78
79        /// The display name of the user ID initiating the invite.
80        #[serde(skip_serializing_if = "Option::is_none")]
81        pub sender_display_name: Option<String>,
82
83        /// The Content URI for the avater of the user ID initiating the invite.
84        #[serde(skip_serializing_if = "Option::is_none")]
85        pub sender_avatar_url: Option<OwnedMxcUri>,
86    }
87
88    /// Response type for the `store_invitation` endpoint.
89    #[response]
90    pub struct Response {
91        /// The generated token.
92        ///
93        /// Must be a string consisting of the characters `[0-9a-zA-Z.=_-]`. Its length must not
94        /// exceed 255 characters and it must not be empty.
95        pub token: String,
96
97        /// A list of [server's long-term public key, generated ephemeral public key].
98        pub public_keys: PublicKeys,
99
100        /// The generated (redacted) display_name.
101        ///
102        /// An example is `f...@b...`.
103        pub display_name: String,
104    }
105
106    impl Request {
107        /// Creates a new `Request with the given medium, email address, room ID and sender.
108        pub fn new(
109            medium: Medium,
110            address: String,
111            room_id: OwnedRoomId,
112            sender: OwnedUserId,
113        ) -> Self {
114            Self {
115                medium,
116                address,
117                room_id,
118                sender,
119                room_alias: None,
120                room_avatar_url: None,
121                room_join_rules: None,
122                room_name: None,
123                room_type: None,
124                sender_display_name: None,
125                sender_avatar_url: None,
126            }
127        }
128
129        /// Creates a new `Request` with the given email address, room ID and sender.
130        pub fn email(address: String, room_id: OwnedRoomId, sender: OwnedUserId) -> Self {
131            Self::new(Medium::Email, address, room_id, sender)
132        }
133    }
134
135    impl Response {
136        /// Creates a new `Response` with the given token, public keys and display name.
137        pub fn new(token: String, public_keys: PublicKeys, display_name: String) -> Self {
138            Self { token, public_keys, display_name }
139        }
140    }
141
142    /// The server's long-term public key and generated ephemeral public key.
143    #[derive(Debug, Clone)]
144    #[allow(clippy::exhaustive_structs)]
145    pub struct PublicKeys {
146        /// The server's long-term public key.
147        pub server_key: PublicKey,
148
149        /// The generated ephemeral public key.
150        pub ephemeral_key: PublicKey,
151    }
152
153    impl<'de> Deserialize<'de> for PublicKeys {
154        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
155        where
156            D: serde::Deserializer<'de>,
157        {
158            let [server_key, ephemeral_key] = <[PublicKey; 2]>::deserialize(deserializer)?;
159
160            Ok(Self { server_key, ephemeral_key })
161        }
162    }
163
164    impl Serialize for PublicKeys {
165        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
166        where
167            S: serde::Serializer,
168        {
169            let mut seq = serializer.serialize_seq(Some(2))?;
170
171            seq.serialize_element(&self.server_key)?;
172            seq.serialize_element(&self.ephemeral_key)?;
173
174            seq.end()
175        }
176    }
177
178    /// A server's long-term or ephemeral public key.
179    #[derive(Clone, Debug, Serialize, Deserialize)]
180    #[non_exhaustive]
181    pub struct PublicKey {
182        /// The public key, encoded using unpadded base64.
183        pub public_key: IdentityServerBase64PublicKey,
184
185        /// The URI of an endpoint where the validity of this key can be checked by passing it as a
186        /// `public_key` query parameter.
187        pub key_validity_url: String,
188    }
189
190    impl PublicKey {
191        /// Constructs a new `PublicKey` with the given encoded public key and key validity URL.
192        pub fn new(public_key: IdentityServerBase64PublicKey, key_validity_url: String) -> Self {
193            Self { public_key, key_validity_url }
194        }
195    }
196
197    impl From<PublicKey> for ruma_events::room::third_party_invite::PublicKey {
198        fn from(key: PublicKey) -> Self {
199            let mut new_key = Self::new(key.public_key);
200            new_key.key_validity_url = Some(key.key_validity_url);
201            new_key
202        }
203    }
204
205    impl From<Response> for RoomThirdPartyInviteEventContent {
206        fn from(response: Response) -> Self {
207            let mut content = RoomThirdPartyInviteEventContent::new(
208                response.display_name,
209                response.public_keys.server_key.key_validity_url.clone(),
210                response.public_keys.server_key.public_key.clone(),
211            );
212            content.public_keys = Some(vec![
213                response.public_keys.server_key.into(),
214                response.public_keys.ephemeral_key.into(),
215            ]);
216            content
217        }
218    }
219}