1
0
Fork 0
mirror of https://github.com/mat-1/metasearch2.git synced 2025-08-02 15:26:04 +00:00

csrf and xss fix

thanks @JorianWoltjer <3
This commit is contained in:
mat 2025-07-07 06:25:04 +09:00
parent 7a3e5f04bc
commit ad1fb8a9af
2 changed files with 35 additions and 11 deletions

View file

@ -6,6 +6,7 @@ use axum::{
response::{IntoResponse, Response},
Extension,
};
use reqwest::header;
use tracing::error;
use crate::{config::Config, engines};
@ -42,6 +43,9 @@ pub async fn route(
if res.content_length().unwrap_or_default() > max_size {
return (StatusCode::PAYLOAD_TOO_LARGE, "Image too large").into_response();
}
const ALLOWED_IMAGE_TYPES: &[&str] = &["apng", "avif", "gif", "jpeg", "png", "webp"];
// validate content-type
let content_type = res
.headers()
@ -49,8 +53,15 @@ pub async fn route(
.and_then(|v| v.to_str().ok())
.unwrap_or_default()
.to_string();
if !content_type.starts_with("image/") {
return (StatusCode::BAD_REQUEST, "Not an image").into_response();
let Some((base_type, subtype)) = content_type.split_once("/") else {
return (StatusCode::UNSUPPORTED_MEDIA_TYPE, "Invalid Content-Type").into_response();
};
if base_type != "image" {
return (StatusCode::UNSUPPORTED_MEDIA_TYPE, "Not an image").into_response();
}
if !ALLOWED_IMAGE_TYPES.contains(&subtype) {
return (StatusCode::UNSUPPORTED_MEDIA_TYPE, "Image type not allowed").into_response();
}
let mut image_bytes = Vec::new();
@ -63,11 +74,10 @@ pub async fn route(
(
[
(axum::http::header::CONTENT_TYPE, content_type),
(
axum::http::header::CACHE_CONTROL,
"public, max-age=31536000".to_owned(),
),
(header::CONTENT_TYPE, content_type),
(header::CACHE_CONTROL, "public, max-age=31536000".to_owned()),
(header::X_CONTENT_TYPE_OPTIONS, "nosniff".to_owned()),
(header::CONTENT_DISPOSITION, "attachment".to_owned()),
],
image_bytes,
)

View file

@ -1,6 +1,6 @@
use axum::{
http::{header, StatusCode},
response::IntoResponse,
http::{header, HeaderMap, StatusCode},
response::{IntoResponse, Response},
Extension, Form,
};
use axum_extra::extract::{cookie::Cookie, CookieJar};
@ -69,10 +69,24 @@ pub struct Settings {
pub stylesheet_str: String,
}
pub async fn post(mut jar: CookieJar, Form(settings): Form<Settings>) -> impl IntoResponse {
pub async fn post(
headers: HeaderMap,
mut jar: CookieJar,
Form(settings): Form<Settings>,
) -> Response {
let Some(origin) = headers.get("origin").and_then(|h| h.to_str().ok()) else {
return (StatusCode::BAD_REQUEST, "Missing or invalid Origin header").into_response();
};
let Some(host) = headers.get("host").and_then(|h| h.to_str().ok()) else {
return (StatusCode::BAD_REQUEST, "Missing or invalid Host header").into_response();
};
if origin != format!("http://{host}") && origin != format!("https://{host}") {
return (StatusCode::BAD_REQUEST, "Origin does not match Host").into_response();
}
let mut settings_cookie = Cookie::new("settings", serde_json::to_string(&settings).unwrap());
settings_cookie.make_permanent();
jar = jar.add(settings_cookie);
(StatusCode::FOUND, [(header::LOCATION, "/settings")], jar)
(StatusCode::FOUND, [(header::LOCATION, "/settings")], jar).into_response()
}