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 the session activity in the database
This commit is contained in:
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -2399,6 +2399,15 @@ dependencies = [
|
|||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ipnetwork"
|
||||||
|
version = "0.20.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iri-string"
|
name = "iri-string"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -5177,6 +5186,7 @@ dependencies = [
|
|||||||
"hashlink",
|
"hashlink",
|
||||||
"hex",
|
"hex",
|
||||||
"indexmap 2.0.0",
|
"indexmap 2.0.0",
|
||||||
|
"ipnetwork",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@ -5303,6 +5313,7 @@ dependencies = [
|
|||||||
"hkdf",
|
"hkdf",
|
||||||
"hmac",
|
"hmac",
|
||||||
"home",
|
"home",
|
||||||
|
"ipnetwork",
|
||||||
"itoa",
|
"itoa",
|
||||||
"log",
|
"log",
|
||||||
"md-5",
|
"md-5",
|
||||||
|
@ -141,7 +141,9 @@ impl Options {
|
|||||||
compat_token_ttl: config.experimental.compat_token_ttl,
|
compat_token_ttl: config.experimental.compat_token_ttl,
|
||||||
};
|
};
|
||||||
|
|
||||||
let activity_tracker = ActivityTracker::new(pool.clone(), Duration::from_secs(60 * 5));
|
// Initialize the activity tracker
|
||||||
|
// Activity is flushed every minute
|
||||||
|
let activity_tracker = ActivityTracker::new(pool.clone(), Duration::from_secs(60));
|
||||||
|
|
||||||
// Explicitly the config to properly zeroize secret keys
|
// Explicitly the config to properly zeroize secret keys
|
||||||
drop(config);
|
drop(config);
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
use std::{collections::HashMap, net::IpAddr};
|
use std::{collections::HashMap, net::IpAddr};
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use mas_storage::Repository;
|
use mas_storage::{user::BrowserSessionRepository, Repository, RepositoryAccess};
|
||||||
use opentelemetry::{
|
use opentelemetry::{
|
||||||
metrics::{Counter, Histogram},
|
metrics::{Counter, Histogram},
|
||||||
Key,
|
Key,
|
||||||
@ -38,6 +38,8 @@ const RESULT: Key = Key::from_static_str("result");
|
|||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
struct ActivityRecord {
|
struct ActivityRecord {
|
||||||
|
// XXX: We don't actually use the start time for now
|
||||||
|
#[allow(dead_code)]
|
||||||
start_time: DateTime<Utc>,
|
start_time: DateTime<Utc>,
|
||||||
end_time: DateTime<Utc>,
|
end_time: DateTime<Utc>,
|
||||||
ip: Option<IpAddr>,
|
ip: Option<IpAddr>,
|
||||||
@ -195,18 +197,47 @@ impl Worker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fallible part of [`Self::flush`].
|
/// Fallible part of [`Self::flush`].
|
||||||
|
#[tracing::instrument(name = "activity_tracker.flush", skip(self))]
|
||||||
async fn try_flush(&mut self) -> Result<(), anyhow::Error> {
|
async fn try_flush(&mut self) -> Result<(), anyhow::Error> {
|
||||||
let pending_records = &self.pending_records;
|
let pending_records = &self.pending_records;
|
||||||
|
|
||||||
let repo = mas_storage_pg::PgRepository::from_pool(&self.pool)
|
let mut repo = mas_storage_pg::PgRepository::from_pool(&self.pool)
|
||||||
.await?
|
.await?
|
||||||
.boxed();
|
.boxed();
|
||||||
|
|
||||||
|
let mut browser_sessions = Vec::new();
|
||||||
|
let mut oauth2_sessions = Vec::new();
|
||||||
|
let mut compat_sessions = Vec::new();
|
||||||
|
|
||||||
|
for ((kind, id), record) in pending_records {
|
||||||
|
match kind {
|
||||||
|
SessionKind::Browser => {
|
||||||
|
browser_sessions.push((*id, record.end_time, record.ip));
|
||||||
|
}
|
||||||
|
SessionKind::OAuth2 => {
|
||||||
|
oauth2_sessions.push((*id, record.end_time, record.ip));
|
||||||
|
}
|
||||||
|
SessionKind::Compat => {
|
||||||
|
compat_sessions.push((*id, record.end_time, record.ip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"Flushing {} activity records to the database",
|
"Flushing {} activity records to the database",
|
||||||
pending_records.len()
|
pending_records.len()
|
||||||
);
|
);
|
||||||
// TODO: actually save the records
|
|
||||||
|
repo.browser_session()
|
||||||
|
.record_batch_activity(browser_sessions)
|
||||||
|
.await?;
|
||||||
|
repo.oauth2_session()
|
||||||
|
.record_batch_activity(oauth2_sessions)
|
||||||
|
.await?;
|
||||||
|
repo.compat_session()
|
||||||
|
.record_batch_activity(compat_sessions)
|
||||||
|
.await?;
|
||||||
|
|
||||||
repo.save().await?;
|
repo.save().await?;
|
||||||
self.pending_records.clear();
|
self.pending_records.clear();
|
||||||
|
|
||||||
|
16
crates/storage-pg/.sqlx/query-8a7461d5f633b7b441b9bc83f78900ccee5a76328a7fad97b650f7e4c921bd7b.json
generated
Normal file
16
crates/storage-pg/.sqlx/query-8a7461d5f633b7b441b9bc83f78900ccee5a76328a7fad97b650f7e4c921bd7b.json
generated
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n UPDATE user_sessions\n SET last_active_at = GREATEST(t.last_active_at, user_sessions.last_active_at)\n , last_active_ip = COALESCE(t.last_active_ip, user_sessions.last_active_ip)\n FROM (\n SELECT *\n FROM UNNEST($1::uuid[], $2::timestamptz[], $3::inet[]) \n AS t(user_session_id, last_active_at, last_active_ip)\n ) AS t\n WHERE user_sessions.user_session_id = t.user_session_id\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"UuidArray",
|
||||||
|
"TimestamptzArray",
|
||||||
|
"InetArray"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "8a7461d5f633b7b441b9bc83f78900ccee5a76328a7fad97b650f7e4c921bd7b"
|
||||||
|
}
|
16
crates/storage-pg/.sqlx/query-d0c02576b1550fe2eb877d24f7cdfc819307ee0c47af9fbbf1a3b484290b321d.json
generated
Normal file
16
crates/storage-pg/.sqlx/query-d0c02576b1550fe2eb877d24f7cdfc819307ee0c47af9fbbf1a3b484290b321d.json
generated
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n UPDATE oauth2_sessions\n SET last_active_at = GREATEST(t.last_active_at, oauth2_sessions.last_active_at)\n , last_active_ip = COALESCE(t.last_active_ip, oauth2_sessions.last_active_ip)\n FROM (\n SELECT *\n FROM UNNEST($1::uuid[], $2::timestamptz[], $3::inet[]) \n AS t(oauth2_session_id, last_active_at, last_active_ip)\n ) AS t\n WHERE oauth2_sessions.oauth2_session_id = t.oauth2_session_id\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"UuidArray",
|
||||||
|
"TimestamptzArray",
|
||||||
|
"InetArray"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "d0c02576b1550fe2eb877d24f7cdfc819307ee0c47af9fbbf1a3b484290b321d"
|
||||||
|
}
|
16
crates/storage-pg/.sqlx/query-d4d25682c10be7a3e3ee989fb9dae92e19023b8ecb6fe6e1d7cabe2cf0efd930.json
generated
Normal file
16
crates/storage-pg/.sqlx/query-d4d25682c10be7a3e3ee989fb9dae92e19023b8ecb6fe6e1d7cabe2cf0efd930.json
generated
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"db_name": "PostgreSQL",
|
||||||
|
"query": "\n UPDATE compat_sessions\n SET last_active_at = GREATEST(t.last_active_at, compat_sessions.last_active_at)\n , last_active_ip = COALESCE(t.last_active_ip, compat_sessions.last_active_ip)\n FROM (\n SELECT *\n FROM UNNEST($1::uuid[], $2::timestamptz[], $3::inet[]) \n AS t(compat_session_id, last_active_at, last_active_ip)\n ) AS t\n WHERE compat_sessions.compat_session_id = t.compat_session_id\n ",
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"UuidArray",
|
||||||
|
"TimestamptzArray",
|
||||||
|
"InetArray"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nullable": []
|
||||||
|
},
|
||||||
|
"hash": "d4d25682c10be7a3e3ee989fb9dae92e19023b8ecb6fe6e1d7cabe2cf0efd930"
|
||||||
|
}
|
@ -9,7 +9,7 @@ repository.workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = "0.1.73"
|
async-trait = "0.1.73"
|
||||||
sqlx = { version = "0.7.1", features = ["runtime-tokio-rustls", "postgres", "migrate", "chrono", "json", "uuid"] }
|
sqlx = { version = "0.7.1", features = ["runtime-tokio-rustls", "postgres", "migrate", "chrono", "json", "uuid", "ipnetwork"] }
|
||||||
sea-query = { version = "0.30.1", features = ["derive", "attr", "with-uuid", "with-chrono", "postgres-array"] }
|
sea-query = { version = "0.30.1", features = ["derive", "attr", "with-uuid", "with-chrono", "postgres-array"] }
|
||||||
sea-query-binder = { version = "0.5.0", features = ["sqlx-postgres", "with-uuid", "with-chrono", "postgres-array"] }
|
sea-query-binder = { version = "0.5.0", features = ["sqlx-postgres", "with-uuid", "with-chrono", "postgres-array"] }
|
||||||
chrono.workspace = true
|
chrono.workspace = true
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
-- Copyright 2023 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.
|
||||||
|
|
||||||
|
-- This adds a `last_active_at` timestamp and a `last_active_ip` column
|
||||||
|
-- to the `oauth2_sessions`, `user_sessions` and `compat_sessions` tables.
|
||||||
|
-- The timestamp is indexed with the `user_id`, as they are likely to be queried together.
|
||||||
|
ALTER TABLE "oauth2_sessions"
|
||||||
|
ADD COLUMN "last_active_at" TIMESTAMP WITH TIME ZONE,
|
||||||
|
ADD COLUMN "last_active_ip" INET;
|
||||||
|
|
||||||
|
CREATE INDEX "oauth2_sessions_user_id_last_active_at"
|
||||||
|
ON "oauth2_sessions" ("user_id", "last_active_at");
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE "user_sessions"
|
||||||
|
ADD COLUMN "last_active_at" TIMESTAMP WITH TIME ZONE,
|
||||||
|
ADD COLUMN "last_active_ip" INET;
|
||||||
|
|
||||||
|
CREATE INDEX "user_sessions_user_id_last_active_at"
|
||||||
|
ON "user_sessions" ("user_id", "last_active_at");
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE "compat_sessions"
|
||||||
|
ADD COLUMN "last_active_at" TIMESTAMP WITH TIME ZONE,
|
||||||
|
ADD COLUMN "last_active_ip" INET;
|
||||||
|
|
||||||
|
CREATE INDEX "compat_sessions_user_id_last_active_at"
|
||||||
|
ON "compat_sessions" ("user_id", "last_active_at");
|
@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use mas_data_model::{
|
use mas_data_model::{
|
||||||
@ -505,4 +507,51 @@ impl<'c> CompatSessionRepository for PgCompatSessionRepository<'c> {
|
|||||||
.try_into()
|
.try_into()
|
||||||
.map_err(DatabaseError::to_invalid_operation)
|
.map_err(DatabaseError::to_invalid_operation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(
|
||||||
|
name = "db.compat_session.record_batch_activity",
|
||||||
|
skip_all,
|
||||||
|
fields(
|
||||||
|
db.statement,
|
||||||
|
),
|
||||||
|
err,
|
||||||
|
)]
|
||||||
|
async fn record_batch_activity(
|
||||||
|
&mut self,
|
||||||
|
activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let mut ids = Vec::with_capacity(activity.len());
|
||||||
|
let mut last_activities = Vec::with_capacity(activity.len());
|
||||||
|
let mut ips = Vec::with_capacity(activity.len());
|
||||||
|
|
||||||
|
for (id, last_activity, ip) in activity {
|
||||||
|
ids.push(Uuid::from(id));
|
||||||
|
last_activities.push(last_activity);
|
||||||
|
ips.push(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
UPDATE compat_sessions
|
||||||
|
SET last_active_at = GREATEST(t.last_active_at, compat_sessions.last_active_at)
|
||||||
|
, last_active_ip = COALESCE(t.last_active_ip, compat_sessions.last_active_ip)
|
||||||
|
FROM (
|
||||||
|
SELECT *
|
||||||
|
FROM UNNEST($1::uuid[], $2::timestamptz[], $3::inet[])
|
||||||
|
AS t(compat_session_id, last_active_at, last_active_ip)
|
||||||
|
) AS t
|
||||||
|
WHERE compat_sessions.compat_session_id = t.compat_session_id
|
||||||
|
"#,
|
||||||
|
&ids,
|
||||||
|
&last_activities,
|
||||||
|
&ips as &[Option<IpAddr>],
|
||||||
|
)
|
||||||
|
.traced()
|
||||||
|
.execute(&mut *self.conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
DatabaseError::ensure_affected_rows(&res, ids.len().try_into().unwrap_or(u64::MAX))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use mas_data_model::{BrowserSession, Client, Session, SessionState, User};
|
use mas_data_model::{BrowserSession, Client, Session, SessionState, User};
|
||||||
@ -362,4 +364,51 @@ impl<'c> OAuth2SessionRepository for PgOAuth2SessionRepository<'c> {
|
|||||||
.try_into()
|
.try_into()
|
||||||
.map_err(DatabaseError::to_invalid_operation)
|
.map_err(DatabaseError::to_invalid_operation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(
|
||||||
|
name = "db.oauth2_session.record_batch_activity",
|
||||||
|
skip_all,
|
||||||
|
fields(
|
||||||
|
db.statement,
|
||||||
|
),
|
||||||
|
err,
|
||||||
|
)]
|
||||||
|
async fn record_batch_activity(
|
||||||
|
&mut self,
|
||||||
|
activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let mut ids = Vec::with_capacity(activity.len());
|
||||||
|
let mut last_activities = Vec::with_capacity(activity.len());
|
||||||
|
let mut ips = Vec::with_capacity(activity.len());
|
||||||
|
|
||||||
|
for (id, last_activity, ip) in activity {
|
||||||
|
ids.push(Uuid::from(id));
|
||||||
|
last_activities.push(last_activity);
|
||||||
|
ips.push(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
UPDATE oauth2_sessions
|
||||||
|
SET last_active_at = GREATEST(t.last_active_at, oauth2_sessions.last_active_at)
|
||||||
|
, last_active_ip = COALESCE(t.last_active_ip, oauth2_sessions.last_active_ip)
|
||||||
|
FROM (
|
||||||
|
SELECT *
|
||||||
|
FROM UNNEST($1::uuid[], $2::timestamptz[], $3::inet[])
|
||||||
|
AS t(oauth2_session_id, last_active_at, last_active_ip)
|
||||||
|
) AS t
|
||||||
|
WHERE oauth2_sessions.oauth2_session_id = t.oauth2_session_id
|
||||||
|
"#,
|
||||||
|
&ids,
|
||||||
|
&last_activities,
|
||||||
|
&ips as &[Option<IpAddr>],
|
||||||
|
)
|
||||||
|
.traced()
|
||||||
|
.execute(&mut *self.conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
DatabaseError::ensure_affected_rows(&res, ids.len().try_into().unwrap_or(u64::MAX))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use mas_data_model::{
|
use mas_data_model::{
|
||||||
@ -504,4 +506,51 @@ impl<'c> BrowserSessionRepository for PgBrowserSessionRepository<'c> {
|
|||||||
let authentication = Authentication::try_from(authentication)?;
|
let authentication = Authentication::try_from(authentication)?;
|
||||||
Ok(Some(authentication))
|
Ok(Some(authentication))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(
|
||||||
|
name = "db.browser_session.record_batch_activity",
|
||||||
|
skip_all,
|
||||||
|
fields(
|
||||||
|
db.statement,
|
||||||
|
),
|
||||||
|
err,
|
||||||
|
)]
|
||||||
|
async fn record_batch_activity(
|
||||||
|
&mut self,
|
||||||
|
activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let mut ids = Vec::with_capacity(activity.len());
|
||||||
|
let mut last_activities = Vec::with_capacity(activity.len());
|
||||||
|
let mut ips = Vec::with_capacity(activity.len());
|
||||||
|
|
||||||
|
for (id, last_activity, ip) in activity {
|
||||||
|
ids.push(Uuid::from(id));
|
||||||
|
last_activities.push(last_activity);
|
||||||
|
ips.push(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = sqlx::query!(
|
||||||
|
r#"
|
||||||
|
UPDATE user_sessions
|
||||||
|
SET last_active_at = GREATEST(t.last_active_at, user_sessions.last_active_at)
|
||||||
|
, last_active_ip = COALESCE(t.last_active_ip, user_sessions.last_active_ip)
|
||||||
|
FROM (
|
||||||
|
SELECT *
|
||||||
|
FROM UNNEST($1::uuid[], $2::timestamptz[], $3::inet[])
|
||||||
|
AS t(user_session_id, last_active_at, last_active_ip)
|
||||||
|
) AS t
|
||||||
|
WHERE user_sessions.user_session_id = t.user_session_id
|
||||||
|
"#,
|
||||||
|
&ids,
|
||||||
|
&last_activities,
|
||||||
|
&ips as &[Option<IpAddr>],
|
||||||
|
)
|
||||||
|
.traced()
|
||||||
|
.execute(&mut *self.conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
DatabaseError::ensure_affected_rows(&res, ids.len().try_into().unwrap_or(u64::MAX))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use mas_data_model::{CompatSession, CompatSsoLogin, Device, User};
|
use mas_data_model::{CompatSession, CompatSsoLogin, Device, User};
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
use ulid::Ulid;
|
use ulid::Ulid;
|
||||||
@ -236,6 +239,21 @@ pub trait CompatSessionRepository: Send + Sync {
|
|||||||
///
|
///
|
||||||
/// Returns [`Self::Error`] if the underlying repository fails
|
/// Returns [`Self::Error`] if the underlying repository fails
|
||||||
async fn count(&mut self, filter: CompatSessionFilter<'_>) -> Result<usize, Self::Error>;
|
async fn count(&mut self, filter: CompatSessionFilter<'_>) -> Result<usize, Self::Error>;
|
||||||
|
|
||||||
|
/// Record a batch of [`Session`] activity
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `activity`: A list of tuples containing the session ID, the last
|
||||||
|
/// activity timestamp and the IP address of the client
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns [`Self::Error`] if the underlying repository fails
|
||||||
|
async fn record_batch_activity(
|
||||||
|
&mut self,
|
||||||
|
activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
|
||||||
|
) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
repository_impl!(CompatSessionRepository:
|
repository_impl!(CompatSessionRepository:
|
||||||
@ -269,4 +287,9 @@ repository_impl!(CompatSessionRepository:
|
|||||||
) -> Result<Page<(CompatSession, Option<CompatSsoLogin>)>, Self::Error>;
|
) -> Result<Page<(CompatSession, Option<CompatSsoLogin>)>, Self::Error>;
|
||||||
|
|
||||||
async fn count(&mut self, filter: CompatSessionFilter<'_>) -> Result<usize, Self::Error>;
|
async fn count(&mut self, filter: CompatSessionFilter<'_>) -> Result<usize, Self::Error>;
|
||||||
|
|
||||||
|
async fn record_batch_activity(
|
||||||
|
&mut self,
|
||||||
|
activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
|
||||||
|
) -> Result<(), Self::Error>;
|
||||||
);
|
);
|
||||||
|
@ -12,7 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use mas_data_model::{BrowserSession, Client, Session, User};
|
use mas_data_model::{BrowserSession, Client, Session, User};
|
||||||
use oauth2_types::scope::Scope;
|
use oauth2_types::scope::Scope;
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
@ -268,6 +271,21 @@ pub trait OAuth2SessionRepository: Send + Sync {
|
|||||||
///
|
///
|
||||||
/// Returns [`Self::Error`] if the underlying repository fails
|
/// Returns [`Self::Error`] if the underlying repository fails
|
||||||
async fn count(&mut self, filter: OAuth2SessionFilter<'_>) -> Result<usize, Self::Error>;
|
async fn count(&mut self, filter: OAuth2SessionFilter<'_>) -> Result<usize, Self::Error>;
|
||||||
|
|
||||||
|
/// Record a batch of [`Session`] activity
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `activity`: A list of tuples containing the session ID, the last
|
||||||
|
/// activity timestamp and the IP address of the client
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns [`Self::Error`] if the underlying repository fails
|
||||||
|
async fn record_batch_activity(
|
||||||
|
&mut self,
|
||||||
|
activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
|
||||||
|
) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
repository_impl!(OAuth2SessionRepository:
|
repository_impl!(OAuth2SessionRepository:
|
||||||
@ -310,4 +328,9 @@ repository_impl!(OAuth2SessionRepository:
|
|||||||
) -> Result<Page<Session>, Self::Error>;
|
) -> Result<Page<Session>, Self::Error>;
|
||||||
|
|
||||||
async fn count(&mut self, filter: OAuth2SessionFilter<'_>) -> Result<usize, Self::Error>;
|
async fn count(&mut self, filter: OAuth2SessionFilter<'_>) -> Result<usize, Self::Error>;
|
||||||
|
|
||||||
|
async fn record_batch_activity(
|
||||||
|
&mut self,
|
||||||
|
activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
|
||||||
|
) -> Result<(), Self::Error>;
|
||||||
);
|
);
|
||||||
|
@ -12,7 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use mas_data_model::{
|
use mas_data_model::{
|
||||||
Authentication, BrowserSession, Password, UpstreamOAuthAuthorizationSession, User,
|
Authentication, BrowserSession, Password, UpstreamOAuthAuthorizationSession, User,
|
||||||
};
|
};
|
||||||
@ -227,6 +230,21 @@ pub trait BrowserSessionRepository: Send + Sync {
|
|||||||
&mut self,
|
&mut self,
|
||||||
user_session: &BrowserSession,
|
user_session: &BrowserSession,
|
||||||
) -> Result<Option<Authentication>, Self::Error>;
|
) -> Result<Option<Authentication>, Self::Error>;
|
||||||
|
|
||||||
|
/// Record a batch of [`Session`] activity
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
///
|
||||||
|
/// * `activity`: A list of tuples containing the session ID, the last
|
||||||
|
/// activity timestamp and the IP address of the client
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns [`Self::Error`] if the underlying repository fails
|
||||||
|
async fn record_batch_activity(
|
||||||
|
&mut self,
|
||||||
|
activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
|
||||||
|
) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
repository_impl!(BrowserSessionRepository:
|
repository_impl!(BrowserSessionRepository:
|
||||||
@ -272,4 +290,9 @@ repository_impl!(BrowserSessionRepository:
|
|||||||
&mut self,
|
&mut self,
|
||||||
user_session: &BrowserSession,
|
user_session: &BrowserSession,
|
||||||
) -> Result<Option<Authentication>, Self::Error>;
|
) -> Result<Option<Authentication>, Self::Error>;
|
||||||
|
|
||||||
|
async fn record_batch_activity(
|
||||||
|
&mut self,
|
||||||
|
activity: Vec<(Ulid, DateTime<Utc>, Option<IpAddr>)>,
|
||||||
|
) -> Result<(), Self::Error>;
|
||||||
);
|
);
|
||||||
|
Reference in New Issue
Block a user