tuwunel_api/client/admin/media/
query_media.rs1use axum::extract::State;
2use ruma::{Mxc, ServerName, UInt};
3use synapse_admin_api::media::query_media::v1::{MediaInfo, Request, Response};
4use tuwunel_core::{Result, err};
5use tuwunel_service::media::UserMediaEntry;
6
7use crate::{Ruma, client::admin::require_admin};
8
9pub(crate) async fn admin_query_media_route(
11 State(services): State<crate::State>,
12 body: Ruma<Request>,
13) -> Result<Response> {
14 require_admin(&services, body.sender_user()).await?;
15
16 let mxc = Mxc {
17 server_name: &body.server_name,
18 media_id: &body.media_id,
19 };
20
21 let entry = services
22 .media
23 .media_entry(&mxc)
24 .await
25 .ok_or_else(|| err!(Request(NotFound("Unknown media"))))?;
26
27 let local = services.globals.server_is_ours(&body.server_name);
28
29 Ok(Response {
30 media_info: into_media_info(local, &body.server_name, entry),
31 })
32}
33
34fn into_media_info(local: bool, server_name: &ServerName, entry: UserMediaEntry) -> MediaInfo {
35 MediaInfo {
36 media_origin: (!local).then(|| server_name.to_owned()),
37 user_id: entry.user_id.filter(|_| local),
38 media_id: entry
39 .mxc
40 .media_id()
41 .unwrap_or_default()
42 .to_owned(),
43 media_type: entry.media_type.unwrap_or_default(),
44 media_length: entry
45 .media_length
46 .and_then(|len| UInt::try_from(len).ok()),
47 upload_name: entry.upload_name,
48 created_ts: UInt::try_from(entry.created_ts).unwrap_or(UInt::MAX),
49 filesystem_id: None,
50 url_cache: None,
51 last_access_ts: None,
52 quarantined_by: None,
53 authenticated: None,
54 safe_from_quarantine: local.then_some(false),
55 sha256: None,
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use ruma::{UInt, server_name, user_id};
62
63 use super::{UserMediaEntry, into_media_info};
64
65 fn entry(
66 user: bool,
67 media_type: Option<&str>,
68 upload_name: Option<&str>,
69 media_length: Option<u64>,
70 created_ts: u64,
71 ) -> UserMediaEntry {
72 UserMediaEntry {
73 mxc: "mxc://example.org/abc123".into(),
74 media_type: media_type.map(ToOwned::to_owned),
75 upload_name: upload_name.map(ToOwned::to_owned),
76 media_length,
77 created_ts,
78 user_id: user.then(|| user_id!("@alice:example.org").to_owned()),
79 }
80 }
81
82 #[test]
83 fn local_media_fills_uploader_and_constants() {
84 let info = into_media_info(
85 true,
86 server_name!("example.org"),
87 entry(true, Some("image/png"), Some("pic.png"), Some(1024), 1_600_000_000_000),
88 );
89
90 assert_eq!(info.media_origin, None);
91 assert_eq!(info.user_id, Some(user_id!("@alice:example.org").to_owned()));
92 assert_eq!(info.media_id, "abc123");
93 assert_eq!(info.media_type, "image/png");
94 assert_eq!(info.media_length, Some(UInt::from(1024_u32)));
95 assert_eq!(info.upload_name.as_deref(), Some("pic.png"));
96 assert_eq!(info.created_ts, UInt::try_from(1_600_000_000_000_u64).unwrap());
97 assert_eq!(info.safe_from_quarantine, Some(false));
98 assert_eq!(info.filesystem_id, None);
99 assert_eq!(info.url_cache, None);
100 assert_eq!(info.last_access_ts, None);
101 assert_eq!(info.quarantined_by, None);
102 assert_eq!(info.authenticated, None);
103 assert_eq!(info.sha256, None);
104 }
105
106 #[test]
107 fn remote_media_sets_origin_and_drops_uploader() {
108 let info = into_media_info(
109 false,
110 server_name!("remote.example.com"),
111 entry(true, Some("image/png"), Some("pic.png"), Some(1024), 1_600_000_000_000),
112 );
113
114 assert_eq!(info.media_origin, Some(server_name!("remote.example.com").to_owned()));
115 assert_eq!(info.user_id, None);
116 assert_eq!(info.safe_from_quarantine, None);
117 }
118
119 #[test]
120 fn absent_derivables_stay_null() {
121 let info =
122 into_media_info(true, server_name!("example.org"), entry(false, None, None, None, 0));
123
124 assert_eq!(info.media_type, "");
125 assert_eq!(info.media_length, None);
126 assert_eq!(info.upload_name, None);
127 assert_eq!(info.user_id, None);
128 assert_eq!(info.created_ts, UInt::from(0_u32));
129 }
130
131 #[test]
132 fn oversized_lengths_saturate() {
133 let info = into_media_info(
134 true,
135 server_name!("example.org"),
136 entry(true, Some("image/png"), Some("pic.png"), Some(u64::MAX), u64::MAX),
137 );
138
139 assert_eq!(info.media_length, None);
140 assert_eq!(info.created_ts, UInt::MAX);
141 }
142}