From 4edfdecbb737af3c8ee17fa7f642db6676d68546 Mon Sep 17 00:00:00 2001 From: "R. Tyler Croy" Date: Mon, 5 Jul 2021 13:25:52 -0700 Subject: [PATCH] Implement a slick little safe redirecting middleware for ?return=/ This will help all APIs behave identically for UI-requested redirects --- src/routes/api.rs | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/routes/api.rs b/src/routes/api.rs index 96b8322..93f0bdc 100644 --- a/src/routes/api.rs +++ b/src/routes/api.rs @@ -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, } +/** + * 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>, + next: Next<'a, AppState<'static>>, +) -> Pin + 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>) { 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>) -> 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()) }