From 93e7cf461d7702ea4d9d6cd622c29fcc95eb3d0b Mon Sep 17 00:00:00 2001 From: strawberry Date: Sun, 7 Jul 2024 14:56:18 -0400 Subject: [PATCH] add client IP logging to media requests Signed-off-by: strawberry --- src/api/client/media.rs | 60 +++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/src/api/client/media.rs b/src/api/client/media.rs index 44978caf..9d3fbabe 100644 --- a/src/api/client/media.rs +++ b/src/api/client/media.rs @@ -2,6 +2,7 @@ use std::{io::Cursor, sync::Arc, time::Duration}; +use axum_client_ip::InsecureClientIp; use conduit::{debug, error, utils::math::ruma_from_usize, warn}; use image::io::Reader as ImgReader; use ipaddress::IPAddress; @@ -64,18 +65,22 @@ pub(crate) async fn get_media_config_v1_route( /// # `GET /_matrix/media/v3/preview_url` /// /// Returns URL preview. +#[tracing::instrument(skip_all, fields(%client), name = "url_preview")] pub(crate) async fn get_media_preview_route( - body: Ruma, + InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result { + let sender_user = body.sender_user.as_ref().expect("user is authenticated"); + let url = &body.url; if !url_preview_allowed(url) { + warn!(%sender_user, "URL is not allowed to be previewed: {url}"); return Err(Error::BadRequest(ErrorKind::forbidden(), "URL is not allowed to be previewed")); } match get_url_preview(url).await { Ok(preview) => { let res = serde_json::value::to_raw_value(&preview).map_err(|e| { - error!("Failed to convert UrlPreviewData into a serde json value: {}", e); + error!(%sender_user, "Failed to convert UrlPreviewData into a serde json value: {e}"); Error::BadRequest( ErrorKind::LimitExceeded { retry_after: Some(RetryAfter::Delay(Duration::from_secs(5))), @@ -87,7 +92,7 @@ pub(crate) async fn get_media_preview_route( Ok(get_media_preview::v3::Response::from_raw_value(res)) }, Err(e) => { - warn!("Failed to generate a URL preview: {e}"); + warn!(%sender_user, "Failed to generate a URL preview: {e}"); // there doesn't seem to be an agreed-upon error code in the spec. // the only response codes in the preview_url spec page are 200 and 429. @@ -108,10 +113,13 @@ pub(crate) async fn get_media_preview_route( /// See /// /// Returns URL preview. +#[tracing::instrument(skip_all, fields(%client), name = "url_preview")] pub(crate) async fn get_media_preview_v1_route( - body: Ruma, + InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result> { - get_media_preview_route(body).await.map(RumaResponse) + get_media_preview_route(InsecureClientIp(client), body) + .await + .map(RumaResponse) } /// # `POST /_matrix/media/v3/upload` @@ -120,8 +128,9 @@ pub(crate) async fn get_media_preview_v1_route( /// /// - Some metadata will be saved in the database /// - Media will be saved in the media/ directory +#[tracing::instrument(skip_all, fields(%client), name = "media_upload")] pub(crate) async fn create_content_route( - body: Ruma, + InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result { let sender_user = body.sender_user.as_ref().expect("user is authenticated"); @@ -167,10 +176,13 @@ pub(crate) async fn create_content_route( /// /// - Some metadata will be saved in the database /// - Media will be saved in the media/ directory +#[tracing::instrument(skip_all, fields(%client), name = "media_upload")] pub(crate) async fn create_content_v1_route( - body: Ruma, + InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result> { - create_content_route(body).await.map(RumaResponse) + create_content_route(InsecureClientIp(client), body) + .await + .map(RumaResponse) } /// # `GET /_matrix/media/v3/download/{serverName}/{mediaId}` @@ -181,7 +193,10 @@ pub(crate) async fn create_content_v1_route( /// - Only redirects if `allow_redirect` is true /// - Uses client-provided `timeout_ms` if available, else defaults to 20 /// seconds -pub(crate) async fn get_content_route(body: Ruma) -> Result { +#[tracing::instrument(skip_all, fields(%client), name = "media_get")] +pub(crate) async fn get_content_route( + InsecureClientIp(client): InsecureClientIp, body: Ruma, +) -> Result { let mxc = format!("mxc://{}/{}", body.server_name, body.media_id); if let Some(FileMeta { @@ -243,10 +258,13 @@ pub(crate) async fn get_content_route(body: Ruma) -> R /// - Only redirects if `allow_redirect` is true /// - Uses client-provided `timeout_ms` if available, else defaults to 20 /// seconds +#[tracing::instrument(skip_all, fields(%client), name = "media_get")] pub(crate) async fn get_content_v1_route( - body: Ruma, + InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result> { - get_content_route(body).await.map(RumaResponse) + get_content_route(InsecureClientIp(client), body) + .await + .map(RumaResponse) } /// # `GET /_matrix/media/v3/download/{serverName}/{mediaId}/{fileName}` @@ -257,8 +275,9 @@ pub(crate) async fn get_content_v1_route( /// - Only redirects if `allow_redirect` is true /// - Uses client-provided `timeout_ms` if available, else defaults to 20 /// seconds +#[tracing::instrument(skip_all, fields(%client), name = "media_get")] pub(crate) async fn get_content_as_filename_route( - body: Ruma, + InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result { let mxc = format!("mxc://{}/{}", body.server_name, body.media_id); @@ -328,10 +347,13 @@ pub(crate) async fn get_content_as_filename_route( /// - Only redirects if `allow_redirect` is true /// - Uses client-provided `timeout_ms` if available, else defaults to 20 /// seconds +#[tracing::instrument(skip_all, fields(%client), name = "media_get")] pub(crate) async fn get_content_as_filename_v1_route( - body: Ruma, + InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result> { - get_content_as_filename_route(body).await.map(RumaResponse) + get_content_as_filename_route(InsecureClientIp(client), body) + .await + .map(RumaResponse) } /// # `GET /_matrix/media/v3/thumbnail/{serverName}/{mediaId}` @@ -342,8 +364,9 @@ pub(crate) async fn get_content_as_filename_v1_route( /// - Only redirects if `allow_redirect` is true /// - Uses client-provided `timeout_ms` if available, else defaults to 20 /// seconds +#[tracing::instrument(skip_all, fields(%client), name = "media_thumbnail_get")] pub(crate) async fn get_content_thumbnail_route( - body: Ruma, + InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result { let mxc = format!("mxc://{}/{}", body.server_name, body.media_id); @@ -453,10 +476,13 @@ pub(crate) async fn get_content_thumbnail_route( /// - Only redirects if `allow_redirect` is true /// - Uses client-provided `timeout_ms` if available, else defaults to 20 /// seconds +#[tracing::instrument(skip_all, fields(%client), name = "media_thumbnail_get")] pub(crate) async fn get_content_thumbnail_v1_route( - body: Ruma, + InsecureClientIp(client): InsecureClientIp, body: Ruma, ) -> Result> { - get_content_thumbnail_route(body).await.map(RumaResponse) + get_content_thumbnail_route(InsecureClientIp(client), body) + .await + .map(RumaResponse) } async fn get_remote_content(