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 rumamaster
parent
5c882f89e8
commit
242d46c9a1
|
@ -102,6 +102,7 @@ jobs:
|
||||||
- linux / features-markdown
|
- linux / features-markdown
|
||||||
- linux / features-socks
|
- linux / features-socks
|
||||||
- linux / features-sso_login
|
- linux / features-sso_login
|
||||||
|
- linux / features-require_auth_for_profile_requests
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- name: linux / features-no-encryption
|
- name: linux / features-no-encryption
|
||||||
|
@ -119,6 +120,9 @@ jobs:
|
||||||
- name: linux / features-rustls-tls
|
- name: linux / features-rustls-tls
|
||||||
cargo_args: --no-default-features --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
|
- name: linux / features-markdown
|
||||||
cargo_args: --features markdown
|
cargo_args: --features markdown
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ features = ["docs"]
|
||||||
rustdoc-args = ["--cfg", "feature=\"docs\""]
|
rustdoc-args = ["--cfg", "feature=\"docs\""]
|
||||||
|
|
||||||
[features]
|
[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"]
|
encryption = ["matrix-sdk-base/encryption"]
|
||||||
sled_state_store = ["matrix-sdk-base/sled_state_store"]
|
sled_state_store = ["matrix-sdk-base/sled_state_store"]
|
||||||
|
@ -25,6 +25,7 @@ native-tls = ["reqwest/native-tls"]
|
||||||
rustls-tls = ["reqwest/rustls-tls"]
|
rustls-tls = ["reqwest/rustls-tls"]
|
||||||
socks = ["reqwest/socks"]
|
socks = ["reqwest/socks"]
|
||||||
sso_login = ["warp", "rand", "tokio-stream"]
|
sso_login = ["warp", "rand", "tokio-stream"]
|
||||||
|
require_auth_for_profile_requests = []
|
||||||
|
|
||||||
docs = ["encryption", "sled_cryptostore", "sled_state_store", "sso_login"]
|
docs = ["encryption", "sled_cryptostore", "sled_state_store", "sso_login"]
|
||||||
|
|
||||||
|
|
|
@ -405,6 +405,7 @@ pub struct RequestConfig {
|
||||||
pub(crate) timeout: Duration,
|
pub(crate) timeout: Duration,
|
||||||
pub(crate) retry_limit: Option<u64>,
|
pub(crate) retry_limit: Option<u64>,
|
||||||
pub(crate) retry_timeout: Option<Duration>,
|
pub(crate) retry_timeout: Option<Duration>,
|
||||||
|
pub(crate) force_auth: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
|
@ -425,6 +426,7 @@ impl Default for RequestConfig {
|
||||||
timeout: DEFAULT_REQUEST_TIMEOUT,
|
timeout: DEFAULT_REQUEST_TIMEOUT,
|
||||||
retry_limit: Default::default(),
|
retry_limit: Default::default(),
|
||||||
retry_timeout: Default::default(),
|
retry_timeout: Default::default(),
|
||||||
|
force_auth: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -459,6 +461,14 @@ impl RequestConfig {
|
||||||
self.retry_timeout = Some(retry_timeout);
|
self.retry_timeout = Some(retry_timeout);
|
||||||
self
|
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 {
|
impl Client {
|
||||||
|
@ -610,7 +620,14 @@ impl Client {
|
||||||
pub async fn avatar_url(&self) -> Result<Option<MxcUri>> {
|
pub async fn avatar_url(&self) -> Result<Option<MxcUri>> {
|
||||||
let user_id = self.user_id().await.ok_or(Error::AuthenticationRequired)?;
|
let user_id = self.user_id().await.ok_or(Error::AuthenticationRequired)?;
|
||||||
let request = get_avatar_url::Request::new(&user_id);
|
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)
|
Ok(response.avatar_url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,10 @@ pub enum HttpError {
|
||||||
#[error("the queried endpoint requires authentication but was called before logging in")]
|
#[error("the queried endpoint requires authentication but was called before logging in")]
|
||||||
AuthenticationRequired,
|
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.
|
/// Queried endpoint is not meant for clients.
|
||||||
#[error("the queried endpoint is not meant for clients")]
|
#[error("the queried endpoint is not meant for clients")]
|
||||||
NotClientRequest,
|
NotClientRequest,
|
||||||
|
|
|
@ -105,9 +105,22 @@ impl HttpClient {
|
||||||
session: Arc<RwLock<Option<Session>>>,
|
session: Arc<RwLock<Option<Session>>>,
|
||||||
config: Option<RequestConfig>,
|
config: Option<RequestConfig>,
|
||||||
) -> Result<http::Response<Bytes>, HttpError> {
|
) -> Result<http::Response<Bytes>, HttpError> {
|
||||||
|
let config = match config {
|
||||||
|
Some(config) => config,
|
||||||
|
None => self.request_config,
|
||||||
|
};
|
||||||
|
|
||||||
let request = {
|
let request = {
|
||||||
let read_guard;
|
let read_guard;
|
||||||
let access_token = match Request::METADATA.authentication {
|
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 => {
|
AuthScheme::AccessToken => {
|
||||||
read_guard = session.read().await;
|
read_guard = session.read().await;
|
||||||
|
|
||||||
|
@ -119,16 +132,12 @@ impl HttpClient {
|
||||||
}
|
}
|
||||||
AuthScheme::None => SendAccessToken::None,
|
AuthScheme::None => SendAccessToken::None,
|
||||||
_ => return Err(HttpError::NotClientRequest),
|
_ => return Err(HttpError::NotClientRequest),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
request.try_into_http_request(&self.homeserver.to_string(), access_token)?
|
request.try_into_http_request(&self.homeserver.to_string(), access_token)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let config = match config {
|
|
||||||
Some(config) => config,
|
|
||||||
None => self.request_config,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.inner.send_request(request, config).await
|
self.inner.send_request(request, config).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,9 @@
|
||||||
//! * `markdown`: Support for sending markdown formatted messages.
|
//! * `markdown`: Support for sending markdown formatted messages.
|
||||||
//! * `socks`: Enables SOCKS support in reqwest, the default HTTP client.
|
//! * `socks`: Enables SOCKS support in reqwest, the default HTTP client.
|
||||||
//! * `sso_login`: Enables SSO login with a local http server.
|
//! * `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(
|
#![deny(
|
||||||
missing_debug_implementations,
|
missing_debug_implementations,
|
||||||
|
|
Loading…
Reference in New Issue