Skip to main content

pubhubs/api/
hub.rs

1//! Endpoints provided by a hub
2use actix_web::http;
3use serde::{Deserialize, Serialize};
4
5use crate::api::*;
6use crate::misc::serde_ext::bytes_wrapper::B64UU;
7
8/// Basic information advertised by the hub
9pub struct InfoEP {}
10impl EndpointDetails for InfoEP {
11    type RequestType = NoPayload;
12    type ResponseType = Result<InfoResp>;
13
14    const METHOD: http::Method = http::Method::GET;
15    const PATH: &'static str = ".ph/info";
16}
17
18#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
19#[serde(deny_unknown_fields)]
20#[must_use]
21pub struct InfoResp {
22    /// Key used by the hub to sign requests to the other hubs with
23    ///
24    /// (Not currently returned by actual hubs.)
25    #[serde(default)]
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub verifying_key: Option<VerifyingKey>,
28
29    /// String describing the hub version, likely the result of `git describe --tags`
30    pub hub_version: String,
31
32    /// URL to this hub's client
33    pub hub_client_url: url::Url,
34
35    /// Changeable information about this hub.
36    #[serde(default)]
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub dynamic: Option<DynamicHubInfo>,
39}
40
41/// Type for [`InfoResp::dynamic`]
42#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
43#[serde(deny_unknown_fields)]
44#[must_use]
45pub struct DynamicHubInfo {
46    /// The last time these settings were reloaded by the hub
47    pub last_reload: NumericDate,
48
49    /// Hub settings set by admin
50    pub settings: serde_json::Value,
51}
52
53/// Endpoint that start the authentication of a (not yet existing) user
54pub struct EnterStartEP {}
55impl EndpointDetails for EnterStartEP {
56    type RequestType = NoPayload;
57    type ResponseType = Result<EnterStartResp>;
58
59    const METHOD: http::Method = http::Method::POST; // to dissuade caching
60    const PATH: &'static str = ".ph/enter-start";
61}
62
63/// What's returned by [`EnterStartEP`].
64#[derive(Serialize, Deserialize, Debug, Clone)]
65#[serde(deny_unknown_fields)]
66#[must_use]
67pub struct EnterStartResp {
68    /// Opaque state that needs to be send to the [`EnterCompleteEP`] later on
69    pub state: EnterState,
70
71    /// Opaque number used only once to be included in the hub pseudonym package.
72    pub nonce: EnterNonce,
73}
74
75/// Type of [`EnterStartResp::state`]
76#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
77#[serde(transparent)]
78pub struct EnterState {
79    pub(crate) inner: B64UU,
80}
81
82impl From<B64UU> for EnterState {
83    fn from(inner: B64UU) -> Self {
84        Self { inner }
85    }
86}
87
88/// Type of [`EnterStartResp::nonce`]
89#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
90#[serde(transparent)]
91pub struct EnterNonce {
92    pub(crate) inner: B64UU,
93}
94impl From<B64UU> for EnterNonce {
95    fn from(inner: B64UU) -> Self {
96        Self { inner }
97    }
98}
99
100/// Endpoint to complete user authentication
101pub struct EnterCompleteEP {}
102impl EndpointDetails for EnterCompleteEP {
103    type RequestType = EnterCompleteReq;
104    type ResponseType = Result<EnterCompleteResp>;
105
106    const METHOD: http::Method = http::Method::POST; // to dissuade caching
107    const PATH: &'static str = ".ph/enter-complete";
108}
109
110/// What's sent to [`EnterCompleteEP`]
111#[derive(Serialize, Deserialize, Debug, Clone)]
112#[serde(deny_unknown_fields)]
113pub struct EnterCompleteReq {
114    /// The one you got from [`EnterStartResp::state`]
115    pub state: EnterState,
116
117    /// The hashed hub pseudonym package obtained from pubhubs central.
118    /// Should include the [`EnterStartResp::nonce`] belonging to the [`Self::state`].
119    pub hhpp: Signed<sso::HashedHubPseudonymPackage>,
120}
121
122/// What's returned by [`EnterCompleteEP`].
123#[derive(Serialize, Deserialize, Debug, Clone)]
124#[serde(deny_unknown_fields)]
125#[must_use]
126pub enum EnterCompleteResp {
127    /// Start again at [`EnterStartEP`]
128    RetryFromStart,
129
130    Entered {
131        /// Synapse access token
132        access_token: String,
133
134        /// Device ID.  (Not sure if it's useful to the global client, though.)
135        device_id: String,
136
137        /// True if this is the first time this user enters this hub.
138        new_user: bool,
139
140        /// Matrix id to use in combination with the [`Self::Entered::access_token`] to log in.
141        mxid: String,
142    },
143}