1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-20 12:02:22 +03:00

frontend: Show all compatibilities sessions, not just SSO logins

Also cleans up a bunch of things in the frontend
This commit is contained in:
Quentin Gliech
2023-07-06 17:49:50 +02:00
parent 76653f9638
commit ca520dfd9a
25 changed files with 708 additions and 369 deletions

View File

@@ -14,14 +14,20 @@
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use mas_data_model::{CompatSession, CompatSessionState, Device, User};
use mas_storage::{compat::CompatSessionRepository, Clock};
use mas_data_model::{
CompatSession, CompatSessionState, CompatSsoLogin, CompatSsoLoginState, Device, User,
};
use mas_storage::{compat::CompatSessionRepository, Clock, Page, Pagination};
use rand::RngCore;
use sqlx::PgConnection;
use sqlx::{PgConnection, QueryBuilder};
use ulid::Ulid;
use url::Url;
use uuid::Uuid;
use crate::{tracing::ExecuteExt, DatabaseError, DatabaseInconsistencyError, LookupResultExt};
use crate::{
pagination::QueryBuilderExt, tracing::ExecuteExt, DatabaseError, DatabaseInconsistencyError,
LookupResultExt,
};
/// An implementation of [`CompatSessionRepository`] for a PostgreSQL connection
pub struct PgCompatSessionRepository<'c> {
@@ -75,6 +81,101 @@ impl TryFrom<CompatSessionLookup> for CompatSession {
}
}
#[derive(sqlx::FromRow)]
struct CompatSessionAndSsoLoginLookup {
compat_session_id: Uuid,
device_id: String,
user_id: Uuid,
created_at: DateTime<Utc>,
finished_at: Option<DateTime<Utc>>,
is_synapse_admin: bool,
compat_sso_login_id: Option<Uuid>,
compat_sso_login_token: Option<String>,
compat_sso_login_redirect_uri: Option<String>,
compat_sso_login_created_at: Option<DateTime<Utc>>,
compat_sso_login_fulfilled_at: Option<DateTime<Utc>>,
compat_sso_login_exchanged_at: Option<DateTime<Utc>>,
}
impl TryFrom<CompatSessionAndSsoLoginLookup> for (CompatSession, Option<CompatSsoLogin>) {
type Error = DatabaseInconsistencyError;
fn try_from(value: CompatSessionAndSsoLoginLookup) -> Result<Self, Self::Error> {
let id = value.compat_session_id.into();
let device = Device::try_from(value.device_id).map_err(|e| {
DatabaseInconsistencyError::on("compat_sessions")
.column("device_id")
.row(id)
.source(e)
})?;
let state = match value.finished_at {
None => CompatSessionState::Valid,
Some(finished_at) => CompatSessionState::Finished { finished_at },
};
let session = CompatSession {
id,
state,
user_id: value.user_id.into(),
device,
created_at: value.created_at,
is_synapse_admin: value.is_synapse_admin,
};
match (
value.compat_sso_login_id,
value.compat_sso_login_token,
value.compat_sso_login_redirect_uri,
value.compat_sso_login_created_at,
value.compat_sso_login_fulfilled_at,
value.compat_sso_login_exchanged_at,
) {
(None, None, None, None, None, None) => Ok((session, None)),
(
Some(id),
Some(login_token),
Some(redirect_uri),
Some(created_at),
fulfilled_at,
exchanged_at,
) => {
let id = id.into();
let redirect_uri = Url::parse(&redirect_uri).map_err(|e| {
DatabaseInconsistencyError::on("compat_sso_logins")
.column("redirect_uri")
.row(id)
.source(e)
})?;
let state = match (fulfilled_at, exchanged_at) {
(Some(fulfilled_at), None) => CompatSsoLoginState::Fulfilled {
fulfilled_at,
session_id: session.id,
},
(Some(fulfilled_at), Some(exchanged_at)) => CompatSsoLoginState::Exchanged {
fulfilled_at,
exchanged_at,
session_id: session.id,
},
_ => return Err(DatabaseInconsistencyError::on("compat_sso_logins").row(id)),
};
let login = CompatSsoLogin {
id,
redirect_uri,
login_token,
created_at,
state,
};
Ok((session, Some(login)))
}
_ => Err(DatabaseInconsistencyError::on("compat_sso_logins").row(id)),
}
}
}
#[async_trait]
impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
type Error = DatabaseError;
@@ -201,4 +302,53 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
Ok(compat_session)
}
#[tracing::instrument(
name = "db.compat_session.list_paginated",
skip_all,
fields(
db.statement,
%user.id,
),
err,
)]
async fn list_paginated(
&mut self,
user: &User,
pagination: Pagination,
) -> Result<Page<(CompatSession, Option<CompatSsoLogin>)>, Self::Error> {
let mut query = QueryBuilder::new(
r#"
SELECT cs.compat_session_id
, cs.device_id
, cs.user_id
, cs.created_at
, cs.finished_at
, cs.is_synapse_admin
, cl.compat_sso_login_id
, cl.login_token as compat_sso_login_token
, cl.redirect_uri as compat_sso_login_redirect_uri
, cl.created_at as compat_sso_login_created_at
, cl.fulfilled_at as compat_sso_login_fulfilled_at
, cl.exchanged_at as compat_sso_login_exchanged_at
FROM compat_sessions cs
LEFT JOIN compat_sso_logins cl USING (compat_session_id)
"#,
);
query
.push(" WHERE cs.user_id = ")
.push_bind(Uuid::from(user.id))
.generate_pagination("cs.compat_session_id", pagination);
let edges: Vec<CompatSessionAndSsoLoginLookup> = query
.build_query_as()
.traced()
.fetch_all(&mut *self.conn)
.await?;
let page = pagination.process(edges).try_map(TryFrom::try_from)?;
Ok(page)
}
}