1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
// Copyright 2024 New Vector Ltd.
// Copyright 2024 Kévin Commaille.
//
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
//! Methods related to the account management URL.
//!
//! This is a Matrix extension introduced in [MSC2965](https://github.com/matrix-org/matrix-spec-proposals/pull/2965).
use serde::Serialize;
use serde_with::skip_serializing_none;
use url::Url;
use crate::error::AccountManagementError;
/// An account management action that a user can take, including a device ID for
/// the actions that support it.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(tag = "action")]
#[non_exhaustive]
pub enum AccountManagementActionFull {
/// `org.matrix.profile`
///
/// The user wishes to view their profile (name, avatar, contact details).
#[serde(rename = "org.matrix.profile")]
Profile,
/// `org.matrix.sessions_list`
///
/// The user wishes to view a list of their sessions.
#[serde(rename = "org.matrix.sessions_list")]
SessionsList,
/// `org.matrix.session_view`
///
/// The user wishes to view the details of a specific session.
#[serde(rename = "org.matrix.session_view")]
SessionView {
/// The ID of the session to view the details of.
device_id: String,
},
/// `org.matrix.session_end`
///
/// The user wishes to end/log out of a specific session.
#[serde(rename = "org.matrix.session_end")]
SessionEnd {
/// The ID of the session to end.
device_id: String,
},
/// `org.matrix.account_deactivate`
///
/// The user wishes to deactivate their account.
#[serde(rename = "org.matrix.account_deactivate")]
AccountDeactivate,
/// `org.matrix.cross_signing_reset`
///
/// The user wishes to reset their cross-signing keys.
#[serde(rename = "org.matrix.cross_signing_reset")]
CrossSigningReset,
}
#[skip_serializing_none]
#[derive(Debug, Clone, Serialize)]
struct AccountManagementData {
#[serde(flatten)]
action: Option<AccountManagementActionFull>,
id_token_hint: Option<String>,
}
/// Build the URL for accessing the account management capabilities.
///
/// # Arguments
///
/// * `account_management_uri` - The URL to access the issuer's account
/// management capabilities.
///
/// * `action` - The action that the user wishes to take.
///
/// * `id_token_hint` - An ID Token that was previously issued to the client,
/// used as a hint for which user is requesting to manage their account.
///
/// # Returns
///
/// A URL to be opened in a web browser where the end-user will be able to
/// access the account management capabilities of the issuer.
///
/// # Errors
///
/// Returns an error if serializing the URL fails.
pub fn build_account_management_url(
mut account_management_uri: Url,
action: Option<AccountManagementActionFull>,
id_token_hint: Option<String>,
) -> Result<Url, AccountManagementError> {
let data = AccountManagementData {
action,
id_token_hint,
};
let extra_query = serde_urlencoded::to_string(data)?;
if !extra_query.is_empty() {
// Add our parameters to the query, because the URL might already have one.
let mut full_query = account_management_uri
.query()
.map(ToOwned::to_owned)
.unwrap_or_default();
if !full_query.is_empty() {
full_query.push('&');
}
full_query.push_str(&extra_query);
account_management_uri.set_query(Some(&full_query));
}
Ok(account_management_uri)
}