Implement a slick little safe redirecting middleware for ?return=/

This will help all APIs behave identically for UI-requested redirects
This commit is contained in:
R Tyler Croy 2021-07-05 13:25:52 -07:00
parent 57805bdb01
commit 4edfdecbb7
No known key found for this signature in database
GPG Key ID: E5C92681BEF6CEA2
1 changed files with 36 additions and 10 deletions

View File

@ -4,7 +4,9 @@
use crate::state::*;
use log::*;
use serde::Deserialize;
use tide::{Request, Server};
use std::future::Future;
use std::pin::Pin;
use tide::{Next, Request, Server};
#[derive(Clone, Debug, Deserialize)]
struct ApiParams {
@ -12,22 +14,46 @@ struct ApiParams {
redirect: Option<String>,
}
/**
* The handle_redirects middleware will intercept the `?return=/` query string parameter and ensure
* that the API performs the expected redirect upon the completion of the route.
*
* In the cases where somebody attempts to shove a URL into that `return` parameter, it will be
* ignored and no redirect will be offered
*/
fn handle_redirects<'a>(
request: Request<AppState<'static>>,
next: Next<'a, AppState<'static>>,
) -> Pin<Box<dyn Future<Output = tide::Result> + Send + 'a>> {
Box::pin(async {
trace!("Running handle_redirects middleware");
let qs: ApiParams = request.query()?;
let res = Ok(next.run(request).await);
trace!("handle_redirects: returned to middleware");
if let Some(redirect) = &qs.redirect {
debug!("Redirecting back to {}", redirect);
if redirect.starts_with("/") {
return Ok(tide::Redirect::new(&redirect).into());
}
warn!("Refusign to redirect to a URL: {:?}", redirect);
}
res
})
}
pub fn register(app: &mut Server<AppState<'static>>) {
let mut api = tide::with_state(app.state().clone());
api.at("project/:slug/run").get(run_project);
api.with(handle_redirects);
app.at("/api").nest(api);
}
async fn run_project(req: Request<AppState<'static>>) -> tide::Result {
debug!("Running project: {:?}", req.param("slug"));
let qs: ApiParams = req.query()?;
if let Some(redirect) = &qs.redirect {
info!("Redirecting back to {}", redirect);
if !redirect.starts_with("/") {
warn!("Unsafe redirect, ignoring: {:?}", redirect);
}
return Ok(tide::Redirect::new(&redirect).into());
}
Ok("Run".into())
}