feat: deny non hx-requests on fragment
This commit is contained in:
parent
1da83c0016
commit
31e2cab280
2 changed files with 57 additions and 7 deletions
|
@ -4,9 +4,14 @@ use axum::{
|
|||
routing::get,
|
||||
Router,
|
||||
};
|
||||
use axum_extra::TypedHeader;
|
||||
use reqwest::StatusCode;
|
||||
|
||||
use crate::{templates::DownloadLinkTemplate, AppState, AsyncRemoveRecord};
|
||||
use crate::{
|
||||
templates::{self, DownloadLinkTemplate},
|
||||
util::headers::HxRequest,
|
||||
AppState, AsyncRemoveRecord,
|
||||
};
|
||||
|
||||
pub fn get_link_router() -> Router<AppState> {
|
||||
// Link pages
|
||||
|
@ -62,12 +67,22 @@ async fn link_delete(
|
|||
|
||||
async fn remaining(
|
||||
State(state): State<AppState>,
|
||||
hx_request: Option<TypedHeader<HxRequest>>,
|
||||
axum::extract::Path(id): axum::extract::Path<String>,
|
||||
) -> impl IntoResponse {
|
||||
let records = state.records.lock().await;
|
||||
if let Some(record) = records.get(&id) {
|
||||
Html(crate::templates::get_downloads_remaining_text(record))
|
||||
} else {
|
||||
Html("?".to_string())
|
||||
) -> Result<impl IntoResponse, (StatusCode, String)> {
|
||||
if hx_request.is_none() {
|
||||
return Err((
|
||||
StatusCode::BAD_REQUEST,
|
||||
"Attempt to fetch html fragment from non-htmx request".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let records = state.records.lock().await;
|
||||
|
||||
Ok(Html(
|
||||
records
|
||||
.get(&id)
|
||||
.map(templates::get_downloads_remaining_text)
|
||||
.unwrap_or_else(|| "?".to_string()),
|
||||
))
|
||||
}
|
||||
|
|
|
@ -31,3 +31,38 @@ impl Header for ForwardedFor {
|
|||
values.extend(std::iter::once(HeaderValue::from_str(&self.0).unwrap()));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HxRequest;
|
||||
|
||||
pub static HXR_TEXT: &str = "hx-request";
|
||||
|
||||
pub static HXR_NAME: HeaderName = HeaderName::from_static(HXR_TEXT);
|
||||
|
||||
impl Header for HxRequest {
|
||||
fn name() -> &'static HeaderName {
|
||||
&FF_NAME
|
||||
}
|
||||
|
||||
fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
|
||||
where
|
||||
Self: Sized,
|
||||
I: Iterator<Item = &'i headers::HeaderValue>,
|
||||
{
|
||||
let value = values
|
||||
.next()
|
||||
.ok_or_else(headers::Error::invalid)?
|
||||
.to_str()
|
||||
.map_err(|_| headers::Error::invalid())?
|
||||
.to_owned();
|
||||
|
||||
match &value[..] {
|
||||
"true" => Ok(HxRequest),
|
||||
_ => Err(headers::Error::invalid()),
|
||||
}
|
||||
}
|
||||
|
||||
fn encode<E: Extend<headers::HeaderValue>>(&self, values: &mut E) {
|
||||
values.extend(std::iter::once(HeaderValue::from_static("true")));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue