mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-08-31 02:22:29 +00:00
feat: moderation API for pulling reported images. (#880)
Signed-off-by: IAmTomahawkx <iamtomahawkx@gmail.com> Release-As: 0.15.1
This commit is contained in:
@@ -70,6 +70,8 @@ trust_cloudflare = false
|
|||||||
easypwned = ""
|
easypwned = ""
|
||||||
# Tenor API Key
|
# Tenor API Key
|
||||||
tenor_key = ""
|
tenor_key = ""
|
||||||
|
# Admin keys for future admin api and for bonfire reported image fetching
|
||||||
|
admin_keys = []
|
||||||
|
|
||||||
[api.security.captcha]
|
[api.security.captcha]
|
||||||
# hCaptcha configuration
|
# hCaptcha configuration
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ pub struct ApiSecurity {
|
|||||||
pub trust_cloudflare: bool,
|
pub trust_cloudflare: bool,
|
||||||
pub easypwned: String,
|
pub easypwned: String,
|
||||||
pub tenor_key: String,
|
pub tenor_key: String,
|
||||||
|
pub admin_keys: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use std::{
|
|||||||
|
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{DefaultBodyLimit, Path, State},
|
extract::{DefaultBodyLimit, Path, State},
|
||||||
http::{header, Method},
|
http::{header, HeaderMap, Method},
|
||||||
response::{IntoResponse, Redirect, Response},
|
response::{IntoResponse, Redirect, Response},
|
||||||
routing::{get, post},
|
routing::{get, post},
|
||||||
Json, Router,
|
Json, Router,
|
||||||
@@ -58,6 +58,7 @@ pub async fn router() -> Router<AppState> {
|
|||||||
)
|
)
|
||||||
.route("/:tag/:file_id", get(fetch_preview))
|
.route("/:tag/:file_id", get(fetch_preview))
|
||||||
.route("/:tag/:file_id/:file_name", get(fetch_file))
|
.route("/:tag/:file_id/:file_name", get(fetch_file))
|
||||||
|
.route("/mod/:tag/:file_id/:file_name", get(fetch_file_mod))
|
||||||
.layer(cors)
|
.layer(cors)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,3 +504,67 @@ async fn fetch_file(
|
|||||||
.into_response()
|
.into_response()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fetch original file (Moderation)
|
||||||
|
///
|
||||||
|
/// This is intentionally left out of the OpenApi docs.
|
||||||
|
/// It uses the config key api.security.admin_keys to determine access. This is intended for server to server communication.
|
||||||
|
async fn fetch_file_mod(
|
||||||
|
State(db): State<Database>,
|
||||||
|
headers: HeaderMap,
|
||||||
|
Path((tag, file_id, file_name)): Path<(Tag, String, String)>,
|
||||||
|
) -> Result<Response> {
|
||||||
|
let config = revolt_config::config().await;
|
||||||
|
|
||||||
|
let token = headers
|
||||||
|
.get("X-Admin-Token")
|
||||||
|
.and_then(|value| value.to_str().ok())
|
||||||
|
.ok_or_else(|| create_error!(NotAuthenticated))?;
|
||||||
|
|
||||||
|
if !config
|
||||||
|
.api
|
||||||
|
.security
|
||||||
|
.admin_keys
|
||||||
|
.iter()
|
||||||
|
.any(|tok| tok == token)
|
||||||
|
{
|
||||||
|
return Err(create_error!(NotAuthenticated));
|
||||||
|
}
|
||||||
|
|
||||||
|
let tag: &'static str = tag.clone().into();
|
||||||
|
let file = db.fetch_attachment(tag, &file_id).await?;
|
||||||
|
|
||||||
|
// Ignore files that haven't been attached
|
||||||
|
if file.used_for.is_none() {
|
||||||
|
return Err(create_error!(NotFound));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure filename is correct
|
||||||
|
if file_name != file.filename {
|
||||||
|
if file_name == "original" {
|
||||||
|
let safe_filename = encode_component(&file.filename);
|
||||||
|
|
||||||
|
return Ok(
|
||||||
|
Redirect::permanent(&format!("/{tag}/{file_id}/{}", safe_filename)).into_response(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(create_error!(NotFound));
|
||||||
|
}
|
||||||
|
|
||||||
|
let hash = file.as_hash(&db).await?;
|
||||||
|
retrieve_file_by_hash(&hash).await.map(|data| {
|
||||||
|
(
|
||||||
|
[
|
||||||
|
(header::CONTENT_TYPE, hash.content_type),
|
||||||
|
(header::CONTENT_DISPOSITION, "attachment".to_owned()),
|
||||||
|
(
|
||||||
|
header::CACHE_CONTROL,
|
||||||
|
"private, max-age=300, must-revalidate".to_owned(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
data,
|
||||||
|
)
|
||||||
|
.into_response()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user