matrix-sdk: require_auth_for_profile_requests feature and force_auth request config
forces authentication for `get_avatar` which was previously done with the unstable-synapse-quirks feature in ruma
This commit is contained in:
parent
5c882f89e8
commit
242d46c9a1
6 changed files with 59 additions and 21 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
@ -102,6 +102,7 @@ jobs:
|
|||
- linux / features-markdown
|
||||
- linux / features-socks
|
||||
- linux / features-sso_login
|
||||
- linux / features-require_auth_for_profile_requests
|
||||
|
||||
include:
|
||||
- name: linux / features-no-encryption
|
||||
|
@ -119,6 +120,9 @@ jobs:
|
|||
- name: linux / features-rustls-tls
|
||||
cargo_args: --no-default-features --features rustls-tls
|
||||
|
||||
- name: linux / features-require_auth_for_profile_requests
|
||||
cargo_args: --no-default-features --features "require_auth_for_profile_requests, native-tls"
|
||||
|
||||
- name: linux / features-markdown
|
||||
cargo_args: --features markdown
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ features = ["docs"]
|
|||
rustdoc-args = ["--cfg", "feature=\"docs\""]
|
||||
|
||||
[features]
|
||||
default = ["encryption", "sled_cryptostore", "sled_state_store", "native-tls"]
|
||||
default = ["encryption", "sled_cryptostore", "sled_state_store", "require_auth_for_profile_requests", "native-tls"]
|
||||
|
||||
encryption = ["matrix-sdk-base/encryption"]
|
||||
sled_state_store = ["matrix-sdk-base/sled_state_store"]
|
||||
|
@ -25,6 +25,7 @@ native-tls = ["reqwest/native-tls"]
|
|||
rustls-tls = ["reqwest/rustls-tls"]
|
||||
socks = ["reqwest/socks"]
|
||||
sso_login = ["warp", "rand", "tokio-stream"]
|
||||
require_auth_for_profile_requests = []
|
||||
|
||||
docs = ["encryption", "sled_cryptostore", "sled_state_store", "sso_login"]
|
||||
|
||||
|
|
|
@ -405,6 +405,7 @@ pub struct RequestConfig {
|
|||
pub(crate) timeout: Duration,
|
||||
pub(crate) retry_limit: Option<u64>,
|
||||
pub(crate) retry_timeout: Option<Duration>,
|
||||
pub(crate) force_auth: bool,
|
||||
}
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
|
@ -425,6 +426,7 @@ impl Default for RequestConfig {
|
|||
timeout: DEFAULT_REQUEST_TIMEOUT,
|
||||
retry_limit: Default::default(),
|
||||
retry_timeout: Default::default(),
|
||||
force_auth: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -459,6 +461,14 @@ impl RequestConfig {
|
|||
self.retry_timeout = Some(retry_timeout);
|
||||
self
|
||||
}
|
||||
|
||||
/// Force sending authorization even if the endpoint does not require it. Default is only
|
||||
/// sending authorization if it is required
|
||||
#[cfg(feature = "require_auth_for_profile_requests")]
|
||||
pub(crate) fn force_auth(mut self) -> Self {
|
||||
self.force_auth = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Client {
|
||||
|
@ -610,7 +620,14 @@ impl Client {
|
|||
pub async fn avatar_url(&self) -> Result<Option<MxcUri>> {
|
||||
let user_id = self.user_id().await.ok_or(Error::AuthenticationRequired)?;
|
||||
let request = get_avatar_url::Request::new(&user_id);
|
||||
let response = self.send(request, None).await?;
|
||||
|
||||
#[cfg(not(feature = "require_auth_for_profile_requests"))]
|
||||
let config = None;
|
||||
|
||||
#[cfg(feature = "require_auth_for_profile_requests")]
|
||||
let config = Some(RequestConfig::new().force_auth());
|
||||
|
||||
let response = self.send(request, config).await?;
|
||||
Ok(response.avatar_url)
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,10 @@ pub enum HttpError {
|
|||
#[error("the queried endpoint requires authentication but was called before logging in")]
|
||||
AuthenticationRequired,
|
||||
|
||||
/// Client tried to force authentication but did not provide an access token.
|
||||
#[error("tried to force authentication but no access token was provided")]
|
||||
ForcedAuthenticationWithoutAccessToken,
|
||||
|
||||
/// Queried endpoint is not meant for clients.
|
||||
#[error("the queried endpoint is not meant for clients")]
|
||||
NotClientRequest,
|
||||
|
|
|
@ -105,30 +105,39 @@ impl HttpClient {
|
|||
session: Arc<RwLock<Option<Session>>>,
|
||||
config: Option<RequestConfig>,
|
||||
) -> Result<http::Response<Bytes>, HttpError> {
|
||||
let request = {
|
||||
let read_guard;
|
||||
let access_token = match Request::METADATA.authentication {
|
||||
AuthScheme::AccessToken => {
|
||||
read_guard = session.read().await;
|
||||
|
||||
if let Some(session) = read_guard.as_ref() {
|
||||
SendAccessToken::IfRequired(session.access_token.as_str())
|
||||
} else {
|
||||
return Err(HttpError::AuthenticationRequired);
|
||||
}
|
||||
}
|
||||
AuthScheme::None => SendAccessToken::None,
|
||||
_ => return Err(HttpError::NotClientRequest),
|
||||
};
|
||||
|
||||
request.try_into_http_request(&self.homeserver.to_string(), access_token)?
|
||||
};
|
||||
|
||||
let config = match config {
|
||||
Some(config) => config,
|
||||
None => self.request_config,
|
||||
};
|
||||
|
||||
let request = {
|
||||
let read_guard;
|
||||
let access_token = if config.force_auth {
|
||||
read_guard = session.read().await;
|
||||
if let Some(session) = read_guard.as_ref() {
|
||||
SendAccessToken::Always(session.access_token.as_str())
|
||||
} else {
|
||||
return Err(HttpError::ForcedAuthenticationWithoutAccessToken);
|
||||
}
|
||||
} else {
|
||||
match Request::METADATA.authentication {
|
||||
AuthScheme::AccessToken => {
|
||||
read_guard = session.read().await;
|
||||
|
||||
if let Some(session) = read_guard.as_ref() {
|
||||
SendAccessToken::IfRequired(session.access_token.as_str())
|
||||
} else {
|
||||
return Err(HttpError::AuthenticationRequired);
|
||||
}
|
||||
}
|
||||
AuthScheme::None => SendAccessToken::None,
|
||||
_ => return Err(HttpError::NotClientRequest),
|
||||
}
|
||||
};
|
||||
|
||||
request.try_into_http_request(&self.homeserver.to_string(), access_token)?
|
||||
};
|
||||
|
||||
self.inner.send_request(request, config).await
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,9 @@
|
|||
//! * `markdown`: Support for sending markdown formatted messages.
|
||||
//! * `socks`: Enables SOCKS support in reqwest, the default HTTP client.
|
||||
//! * `sso_login`: Enables SSO login with a local http server.
|
||||
//! * `require_auth_for_profile_requests`: Whether to send the access token in the authentication
|
||||
//! header when calling endpoints that retrieve profile data. This matches the synapse
|
||||
//! configuration `require_auth_for_profile_requests`. Enabled by default.
|
||||
|
||||
#![deny(
|
||||
missing_debug_implementations,
|
||||
|
|
Loading…
Reference in a new issue