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
Save which user session created a compat session
This also exposes the user session in the GraphQL API, and allow filtering on browser session ID on the app session list.
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT compat_session_id\n , device_id\n , user_id\n , created_at\n , finished_at\n , is_synapse_admin\n , last_active_at\n , last_active_ip as \"last_active_ip: IpAddr\"\n FROM compat_sessions\n WHERE compat_session_id = $1\n ",
|
||||
"query": "\n SELECT compat_session_id\n , device_id\n , user_id\n , user_session_id\n , created_at\n , finished_at\n , is_synapse_admin\n , last_active_at\n , last_active_ip as \"last_active_ip: IpAddr\"\n FROM compat_sessions\n WHERE compat_session_id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@ -20,26 +20,31 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "user_session_id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "created_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"ordinal": 5,
|
||||
"name": "finished_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"ordinal": 6,
|
||||
"name": "is_synapse_admin",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"ordinal": 7,
|
||||
"name": "last_active_at",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"ordinal": 8,
|
||||
"name": "last_active_ip: IpAddr",
|
||||
"type_info": "Inet"
|
||||
}
|
||||
@ -53,6 +58,7 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
@ -60,5 +66,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "23c03635d6433099a4353ba0c80b88737724edb16315832891550e29088d02bf"
|
||||
"hash": "04e25c9267bf2eb143a6445345229081e7b386743a93b3833ef8ad9d09972f3b"
|
||||
}
|
19
crates/storage-pg/.sqlx/query-4070549b235e059eaeccc4751b480ccb30ad5b62d933b4efb03491124a9361ad.json
generated
Normal file
19
crates/storage-pg/.sqlx/query-4070549b235e059eaeccc4751b480ccb30ad5b62d933b4efb03491124a9361ad.json
generated
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO compat_sessions \n (compat_session_id, user_id, device_id,\n user_session_id, created_at, is_synapse_admin)\n VALUES ($1, $2, $3, $4, $5, $6)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Uuid",
|
||||
"Text",
|
||||
"Uuid",
|
||||
"Timestamptz",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "4070549b235e059eaeccc4751b480ccb30ad5b62d933b4efb03491124a9361ad"
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO compat_sessions (compat_session_id, user_id, device_id, created_at, is_synapse_admin)\n VALUES ($1, $2, $3, $4, $5)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Uuid",
|
||||
"Text",
|
||||
"Timestamptz",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "cff3ac0fff62ffdc5640fce08c2ffabc1d89202561b736c5d03b501dfcd8d886"
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
-- Copyright 2024 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.
|
||||
|
||||
-- Adds an optional link between the compatibility sessions and the user sessions
|
||||
ALTER TABLE compat_sessions
|
||||
ADD COLUMN user_session_id UUID
|
||||
REFERENCES user_sessions (user_session_id)
|
||||
ON DELETE SET NULL;
|
@ -102,11 +102,12 @@ impl TryFrom<AppSessionLookup> for AppSession {
|
||||
last_active_ip,
|
||||
} = value;
|
||||
|
||||
let user_session_id = user_session_id.map(Ulid::from);
|
||||
|
||||
match (
|
||||
compat_session_id,
|
||||
oauth2_session_id,
|
||||
oauth2_client_id,
|
||||
user_session_id,
|
||||
user_id,
|
||||
scope_list,
|
||||
device_id,
|
||||
@ -116,7 +117,6 @@ impl TryFrom<AppSessionLookup> for AppSession {
|
||||
Some(compat_session_id),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(user_id),
|
||||
None,
|
||||
Some(device_id),
|
||||
@ -140,6 +140,7 @@ impl TryFrom<AppSessionLookup> for AppSession {
|
||||
state,
|
||||
user_id: user_id.into(),
|
||||
device,
|
||||
user_session_id,
|
||||
created_at,
|
||||
is_synapse_admin,
|
||||
last_active_at,
|
||||
@ -153,7 +154,6 @@ impl TryFrom<AppSessionLookup> for AppSession {
|
||||
None,
|
||||
Some(oauth2_session_id),
|
||||
Some(oauth2_client_id),
|
||||
user_session_id,
|
||||
user_id,
|
||||
Some(scope_list),
|
||||
None,
|
||||
@ -180,7 +180,7 @@ impl TryFrom<AppSessionLookup> for AppSession {
|
||||
created_at,
|
||||
client_id: oauth2_client_id.into(),
|
||||
user_id: user_id.map(Ulid::from),
|
||||
user_session_id: user_session_id.map(Ulid::from),
|
||||
user_session_id,
|
||||
scope,
|
||||
last_active_at,
|
||||
last_active_ip,
|
||||
@ -269,6 +269,10 @@ impl<'c> AppSessionRepository for PgAppSessionRepository<'c> {
|
||||
Expr::col((OAuth2Sessions::Table, OAuth2Sessions::FinishedAt)).is_not_null()
|
||||
}
|
||||
}))
|
||||
.and_where_option(filter.browser_session().map(|browser_session| {
|
||||
Expr::col((OAuth2Sessions::Table, OAuth2Sessions::UserSessionId))
|
||||
.eq(Uuid::from(browser_session.id))
|
||||
}))
|
||||
.and_where_option(filter.device().map(|device| {
|
||||
Expr::val(device.to_scope_token().to_string()).eq(PgFunc::any(Expr::col((
|
||||
OAuth2Sessions::Table,
|
||||
@ -288,7 +292,10 @@ impl<'c> AppSessionRepository for PgAppSessionRepository<'c> {
|
||||
)
|
||||
.expr_as(Expr::cust("NULL"), AppSessionLookupIden::Oauth2SessionId)
|
||||
.expr_as(Expr::cust("NULL"), AppSessionLookupIden::Oauth2ClientId)
|
||||
.expr_as(Expr::cust("NULL"), AppSessionLookupIden::UserSessionId)
|
||||
.expr_as(
|
||||
Expr::col((CompatSessions::Table, CompatSessions::UserSessionId)),
|
||||
AppSessionLookupIden::UserSessionId,
|
||||
)
|
||||
.expr_as(
|
||||
Expr::col((CompatSessions::Table, CompatSessions::UserId)),
|
||||
AppSessionLookupIden::UserId,
|
||||
@ -329,6 +336,10 @@ impl<'c> AppSessionRepository for PgAppSessionRepository<'c> {
|
||||
Expr::col((CompatSessions::Table, CompatSessions::FinishedAt)).is_not_null()
|
||||
}
|
||||
}))
|
||||
.and_where_option(filter.browser_session().map(|browser_session| {
|
||||
Expr::col((CompatSessions::Table, CompatSessions::UserSessionId))
|
||||
.eq(Uuid::from(browser_session.id))
|
||||
}))
|
||||
.and_where_option(filter.device().map(|device| {
|
||||
Expr::col((CompatSessions::Table, CompatSessions::DeviceId)).eq(device.to_string())
|
||||
}))
|
||||
@ -385,6 +396,10 @@ impl<'c> AppSessionRepository for PgAppSessionRepository<'c> {
|
||||
Expr::col((OAuth2Sessions::Table, OAuth2Sessions::FinishedAt)).is_not_null()
|
||||
}
|
||||
}))
|
||||
.and_where_option(filter.browser_session().map(|browser_session| {
|
||||
Expr::col((OAuth2Sessions::Table, OAuth2Sessions::UserSessionId))
|
||||
.eq(Uuid::from(browser_session.id))
|
||||
}))
|
||||
.and_where_option(filter.device().map(|device| {
|
||||
Expr::val(device.to_scope_token().to_string()).eq(PgFunc::any(Expr::col((
|
||||
OAuth2Sessions::Table,
|
||||
@ -406,6 +421,10 @@ impl<'c> AppSessionRepository for PgAppSessionRepository<'c> {
|
||||
Expr::col((CompatSessions::Table, CompatSessions::FinishedAt)).is_not_null()
|
||||
}
|
||||
}))
|
||||
.and_where_option(filter.browser_session().map(|browser_session| {
|
||||
Expr::col((CompatSessions::Table, CompatSessions::UserSessionId))
|
||||
.eq(Uuid::from(browser_session.id))
|
||||
}))
|
||||
.and_where_option(filter.device().map(|device| {
|
||||
Expr::col((CompatSessions::Table, CompatSessions::DeviceId)).eq(device.to_string())
|
||||
}))
|
||||
@ -493,7 +512,7 @@ mod tests {
|
||||
let device = Device::generate(&mut rng);
|
||||
let compat_session = repo
|
||||
.compat_session()
|
||||
.add(&mut rng, &clock, &user, device.clone(), false)
|
||||
.add(&mut rng, &clock, &user, device.clone(), None, false)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -87,7 +87,7 @@ mod tests {
|
||||
let device_str = device.as_str().to_owned();
|
||||
let session = repo
|
||||
.compat_session()
|
||||
.add(&mut rng, &clock, &user, device.clone(), false)
|
||||
.add(&mut rng, &clock, &user, device.clone(), None, false)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(session.user_id, user.id);
|
||||
@ -203,7 +203,7 @@ mod tests {
|
||||
let device = Device::generate(&mut rng);
|
||||
let sso_login_session = repo
|
||||
.compat_session()
|
||||
.add(&mut rng, &clock, &user, device, false)
|
||||
.add(&mut rng, &clock, &user, device, None, false)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -291,7 +291,7 @@ mod tests {
|
||||
let device = Device::generate(&mut rng);
|
||||
let session = repo
|
||||
.compat_session()
|
||||
.add(&mut rng, &clock, &user, device, false)
|
||||
.add(&mut rng, &clock, &user, device, None, false)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -411,7 +411,7 @@ mod tests {
|
||||
let device = Device::generate(&mut rng);
|
||||
let session = repo
|
||||
.compat_session()
|
||||
.add(&mut rng, &clock, &user, device, false)
|
||||
.add(&mut rng, &clock, &user, device, None, false)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@ -584,7 +584,7 @@ mod tests {
|
||||
let device = Device::generate(&mut rng);
|
||||
let session = repo
|
||||
.compat_session()
|
||||
.add(&mut rng, &clock, &user, device, false)
|
||||
.add(&mut rng, &clock, &user, device, None, false)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
@ -17,7 +17,8 @@ use std::net::IpAddr;
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Utc};
|
||||
use mas_data_model::{
|
||||
CompatSession, CompatSessionState, CompatSsoLogin, CompatSsoLoginState, Device, User,
|
||||
BrowserSession, CompatSession, CompatSessionState, CompatSsoLogin, CompatSsoLoginState, Device,
|
||||
User,
|
||||
};
|
||||
use mas_storage::{
|
||||
compat::{CompatSessionFilter, CompatSessionRepository},
|
||||
@ -55,6 +56,7 @@ struct CompatSessionLookup {
|
||||
compat_session_id: Uuid,
|
||||
device_id: String,
|
||||
user_id: Uuid,
|
||||
user_session_id: Option<Uuid>,
|
||||
created_at: DateTime<Utc>,
|
||||
finished_at: Option<DateTime<Utc>>,
|
||||
is_synapse_admin: bool,
|
||||
@ -83,6 +85,7 @@ impl TryFrom<CompatSessionLookup> for CompatSession {
|
||||
id,
|
||||
state,
|
||||
user_id: value.user_id.into(),
|
||||
user_session_id: value.user_session_id.map(Ulid::from),
|
||||
device,
|
||||
created_at: value.created_at,
|
||||
is_synapse_admin: value.is_synapse_admin,
|
||||
@ -100,6 +103,7 @@ struct CompatSessionAndSsoLoginLookup {
|
||||
compat_session_id: Uuid,
|
||||
device_id: String,
|
||||
user_id: Uuid,
|
||||
user_session_id: Option<Uuid>,
|
||||
created_at: DateTime<Utc>,
|
||||
finished_at: Option<DateTime<Utc>>,
|
||||
is_synapse_admin: bool,
|
||||
@ -135,6 +139,7 @@ impl TryFrom<CompatSessionAndSsoLoginLookup> for (CompatSession, Option<CompatSs
|
||||
state,
|
||||
user_id: value.user_id.into(),
|
||||
device,
|
||||
user_session_id: value.user_session_id.map(Ulid::from),
|
||||
created_at: value.created_at,
|
||||
is_synapse_admin: value.is_synapse_admin,
|
||||
last_active_at: value.last_active_at,
|
||||
@ -214,6 +219,7 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
|
||||
SELECT compat_session_id
|
||||
, device_id
|
||||
, user_id
|
||||
, user_session_id
|
||||
, created_at
|
||||
, finished_at
|
||||
, is_synapse_admin
|
||||
@ -251,6 +257,7 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
|
||||
clock: &dyn Clock,
|
||||
user: &User,
|
||||
device: Device,
|
||||
browser_session: Option<&BrowserSession>,
|
||||
is_synapse_admin: bool,
|
||||
) -> Result<CompatSession, Self::Error> {
|
||||
let created_at = clock.now();
|
||||
@ -259,12 +266,15 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
|
||||
|
||||
sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO compat_sessions (compat_session_id, user_id, device_id, created_at, is_synapse_admin)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
INSERT INTO compat_sessions
|
||||
(compat_session_id, user_id, device_id,
|
||||
user_session_id, created_at, is_synapse_admin)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
"#,
|
||||
Uuid::from(id),
|
||||
Uuid::from(user.id),
|
||||
device.as_str(),
|
||||
browser_session.map(|s| Uuid::from(s.id)),
|
||||
created_at,
|
||||
is_synapse_admin,
|
||||
)
|
||||
@ -277,6 +287,7 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
|
||||
state: CompatSessionState::default(),
|
||||
user_id: user.id,
|
||||
device,
|
||||
user_session_id: browser_session.map(|s| s.id),
|
||||
created_at,
|
||||
is_synapse_admin,
|
||||
last_active_at: None,
|
||||
@ -350,6 +361,10 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
|
||||
Expr::col((CompatSessions::Table, CompatSessions::UserId)),
|
||||
CompatSessionAndSsoLoginLookupIden::UserId,
|
||||
)
|
||||
.expr_as(
|
||||
Expr::col((CompatSessions::Table, CompatSessions::UserSessionId)),
|
||||
CompatSessionAndSsoLoginLookupIden::UserSessionId,
|
||||
)
|
||||
.expr_as(
|
||||
Expr::col((CompatSessions::Table, CompatSessions::CreatedAt)),
|
||||
CompatSessionAndSsoLoginLookupIden::CreatedAt,
|
||||
|
@ -53,6 +53,7 @@ pub enum CompatSessions {
|
||||
CompatSessionId,
|
||||
UserId,
|
||||
DeviceId,
|
||||
UserSessionId,
|
||||
CreatedAt,
|
||||
FinishedAt,
|
||||
IsSynapseAdmin,
|
||||
|
Reference in New Issue
Block a user