From 16055300c760c636399f555ce30c07deff2a6820 Mon Sep 17 00:00:00 2001 From: Yves Fischer Date: Mon, 26 Nov 2018 21:01:09 +0100 Subject: Redo response builder usage - Set correct content-type header - Refactor views to use one base-view --- src/request_handler/handler_login.rs | 17 ++-- src/request_handler/mod.rs | 39 +++++--- src/request_handler/views.rs | 179 +++++++++++++++-------------------- 3 files changed, 116 insertions(+), 119 deletions(-) (limited to 'src') diff --git a/src/request_handler/handler_login.rs b/src/request_handler/handler_login.rs index bfa7016..aa93e96 100644 --- a/src/request_handler/handler_login.rs +++ b/src/request_handler/handler_login.rs @@ -14,9 +14,9 @@ use super::*; pub(in super) fn GET<'a>(header_infos: &HeaderExtract, state: &ApplicationState, path_rest: &'a str) -> Response { if is_logged_in(&header_infos.cookies, &state.cookie_store) { - make_response(StatusCode::OK, views::login_is_logged_in()) + Response::builder().set_defaults().body(views::login_is_logged_in()).unwrap() } else { - make_response(StatusCode::OK, views::login_login_form(path_rest)) + Response::builder().set_defaults().body(views::login_login_form(path_rest)).unwrap() } } @@ -51,10 +51,9 @@ pub(in super) fn POST<'a>(header_infos: &HeaderExtract, state: &ApplicationState let redirect = redirect.unwrap_or(Default::default()); if header_infos.totp_secrets.is_empty() { - return error_handler_internal("no secrets configured".to_string()) + return error_handler_internal("no secrets configured".to_string()); } - let mut ret = Response::builder(); if test_secrets(&header_infos.totp_secrets, &token.unwrap()) { let cookie_value = state.cookie_store.create_authenticated_cookie(); let cookie = CookieBuilder::new(COOKIE_NAME, cookie_value.to_string()) @@ -62,10 +61,14 @@ pub(in super) fn POST<'a>(header_infos: &HeaderExtract, state: &ApplicationState .path("/") .max_age(state.cookie_max_age) .finish(); - ret.header(SET_COOKIE, cookie.to_string()); warn!("Authenticated user with cookie {}", cookie); - ret.body(views::login_auth_success(&redirect)).unwrap() + Response::builder() + .set_defaults() + .header(SET_COOKIE, cookie.to_string()) + .body(views::login_auth_success(&redirect)).unwrap() } else { - ret.body(views::login_auth_fail()).unwrap() + Response::builder() + .set_defaults() + .body(views::login_auth_fail()).unwrap() } } \ No newline at end of file diff --git a/src/request_handler/mod.rs b/src/request_handler/mod.rs index 2e92821..72e9142 100644 --- a/src/request_handler/mod.rs +++ b/src/request_handler/mod.rs @@ -12,6 +12,7 @@ use std::cell::RefCell; use time; use http::{Request, Response, StatusCode, Method}; +use http::response::Builder; use tokio::prelude::*; use horrorshow; use cookie::{Cookie, CookieBuilder}; @@ -55,12 +56,24 @@ pub struct RequestHandler { routing_table: router::RoutingTable, } -pub(in request_handler) fn make_response(code: StatusCode, body: String) -> Response { - Response::builder().status(code).body(body).unwrap() +pub trait ResponseBuilderExtra { + fn set_defaults(&mut self) -> &mut Self; +} + +impl ResponseBuilderExtra for Builder { + fn set_defaults(&mut self) -> &mut Self { + self + .status(StatusCode::OK) + .header(::http::header::CONTENT_TYPE, "text/html; charset=utf-8") + .header("X-Frame-Options", "DENY") + } } pub(in request_handler) fn error_handler_internal(body: String) -> Response { - Response::builder().status(StatusCode::INTERNAL_SERVER_ERROR).body(body).unwrap() + Response::builder() + .set_defaults() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(body).unwrap() } impl HttpHandler for RequestHandler { @@ -71,8 +84,8 @@ impl HttpHandler for RequestHandler { Ok((Route::Logout, rest)) => logout(state, &req, rest), Ok((Route::Check, rest)) => check(state, &req, rest), Err(error) => match error { - router::NoMatchingRoute => - make_response(StatusCode::NOT_FOUND, "Resource not found".to_string()), + router::NoMatchingRoute => Response::builder().set_defaults() + .status(StatusCode::NOT_FOUND).body("Resource not found".to_string()).unwrap(), } } } @@ -111,7 +124,8 @@ fn info<'a>(request_handler: &RequestHandler, state: &super::ApplicationState, } else { views::info(path_rest) }; - Response::builder().body(view).unwrap() + Response::builder().set_defaults() + .body(view).unwrap() } fn login<'a>(state: &super::ApplicationState, req: &Request, path_rest: &'a str, @@ -127,15 +141,15 @@ fn login<'a>(state: &super::ApplicationState, req: &Request, path_rest: & } } +// unimplemented fn logout<'a>(state: &super::ApplicationState, req: &Request, path_rest: &'a str, ) -> Response { let header_infos = match parse_header_infos(req) { Ok(infos) => infos, Err(message) => return error_handler_internal(message), }; - - let body = format!("Rest: {}", path_rest); - Response::builder().body(body.to_string()).unwrap() + Response::builder().set_defaults() + .body(format!("Rest: {}", path_rest)).unwrap() } @@ -145,9 +159,12 @@ fn check<'a>(state: &super::ApplicationState, req: &Request, path_rest: & Err(message) => return error_handler_internal(message), }; if is_logged_in(&header_infos.cookies, &state.cookie_store) { - make_response(StatusCode::OK, "".to_string()) + Response::builder().set_defaults() + .body(Default::default()).unwrap() } else { - make_response(StatusCode::UNAUTHORIZED, "Cookie expired".to_string()) + Response::builder().set_defaults() + .status(StatusCode::UNAUTHORIZED) + .body("Cookie expired".to_string()).unwrap() } } diff --git a/src/request_handler/views.rs b/src/request_handler/views.rs index ee020eb..1a239a4 100644 --- a/src/request_handler/views.rs +++ b/src/request_handler/views.rs @@ -1,138 +1,115 @@ -use horrorshow::Template; +use std::boxed::Box; +use horrorshow::{Render, RenderBox, Template}; -pub(in super) fn info_debug<'a>(path_rest: &'a str, cookies: Vec<(String, String)>) -> String { + +fn render_base_template(title: &'static str, page_body: Box) -> String { (html! { : horrorshow::helper::doctype::HTML; html { head { - title: "Hello world!"; + title: title; + meta(name="viewport", content="width=device-width, initial-scale=1.5"); } body { - h1(id = "heading") { - : "Hello! This is "; - : "And path rest is: "; - : path_rest; - : "... ok :)"; - } - h2: "Valid cookies are:"; - table(border="1") { - thead { - th: "Cookie value"; - th: "Valid until"; - } - tbody { - @ for (name, valid_until) in cookies { - tr { - td: name; - td: valid_until; - } - } - } - } + : page_body; } } }).into_string().unwrap() } -pub(in super) fn info<'a>(path_rest: &'a str) -> String { - (html! { - : horrorshow::helper::doctype::HTML; - html { - head { - title: "Hello world!"; +pub(in super) fn info_debug<'a>(path_rest: &'a str, cookies: Vec<(String, String)>) -> String { + let path = path_rest.to_string(); + render_base_template("Info (debug)", box_html! { + h1(id = "heading") { + : "Hello! This is "; + : "And path rest is: "; + : path; + : "... ok :)"; + } + h2: "Valid cookies are:"; + table(border="1") { + thead { + th: "Cookie value"; + th: "Valid until"; } - body { - h1(id = "heading") { - : "Hello! This is "; - : "And path rest is: "; - : path_rest; - : "... ok :)"; + tbody { + @ for (name, valid_until) in cookies { + tr { + td: name; + td: valid_until; + } } } } - }).into_string().unwrap() + }) +} + +pub(in super) fn info<'a>(path_rest: &'a str) -> String { + let path = path_rest.to_string(); + render_base_template("Info", box_html! { + h1(id = "heading") { + : "Hello! This is "; + : "And path rest is: "; + : path; + : "... ok :)"; + } + }) } pub(in super) fn login_is_logged_in() -> String { - (html! { - : horrorshow::helper::doctype::HTML; - html { - head { - title: "TOTP Login"; - } - body { - h1(id = "heading") { - : "Currently logged in" - } - } + render_base_template("Logged in", box_html! { + h1(id = "heading") { + : "Currently logged in" } - }).into_string().unwrap() + }) } pub(in super) fn login_login_form<'a>(redirect: &'a str) -> String { - (html! { - : horrorshow::helper::doctype::HTML; - html { - head { - title: "TOTP Login"; - } - body { - h1(id = "heading") { - : "Login" - } - form(method="POST") { - label(for="token") { + let redirect = redirect.to_string(); + render_base_template("TOTP Login", box_html! { + h1(id = "heading") { + : "Login" + } + form(method="POST") { + div { + label(for="token") { : "Enter TOTP token" - } - input(name="token",id="token",type="text"); - input(name="redirect", type="hidden", value=redirect); - input(name="send",type="submit",value="Submit"); } } + div { + input(name="token",id="token",type="number",autocomplete="off",required=""); + input(name="redirect", type="hidden", value=redirect); + } + div { + input(name="send",type="submit",value="Submit"); + } } - }).into_string().unwrap() + }) } pub(in super) fn login_auth_success(redirect: &String) -> String { - (html! { - : horrorshow::helper::doctype::HTML; - html { - head { - title: "TOTP Successful"; - meta(http-equiv="refresh", content=format!("3; URL={}", redirect)) - } - body { - h1(id = "heading") { - : "Login succesful" - } - a(href=redirect) { - : "Try again... redirecting to "; - } - span { - : format!("{}", redirect) - } - } + let redirect = redirect.clone(); + render_base_template("Login successful", box_html! { + h1(id = "heading") { + : "Login succesful" } - }).into_string().unwrap() + a(href=&redirect) { + : "redirecting to "; + } + span { + : format!("{}", redirect) + } + }) } pub(in super) fn login_auth_fail() -> String { - (html! { - : horrorshow::helper::doctype::HTML; - html { - head { - title: "TOTP Login failed"; - meta(http-equiv="refresh", content="1") - } - body { - h1(id = "heading") { - : "Login failed" - } - a(href="login") { - : "Try again... " - } - } + render_base_template("Login failed", box_html! { + h1(id = "heading") { + : "Login failed" } - }).into_string().unwrap() + a(href="login") { + : "Try again... " + } + }) } \ No newline at end of file -- cgit v1.2.1