fix(media): use csp instead of modifying content-type
This commit is contained in:
parent
7b19618136
commit
1dbb3433e0
2 changed files with 24 additions and 24 deletions
|
@ -22,14 +22,6 @@ pub async fn get_media_config_route(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sanitize_content_type(content_type: String) -> String {
|
|
||||||
if content_type == "image/jpeg" || content_type == "image/png" {
|
|
||||||
content_type
|
|
||||||
} else {
|
|
||||||
"application/octet-stream".to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # `POST /_matrix/media/r0/upload`
|
/// # `POST /_matrix/media/r0/upload`
|
||||||
///
|
///
|
||||||
/// Permanently save media in the server.
|
/// Permanently save media in the server.
|
||||||
|
@ -108,13 +100,13 @@ pub async fn get_content_route(
|
||||||
|
|
||||||
if let Some(FileMeta {
|
if let Some(FileMeta {
|
||||||
content_disposition,
|
content_disposition,
|
||||||
|
content_type,
|
||||||
file,
|
file,
|
||||||
..
|
|
||||||
}) = services().media.get(mxc.clone()).await?
|
}) = services().media.get(mxc.clone()).await?
|
||||||
{
|
{
|
||||||
Ok(get_content::v3::Response {
|
Ok(get_content::v3::Response {
|
||||||
file,
|
file,
|
||||||
content_type: Some("application/octet-stream".to_owned()),
|
content_type,
|
||||||
content_disposition,
|
content_disposition,
|
||||||
cross_origin_resource_policy: Some("cross-origin".to_owned()),
|
cross_origin_resource_policy: Some("cross-origin".to_owned()),
|
||||||
})
|
})
|
||||||
|
@ -124,7 +116,7 @@ pub async fn get_content_route(
|
||||||
|
|
||||||
Ok(get_content::v3::Response {
|
Ok(get_content::v3::Response {
|
||||||
content_disposition: remote_content_response.content_disposition,
|
content_disposition: remote_content_response.content_disposition,
|
||||||
content_type: Some("application/octet-stream".to_owned()),
|
content_type: remote_content_response.content_type,
|
||||||
file: remote_content_response.file,
|
file: remote_content_response.file,
|
||||||
cross_origin_resource_policy: Some("cross-origin".to_owned()),
|
cross_origin_resource_policy: Some("cross-origin".to_owned()),
|
||||||
})
|
})
|
||||||
|
@ -143,10 +135,13 @@ pub async fn get_content_as_filename_route(
|
||||||
) -> Result<get_content_as_filename::v3::Response> {
|
) -> Result<get_content_as_filename::v3::Response> {
|
||||||
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
|
let mxc = format!("mxc://{}/{}", body.server_name, body.media_id);
|
||||||
|
|
||||||
if let Some(FileMeta { file, .. }) = services().media.get(mxc.clone()).await? {
|
if let Some(FileMeta {
|
||||||
|
file, content_type, ..
|
||||||
|
}) = services().media.get(mxc.clone()).await?
|
||||||
|
{
|
||||||
Ok(get_content_as_filename::v3::Response {
|
Ok(get_content_as_filename::v3::Response {
|
||||||
file,
|
file,
|
||||||
content_type: Some("application/octet-stream".to_owned()),
|
content_type,
|
||||||
content_disposition: Some(format!("inline; filename={}", body.filename)),
|
content_disposition: Some(format!("inline; filename={}", body.filename)),
|
||||||
cross_origin_resource_policy: Some("cross-origin".to_owned()),
|
cross_origin_resource_policy: Some("cross-origin".to_owned()),
|
||||||
})
|
})
|
||||||
|
@ -156,7 +151,7 @@ pub async fn get_content_as_filename_route(
|
||||||
|
|
||||||
Ok(get_content_as_filename::v3::Response {
|
Ok(get_content_as_filename::v3::Response {
|
||||||
content_disposition: Some(format!("inline: filename={}", body.filename)),
|
content_disposition: Some(format!("inline: filename={}", body.filename)),
|
||||||
content_type: Some("application/octet-stream".to_owned()),
|
content_type: remote_content_response.content_type,
|
||||||
file: remote_content_response.file,
|
file: remote_content_response.file,
|
||||||
cross_origin_resource_policy: Some("cross-origin".to_owned()),
|
cross_origin_resource_policy: Some("cross-origin".to_owned()),
|
||||||
})
|
})
|
||||||
|
@ -192,11 +187,11 @@ pub async fn get_content_thumbnail_route(
|
||||||
{
|
{
|
||||||
Ok(get_content_thumbnail::v3::Response {
|
Ok(get_content_thumbnail::v3::Response {
|
||||||
file,
|
file,
|
||||||
content_type: content_type.map(sanitize_content_type),
|
content_type,
|
||||||
cross_origin_resource_policy: Some("cross-origin".to_owned()),
|
cross_origin_resource_policy: Some("cross-origin".to_owned()),
|
||||||
})
|
})
|
||||||
} else if &*body.server_name != services().globals.server_name() && body.allow_remote {
|
} else if &*body.server_name != services().globals.server_name() && body.allow_remote {
|
||||||
let mut get_thumbnail_response = services()
|
let get_thumbnail_response = services()
|
||||||
.sending
|
.sending
|
||||||
.send_federation_request(
|
.send_federation_request(
|
||||||
&body.server_name,
|
&body.server_name,
|
||||||
|
@ -225,10 +220,6 @@ pub async fn get_content_thumbnail_route(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
get_thumbnail_response.content_type = get_thumbnail_response
|
|
||||||
.content_type
|
|
||||||
.map(sanitize_content_type);
|
|
||||||
|
|
||||||
Ok(get_thumbnail_response)
|
Ok(get_thumbnail_response)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::BadRequest(ErrorKind::NotFound, "Media not found."))
|
Err(Error::BadRequest(ErrorKind::NotFound, "Media not found."))
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -2,7 +2,8 @@ use std::{future::Future, io, net::SocketAddr, sync::atomic, time::Duration};
|
||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{DefaultBodyLimit, FromRequestParts, MatchedPath},
|
extract::{DefaultBodyLimit, FromRequestParts, MatchedPath},
|
||||||
response::IntoResponse,
|
middleware::map_response,
|
||||||
|
response::{IntoResponse, Response},
|
||||||
routing::{any, get, on, MethodFilter},
|
routing::{any, get, on, MethodFilter},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
|
@ -13,7 +14,7 @@ use figment::{
|
||||||
Figment,
|
Figment,
|
||||||
};
|
};
|
||||||
use http::{
|
use http::{
|
||||||
header::{self, HeaderName},
|
header::{self, HeaderName, CONTENT_SECURITY_POLICY},
|
||||||
Method, StatusCode, Uri,
|
Method, StatusCode, Uri,
|
||||||
};
|
};
|
||||||
use ruma::api::{
|
use ruma::api::{
|
||||||
|
@ -141,6 +142,13 @@ async fn main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds additional headers to prevent any potential XSS attacks via the media repo
|
||||||
|
async fn set_csp_header(response: Response) -> impl IntoResponse {
|
||||||
|
(
|
||||||
|
[(CONTENT_SECURITY_POLICY, "sandbox; default-src 'none'; script-src 'none'; plugin-types application/pdf; style-src 'unsafe-inline'; object-src 'self';")], response
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async fn run_server() -> io::Result<()> {
|
async fn run_server() -> io::Result<()> {
|
||||||
let config = &services().globals.config;
|
let config = &services().globals.config;
|
||||||
let addr = SocketAddr::from((config.address, config.port));
|
let addr = SocketAddr::from((config.address, config.port));
|
||||||
|
@ -181,6 +189,7 @@ async fn run_server() -> io::Result<()> {
|
||||||
])
|
])
|
||||||
.max_age(Duration::from_secs(86400)),
|
.max_age(Duration::from_secs(86400)),
|
||||||
)
|
)
|
||||||
|
.layer(map_response(set_csp_header))
|
||||||
.layer(DefaultBodyLimit::max(
|
.layer(DefaultBodyLimit::max(
|
||||||
config
|
config
|
||||||
.max_request_size
|
.max_request_size
|
||||||
|
@ -219,7 +228,7 @@ async fn run_server() -> io::Result<()> {
|
||||||
async fn spawn_task<B: Send + 'static>(
|
async fn spawn_task<B: Send + 'static>(
|
||||||
req: http::Request<B>,
|
req: http::Request<B>,
|
||||||
next: axum::middleware::Next<B>,
|
next: axum::middleware::Next<B>,
|
||||||
) -> std::result::Result<axum::response::Response, StatusCode> {
|
) -> std::result::Result<Response, StatusCode> {
|
||||||
if services().globals.shutdown.load(atomic::Ordering::Relaxed) {
|
if services().globals.shutdown.load(atomic::Ordering::Relaxed) {
|
||||||
return Err(StatusCode::SERVICE_UNAVAILABLE);
|
return Err(StatusCode::SERVICE_UNAVAILABLE);
|
||||||
}
|
}
|
||||||
|
@ -231,7 +240,7 @@ async fn spawn_task<B: Send + 'static>(
|
||||||
async fn unrecognized_method<B: Send>(
|
async fn unrecognized_method<B: Send>(
|
||||||
req: http::Request<B>,
|
req: http::Request<B>,
|
||||||
next: axum::middleware::Next<B>,
|
next: axum::middleware::Next<B>,
|
||||||
) -> std::result::Result<axum::response::Response, StatusCode> {
|
) -> std::result::Result<Response, StatusCode> {
|
||||||
let method = req.method().clone();
|
let method = req.method().clone();
|
||||||
let uri = req.uri().clone();
|
let uri = req.uri().clone();
|
||||||
let inner = next.run(req).await;
|
let inner = next.run(req).await;
|
||||||
|
|
Loading…
Add table
Reference in a new issue