You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-29 22:01:14 +03:00
Allow fetching more nodes by their IDs
This commit is contained in:
@ -24,10 +24,10 @@
|
||||
|
||||
use async_graphql::{Context, Description, EmptyMutation, EmptySubscription, ID};
|
||||
use mas_axum_utils::SessionInfo;
|
||||
use model::NodeType;
|
||||
use mas_storage::LookupResultExt;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use self::model::{BrowserSession, Node, User};
|
||||
use self::model::{BrowserSession, Node, NodeType, OAuth2Client, User, UserEmail};
|
||||
|
||||
mod model;
|
||||
|
||||
@ -80,33 +80,122 @@ impl RootQuery {
|
||||
Ok(session.map(User::from))
|
||||
}
|
||||
|
||||
/// Fetches an object given its ID.
|
||||
async fn node(&self, ctx: &Context<'_>, id: ID) -> Result<Option<Node>, async_graphql::Error> {
|
||||
let (node_type, id) = NodeType::from_id(&id)?;
|
||||
/// Fetch an OAuth 2.0 client by its ID.
|
||||
async fn oauth2_client(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
id: ID,
|
||||
) -> Result<Option<OAuth2Client>, async_graphql::Error> {
|
||||
let id = NodeType::OAuth2Client.extract_ulid(&id)?;
|
||||
let database = ctx.data::<PgPool>()?;
|
||||
let mut conn = database.acquire().await?;
|
||||
|
||||
let client = mas_storage::oauth2::client::lookup_client(&mut conn, id)
|
||||
.await
|
||||
.to_option()?;
|
||||
|
||||
Ok(client.map(OAuth2Client))
|
||||
}
|
||||
|
||||
/// Fetch a user by its ID.
|
||||
async fn user(&self, ctx: &Context<'_>, id: ID) -> Result<Option<User>, async_graphql::Error> {
|
||||
let id = NodeType::User.extract_ulid(&id)?;
|
||||
let database = ctx.data::<PgPool>()?;
|
||||
let session_info = ctx.data::<SessionInfo>()?;
|
||||
let mut conn = database.acquire().await?;
|
||||
let session = session_info.load_session(&mut conn).await?;
|
||||
|
||||
let Some(session) = session else { return Ok(None) };
|
||||
let current_user = session.user;
|
||||
|
||||
match node_type {
|
||||
// TODO
|
||||
NodeType::Authentication
|
||||
| NodeType::BrowserSession
|
||||
| NodeType::CompatSession
|
||||
| NodeType::CompatSsoLogin
|
||||
| NodeType::OAuth2Client
|
||||
| NodeType::UserEmail
|
||||
| NodeType::OAuth2Session => Ok(None),
|
||||
|
||||
NodeType::User => {
|
||||
if session.user.data == id {
|
||||
Ok(Some(Box::new(User(session.user)).into()))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
if current_user.data == id {
|
||||
Ok(Some(User(current_user)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch a browser session by its ID.
|
||||
async fn browser_session(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
id: ID,
|
||||
) -> Result<Option<BrowserSession>, async_graphql::Error> {
|
||||
let id = NodeType::BrowserSession.extract_ulid(&id)?;
|
||||
let database = ctx.data::<PgPool>()?;
|
||||
let session_info = ctx.data::<SessionInfo>()?;
|
||||
let mut conn = database.acquire().await?;
|
||||
let session = session_info.load_session(&mut conn).await?;
|
||||
|
||||
let Some(session) = session else { return Ok(None) };
|
||||
let current_user = session.user;
|
||||
|
||||
let browser_session = mas_storage::user::lookup_active_session(&mut conn, id)
|
||||
.await
|
||||
.to_option()?;
|
||||
|
||||
let ret = browser_session.and_then(|browser_session| {
|
||||
if browser_session.user.data == current_user.data {
|
||||
Some(BrowserSession(browser_session))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Fetch a user email by its ID.
|
||||
async fn user_email(
|
||||
&self,
|
||||
ctx: &Context<'_>,
|
||||
id: ID,
|
||||
) -> Result<Option<UserEmail>, async_graphql::Error> {
|
||||
let id = NodeType::UserEmail.extract_ulid(&id)?;
|
||||
let database = ctx.data::<PgPool>()?;
|
||||
let session_info = ctx.data::<SessionInfo>()?;
|
||||
let mut conn = database.acquire().await?;
|
||||
let session = session_info.load_session(&mut conn).await?;
|
||||
|
||||
let Some(session) = session else { return Ok(None) };
|
||||
let current_user = session.user;
|
||||
|
||||
let user_email = mas_storage::user::lookup_user_email_by_id(&mut conn, ¤t_user, id)
|
||||
.await
|
||||
.to_option()?;
|
||||
|
||||
Ok(user_email.map(UserEmail))
|
||||
}
|
||||
|
||||
/// Fetches an object given its ID.
|
||||
async fn node(&self, ctx: &Context<'_>, id: ID) -> Result<Option<Node>, async_graphql::Error> {
|
||||
let (node_type, _id) = NodeType::from_id(&id)?;
|
||||
|
||||
let ret = match node_type {
|
||||
// TODO
|
||||
NodeType::Authentication
|
||||
| NodeType::CompatSession
|
||||
| NodeType::CompatSsoLogin
|
||||
| NodeType::OAuth2Session => None,
|
||||
|
||||
NodeType::OAuth2Client => self
|
||||
.oauth2_client(ctx, id)
|
||||
.await?
|
||||
.map(|c| Node::OAuth2Client(Box::new(c))),
|
||||
|
||||
NodeType::UserEmail => self
|
||||
.user_email(ctx, id)
|
||||
.await?
|
||||
.map(|e| Node::UserEmail(Box::new(e))),
|
||||
|
||||
NodeType::BrowserSession => self
|
||||
.browser_session(ctx, id)
|
||||
.await?
|
||||
.map(|s| Node::BrowserSession(Box::new(s))),
|
||||
|
||||
NodeType::User => self.user(ctx, id).await?.map(|u| Node::User(Box::new(u))),
|
||||
};
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ pub enum InvalidID {
|
||||
InvalidFormat,
|
||||
InvalidUlid(#[from] ulid::DecodeError),
|
||||
UnknownPrefix,
|
||||
TypeMismatch { got: NodeType, expected: NodeType },
|
||||
}
|
||||
|
||||
impl NodeType {
|
||||
@ -90,6 +91,19 @@ impl NodeType {
|
||||
pub fn from_id(id: &ID) -> Result<(Self, Ulid), InvalidID> {
|
||||
Self::deserialize(&id.0)
|
||||
}
|
||||
|
||||
pub fn extract_ulid(self, id: &ID) -> Result<Ulid, InvalidID> {
|
||||
let (node_type, ulid) = Self::deserialize(&id.0)?;
|
||||
|
||||
if node_type == self {
|
||||
Ok(ulid)
|
||||
} else {
|
||||
Err(InvalidID::TypeMismatch {
|
||||
got: node_type,
|
||||
expected: self,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An object with an ID.
|
||||
|
@ -256,7 +256,7 @@ impl User {
|
||||
|
||||
/// A user email address
|
||||
#[derive(Description)]
|
||||
pub struct UserEmail(mas_data_model::UserEmail<PostgresqlBackend>);
|
||||
pub struct UserEmail(pub mas_data_model::UserEmail<PostgresqlBackend>);
|
||||
|
||||
#[Object(use_type_description)]
|
||||
impl UserEmail {
|
||||
|
Reference in New Issue
Block a user