Skip to main content

pubhubs/api/
mod.rs

1//! Types describing the pubhubs API
2//!
3//! The different endpoints offered by the PubHubs servers and hubs are described by types
4//! implementing the [`EndpointDetails`] trait.
5//!
6//! # Overview for web clients
7//!
8//! For reference, the flows described below to enter pubhubs, to enter a hub and to obtain a pubhubs card
9//! are also implemented by the `pubhubs enter` CLI tool see [`crate::cli`], which
10//! is usually invoked via `cargo run enter`.
11//!
12//! ## Entering pubhubs
13//!
14//!  1. Everything starts with the global client, knowing only the url of pubhubs central (PHC),
15//!     obtaining general information about the rest of the pubhubs environment
16//!     from the [`phc::user::WelcomeEP`] endpoint of PHC, including, for example, the url of
17//!     the authentication server and transcryptor.
18//!
19//!  2. Next the user authenticates towards the
20//!     authentication server in order to obtain **[`Attr`]ibutes**.
21//!  
22//!     -  The global client first gets the available authentication methods via [`auths::WelcomeEP`], and
23//!     -  then obtains the attributes using the [`auths::AuthStartEP`]
24//!        and [`auths::AuthCompleteEP`] endpoints.
25//!
26//!  3. Using those [`Attr`]ibutes the global client can 'enter' PubHubs via the
27//!     [`phc::user::EnterEP`], registering a new account if needed.
28//!     or logging into an existing account.  The result of entering PubHubs is not
29//!     a session cookie, but an **[`phc::user::AuthToken`]** that must be passed along
30//!     in the `Authorization` header of most subsequent requests from the global client to PHC.
31//!
32//!  4. After having entered pubhubs, the global client retrieves details on the [`phc::user::UserState`] via
33//!     the [`phc::user::StateEP`] endpoint (authenticating using the previously obtained auth token).  
34//!     The user state includes (among other details), a list of stored **user objects**,
35//!     [`phc::user::UserState::stored_objects`], which can be retrieved using
36//!     [`phc::user::GetObjectEP`] (and stored using [`phc::user::OverwriteObjectEP`] and
37//!     [`phc::user::NewObjectEP`]).
38//!
39//!  5. The contents of user objects should be encrypted by the global client. Indeed, there's
40//!     no need for PHC to be able to read the contents of these user objects.
41//!     But where can the global client store the 'user object key' used to encrypt
42//!     these objects?  Not in plaintext at PHC!  Instead, the authentication server provides
43//!     **attribute keys** via [`auths::AttrKeysEP`] with which the global client can encrypt its
44//!     'user object key' before storing it at PHC in a designated user object.  Other user objects
45//!     can then be encrypted using this user object key.
46//!
47//! ## Entering hubs
48//!
49//! Entering a hub is slightly more involved, as pubhubs central is not allowed to know the hub and
50//! the transcryptor is not allowed to know the user.  These privacy guarantees can be achieved by
51//! clever use of elliptic curves as described in [the whitepaper](https://academic.oup.com/logcom/article/34/7/1377/7319213)  
52//! The procedure below uses the same
53//! ideas but has been modified to prevent already generated pseudonyms from being linked
54//! when a cryptographically relevant quantum computer materializes.
55//! For the cryptographic details, see [`sso`].
56//!
57//!  1. The global client obtains a sealed  **[`sso::PolymorphicPseudonymPackage`] (PPP)**
58//!     from PHC via [`phc::user::PppEP`] and a **hub nonce** and **hub state**
59//!     pair from the hub via [`hub::EnterStartEP`].
60//!
61//!  2. The global client sends the PPP, hub nonce and hub id to the transcryptor's
62//!     [`tr::EhppEP`], which yields a sealed **[`sso::EncryptedHubPseudonymPackage`] (EHPP)**.
63//!
64//!  3. This EHPP is forwarded back to PHC, to the [`phc::user::HhppEP`], yielding a signed
65//!     **[`sso::HashedHubPseudonymPackage`] (HHPP)**.
66//!
67//!  4. This HHPP is sent back by the global client to the hub's [`hub::EnterCompleteEP`],
68//!     together with the **hub state**, which results in a Synapse access token to the hub.
69//!
70//! ## PubHubs card
71//!
72//! Pubhubs also issues yivi 'PubHubs cards'.  To obtain one for the user:
73//!
74//!  1. First enter pubhubs, and get a signed [`phc::user::CardPseudPackage`] from PHC via
75//!     [`phc::user::CardPseudEP`].
76//!
77//!  2. Then pass this to [`auths::CardEP`] to get:
78//!
79//!     - An [`auths::CardResp::Success::attr`] [`Attr`]ibute that can be added to the user's
80//!       account via the [`phc::user::EnterEP`] endpoint.  Note that instead of passing an
81//!       identifying attribute, one may also authenticate by putting auth token in the
82//!       `Authorization` header.
83//!
84//!     - An [`auths::CardResp::Success::issuance_request`] that can be used to start an issuance
85//!       session with the authentication server's yivi server to issue the card to the user.  It's
86//!       important that this is done _after_ adding the card to user's yivi app lest the user
87//!       might end up with a card that does not work.
88//!
89//!  In the flow above, the user may have to scan two Yivi QR codes: one to disclosure attributes
90//!  to enter pubhubs, and then another QR code to receive the PubHubs card.  The disclosure and
91//!  issuance Yivi sessions can be combined into one 'chained session' as follows.
92//!
93//!  1. When entering PubHubs, set [`auths::AuthStartReq::yivi_chained_session`] to `true`.
94//!
95//!     This causes the yivi server to not immediately return the disclosure result to the browser,
96//!     but first to the `auths::YIVI_NEXT_SESSION_PATH` endpoint of this authentication server.
97//!
98//!  2. When the authentication server receives this disclosure, it will keep the yivi server
99//!     waiting, and will make the disclosure available via [`auths::YiviWaitForResultEP`].
100//!     (The disclosure can unfortunately not be obtained in the regular way from the yivi server
101//!     until the authentication server releases the yivi server.)
102//!
103//!  3. Using this disclosure, one can obtain [`Attr`]ibutes, enter PubHubs, obtain a PubHubs card,
104//!     and add this card to the user's account, exactly as before.
105//!  
106//!  4. But now instead of passing it directly to the yivi server (which involves scanning a second
107//!     QR code), [`auths::CardResp::Success::issuance_request`] can be passed via the
108//!     [`auths::YiviReleaseNextSessionEP`] endpoint of the authentication server to the waiting yivi
109//!     server, which will cause the current disclosure session to be followed-up by the pubhubs
110//!     card issuance session - without the user having to scan a second QR code.
111//!
112//! # Errors
113//!
114//! A request to a pubhubs endpoint may fail in several ways.
115//!
116//!  1. Errors that are par for the course are generally encoded in
117//!     [`EndpointDetails::ResponseType`] types themselves.  For example,
118//!     [`phc::user::EnterResp::AccountDoesNotExist`] is returned when a user tries to log into an
119//!     account that does not exist.  It should always be clear to the caller how to act on these errors.
120//!
121//!  2. Other errors, such as unexpected errors, or errors caused by the caller breaking protocol
122//!     in some avoidable manner are generally  returned via the [`ErrorCode`]
123//!     in the `Result<EndpointDetails::ResponseType, ErrorCode>`.
124//!
125//!     - **[`ErrorCode::InternalError`]**: something unexpected went wrong internally.  
126//!       Consult the logs of the server for more details.  Retrying the request is not
127//!       recommended.
128//!
129//!     - **[`ErrorCode::PleaseRetry`]**
130//!       just wait a moment, and retry the same request.
131//!
132//!     - **[`ErrorCode::BadRequest`]**: there's something unexpected is wrong with the request - do not
133//!       retransmit the same request.
134//!
135//!  3. It may, however, happen that a request is rejected before it reaches our code, for example,
136//!     by the HTTP framework [`actix_web`] or by the reverse proxy.  One may in that case encounter a
137//!     HTTP status code (or even a TCP/TLS disconnect).  Notable HTTP status codes are:
138//!
139//!      - **400 - Bad Request**  Occurs, for example, when the json in the request body cannot be deserialized
140//!        to the [`EndpointDetails::RequestType`].
141//!
142//!      - **502 - Bad Gateway**  Occurs, for example, when one of the servers is (temporarily)
143//!        down.  The client should try the same request again.
144//!
145//!  4. A response may also be rejected when it arrives at a browser, for example, due to improperly set
146//!     [Cross-Origin Resource Sharing] headers.  
147//!
148//! [Cross-Origin Resource Sharing]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS
149//! [`Attr`]: crate::attr::Attr
150//!
151//! # Changelog of breaking changes
152//!
153//! ## 2025-06-25
154//!  - Removed `Expired` and `InvalidSignature` error codes.
155//!  - Added [`phc::user::EnterResp::RetryWithNewIdentifyingAttr`] and
156//!    [`phc::user::EnterResp::RetryWithNewAddAttr`] variants.
157//!
158//! ## 2025-07-14
159//!  - Renamed `phc::user::EnterResp::Entered::auth_token` to
160//!    [`phc::user::EnterResp::Entered::auth_token_package`], and changed its type,
161//!    replacing [`phc::user::AuthToken`]
162//!    with [`phc::user::AuthTokenPackage`] (which contains an expiry date). Instead of
163//!    `{ "Ok": "AuThToken..." }` the `auth_token(_package)` field will now
164//!    be of the form `{ "Ok": { "auth_token": "AuThToken", "expires": 123456789 } }`.
165mod common;
166pub use common::*;
167mod signed;
168pub use signed::*;
169mod sealed;
170pub use sealed::*;
171
172mod discovery;
173pub use discovery::*;
174
175#[cfg(test)]
176mod wire_compat;
177
178pub mod admin;
179
180pub mod auths;
181pub mod hub;
182pub mod phc;
183pub mod server;
184pub mod tr;
185
186pub mod sso;
187
188pub use crate::misc::jwt::NumericDate;