pinakes-server: validate GPS coordinate bounds; validate saved search fields and sort_order
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: Idca86117aeeff4afd489ee00bb5c70a36a6a6964
This commit is contained in:
parent
18fda530f2
commit
61eb2335d3
4 changed files with 51 additions and 0 deletions
|
|
@ -152,6 +152,14 @@ pub async fn get_map_photos(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Query(query): Query<MapQuery>,
|
Query(query): Query<MapQuery>,
|
||||||
) -> Result<impl IntoResponse, ApiError> {
|
) -> Result<impl IntoResponse, ApiError> {
|
||||||
|
let valid_lat = |v: f64| v.is_finite() && (-90.0..=90.0).contains(&v);
|
||||||
|
let valid_lon = |v: f64| v.is_finite() && (-180.0..=180.0).contains(&v);
|
||||||
|
if !valid_lat(query.lat1) || !valid_lat(query.lat2) {
|
||||||
|
return Err(ApiError::bad_request("latitude must be in [-90, 90]"));
|
||||||
|
}
|
||||||
|
if !valid_lon(query.lon1) || !valid_lon(query.lon2) {
|
||||||
|
return Err(ApiError::bad_request("longitude must be in [-180, 180]"));
|
||||||
|
}
|
||||||
// Validate bounding box
|
// Validate bounding box
|
||||||
let min_lat = query.lat1.min(query.lat2);
|
let min_lat = query.lat1.min(query.lat2);
|
||||||
let max_lat = query.lat1.max(query.lat2);
|
let max_lat = query.lat1.max(query.lat2);
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,43 @@ pub struct SavedSearchResponse {
|
||||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VALID_SORT_ORDERS: &[&str] = &[
|
||||||
|
"date_asc",
|
||||||
|
"date_desc",
|
||||||
|
"name_asc",
|
||||||
|
"name_desc",
|
||||||
|
"size_asc",
|
||||||
|
"size_desc",
|
||||||
|
];
|
||||||
|
|
||||||
pub async fn create_saved_search(
|
pub async fn create_saved_search(
|
||||||
State(state): State<AppState>,
|
State(state): State<AppState>,
|
||||||
Json(req): Json<CreateSavedSearchRequest>,
|
Json(req): Json<CreateSavedSearchRequest>,
|
||||||
) -> Result<Json<SavedSearchResponse>, ApiError> {
|
) -> Result<Json<SavedSearchResponse>, ApiError> {
|
||||||
|
let name_len = req.name.chars().count();
|
||||||
|
if name_len == 0 || name_len > 255 {
|
||||||
|
return Err(ApiError(
|
||||||
|
pinakes_core::error::PinakesError::InvalidOperation(
|
||||||
|
"name must be 1-255 characters".into(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if req.query.is_empty() || req.query.len() > 2048 {
|
||||||
|
return Err(ApiError(
|
||||||
|
pinakes_core::error::PinakesError::InvalidOperation(
|
||||||
|
"query must be 1-2048 bytes".into(),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if let Some(ref sort) = req.sort_order
|
||||||
|
&& !VALID_SORT_ORDERS.contains(&sort.as_str()) {
|
||||||
|
return Err(ApiError(
|
||||||
|
pinakes_core::error::PinakesError::InvalidOperation(format!(
|
||||||
|
"sort_order must be one of: {}",
|
||||||
|
VALID_SORT_ORDERS.join(", ")
|
||||||
|
)),
|
||||||
|
));
|
||||||
|
}
|
||||||
let id = uuid::Uuid::now_v7();
|
let id = uuid::Uuid::now_v7();
|
||||||
state
|
state
|
||||||
.storage
|
.storage
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,13 @@ pub async fn add_subtitle(
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if req
|
||||||
|
.language
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|l| l.is_empty() || l.len() > 64)
|
||||||
|
{
|
||||||
|
return Err(ApiError::bad_request("language must be 1-64 bytes"));
|
||||||
|
}
|
||||||
let subtitle = Subtitle {
|
let subtitle = Subtitle {
|
||||||
id: Uuid::now_v7(),
|
id: Uuid::now_v7(),
|
||||||
media_id: MediaId(id),
|
media_id: MediaId(id),
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@ pub async fn start_transcode(
|
||||||
Path(id): Path<Uuid>,
|
Path(id): Path<Uuid>,
|
||||||
Json(req): Json<CreateTranscodeRequest>,
|
Json(req): Json<CreateTranscodeRequest>,
|
||||||
) -> Result<Json<serde_json::Value>, ApiError> {
|
) -> Result<Json<serde_json::Value>, ApiError> {
|
||||||
|
if req.profile.is_empty() || req.profile.len() > 255 {
|
||||||
|
return Err(ApiError::bad_request("profile must be 1-255 bytes"));
|
||||||
|
}
|
||||||
let job_id = state
|
let job_id = state
|
||||||
.job_queue
|
.job_queue
|
||||||
.submit(pinakes_core::jobs::JobKind::Transcode {
|
.submit(pinakes_core::jobs::JobKind::Transcode {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue