Skip to main content

mas_handlers/views/
logout.rs

1// Copyright 2025, 2026 Element Creations Ltd.
2// Copyright 2024, 2025 New Vector Ltd.
3// Copyright 2021-2024 The Matrix.org Foundation C.I.C.
4//
5// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
6// Please see LICENSE files in the repository root for full details.
7
8use axum::{
9    extract::{Form, State},
10    response::IntoResponse,
11};
12use mas_axum_utils::{
13    InternalError, RecordAsRequester, SessionInfoExt,
14    cookies::CookieJar,
15    csrf::{CsrfExt, ProtectedForm},
16};
17use mas_data_model::{BoxClock, Clock};
18use mas_router::{PostAuthAction, UrlBuilder};
19use mas_storage::{BoxRepository, user::BrowserSessionRepository};
20
21use crate::BoundActivityTracker;
22
23#[tracing::instrument(name = "handlers.views.logout.post", skip_all)]
24pub(crate) async fn post(
25    clock: BoxClock,
26    mut repo: BoxRepository,
27    cookie_jar: CookieJar,
28    State(url_builder): State<UrlBuilder>,
29    activity_tracker: BoundActivityTracker,
30    Form(form): Form<ProtectedForm<Option<PostAuthAction>>>,
31) -> Result<impl IntoResponse, InternalError> {
32    let form = cookie_jar.verify_form(&clock, form)?;
33
34    let (session_info, cookie_jar) = cookie_jar.session_info();
35
36    if let Some(session_id) = session_info.current_session_id() {
37        let maybe_session = repo.browser_session().lookup(session_id).await?;
38        if let Some(session) = maybe_session
39            && session.finished_at.is_none()
40        {
41            // Attribute this request (and its log line) to the user being
42            // logged out.
43            session.maybe_record_as_requester();
44
45            activity_tracker
46                .record_browser_session(&clock, &session)
47                .await;
48
49            repo.browser_session().finish(&clock, session).await?;
50        }
51    }
52
53    repo.save().await?;
54
55    // We always want to clear out the session cookie, even if the session was
56    // invalid
57    let cookie_jar = cookie_jar.update_session_info(&session_info.mark_session_ended(clock.now()));
58
59    let destination = if let Some(action) = form {
60        action.go_next(&url_builder)
61    } else {
62        url_builder.redirect(&mas_router::Login::default())
63    };
64
65    Ok((cookie_jar, destination))
66}