Abstract and dedup the general UIAA pattern into api::router.

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk
2025-09-10 10:08:11 +00:00
parent 8ed61aecb0
commit 54b347b855
5 changed files with 103 additions and 180 deletions

View File

@@ -1,5 +1,6 @@
mod appservice;
mod server;
mod uiaa;
use std::{fmt::Debug, time::SystemTime};
@@ -35,6 +36,7 @@ use ruma::{
use tuwunel_core::{Err, Error, Result, is_less_than, utils::result::LogDebugErr};
use tuwunel_service::{Services, appservice::RegistrationInfo};
pub(crate) use self::uiaa::auth_uiaa;
use self::{appservice::auth_appservice, server::auth_server};
use super::request::Request;

View File

@@ -0,0 +1,81 @@
use ruma::{
CanonicalJsonValue, OwnedUserId,
api::{
IncomingRequest,
client::uiaa::{AuthData, AuthFlow, AuthType, Jwt, UiaaInfo},
},
};
use tuwunel_core::{Err, Error, Result, err, utils};
use tuwunel_service::{Services, uiaa::SESSION_ID_LENGTH};
use crate::{Ruma, client::jwt};
pub(crate) async fn auth_uiaa<T>(services: &Services, body: &Ruma<T>) -> Result<OwnedUserId>
where
T: IncomingRequest + Send + Sync,
{
let flows = [
AuthFlow::new([AuthType::Password].into()),
AuthFlow::new([AuthType::Jwt].into()),
];
let mut uiaainfo = UiaaInfo {
flows: flows.into(),
..Default::default()
};
match body
.json_body
.as_ref()
.and_then(CanonicalJsonValue::as_object)
.and_then(|body| body.get("auth"))
.cloned()
.map(CanonicalJsonValue::into)
.map(serde_json::from_value)
.transpose()?
{
| Some(AuthData::Jwt(Jwt { ref token, .. })) => {
let sender_user = jwt::validate_user(services, token)?;
if !services.users.exists(&sender_user).await {
return Err!(Request(NotFound("User {sender_user} is not registered.")));
}
// Success!
Ok(sender_user)
},
| Some(ref auth) => {
let sender_user = body
.sender_user
.as_deref()
.ok_or_else(|| err!(Request(MissingToken("Missing access token."))))?;
let (worked, uiaainfo) = services
.uiaa
.try_auth(sender_user, body.sender_device(), auth, &uiaainfo)
.await?;
if !worked {
return Err(Error::Uiaa(uiaainfo));
}
// Success!
Ok(sender_user.to_owned())
},
| _ => match body.json_body {
| Some(ref json) => {
let sender_user = body
.sender_user
.as_ref()
.ok_or_else(|| err!(Request(MissingToken("Missing access token."))))?;
uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
services
.uiaa
.create(sender_user, body.sender_device(), &uiaainfo, json);
Err(Error::Uiaa(uiaainfo))
},
| _ => Err!(Request(NotJson("JSON body is not valid"))),
},
}
}