@@ -159,7 +159,11 @@ impl Service {
|
||||
|
||||
/// Downloads a file.
|
||||
pub async fn get(&self, mxc: &Mxc<'_>) -> Result<Option<FileMeta>> {
|
||||
match self.db.search_file_metadata(mxc, &Dim::default()).await {
|
||||
match self
|
||||
.db
|
||||
.search_file_metadata(mxc, &Dim::default())
|
||||
.await
|
||||
{
|
||||
| Ok(Metadata { content_disposition, content_type, key }) => {
|
||||
let mut content = Vec::with_capacity(8192);
|
||||
let path = self.get_media_file(&key);
|
||||
|
||||
@@ -82,7 +82,10 @@ async fn request_url_preview(&self, url: &Url) -> Result<UrlPreviewData> {
|
||||
}
|
||||
}
|
||||
|
||||
let Some(content_type) = response.headers().get(reqwest::header::CONTENT_TYPE) else {
|
||||
let Some(content_type) = response
|
||||
.headers()
|
||||
.get(reqwest::header::CONTENT_TYPE)
|
||||
else {
|
||||
return Err!(Request(Unknown("Unknown or invalid Content-Type header")));
|
||||
};
|
||||
|
||||
@@ -108,14 +111,21 @@ pub async fn download_image(&self, url: &str) -> Result<UrlPreviewData> {
|
||||
use ruma::Mxc;
|
||||
use tuwunel_core::utils::random_string;
|
||||
|
||||
let image = self.services.client.url_preview.get(url).send().await?;
|
||||
let image = self
|
||||
.services
|
||||
.client
|
||||
.url_preview
|
||||
.get(url)
|
||||
.send()
|
||||
.await?;
|
||||
let image = image.bytes().await?;
|
||||
let mxc = Mxc {
|
||||
server_name: self.services.globals.server_name(),
|
||||
media_id: &random_string(super::MXC_LENGTH),
|
||||
};
|
||||
|
||||
self.create(&mxc, None, None, None, &image).await?;
|
||||
self.create(&mxc, None, None, None, &image)
|
||||
.await?;
|
||||
|
||||
let cursor = std::io::Cursor::new(&image);
|
||||
let (width, height) = match ImageReader::new(cursor).with_guessed_format() {
|
||||
@@ -152,13 +162,20 @@ async fn download_html(&self, url: &str) -> Result<UrlPreviewData> {
|
||||
let mut bytes: Vec<u8> = Vec::new();
|
||||
while let Some(chunk) = response.chunk().await? {
|
||||
bytes.extend_from_slice(&chunk);
|
||||
if bytes.len() > self.services.globals.url_preview_max_spider_size() {
|
||||
if bytes.len()
|
||||
> self
|
||||
.services
|
||||
.globals
|
||||
.url_preview_max_spider_size()
|
||||
{
|
||||
debug!(
|
||||
"Response body from URL {} exceeds url_preview_max_spider_size ({}), not \
|
||||
processing the rest of the response body and assuming our necessary data is in \
|
||||
this range.",
|
||||
url,
|
||||
self.services.globals.url_preview_max_spider_size()
|
||||
self.services
|
||||
.globals
|
||||
.url_preview_max_spider_size()
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -177,7 +194,10 @@ async fn download_html(&self, url: &str) -> Result<UrlPreviewData> {
|
||||
|
||||
/* use OpenGraph title/description, but fall back to HTML if not available */
|
||||
data.title = props.get("title").cloned().or(html.title);
|
||||
data.description = props.get("description").cloned().or(html.description);
|
||||
data.description = props
|
||||
.get("description")
|
||||
.cloned()
|
||||
.or(html.description);
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
@@ -214,8 +234,14 @@ pub fn url_preview_allowed(&self, url: &Url) -> bool {
|
||||
.services
|
||||
.globals
|
||||
.url_preview_domain_explicit_allowlist();
|
||||
let denylist_domain_explicit = self.services.globals.url_preview_domain_explicit_denylist();
|
||||
let allowlist_url_contains = self.services.globals.url_preview_url_contains_allowlist();
|
||||
let denylist_domain_explicit = self
|
||||
.services
|
||||
.globals
|
||||
.url_preview_domain_explicit_denylist();
|
||||
let allowlist_url_contains = self
|
||||
.services
|
||||
.globals
|
||||
.url_preview_url_contains_allowlist();
|
||||
|
||||
if allowlist_domain_contains.contains(&"*".to_owned())
|
||||
|| allowlist_domain_explicit.contains(&"*".to_owned())
|
||||
@@ -262,7 +288,11 @@ pub fn url_preview_allowed(&self, url: &Url) -> bool {
|
||||
}
|
||||
|
||||
// check root domain if available and if user has root domain checks
|
||||
if self.services.globals.url_preview_check_root_domain() {
|
||||
if self
|
||||
.services
|
||||
.globals
|
||||
.url_preview_check_root_domain()
|
||||
{
|
||||
debug!("Checking root domain");
|
||||
match host.split_once('.') {
|
||||
| None => return false,
|
||||
|
||||
@@ -87,11 +87,14 @@ async fn fetch_thumbnail_authenticated(
|
||||
timeout_ms,
|
||||
};
|
||||
|
||||
let Response { content, .. } = self.federation_request(mxc, user, server, request).await?;
|
||||
let Response { content, .. } = self
|
||||
.federation_request(mxc, user, server, request)
|
||||
.await?;
|
||||
|
||||
match content {
|
||||
| FileOrLocation::File(content) =>
|
||||
self.handle_thumbnail_file(mxc, user, dim, content).await,
|
||||
self.handle_thumbnail_file(mxc, user, dim, content)
|
||||
.await,
|
||||
| FileOrLocation::Location(location) => self.handle_location(mxc, user, &location).await,
|
||||
}
|
||||
}
|
||||
@@ -111,7 +114,9 @@ async fn fetch_content_authenticated(
|
||||
timeout_ms,
|
||||
};
|
||||
|
||||
let Response { content, .. } = self.federation_request(mxc, user, server, request).await?;
|
||||
let Response { content, .. } = self
|
||||
.federation_request(mxc, user, server, request)
|
||||
.await?;
|
||||
|
||||
match content {
|
||||
| FileOrLocation::File(content) => self.handle_content_file(mxc, user, content).await,
|
||||
@@ -145,11 +150,14 @@ async fn fetch_thumbnail_unauthenticated(
|
||||
|
||||
let Response {
|
||||
file, content_type, content_disposition, ..
|
||||
} = self.federation_request(mxc, user, server, request).await?;
|
||||
} = self
|
||||
.federation_request(mxc, user, server, request)
|
||||
.await?;
|
||||
|
||||
let content = Content { file, content_type, content_disposition };
|
||||
|
||||
self.handle_thumbnail_file(mxc, user, dim, content).await
|
||||
self.handle_thumbnail_file(mxc, user, dim, content)
|
||||
.await
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
@@ -173,7 +181,9 @@ async fn fetch_content_unauthenticated(
|
||||
|
||||
let Response {
|
||||
file, content_type, content_disposition, ..
|
||||
} = self.federation_request(mxc, user, server, request).await?;
|
||||
} = self
|
||||
.federation_request(mxc, user, server, request)
|
||||
.await?;
|
||||
|
||||
let content = Content { file, content_type, content_disposition };
|
||||
|
||||
@@ -245,11 +255,13 @@ async fn handle_location(
|
||||
user: Option<&UserId>,
|
||||
location: &str,
|
||||
) -> Result<FileMeta> {
|
||||
self.location_request(location).await.map_err(|error| {
|
||||
err!(Request(NotFound(
|
||||
debug_warn!(%mxc, ?user, ?location, ?error, "Fetching media from location failed")
|
||||
)))
|
||||
})
|
||||
self.location_request(location)
|
||||
.await
|
||||
.map_err(|error| {
|
||||
err!(Request(NotFound(
|
||||
debug_warn!(%mxc, ?user, ?location, ?error, "Fetching media from location failed")
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
#[implement(super::Service)]
|
||||
|
||||
@@ -67,8 +67,14 @@ impl super::Service {
|
||||
|
||||
match self.db.search_file_metadata(mxc, &dim).await {
|
||||
| Ok(metadata) => self.get_thumbnail_saved(metadata).await,
|
||||
| _ => match self.db.search_file_metadata(mxc, &Dim::default()).await {
|
||||
| Ok(metadata) => self.get_thumbnail_generate(mxc, &dim, metadata).await,
|
||||
| _ => match self
|
||||
.db
|
||||
.search_file_metadata(mxc, &Dim::default())
|
||||
.await
|
||||
{
|
||||
| Ok(metadata) =>
|
||||
self.get_thumbnail_generate(mxc, &dim, metadata)
|
||||
.await,
|
||||
| _ => Ok(None),
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user