refactor(sdk): Remove methods on OAuth API for account management URL
Instead encourage users to use the ones available on `AuthorizationServerMetadata` because they support both the stable and unstable actions. Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This commit is contained in:
committed by
Damir Jelić
parent
c50bab4847
commit
2d13a682a2
@@ -90,6 +90,12 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
### Refactor
|
||||
|
||||
- [**breaking**] The following variants of `AccountManagementAction` were
|
||||
renamed to match their new names after being merge in the Matrix specification:
|
||||
- `SessionsList` is renamed to `DevicesList`
|
||||
- `SessionView` is renamed to `DeviceView`
|
||||
- `SessionEnd` is renamed to `DeviceDelete`
|
||||
([#6217](https://github.com/matrix-org/matrix-rust-sdk/pull/6217))
|
||||
- [**breaking**] `HumanQrGrantLoginError::UnableToCreateDevice` has been removed
|
||||
([#6141](https://github.com/matrix-org/matrix-rust-sdk/pull/6141)
|
||||
- [**breaking**] Removed `ClientBuilder::enable_oidc_refresh_lock` in favour of using `ClientBuilder::cross_process_lock_config`
|
||||
|
||||
@@ -27,9 +27,7 @@ use matrix_sdk::media::MediaFileHandle as SdkMediaFileHandle;
|
||||
#[cfg(feature = "sqlite")]
|
||||
use matrix_sdk::STATE_STORE_DATABASE_NAME;
|
||||
use matrix_sdk::{
|
||||
authentication::oauth::{
|
||||
AccountManagementActionFull, ClientId, OAuthAuthorizationData, OAuthSession,
|
||||
},
|
||||
authentication::oauth::{ClientId, OAuthAuthorizationData, OAuthError, OAuthSession},
|
||||
deserialized_responses::RawAnySyncOrStrippedTimelineEvent,
|
||||
executor::AbortOnDrop,
|
||||
media::{MediaFormat, MediaRequestParameters, MediaRetentionPolicy, MediaThumbnailSettings},
|
||||
@@ -75,6 +73,9 @@ use oauth2::Scope;
|
||||
use ruma::{
|
||||
api::client::{
|
||||
alias::get_alias,
|
||||
discovery::get_authorization_server_metadata::v1::{
|
||||
AccountManagementActionData, DeviceDeleteData, DeviceViewData,
|
||||
},
|
||||
error::ErrorKind,
|
||||
profile::{AvatarUrl, DisplayName},
|
||||
room::create_room::{v3::CreationContent, RoomPowerLevelsContentOverride},
|
||||
@@ -1312,20 +1313,20 @@ impl Client {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mut url_builder = match self.inner.oauth().account_management_url().await {
|
||||
Ok(Some(url_builder)) => url_builder,
|
||||
Ok(None) => return Ok(None),
|
||||
let server_metadata = match self.inner.oauth().cached_server_metadata().await {
|
||||
Ok(server_metadata) => server_metadata,
|
||||
Err(e) => {
|
||||
error!("Failed retrieving account management URL: {e}");
|
||||
return Err(e.into());
|
||||
error!("Failed retrieving cached server metadata: {e}");
|
||||
return Err(OAuthError::from(e).into());
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(action) = action {
|
||||
url_builder = url_builder.action(action.into());
|
||||
Ok(if let Some(action) = &action {
|
||||
server_metadata.account_management_url_with_action(action.into())
|
||||
} else {
|
||||
server_metadata.account_management_uri
|
||||
}
|
||||
|
||||
Ok(Some(url_builder.build().to_string()))
|
||||
.map(Into::into))
|
||||
}
|
||||
|
||||
pub fn user_id(&self) -> Result<String, ClientError> {
|
||||
@@ -2661,23 +2662,23 @@ pub(crate) struct OidcSessionData {
|
||||
#[derive(uniffi::Enum)]
|
||||
pub enum AccountManagementAction {
|
||||
Profile,
|
||||
SessionsList,
|
||||
SessionView { device_id: String },
|
||||
SessionEnd { device_id: String },
|
||||
DevicesList,
|
||||
DeviceView { device_id: String },
|
||||
DeviceDelete { device_id: String },
|
||||
AccountDeactivate,
|
||||
CrossSigningReset,
|
||||
}
|
||||
|
||||
impl From<AccountManagementAction> for AccountManagementActionFull {
|
||||
fn from(value: AccountManagementAction) -> Self {
|
||||
impl<'a> From<&'a AccountManagementAction> for AccountManagementActionData<'a> {
|
||||
fn from(value: &'a AccountManagementAction) -> Self {
|
||||
match value {
|
||||
AccountManagementAction::Profile => Self::Profile,
|
||||
AccountManagementAction::SessionsList => Self::SessionsList,
|
||||
AccountManagementAction::SessionView { device_id } => {
|
||||
Self::SessionView { device_id: device_id.into() }
|
||||
AccountManagementAction::DevicesList => Self::DevicesList,
|
||||
AccountManagementAction::DeviceView { device_id } => {
|
||||
Self::DeviceView(DeviceViewData::new(device_id.as_str().into()))
|
||||
}
|
||||
AccountManagementAction::SessionEnd { device_id } => {
|
||||
Self::SessionEnd { device_id: device_id.into() }
|
||||
AccountManagementAction::DeviceDelete { device_id } => {
|
||||
Self::DeviceDelete(DeviceDeleteData::new(device_id.as_str().into()))
|
||||
}
|
||||
AccountManagementAction::AccountDeactivate => Self::AccountDeactivate,
|
||||
AccountManagementAction::CrossSigningReset => Self::CrossSigningReset,
|
||||
|
||||
@@ -8,6 +8,9 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
### Features
|
||||
|
||||
- Add `OAuth::cached_server_metadata()` that caches the authorization server
|
||||
metadata for a while.
|
||||
([#6217](https://github.com/matrix-org/matrix-rust-sdk/pull/6217))
|
||||
- Add `QRCodeGrantLoginError::SecureChannel` for secure channel errors
|
||||
([#6141](https://github.com/matrix-org/matrix-rust-sdk/pull/6141)
|
||||
- Add `QRCodeGrantLoginError::UnexpectedMessage` for protocol message errors
|
||||
@@ -79,6 +82,10 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
### Refactor
|
||||
|
||||
- [**breaking**] The functions on the `OAuth` API to access the account
|
||||
management URL and its actions were removed. The methods available on the
|
||||
`AuthorizationServerMetadata` should be used instead.
|
||||
([#6217](https://github.com/matrix-org/matrix-rust-sdk/pull/6217))
|
||||
- [**breaking**] `QRCodeGrantLoginError::UnableToCreateDevice` has been removed
|
||||
([#6141](https://github.com/matrix-org/matrix-rust-sdk/pull/6141)
|
||||
- The `RoomEventCache::paginate_thread_backwards` method is replaced by `RoomEventCache::thread_pagination` which returns a new `ThreadPagination` type, similar to `RoomPagination`.
|
||||
|
||||
@@ -1,236 +0,0 @@
|
||||
// Copyright 2025 Kévin Commaille
|
||||
//
|
||||
// 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.
|
||||
|
||||
//! Types and functions related to the account management URL.
|
||||
//!
|
||||
//! This is a Matrix extension introduced in [MSC4191](https://github.com/matrix-org/matrix-spec-proposals/pull/4191).
|
||||
|
||||
use ruma::{
|
||||
OwnedDeviceId,
|
||||
api::client::discovery::get_authorization_server_metadata::v1::AccountManagementAction,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
/// An account management action that a user can take, including a device ID for
|
||||
/// the actions that support it.
|
||||
///
|
||||
/// The actions are defined in [MSC4191].
|
||||
///
|
||||
/// [MSC4191]: https://github.com/matrix-org/matrix-spec-proposals/pull/4191
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
pub enum AccountManagementActionFull {
|
||||
/// `org.matrix.profile`
|
||||
///
|
||||
/// The user wishes to view their profile (name, avatar, contact details).
|
||||
Profile,
|
||||
|
||||
/// `org.matrix.sessions_list`
|
||||
///
|
||||
/// The user wishes to view a list of their sessions.
|
||||
SessionsList,
|
||||
|
||||
/// `org.matrix.session_view`
|
||||
///
|
||||
/// The user wishes to view the details of a specific session.
|
||||
SessionView {
|
||||
/// The ID of the session to view the details of.
|
||||
device_id: OwnedDeviceId,
|
||||
},
|
||||
|
||||
/// `org.matrix.session_end`
|
||||
///
|
||||
/// The user wishes to end/log out of a specific session.
|
||||
SessionEnd {
|
||||
/// The ID of the session to end.
|
||||
device_id: OwnedDeviceId,
|
||||
},
|
||||
|
||||
/// `org.matrix.account_deactivate`
|
||||
///
|
||||
/// The user wishes to deactivate their account.
|
||||
AccountDeactivate,
|
||||
|
||||
/// `org.matrix.cross_signing_reset`
|
||||
///
|
||||
/// The user wishes to reset their cross-signing keys.
|
||||
CrossSigningReset,
|
||||
}
|
||||
|
||||
impl AccountManagementActionFull {
|
||||
/// Get the [`AccountManagementAction`] matching this
|
||||
/// [`AccountManagementActionFull`].
|
||||
pub fn action_type(&self) -> AccountManagementAction {
|
||||
match self {
|
||||
Self::Profile => AccountManagementAction::Profile,
|
||||
Self::SessionsList => AccountManagementAction::UnstableSessionsList,
|
||||
Self::SessionView { .. } => AccountManagementAction::UnstableSessionView,
|
||||
Self::SessionEnd { .. } => AccountManagementAction::UnstableSessionEnd,
|
||||
Self::AccountDeactivate => AccountManagementAction::AccountDeactivate,
|
||||
Self::CrossSigningReset => AccountManagementAction::CrossSigningReset,
|
||||
}
|
||||
}
|
||||
|
||||
/// Append this action to the query of the given URL.
|
||||
fn append_to_url(&self, url: &mut Url) {
|
||||
let mut query_pairs = url.query_pairs_mut();
|
||||
query_pairs.append_pair("action", self.action_type().as_str());
|
||||
|
||||
match self {
|
||||
Self::SessionView { device_id } | Self::SessionEnd { device_id } => {
|
||||
query_pairs.append_pair("device_id", device_id.as_str());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for the URL for accessing the account management capabilities, as
|
||||
/// defined in [MSC4191].
|
||||
///
|
||||
/// This type can be instantiated with [`OAuth::account_management_url()`] and
|
||||
/// [`OAuth::fetch_account_management_url()`].
|
||||
///
|
||||
/// [`AccountManagementUrlBuilder::build()`] 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.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use matrix_sdk::authentication::oauth::AccountManagementActionFull;
|
||||
/// # _ = async {
|
||||
/// # let client: matrix_sdk::Client = unimplemented!();
|
||||
/// let oauth = client.oauth();
|
||||
///
|
||||
/// // Get the account management URL from the server metadata.
|
||||
/// let Some(url_builder) = oauth.account_management_url().await? else {
|
||||
/// println!("The server doesn't advertise an account management URL");
|
||||
/// return Ok(());
|
||||
/// };
|
||||
///
|
||||
/// // The user wants to see the list of sessions.
|
||||
/// let url =
|
||||
/// url_builder.action(AccountManagementActionFull::SessionsList).build();
|
||||
///
|
||||
/// println!("See your sessions at: {url}");
|
||||
/// # anyhow::Ok(()) };
|
||||
/// ```
|
||||
///
|
||||
/// [MSC4191]: https://github.com/matrix-org/matrix-spec-proposals/pull/4191
|
||||
/// [`OAuth::account_management_url()`]: super::OAuth::account_management_url
|
||||
/// [`OAuth::fetch_account_management_url()`]: super::OAuth::fetch_account_management_url
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AccountManagementUrlBuilder {
|
||||
account_management_uri: Url,
|
||||
action: Option<AccountManagementActionFull>,
|
||||
}
|
||||
|
||||
impl AccountManagementUrlBuilder {
|
||||
/// Construct an [`AccountManagementUrlBuilder`] for the given URL.
|
||||
pub(super) fn new(account_management_uri: Url) -> Self {
|
||||
Self { account_management_uri, action: None }
|
||||
}
|
||||
|
||||
/// Set the action that the user wishes to take.
|
||||
pub fn action(mut self, action: AccountManagementActionFull) -> Self {
|
||||
self.action = Some(action);
|
||||
self
|
||||
}
|
||||
|
||||
/// Build the URL to present to the end user.
|
||||
pub fn build(self) -> Url {
|
||||
// Add our parameters to the query, because the URL might already have one.
|
||||
let mut account_management_uri = self.account_management_uri;
|
||||
|
||||
if let Some(action) = &self.action {
|
||||
action.append_to_url(&mut account_management_uri);
|
||||
}
|
||||
|
||||
account_management_uri
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use ruma::owned_device_id;
|
||||
use url::Url;
|
||||
|
||||
use super::{AccountManagementActionFull, AccountManagementUrlBuilder};
|
||||
|
||||
#[test]
|
||||
fn test_build_account_management_url_actions() {
|
||||
let base_url = Url::parse("https://example.org").unwrap();
|
||||
let device_id = owned_device_id!("ABCDEFG");
|
||||
|
||||
let url = AccountManagementUrlBuilder::new(base_url.clone()).build();
|
||||
assert_eq!(url, base_url);
|
||||
|
||||
let url = AccountManagementUrlBuilder::new(base_url.clone())
|
||||
.action(AccountManagementActionFull::Profile)
|
||||
.build();
|
||||
assert_eq!(url.as_str(), "https://example.org/?action=org.matrix.profile");
|
||||
|
||||
let url = AccountManagementUrlBuilder::new(base_url.clone())
|
||||
.action(AccountManagementActionFull::SessionsList)
|
||||
.build();
|
||||
assert_eq!(url.as_str(), "https://example.org/?action=org.matrix.sessions_list");
|
||||
|
||||
let url = AccountManagementUrlBuilder::new(base_url.clone())
|
||||
.action(AccountManagementActionFull::SessionView { device_id: device_id.clone() })
|
||||
.build();
|
||||
assert_eq!(
|
||||
url.as_str(),
|
||||
"https://example.org/?action=org.matrix.session_view&device_id=ABCDEFG"
|
||||
);
|
||||
|
||||
let url = AccountManagementUrlBuilder::new(base_url.clone())
|
||||
.action(AccountManagementActionFull::SessionEnd { device_id })
|
||||
.build();
|
||||
assert_eq!(
|
||||
url.as_str(),
|
||||
"https://example.org/?action=org.matrix.session_end&device_id=ABCDEFG"
|
||||
);
|
||||
|
||||
let url = AccountManagementUrlBuilder::new(base_url.clone())
|
||||
.action(AccountManagementActionFull::AccountDeactivate)
|
||||
.build();
|
||||
assert_eq!(url.as_str(), "https://example.org/?action=org.matrix.account_deactivate");
|
||||
|
||||
let url = AccountManagementUrlBuilder::new(base_url)
|
||||
.action(AccountManagementActionFull::CrossSigningReset)
|
||||
.build();
|
||||
assert_eq!(url.as_str(), "https://example.org/?action=org.matrix.cross_signing_reset");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_build_account_management_url_with_query() {
|
||||
let base_url = Url::parse("https://example.org/?sid=123456").unwrap();
|
||||
|
||||
let url = AccountManagementUrlBuilder::new(base_url.clone())
|
||||
.action(AccountManagementActionFull::Profile)
|
||||
.build();
|
||||
assert_eq!(url.as_str(), "https://example.org/?sid=123456&action=org.matrix.profile");
|
||||
|
||||
let url = AccountManagementUrlBuilder::new(base_url)
|
||||
.action(AccountManagementActionFull::SessionView {
|
||||
device_id: owned_device_id!("ABCDEFG"),
|
||||
})
|
||||
.build();
|
||||
assert_eq!(
|
||||
url.as_str(),
|
||||
"https://example.org/?sid=123456&action=org.matrix.session_view&device_id=ABCDEFG"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -134,11 +134,10 @@
|
||||
//! account. It can be used to replace most of the Matrix APIs requiring
|
||||
//! User-Interactive Authentication.
|
||||
//!
|
||||
//! An [`AccountManagementUrlBuilder`] can be obtained with
|
||||
//! [`OAuth::account_management_url()`]. Then the action that the user wants to
|
||||
//! perform can be customized with [`AccountManagementUrlBuilder::action()`].
|
||||
//! Finally you can obtain the final URL to present to the user with
|
||||
//! [`AccountManagementUrlBuilder::build()`].
|
||||
//! The account management URL is available as `account_management_uri` on
|
||||
//! [`AuthorizationServerMetadata`]. To build a full account management URL that
|
||||
//! includes the action that the user wants to perform, use
|
||||
//! [`AuthorizationServerMetadata::account_management_url_with_action()`].
|
||||
//!
|
||||
//! # Logout
|
||||
//!
|
||||
@@ -164,12 +163,7 @@
|
||||
use std::sync::OnceLock;
|
||||
#[cfg(feature = "e2e-encryption")]
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::{BTreeSet, HashMap},
|
||||
fmt,
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{borrow::Cow, collections::HashMap, fmt, sync::Arc};
|
||||
|
||||
use as_variant::as_variant;
|
||||
#[cfg(feature = "e2e-encryption")]
|
||||
@@ -192,8 +186,7 @@ pub use oauth2::{ClientId, CsrfToken};
|
||||
use ruma::{
|
||||
DeviceId, OwnedDeviceId,
|
||||
api::client::discovery::get_authorization_server_metadata::{
|
||||
self,
|
||||
v1::{AccountManagementAction, AuthorizationServerMetadata},
|
||||
self, v1::AuthorizationServerMetadata,
|
||||
},
|
||||
serde::Raw,
|
||||
};
|
||||
@@ -203,7 +196,6 @@ use tokio::sync::Mutex;
|
||||
use tracing::{debug, error, instrument, trace, warn};
|
||||
use url::Url;
|
||||
|
||||
mod account_management_url;
|
||||
mod auth_code_builder;
|
||||
#[cfg(feature = "e2e-encryption")]
|
||||
mod cross_process;
|
||||
@@ -223,7 +215,6 @@ use self::qrcode::{
|
||||
LoginWithQrCode,
|
||||
};
|
||||
pub use self::{
|
||||
account_management_url::{AccountManagementActionFull, AccountManagementUrlBuilder},
|
||||
auth_code_builder::{OAuthAuthCodeUrlBuilder, OAuthAuthorizationData},
|
||||
error::OAuthError,
|
||||
};
|
||||
@@ -431,61 +422,24 @@ impl OAuth {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The account management actions supported by the authorization server's
|
||||
/// account management URL.
|
||||
/// Get the cached OAuth 2.0 authorization server metadata of the
|
||||
/// homeserver.
|
||||
///
|
||||
/// Returns an error if the request to get the server metadata fails.
|
||||
pub async fn account_management_actions_supported(
|
||||
&self,
|
||||
) -> Result<BTreeSet<AccountManagementAction>, OAuthError> {
|
||||
let server_metadata = self.server_metadata().await?;
|
||||
|
||||
Ok(server_metadata.account_management_actions_supported)
|
||||
}
|
||||
|
||||
/// Get the account management URL where the user can manage their
|
||||
/// identity-related settings.
|
||||
///
|
||||
/// This will always request the latest server metadata to get the account
|
||||
/// management URL.
|
||||
///
|
||||
/// To avoid making a request each time, you can use
|
||||
/// [`OAuth::account_management_url()`].
|
||||
///
|
||||
/// Returns an [`AccountManagementUrlBuilder`] if the URL was found. An
|
||||
/// optional action to perform can be added with `.action()`, and the final
|
||||
/// URL is obtained with `.build()`.
|
||||
///
|
||||
/// Returns `Ok(None)` if the URL was not found.
|
||||
///
|
||||
/// Returns an error if the request to get the server metadata fails or the
|
||||
/// URL could not be parsed.
|
||||
pub async fn fetch_account_management_url(
|
||||
&self,
|
||||
) -> Result<Option<AccountManagementUrlBuilder>, OAuthError> {
|
||||
let server_metadata = self.server_metadata().await?;
|
||||
Ok(server_metadata.account_management_uri.map(AccountManagementUrlBuilder::new))
|
||||
}
|
||||
|
||||
/// Get the account management URL where the user can manage their
|
||||
/// identity-related settings.
|
||||
///
|
||||
/// This method will cache the URL for a while, if the cache is not
|
||||
/// This method will cache the metadata for a while. If the cache is not
|
||||
/// populated it will request the server metadata, like a call to
|
||||
/// [`OAuth::fetch_account_management_url()`], and cache the resulting URL
|
||||
/// before returning it.
|
||||
/// [`OAuth::server_metadata()`], and cache the response before returning
|
||||
/// it.
|
||||
///
|
||||
/// Returns an [`AccountManagementUrlBuilder`] if the URL was found. An
|
||||
/// optional action to perform can be added with `.action()`, and the final
|
||||
/// URL is obtained with `.build()`.
|
||||
/// In most cases during the authentication process, it is better to always
|
||||
/// fetch the metadata from the server. This is provided for convenience for
|
||||
/// cases where the client doesn't want to incur the extra time necessary to
|
||||
/// make the request.
|
||||
///
|
||||
/// Returns `Ok(None)` if the URL was not found.
|
||||
///
|
||||
/// Returns an error if the request to get the server metadata fails or the
|
||||
/// URL could not be parsed.
|
||||
pub async fn account_management_url(
|
||||
/// Returns an error if a problem occurred when fetching or validating the
|
||||
/// metadata.
|
||||
pub async fn cached_server_metadata(
|
||||
&self,
|
||||
) -> Result<Option<AccountManagementUrlBuilder>, OAuthError> {
|
||||
) -> Result<AuthorizationServerMetadata, OAuthDiscoveryError> {
|
||||
const CACHE_KEY: &str = "SERVER_METADATA";
|
||||
|
||||
let mut cache = self.client.inner.caches.server_metadata.lock().await;
|
||||
@@ -498,11 +452,16 @@ impl OAuth {
|
||||
server_metadata
|
||||
};
|
||||
|
||||
Ok(metadata.account_management_uri.map(AccountManagementUrlBuilder::new))
|
||||
Ok(metadata)
|
||||
}
|
||||
|
||||
/// Fetch the OAuth 2.0 authorization server metadata of the homeserver.
|
||||
///
|
||||
/// This will always request the latest server metadata from the homeserver.
|
||||
///
|
||||
/// To avoid making a request each time, you can use
|
||||
/// [`OAuth::cached_server_metadata()`].
|
||||
///
|
||||
/// Returns an error if a problem occurred when fetching or validating the
|
||||
/// metadata.
|
||||
pub async fn server_metadata(
|
||||
|
||||
@@ -673,7 +673,7 @@ async fn test_register_client() {
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
async fn test_management_url_cache() {
|
||||
async fn test_server_metadata_cache() {
|
||||
let server = MatrixMockServer::new().await;
|
||||
|
||||
let oauth_server = server.oauth();
|
||||
@@ -685,23 +685,13 @@ async fn test_management_url_cache() {
|
||||
// The cache should not contain the entry.
|
||||
assert!(!client.inner.caches.server_metadata.lock().await.contains("SERVER_METADATA"));
|
||||
|
||||
let management_url = oauth
|
||||
.account_management_url()
|
||||
.await
|
||||
.expect("We should be able to fetch the account management url");
|
||||
|
||||
assert!(management_url.is_some());
|
||||
oauth.cached_server_metadata().await.expect("We should be able to fetch the server metadata");
|
||||
|
||||
// Check that the server metadata has been inserted into the cache.
|
||||
assert!(client.inner.caches.server_metadata.lock().await.contains("SERVER_METADATA"));
|
||||
|
||||
// Another call doesn't make another request for the metadata.
|
||||
let management_url = oauth
|
||||
.account_management_url()
|
||||
.await
|
||||
.expect("We should be able to fetch the account management url");
|
||||
|
||||
assert!(management_url.is_some());
|
||||
oauth.cached_server_metadata().await.expect("We should be able to fetch the server_metadata");
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
|
||||
@@ -24,8 +24,7 @@ use futures_util::StreamExt;
|
||||
use matrix_sdk::{
|
||||
Client, ClientBuildError, Result, RoomState,
|
||||
authentication::oauth::{
|
||||
AccountManagementActionFull, ClientId, OAuthAuthorizationData, OAuthError, OAuthSession,
|
||||
UrlOrQuery, UserSession,
|
||||
ClientId, OAuthAuthorizationData, OAuthError, OAuthSession, UrlOrQuery, UserSession,
|
||||
error::OAuthClientRegistrationError,
|
||||
registration::{ApplicationType, ClientMetadata, Localized, OAuthGrantType},
|
||||
},
|
||||
@@ -33,6 +32,7 @@ use matrix_sdk::{
|
||||
encryption::{CrossSigningResetAuthType, recovery::RecoveryState},
|
||||
room::Room,
|
||||
ruma::{
|
||||
api::client::discovery::get_authorization_server_metadata::v1::AccountManagementActionData,
|
||||
events::room::message::{MessageType, OriginalSyncRoomMessageEvent},
|
||||
serde::Raw,
|
||||
},
|
||||
@@ -265,10 +265,10 @@ impl OAuthCli {
|
||||
self.account(None).await;
|
||||
}
|
||||
Some("profile") => {
|
||||
self.account(Some(AccountManagementActionFull::Profile)).await;
|
||||
self.account(Some(AccountManagementActionData::Profile)).await;
|
||||
}
|
||||
Some("sessions") => {
|
||||
self.account(Some(AccountManagementActionFull::SessionsList)).await;
|
||||
Some("devices") => {
|
||||
self.account(Some(AccountManagementActionData::DevicesList)).await;
|
||||
}
|
||||
Some("watch") => match args.next() {
|
||||
Some(sub) => {
|
||||
@@ -375,18 +375,23 @@ impl OAuthCli {
|
||||
}
|
||||
|
||||
/// Get the account management URL.
|
||||
async fn account(&self, action: Option<AccountManagementActionFull>) {
|
||||
let Ok(Some(mut url_builder)) = self.client.oauth().fetch_account_management_url().await
|
||||
else {
|
||||
async fn account(&self, action: Option<AccountManagementActionData<'_>>) {
|
||||
let Ok(server_metadata) = self.client.oauth().cached_server_metadata().await else {
|
||||
println!("\nCould not retrieve the server metadata");
|
||||
return;
|
||||
};
|
||||
|
||||
let url = if let Some(action) = action {
|
||||
server_metadata.account_management_url_with_action(action)
|
||||
} else {
|
||||
server_metadata.account_management_uri
|
||||
};
|
||||
|
||||
let Some(url) = url else {
|
||||
println!("\nThis homeserver does not provide the URL to manage your account");
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(action) = action {
|
||||
url_builder = url_builder.action(action);
|
||||
}
|
||||
|
||||
let url = url_builder.build();
|
||||
println!("\nTo manage your account, visit: {url}");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user