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
Store the browser user-agent when starting a browser session
This commit is contained in:
@ -80,6 +80,7 @@ pub struct BrowserSession {
|
|||||||
pub user: User,
|
pub user: User,
|
||||||
pub created_at: DateTime<Utc>,
|
pub created_at: DateTime<Utc>,
|
||||||
pub finished_at: Option<DateTime<Utc>>,
|
pub finished_at: Option<DateTime<Utc>>,
|
||||||
|
pub user_agent: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BrowserSession {
|
impl BrowserSession {
|
||||||
@ -99,6 +100,7 @@ impl BrowserSession {
|
|||||||
user,
|
user,
|
||||||
created_at: now,
|
created_at: now,
|
||||||
finished_at: None,
|
finished_at: None,
|
||||||
|
user_agent: Some("Mozilla/5.0".to_owned()),
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ async fn start_oauth_session(
|
|||||||
|
|
||||||
let browser_session = repo
|
let browser_session = repo
|
||||||
.browser_session()
|
.browser_session()
|
||||||
.add(&mut rng, &state.clock, user)
|
.add(&mut rng, &state.clock, user, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@ mod tests {
|
|||||||
|
|
||||||
let browser_session = repo
|
let browser_session = repo
|
||||||
.browser_session()
|
.browser_session()
|
||||||
.add(&mut state.rng(), &state.clock, &user)
|
.add(&mut state.rng(), &state.clock, &user, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ mod tests {
|
|||||||
|
|
||||||
let browser_session = repo
|
let browser_session = repo
|
||||||
.browser_session()
|
.browser_session()
|
||||||
.add(&mut state.rng(), &state.clock, &user)
|
.add(&mut state.rng(), &state.clock, &user, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -464,7 +464,7 @@ mod tests {
|
|||||||
|
|
||||||
let browser_session = repo
|
let browser_session = repo
|
||||||
.browser_session()
|
.browser_session()
|
||||||
.add(&mut state.rng(), &state.clock, &user)
|
.add(&mut state.rng(), &state.clock, &user, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -672,7 +672,7 @@ mod tests {
|
|||||||
|
|
||||||
let browser_session = repo
|
let browser_session = repo
|
||||||
.browser_session()
|
.browser_session()
|
||||||
.add(&mut state.rng(), &state.clock, &user)
|
.add(&mut state.rng(), &state.clock, &user, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
extract::{Path, State},
|
extract::{Path, State},
|
||||||
response::{Html, IntoResponse},
|
response::{Html, IntoResponse},
|
||||||
Form,
|
Form, TypedHeader,
|
||||||
};
|
};
|
||||||
use hyper::StatusCode;
|
use hyper::StatusCode;
|
||||||
use mas_axum_utils::{
|
use mas_axum_utils::{
|
||||||
@ -170,8 +170,10 @@ pub(crate) async fn get(
|
|||||||
mut repo: BoxRepository,
|
mut repo: BoxRepository,
|
||||||
State(templates): State<Templates>,
|
State(templates): State<Templates>,
|
||||||
cookie_jar: CookieJar,
|
cookie_jar: CookieJar,
|
||||||
|
user_agent: Option<TypedHeader<headers::UserAgent>>,
|
||||||
Path(link_id): Path<Ulid>,
|
Path(link_id): Path<Ulid>,
|
||||||
) -> Result<impl IntoResponse, RouteError> {
|
) -> Result<impl IntoResponse, RouteError> {
|
||||||
|
let user_agent = user_agent.map(|ua| ua.as_str().to_owned());
|
||||||
let sessions_cookie = UpstreamSessionsCookie::load(&cookie_jar);
|
let sessions_cookie = UpstreamSessionsCookie::load(&cookie_jar);
|
||||||
let (session_id, post_auth_action) = sessions_cookie
|
let (session_id, post_auth_action) = sessions_cookie
|
||||||
.lookup_link(link_id)
|
.lookup_link(link_id)
|
||||||
@ -264,7 +266,10 @@ pub(crate) async fn get(
|
|||||||
.filter(mas_data_model::User::is_valid)
|
.filter(mas_data_model::User::is_valid)
|
||||||
.ok_or(RouteError::UserNotFound)?;
|
.ok_or(RouteError::UserNotFound)?;
|
||||||
|
|
||||||
let session = repo.browser_session().add(&mut rng, &clock, &user).await?;
|
let session = repo
|
||||||
|
.browser_session()
|
||||||
|
.add(&mut rng, &clock, &user, user_agent)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let upstream_session = repo
|
let upstream_session = repo
|
||||||
.upstream_oauth_session()
|
.upstream_oauth_session()
|
||||||
@ -352,9 +357,11 @@ pub(crate) async fn post(
|
|||||||
clock: BoxClock,
|
clock: BoxClock,
|
||||||
mut repo: BoxRepository,
|
mut repo: BoxRepository,
|
||||||
cookie_jar: CookieJar,
|
cookie_jar: CookieJar,
|
||||||
|
user_agent: Option<TypedHeader<headers::UserAgent>>,
|
||||||
Path(link_id): Path<Ulid>,
|
Path(link_id): Path<Ulid>,
|
||||||
Form(form): Form<ProtectedForm<FormData>>,
|
Form(form): Form<ProtectedForm<FormData>>,
|
||||||
) -> Result<impl IntoResponse, RouteError> {
|
) -> Result<impl IntoResponse, RouteError> {
|
||||||
|
let user_agent = user_agent.map(|ua| ua.as_str().to_owned());
|
||||||
let form = cookie_jar.verify_form(&clock, form)?;
|
let form = cookie_jar.verify_form(&clock, form)?;
|
||||||
|
|
||||||
let sessions_cookie = UpstreamSessionsCookie::load(&cookie_jar);
|
let sessions_cookie = UpstreamSessionsCookie::load(&cookie_jar);
|
||||||
@ -503,7 +510,9 @@ pub(crate) async fn post(
|
|||||||
.associate_to_user(&link, &user)
|
.associate_to_user(&link, &user)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
repo.browser_session().add(&mut rng, &clock, &user).await?
|
repo.browser_session()
|
||||||
|
.add(&mut rng, &clock, &user, user_agent)
|
||||||
|
.await?
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => return Err(RouteError::InvalidFormAction),
|
_ => return Err(RouteError::InvalidFormAction),
|
||||||
|
@ -15,7 +15,9 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
extract::{Form, Query, State},
|
extract::{Form, Query, State},
|
||||||
response::{Html, IntoResponse, Response},
|
response::{Html, IntoResponse, Response},
|
||||||
|
TypedHeader,
|
||||||
};
|
};
|
||||||
|
use headers::UserAgent;
|
||||||
use hyper::StatusCode;
|
use hyper::StatusCode;
|
||||||
use mas_axum_utils::{
|
use mas_axum_utils::{
|
||||||
cookies::CookieJar,
|
cookies::CookieJar,
|
||||||
@ -109,8 +111,10 @@ pub(crate) async fn post(
|
|||||||
mut repo: BoxRepository,
|
mut repo: BoxRepository,
|
||||||
Query(query): Query<OptionalPostAuthAction>,
|
Query(query): Query<OptionalPostAuthAction>,
|
||||||
cookie_jar: CookieJar,
|
cookie_jar: CookieJar,
|
||||||
|
user_agent: Option<TypedHeader<UserAgent>>,
|
||||||
Form(form): Form<ProtectedForm<LoginForm>>,
|
Form(form): Form<ProtectedForm<LoginForm>>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
|
let user_agent = user_agent.map(|ua| ua.as_str().to_owned());
|
||||||
if !password_manager.is_enabled() {
|
if !password_manager.is_enabled() {
|
||||||
// XXX: is it necessary to have better errors here?
|
// XXX: is it necessary to have better errors here?
|
||||||
return Ok(StatusCode::METHOD_NOT_ALLOWED.into_response());
|
return Ok(StatusCode::METHOD_NOT_ALLOWED.into_response());
|
||||||
@ -158,6 +162,7 @@ pub(crate) async fn post(
|
|||||||
&clock,
|
&clock,
|
||||||
&form.username,
|
&form.username,
|
||||||
&form.password,
|
&form.password,
|
||||||
|
user_agent,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@ -193,6 +198,7 @@ async fn login(
|
|||||||
clock: &impl Clock,
|
clock: &impl Clock,
|
||||||
username: &str,
|
username: &str,
|
||||||
password: &str,
|
password: &str,
|
||||||
|
user_agent: Option<String>,
|
||||||
) -> Result<BrowserSession, FormError> {
|
) -> Result<BrowserSession, FormError> {
|
||||||
// XXX: we're loosing the error context here
|
// XXX: we're loosing the error context here
|
||||||
// First, lookup the user
|
// First, lookup the user
|
||||||
@ -245,7 +251,7 @@ async fn login(
|
|||||||
// Start a new session
|
// Start a new session
|
||||||
let user_session = repo
|
let user_session = repo
|
||||||
.browser_session()
|
.browser_session()
|
||||||
.add(&mut rng, clock, &user)
|
.add(&mut rng, clock, &user, user_agent)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| FormError::Internal)?;
|
.map_err(|_| FormError::Internal)?;
|
||||||
|
|
||||||
|
@ -17,7 +17,9 @@ use std::{str::FromStr, sync::Arc};
|
|||||||
use axum::{
|
use axum::{
|
||||||
extract::{Form, Query, State},
|
extract::{Form, Query, State},
|
||||||
response::{Html, IntoResponse, Response},
|
response::{Html, IntoResponse, Response},
|
||||||
|
TypedHeader,
|
||||||
};
|
};
|
||||||
|
use headers::UserAgent;
|
||||||
use hyper::StatusCode;
|
use hyper::StatusCode;
|
||||||
use lettre::Address;
|
use lettre::Address;
|
||||||
use mas_axum_utils::{
|
use mas_axum_utils::{
|
||||||
@ -104,8 +106,10 @@ pub(crate) async fn post(
|
|||||||
mut repo: BoxRepository,
|
mut repo: BoxRepository,
|
||||||
Query(query): Query<OptionalPostAuthAction>,
|
Query(query): Query<OptionalPostAuthAction>,
|
||||||
cookie_jar: CookieJar,
|
cookie_jar: CookieJar,
|
||||||
|
user_agent: Option<TypedHeader<UserAgent>>,
|
||||||
Form(form): Form<ProtectedForm<RegisterForm>>,
|
Form(form): Form<ProtectedForm<RegisterForm>>,
|
||||||
) -> Result<Response, FancyError> {
|
) -> Result<Response, FancyError> {
|
||||||
|
let user_agent = user_agent.map(|ua| ua.as_str().to_owned());
|
||||||
if !password_manager.is_enabled() {
|
if !password_manager.is_enabled() {
|
||||||
return Ok(StatusCode::METHOD_NOT_ALLOWED.into_response());
|
return Ok(StatusCode::METHOD_NOT_ALLOWED.into_response());
|
||||||
}
|
}
|
||||||
@ -206,7 +210,10 @@ pub(crate) async fn post(
|
|||||||
|
|
||||||
let next = mas_router::AccountVerifyEmail::new(user_email.id).and_maybe(query.post_auth_action);
|
let next = mas_router::AccountVerifyEmail::new(user_email.id).and_maybe(query.post_auth_action);
|
||||||
|
|
||||||
let session = repo.browser_session().add(&mut rng, &clock, &user).await?;
|
let session = repo
|
||||||
|
.browser_session()
|
||||||
|
.add(&mut rng, &clock, &user, user_agent)
|
||||||
|
.await?;
|
||||||
|
|
||||||
repo.browser_session()
|
repo.browser_session()
|
||||||
.authenticate_with_password(&mut rng, &clock, &session, &user_password)
|
.authenticate_with_password(&mut rng, &clock, &session, &user_password)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"db_name": "PostgreSQL",
|
"db_name": "PostgreSQL",
|
||||||
"query": "\n SELECT s.user_session_id\n , s.created_at AS \"user_session_created_at\"\n , s.finished_at AS \"user_session_finished_at\"\n , u.user_id\n , u.username AS \"user_username\"\n , u.primary_user_email_id AS \"user_primary_user_email_id\"\n , u.created_at AS \"user_created_at\"\n , u.locked_at AS \"user_locked_at\"\n FROM user_sessions s\n INNER JOIN users u\n USING (user_id)\n WHERE s.user_session_id = $1\n ",
|
"query": "\n SELECT s.user_session_id\n , s.created_at AS \"user_session_created_at\"\n , s.finished_at AS \"user_session_finished_at\"\n , s.user_agent AS \"user_session_user_agent\"\n , u.user_id\n , u.username AS \"user_username\"\n , u.primary_user_email_id AS \"user_primary_user_email_id\"\n , u.created_at AS \"user_created_at\"\n , u.locked_at AS \"user_locked_at\"\n FROM user_sessions s\n INNER JOIN users u\n USING (user_id)\n WHERE s.user_session_id = $1\n ",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
@ -20,26 +20,31 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 3,
|
"ordinal": 3,
|
||||||
|
"name": "user_session_user_agent",
|
||||||
|
"type_info": "Text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ordinal": 4,
|
||||||
"name": "user_id",
|
"name": "user_id",
|
||||||
"type_info": "Uuid"
|
"type_info": "Uuid"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 4,
|
"ordinal": 5,
|
||||||
"name": "user_username",
|
"name": "user_username",
|
||||||
"type_info": "Text"
|
"type_info": "Text"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 5,
|
"ordinal": 6,
|
||||||
"name": "user_primary_user_email_id",
|
"name": "user_primary_user_email_id",
|
||||||
"type_info": "Uuid"
|
"type_info": "Uuid"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 6,
|
"ordinal": 7,
|
||||||
"name": "user_created_at",
|
"name": "user_created_at",
|
||||||
"type_info": "Timestamptz"
|
"type_info": "Timestamptz"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ordinal": 7,
|
"ordinal": 8,
|
||||||
"name": "user_locked_at",
|
"name": "user_locked_at",
|
||||||
"type_info": "Timestamptz"
|
"type_info": "Timestamptz"
|
||||||
}
|
}
|
||||||
@ -53,6 +58,7 @@
|
|||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
|
true,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
@ -60,5 +66,5 @@
|
|||||||
true
|
true
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hash": "73fe61f03a41778c6273b1c2dbdb13b91fbccfe5fbdbead8c4868d52a61a0f9d"
|
"hash": "b98052065469a71643bb332cbeb07e0e43c620ffa1a592eb45ab326e0064efa8"
|
||||||
}
|
}
|
@ -1,16 +1,17 @@
|
|||||||
{
|
{
|
||||||
"db_name": "PostgreSQL",
|
"db_name": "PostgreSQL",
|
||||||
"query": "\n INSERT INTO user_sessions (user_session_id, user_id, created_at)\n VALUES ($1, $2, $3)\n ",
|
"query": "\n INSERT INTO user_sessions (user_session_id, user_id, created_at, user_agent)\n VALUES ($1, $2, $3, $4)\n ",
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"Left": [
|
"Left": [
|
||||||
"Uuid",
|
"Uuid",
|
||||||
"Uuid",
|
"Uuid",
|
||||||
"Timestamptz"
|
"Timestamptz",
|
||||||
|
"Text"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"nullable": []
|
"nullable": []
|
||||||
},
|
},
|
||||||
"hash": "c1d90a7f2287ec779c81a521fab19e5ede3fa95484033e0312c30d9b6ecc03f0"
|
"hash": "f41f76c94cd68fca2285b1cc60f426603c84df4ef1c6ce5dc441a63d2dc46f6e"
|
||||||
}
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
-- 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 user_agent column to the user_sessions table
|
||||||
|
ALTER TABLE user_sessions ADD COLUMN user_agent TEXT;
|
@ -18,9 +18,10 @@
|
|||||||
pub enum UserSessions {
|
pub enum UserSessions {
|
||||||
Table,
|
Table,
|
||||||
UserSessionId,
|
UserSessionId,
|
||||||
|
UserId,
|
||||||
CreatedAt,
|
CreatedAt,
|
||||||
FinishedAt,
|
FinishedAt,
|
||||||
UserId,
|
UserAgent,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(sea_query::Iden)]
|
#[derive(sea_query::Iden)]
|
||||||
|
@ -177,7 +177,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let user_session = repo
|
let user_session = repo
|
||||||
.browser_session()
|
.browser_session()
|
||||||
.add(&mut rng, &clock, &user)
|
.add(&mut rng, &clock, &user, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -387,7 +387,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let user1_session = repo
|
let user1_session = repo
|
||||||
.browser_session()
|
.browser_session()
|
||||||
.add(&mut rng, &clock, &user1)
|
.add(&mut rng, &clock, &user1, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
@ -398,7 +398,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let user2_session = repo
|
let user2_session = repo
|
||||||
.browser_session()
|
.browser_session()
|
||||||
.add(&mut rng, &clock, &user2)
|
.add(&mut rng, &clock, &user2, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -53,6 +53,7 @@ struct SessionLookup {
|
|||||||
user_session_id: Uuid,
|
user_session_id: Uuid,
|
||||||
user_session_created_at: DateTime<Utc>,
|
user_session_created_at: DateTime<Utc>,
|
||||||
user_session_finished_at: Option<DateTime<Utc>>,
|
user_session_finished_at: Option<DateTime<Utc>>,
|
||||||
|
user_session_user_agent: Option<String>,
|
||||||
user_id: Uuid,
|
user_id: Uuid,
|
||||||
user_username: String,
|
user_username: String,
|
||||||
user_primary_user_email_id: Option<Uuid>,
|
user_primary_user_email_id: Option<Uuid>,
|
||||||
@ -79,6 +80,7 @@ impl TryFrom<SessionLookup> for BrowserSession {
|
|||||||
user,
|
user,
|
||||||
created_at: value.user_session_created_at,
|
created_at: value.user_session_created_at,
|
||||||
finished_at: value.user_session_finished_at,
|
finished_at: value.user_session_finished_at,
|
||||||
|
user_agent: value.user_session_user_agent,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,6 +141,7 @@ impl<'c> BrowserSessionRepository for PgBrowserSessionRepository<'c> {
|
|||||||
SELECT s.user_session_id
|
SELECT s.user_session_id
|
||||||
, s.created_at AS "user_session_created_at"
|
, s.created_at AS "user_session_created_at"
|
||||||
, s.finished_at AS "user_session_finished_at"
|
, s.finished_at AS "user_session_finished_at"
|
||||||
|
, s.user_agent AS "user_session_user_agent"
|
||||||
, u.user_id
|
, u.user_id
|
||||||
, u.username AS "user_username"
|
, u.username AS "user_username"
|
||||||
, u.primary_user_email_id AS "user_primary_user_email_id"
|
, u.primary_user_email_id AS "user_primary_user_email_id"
|
||||||
@ -175,6 +178,7 @@ impl<'c> BrowserSessionRepository for PgBrowserSessionRepository<'c> {
|
|||||||
rng: &mut (dyn RngCore + Send),
|
rng: &mut (dyn RngCore + Send),
|
||||||
clock: &dyn Clock,
|
clock: &dyn Clock,
|
||||||
user: &User,
|
user: &User,
|
||||||
|
user_agent: Option<String>,
|
||||||
) -> Result<BrowserSession, Self::Error> {
|
) -> Result<BrowserSession, Self::Error> {
|
||||||
let created_at = clock.now();
|
let created_at = clock.now();
|
||||||
let id = Ulid::from_datetime_with_source(created_at.into(), rng);
|
let id = Ulid::from_datetime_with_source(created_at.into(), rng);
|
||||||
@ -182,12 +186,13 @@ impl<'c> BrowserSessionRepository for PgBrowserSessionRepository<'c> {
|
|||||||
|
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
r#"
|
r#"
|
||||||
INSERT INTO user_sessions (user_session_id, user_id, created_at)
|
INSERT INTO user_sessions (user_session_id, user_id, created_at, user_agent)
|
||||||
VALUES ($1, $2, $3)
|
VALUES ($1, $2, $3, $4)
|
||||||
"#,
|
"#,
|
||||||
Uuid::from(id),
|
Uuid::from(id),
|
||||||
Uuid::from(user.id),
|
Uuid::from(user.id),
|
||||||
created_at,
|
created_at,
|
||||||
|
user_agent,
|
||||||
)
|
)
|
||||||
.traced()
|
.traced()
|
||||||
.execute(&mut *self.conn)
|
.execute(&mut *self.conn)
|
||||||
@ -199,6 +204,7 @@ impl<'c> BrowserSessionRepository for PgBrowserSessionRepository<'c> {
|
|||||||
user: user.clone(),
|
user: user.clone(),
|
||||||
created_at,
|
created_at,
|
||||||
finished_at: None,
|
finished_at: None,
|
||||||
|
user_agent,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(session)
|
Ok(session)
|
||||||
@ -265,6 +271,10 @@ impl<'c> BrowserSessionRepository for PgBrowserSessionRepository<'c> {
|
|||||||
Expr::col((UserSessions::Table, UserSessions::FinishedAt)),
|
Expr::col((UserSessions::Table, UserSessions::FinishedAt)),
|
||||||
SessionLookupIden::UserSessionFinishedAt,
|
SessionLookupIden::UserSessionFinishedAt,
|
||||||
)
|
)
|
||||||
|
.expr_as(
|
||||||
|
Expr::col((UserSessions::Table, UserSessions::UserAgent)),
|
||||||
|
SessionLookupIden::UserSessionUserAgent,
|
||||||
|
)
|
||||||
.expr_as(
|
.expr_as(
|
||||||
Expr::col((Users::Table, Users::UserId)),
|
Expr::col((Users::Table, Users::UserId)),
|
||||||
SessionLookupIden::UserId,
|
SessionLookupIden::UserId,
|
||||||
|
@ -433,7 +433,7 @@ async fn test_user_session(pool: PgPool) {
|
|||||||
|
|
||||||
let session = repo
|
let session = repo
|
||||||
.browser_session()
|
.browser_session()
|
||||||
.add(&mut rng, &clock, &user)
|
.add(&mut rng, &clock, &user, None)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(session.user.id, user.id);
|
assert_eq!(session.user.id, user.id);
|
||||||
|
@ -114,6 +114,7 @@ pub trait BrowserSessionRepository: Send + Sync {
|
|||||||
/// * `rng`: The random number generator to use
|
/// * `rng`: The random number generator to use
|
||||||
/// * `clock`: The clock used to generate timestamps
|
/// * `clock`: The clock used to generate timestamps
|
||||||
/// * `user`: The user to create the session for
|
/// * `user`: The user to create the session for
|
||||||
|
/// * `user_agent`: If available, the user agent of the browser
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
@ -123,6 +124,7 @@ pub trait BrowserSessionRepository: Send + Sync {
|
|||||||
rng: &mut (dyn RngCore + Send),
|
rng: &mut (dyn RngCore + Send),
|
||||||
clock: &dyn Clock,
|
clock: &dyn Clock,
|
||||||
user: &User,
|
user: &User,
|
||||||
|
user_agent: Option<String>,
|
||||||
) -> Result<BrowserSession, Self::Error>;
|
) -> Result<BrowserSession, Self::Error>;
|
||||||
|
|
||||||
/// Finish a [`BrowserSession`]
|
/// Finish a [`BrowserSession`]
|
||||||
@ -234,6 +236,7 @@ repository_impl!(BrowserSessionRepository:
|
|||||||
rng: &mut (dyn RngCore + Send),
|
rng: &mut (dyn RngCore + Send),
|
||||||
clock: &dyn Clock,
|
clock: &dyn Clock,
|
||||||
user: &User,
|
user: &User,
|
||||||
|
user_agent: Option<String>,
|
||||||
) -> Result<BrowserSession, Self::Error>;
|
) -> Result<BrowserSession, Self::Error>;
|
||||||
async fn finish(
|
async fn finish(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
Reference in New Issue
Block a user