You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-07-31 09:24:31 +03:00
Simple list of compat sessions
This commit is contained in:
@ -10,7 +10,9 @@ async-graphql = { version = "4.0.16", features = ["chrono", "url"] }
|
||||
chrono = "0.4.23"
|
||||
serde = { version = "1.0.147", features = ["derive"] }
|
||||
sqlx = { version = "0.6.2", features = ["runtime-tokio-rustls", "postgres"] }
|
||||
thiserror = "1.0.37"
|
||||
tokio = { version = "1.21.2", features = ["time"] }
|
||||
tracing = "0.1.37"
|
||||
ulid = "1.0.0"
|
||||
url = "2.3.1"
|
||||
|
||||
|
@ -22,8 +22,9 @@
|
||||
#![warn(clippy::pedantic)]
|
||||
#![allow(clippy::module_name_repetitions, clippy::missing_errors_doc)]
|
||||
|
||||
use async_graphql::{Context, Description, EmptyMutation, EmptySubscription};
|
||||
use async_graphql::{Context, Description, EmptyMutation, EmptySubscription, ID};
|
||||
use mas_axum_utils::SessionInfo;
|
||||
use model::NodeType;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use self::model::{BrowserSession, Node, User};
|
||||
@ -78,4 +79,34 @@ 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)?;
|
||||
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) };
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use async_graphql::{Description, Object, ID};
|
||||
use chrono::{DateTime, Utc};
|
||||
use mas_storage::PostgresqlBackend;
|
||||
|
||||
use super::User;
|
||||
use super::{NodeType, User};
|
||||
|
||||
/// A browser session represents a logged in user in a browser.
|
||||
#[derive(Description)]
|
||||
@ -32,7 +32,7 @@ impl From<mas_data_model::BrowserSession<PostgresqlBackend>> for BrowserSession
|
||||
impl BrowserSession {
|
||||
/// ID of the object.
|
||||
pub async fn id(&self) -> ID {
|
||||
ID(self.0.data.to_string())
|
||||
NodeType::BrowserSession.id(self.0.data)
|
||||
}
|
||||
|
||||
/// The user logged in this session.
|
||||
@ -60,7 +60,7 @@ pub struct Authentication(pub mas_data_model::Authentication<PostgresqlBackend>)
|
||||
impl Authentication {
|
||||
/// ID of the object.
|
||||
pub async fn id(&self) -> ID {
|
||||
ID(self.0.data.to_string())
|
||||
NodeType::Authentication.id(self.0.data)
|
||||
}
|
||||
|
||||
/// When the object was created.
|
||||
|
@ -18,7 +18,7 @@ use mas_data_model::CompatSsoLoginState;
|
||||
use mas_storage::PostgresqlBackend;
|
||||
use url::Url;
|
||||
|
||||
use super::User;
|
||||
use super::{NodeType, User};
|
||||
|
||||
/// A compat session represents a client session which used the legacy Matrix
|
||||
/// login API.
|
||||
@ -29,7 +29,7 @@ pub struct CompatSession(pub mas_data_model::CompatSession<PostgresqlBackend>);
|
||||
impl CompatSession {
|
||||
/// ID of the object.
|
||||
pub async fn id(&self) -> ID {
|
||||
ID(self.0.data.to_string())
|
||||
NodeType::CompatSession.id(self.0.data)
|
||||
}
|
||||
|
||||
/// The user authorized for this session.
|
||||
@ -62,7 +62,7 @@ pub struct CompatSsoLogin(pub mas_data_model::CompatSsoLogin<PostgresqlBackend>)
|
||||
impl CompatSsoLogin {
|
||||
/// ID of the object.
|
||||
pub async fn id(&self) -> ID {
|
||||
ID(self.0.data.to_string())
|
||||
NodeType::CompatSsoLogin.id(self.0.data)
|
||||
}
|
||||
|
||||
/// When the object was created.
|
||||
|
@ -16,14 +16,7 @@ use async_graphql::connection::OpaqueCursor;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ulid::Ulid;
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Copy)]
|
||||
#[serde(rename = "snake_case")]
|
||||
pub enum NodeType {
|
||||
UserEmail,
|
||||
BrowserSession,
|
||||
CompatSsoLogin,
|
||||
OAuth2Session,
|
||||
}
|
||||
pub use super::NodeType;
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct NodeCursor(pub NodeType, pub Ulid);
|
||||
|
@ -12,37 +12,25 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use async_graphql::{Interface, ID};
|
||||
use async_graphql::Interface;
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
mod browser_sessions;
|
||||
mod compat_sessions;
|
||||
mod cursor;
|
||||
mod node;
|
||||
mod oauth;
|
||||
mod users;
|
||||
|
||||
pub use self::{
|
||||
browser_sessions::{Authentication, BrowserSession},
|
||||
compat_sessions::{CompatSession, CompatSsoLogin},
|
||||
cursor::{Cursor, NodeCursor, NodeType},
|
||||
cursor::{Cursor, NodeCursor},
|
||||
node::{Node, NodeType},
|
||||
oauth::{OAuth2Client, OAuth2Consent, OAuth2Session},
|
||||
users::{User, UserEmail},
|
||||
};
|
||||
|
||||
/// An object with an ID.
|
||||
#[derive(Interface)]
|
||||
#[graphql(field(name = "id", desc = "ID of the object.", type = "ID"))]
|
||||
pub enum Node {
|
||||
Authentication(Box<Authentication>),
|
||||
BrowserSession(Box<BrowserSession>),
|
||||
CompatSession(Box<CompatSession>),
|
||||
CompatSsoLogin(Box<CompatSsoLogin>),
|
||||
OAuth2Client(Box<OAuth2Client>),
|
||||
OAuth2Session(Box<OAuth2Session>),
|
||||
User(Box<User>),
|
||||
UserEmail(Box<UserEmail>),
|
||||
}
|
||||
|
||||
#[derive(Interface)]
|
||||
#[graphql(field(
|
||||
name = "created_at",
|
||||
|
107
crates/graphql/src/model/node.rs
Normal file
107
crates/graphql/src/model/node.rs
Normal file
@ -0,0 +1,107 @@
|
||||
// Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use async_graphql::{Interface, ID};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use ulid::Ulid;
|
||||
|
||||
use super::{
|
||||
Authentication, BrowserSession, CompatSession, CompatSsoLogin, OAuth2Client, OAuth2Session,
|
||||
User, UserEmail,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum NodeType {
|
||||
Authentication,
|
||||
BrowserSession,
|
||||
CompatSession,
|
||||
CompatSsoLogin,
|
||||
OAuth2Client,
|
||||
OAuth2Session,
|
||||
User,
|
||||
UserEmail,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
#[error("invalid id")]
|
||||
pub enum InvalidID {
|
||||
InvalidFormat,
|
||||
InvalidUlid(#[from] ulid::DecodeError),
|
||||
UnknownPrefix,
|
||||
}
|
||||
|
||||
impl NodeType {
|
||||
fn to_prefix(self) -> &'static str {
|
||||
match self {
|
||||
NodeType::Authentication => "authentication",
|
||||
NodeType::BrowserSession => "browser_session",
|
||||
NodeType::CompatSession => "compat_session",
|
||||
NodeType::CompatSsoLogin => "compat_sso_login",
|
||||
NodeType::OAuth2Client => "oauth2_client",
|
||||
NodeType::OAuth2Session => "oauth2_session",
|
||||
NodeType::User => "user",
|
||||
NodeType::UserEmail => "user_email",
|
||||
}
|
||||
}
|
||||
|
||||
fn from_prefix(prefix: &str) -> Option<Self> {
|
||||
match prefix {
|
||||
"authentication" => Some(NodeType::Authentication),
|
||||
"browser_session" => Some(NodeType::BrowserSession),
|
||||
"compat_session" => Some(NodeType::CompatSession),
|
||||
"compat_sso_login" => Some(NodeType::CompatSsoLogin),
|
||||
"oauth2_client" => Some(NodeType::OAuth2Client),
|
||||
"oauth2_session" => Some(NodeType::OAuth2Session),
|
||||
"user" => Some(NodeType::User),
|
||||
"user_email" => Some(NodeType::UserEmail),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serialize(self, id: impl Into<Ulid>) -> String {
|
||||
let prefix = self.to_prefix();
|
||||
let id = id.into();
|
||||
format!("{prefix}:{id}")
|
||||
}
|
||||
|
||||
pub fn id(self, id: impl Into<Ulid>) -> ID {
|
||||
ID(self.serialize(id))
|
||||
}
|
||||
|
||||
pub fn deserialize(serialized: &str) -> Result<(Self, Ulid), InvalidID> {
|
||||
let (prefix, id) = serialized.split_once(':').ok_or(InvalidID::InvalidFormat)?;
|
||||
let prefix = NodeType::from_prefix(prefix).ok_or(InvalidID::UnknownPrefix)?;
|
||||
let id = id.parse()?;
|
||||
Ok((prefix, id))
|
||||
}
|
||||
|
||||
pub fn from_id(id: &ID) -> Result<(Self, Ulid), InvalidID> {
|
||||
Self::deserialize(&id.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// An object with an ID.
|
||||
#[derive(Interface)]
|
||||
#[graphql(field(name = "id", desc = "ID of the object.", type = "ID"))]
|
||||
pub enum Node {
|
||||
Authentication(Box<Authentication>),
|
||||
BrowserSession(Box<BrowserSession>),
|
||||
CompatSession(Box<CompatSession>),
|
||||
CompatSsoLogin(Box<CompatSsoLogin>),
|
||||
OAuth2Client(Box<OAuth2Client>),
|
||||
OAuth2Session(Box<OAuth2Session>),
|
||||
User(Box<User>),
|
||||
UserEmail(Box<UserEmail>),
|
||||
}
|
@ -19,7 +19,7 @@ use sqlx::PgPool;
|
||||
use ulid::Ulid;
|
||||
use url::Url;
|
||||
|
||||
use super::{BrowserSession, User};
|
||||
use super::{BrowserSession, NodeType, User};
|
||||
|
||||
/// An OAuth 2.0 session represents a client session which used the OAuth APIs
|
||||
/// to login.
|
||||
@ -30,7 +30,7 @@ pub struct OAuth2Session(pub mas_data_model::Session<PostgresqlBackend>);
|
||||
impl OAuth2Session {
|
||||
/// ID of the object.
|
||||
pub async fn id(&self) -> ID {
|
||||
ID(self.0.data.to_string())
|
||||
NodeType::OAuth2Session.id(self.0.data)
|
||||
}
|
||||
|
||||
/// OAuth 2.0 client used by this session.
|
||||
@ -62,7 +62,7 @@ pub struct OAuth2Client(pub mas_data_model::Client<PostgresqlBackend>);
|
||||
impl OAuth2Client {
|
||||
/// ID of the object.
|
||||
pub async fn id(&self) -> ID {
|
||||
ID(self.0.data.to_string())
|
||||
NodeType::OAuth2Client.id(self.0.data)
|
||||
}
|
||||
|
||||
/// OAuth 2.0 client ID
|
||||
|
@ -44,7 +44,7 @@ impl From<mas_data_model::BrowserSession<PostgresqlBackend>> for User {
|
||||
impl User {
|
||||
/// ID of the object.
|
||||
pub async fn id(&self) -> ID {
|
||||
ID(self.0.data.to_string())
|
||||
NodeType::User.id(self.0.data)
|
||||
}
|
||||
|
||||
/// Username chosen by the user.
|
||||
@ -79,10 +79,10 @@ impl User {
|
||||
|after, before, first, last| async move {
|
||||
let mut conn = database.acquire().await?;
|
||||
let after_id = after
|
||||
.map(|x: OpaqueCursor<NodeCursor>| x.extract_for_type(NodeType::UserEmail))
|
||||
.map(|x: OpaqueCursor<NodeCursor>| x.extract_for_type(NodeType::CompatSsoLogin))
|
||||
.transpose()?;
|
||||
let before_id = before
|
||||
.map(|x: OpaqueCursor<NodeCursor>| x.extract_for_type(NodeType::UserEmail))
|
||||
.map(|x: OpaqueCursor<NodeCursor>| x.extract_for_type(NodeType::CompatSsoLogin))
|
||||
.transpose()?;
|
||||
|
||||
let (has_previous_page, has_next_page, edges) =
|
||||
@ -262,7 +262,7 @@ pub struct UserEmail(mas_data_model::UserEmail<PostgresqlBackend>);
|
||||
impl UserEmail {
|
||||
/// ID of the object.
|
||||
pub async fn id(&self) -> ID {
|
||||
ID(self.0.data.to_string())
|
||||
NodeType::UserEmail.id(self.0.data)
|
||||
}
|
||||
|
||||
/// Email address
|
||||
|
Reference in New Issue
Block a user