diff --git a/examples/get_profiles/src/main.rs b/examples/get_profiles/src/main.rs index 20cb86613..03efd62e7 100644 --- a/examples/get_profiles/src/main.rs +++ b/examples/get_profiles/src/main.rs @@ -2,6 +2,7 @@ use std::{env, process::exit}; use matrix_sdk::{ Client, Result as MatrixResult, + reqwest::StatusCode, ruma::{ OwnedMxcUri, UserId, api::client::profile::{self, AvatarUrl, DisplayName}, @@ -19,12 +20,18 @@ struct UserProfile { /// This function calls the GET profile endpoint /// Spec: /// Ruma: +/// The Matrix spec does not require authentication for this endpoint. However, +/// some server configurations (e.g. Synapse's +/// `require_auth_for_profile_requests`) enforce auth to prevent user +/// enumeration, which will cause `client.send()` to return a 401 error. async fn get_profile(client: Client, mxid: &UserId) -> MatrixResult { // First construct the request you want to make // See https://docs.rs/ruma-client-api/latest/ruma_client_api/index.html for all available Endpoints let request = profile::get_profile::v3::Request::new(mxid.to_owned()); // Start the request using matrix_sdk::Client::send + // To avoid having to deal with auth errors, you can also use + // account().fetch_user_profile() which handles auth correctly. let resp = client.send(request).await?; // Use the response and construct a UserProfile struct. @@ -37,6 +44,18 @@ async fn get_profile(client: Client, mxid: &UserId) -> MatrixResult Ok(user_profile) } +/// This function calls the GET profile endpoint using the authenticated client. +/// It should succeed even if the server requires auth for profile requests. +async fn get_profile_authenticated(client: Client) -> MatrixResult { + let resp = client.account().fetch_user_profile().await?; + + let user_profile = UserProfile { + avatar_url: resp.get_static::()?, + displayname: resp.get_static::()?, + }; + Ok(user_profile) +} + async fn login( homeserver_url: String, username: &str, @@ -69,7 +88,23 @@ async fn main() -> anyhow::Result<()> { let client = login(homeserver_url, &username, &password).await?; let user_id = UserId::parse(username).expect("Couldn't parse the MXID"); - let profile = get_profile(client, &user_id).await?; + let profile = match get_profile(client.clone(), &user_id).await { + Ok(profile) => profile, + Err(e) => { + if e.as_client_api_error() + .is_some_and(|err| err.status_code == StatusCode::UNAUTHORIZED) + { + eprintln!( + "Authentication error: {e}. Check if the server requires authentication for profile requests. Trying to fetch profile using the authenticated client instead..." + ); + get_profile_authenticated(client).await? + } else { + eprintln!("Error fetching profile: {e}"); + UserProfile { avatar_url: None, displayname: None } + } + } + }; + println!("{profile:#?}"); Ok(()) }