pubhubs/servers/phc/
user_sso.rs1use std::rc::Rc;
3
4use curve25519_dalek::RistrettoPoint;
5
6use crate::api;
7use crate::id;
8
9use serde::{Deserialize, Serialize};
10
11use super::server::*;
12use crate::api::phc::user::*;
13use crate::api::sso::*;
14
15impl App {
16 pub(crate) async fn handle_user_ppp(
18 app: Rc<Self>,
19 auth_token: actix_web::web::Header<AuthToken>,
20 ) -> api::Result<PppResp> {
21 let running_state = app.running_state_or_please_retry()?;
22
23 let Ok((user_state, _)) = app
24 .open_auth_token_and_get_user_state(auth_token.into_inner())
25 .await?
26 else {
27 return Ok(PppResp::RetryWithNewAuthToken);
28 };
29
30 let now = api::NumericDate::now();
31
32 let nonce_inner = PpNonceInner {
33 user_id: user_state.id,
34 not_valid_after: now + app.pp_nonce_validity,
35 issued_at: now,
36 };
37
38 Ok(PppResp::Success(api::Sealed::new(
39 &PolymorphicPseudonymPackage {
40 polymorphic_pseudonym: user_state.polymorphic_pseudonym.rerandomize(),
43 nonce: api::Sealed::new(&nonce_inner, &app.pp_nonce_secret)?.into(),
44 },
45 &running_state.t_sealing_secret,
46 )?))
47 }
48
49 pub(crate) async fn handle_user_hhpp(
51 app: Rc<Self>,
52 req: actix_web::web::Json<HhppReq>,
53 auth_token: actix_web::web::Header<AuthToken>,
54 ) -> api::Result<HhppResp> {
55 let running_state = app.running_state_or_please_retry()?;
56
57 let Ok(auth_token_user_id) = app.open_auth_token(auth_token.into_inner()) else {
58 return Ok(HhppResp::RetryWithNewAuthToken);
59 };
60
61 let req = req.into_inner();
62
63 let Ok(EncryptedHubPseudonymPackage {
64 encrypted_hub_pseudonym,
65 hub_nonce,
66 phc_nonce,
67 }) = req.ehpp.open(&running_state.t_sealing_secret)
68 else {
69 log::debug!("invalid Ehpp submitted to Hhpp endpoint");
70 return Ok(HhppResp::RetryWithNewPpp);
71 };
72
73 let Ok(PpNonceInner {
74 user_id: phc_nonce_user_id,
75 issued_at: pp_issued_at,
76 not_valid_after,
77 }) = api::Sealed::<PpNonceInner>::from(phc_nonce).open(&app.pp_nonce_secret)
78 else {
79 log::info!("Ehpp containing invalid PHC nonce submitted to Hhpp endpoint");
80 return Ok(HhppResp::RetryWithNewPpp);
81 };
83
84 if phc_nonce_user_id != auth_token_user_id {
85 log::warn!("user {auth_token_user_id} used {phc_nonce_user_id}'s PP nonce");
86 return Err(api::ErrorCode::BadRequest);
87 }
88
89 if not_valid_after < api::NumericDate::now() {
90 log::debug!("Ehpp containing expired PHC nonce submitted to Hhpp endpoint");
91 return Ok(HhppResp::RetryWithNewPpp);
92 }
93
94 let Some(hub_pseudonym) =
95 encrypted_hub_pseudonym.decrypt_and_check_pk(&app.master_enc_key_part)
96 else {
97 log::warn!("hub pseudonym was encrypted for the wrong public key");
98 return Err(api::ErrorCode::InternalError);
99 };
103
104 let hashed_hub_pseudonym: api::CurvePoint =
105 RistrettoPoint::hash_from_bytes::<sha2::Sha512>(hub_pseudonym.compress().as_bytes())
106 .compress()
107 .into();
108
109 Ok(HhppResp::Success(api::Signed::new_opts(
110 &*app.jwt_key,
111 &HashedHubPseudonymPackage {
112 hashed_hub_pseudonym,
113 pp_issued_at,
114 hub_nonce,
115 },
116 app.pp_nonce_validity,
117 Some(&running_state.constellation),
120 )?))
121 }
122}
123
124#[derive(Serialize, Deserialize, Debug)]
126struct PpNonceInner {
127 not_valid_after: api::NumericDate,
129
130 issued_at: api::NumericDate,
132
133 user_id: id::Id,
135}
136
137api::having_message_code!(PpNonceInner, PpNonce);
138
139impl From<api::Sealed<PpNonceInner>> for PpNonce {
140 fn from(sealed: api::Sealed<PpNonceInner>) -> Self {
141 Self {
142 inner: sealed.inner,
143 }
144 }
145}
146
147impl From<PpNonce> for api::Sealed<PpNonceInner> {
148 fn from(nonce: PpNonce) -> Self {
149 nonce.inner.into()
150 }
151}