From 491ffb553726d4c01962ee147b87f6c7bf16ca4b Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 29 Aug 2020 19:55:03 +0200 Subject: [PATCH] Use await everywhere, do not declare a mutable variable if the body doesn't need to be edited, disable compression --- lang.json | 16 +++++++ src/forward.rs | 116 ++++++++++++++++++++++++++++++++----------------- src/main.rs | 4 +- src/sniff.rs | 15 +++---- 4 files changed, 99 insertions(+), 52 deletions(-) diff --git a/lang.json b/lang.json index 7dd12a9..2839f53 100644 --- a/lang.json +++ b/lang.json @@ -235,6 +235,14 @@ "en": "Couldn't set the form's isAnonymous value.", "fr": "Échec lors de la définition de la valeur isAnonymous du formulaire." }, + "error_forward_clientresp_newform": { + "en": "Failed to send the response body (new form).", + "fr": "Échec lors de l'envoi du corps de la réponse (nouveau formulaire)." + }, + "error_forward_clientresp_std": { + "en": "Failed to send the response body.", + "fr": "Échec lors de l'envoi du corps de la réponse." + }, "error_forwardlogin_db": { "en": "Couldn't connect to the local database.", "fr": "Échec lors de la connexion à la base de données locale." @@ -315,6 +323,10 @@ "en": "The Nextcloud API returned an unexpected result.", "fr": "L'API de Nextcloud a retourné un résultat inattendu." }, + "error_redirect": { + "en": "Failed to redirect.", + "fr": "La redirection a échoué." + }, "error_dirtyhacker": { "en": "Attempt to access an unauthorized resource.", "fr": "Tentative d'accès à une ressource non autorisée." @@ -322,5 +334,9 @@ "error_tplrender": { "en": "Template rendering failed.", "fr": "Le rendu du template a échoué." + }, + "error_tplrender_resp": { + "en": "Sending response failed.", + "fr": "L'envoi de la réponse a échoué." } } diff --git a/src/forward.rs b/src/forward.rs index caca935..2e5c056 100644 --- a/src/forward.rs +++ b/src/forward.rs @@ -31,7 +31,10 @@ pub async fn forward( // They get redirected to the main page. if check_route(route) { debug(&format!("Restricted route blocked: {}", route)); - return Ok(web_redir("/")); + return Ok(web_redir("/").await.map_err(|e| { + eprintln!("error_redirect: {}", e); + crash(get_lang(&req), "error_redirect") + })?); } let forwarded_req = forge_from(route, &req, &url, &client); @@ -63,42 +66,57 @@ pub async fn forward( { client_resp.header(header_name.clone(), header_value.clone()); } - - // retreive the body from the request result - let response_body = res.body().limit(PAYLOAD_LIMIT).await.map_err(|e| { - eprintln!("error_forward_resp: {}", e); - crash(get_lang(&req), "error_forward_resp") - })?; - - // if a new form is created, automatically set some fields. - // this is very hackish but it works! for now. - let form_id = check_new_form(route, &response_body); - if form_id > 0 { - debug(&format!( - "New form. Forging request to set isAnonymous for id {}", - form_id - )); - - let forged_body = format!( - r#"{{"id":{},"keyValuePairs":{{"isAnonymous":true}}}}"#, - form_id - ); - let update_req = forge_from("/apps/forms/api/v1/form/update", &req, &url, &client) - .set_header("content-length", forged_body.len()) - .set_header("content-type", "application/json;charset=utf-8"); - - let res = update_req.send_body(forged_body).await.map_err(|e| { - eprintln!("error_forward_isanon: {}", e); - crash(get_lang(&req), "error_forward_isanon") + + // sparing the use of a mutable body when not needed + // For now, the body only needs to be modified when the route + // is "create a new form" route + if route == "/apps/forms/api/v1/form" { + // retreive the body from the request result + let response_body = res.body().limit(PAYLOAD_LIMIT).await.map_err(|e| { + eprintln!("error_forward_resp: {}", e); + crash(get_lang(&req), "error_forward_resp") })?; - debug(&format!("(new_form) Request returned {}", res.status())); + + // if a new form is created, automatically set some fields. + // this is very hackish but it works! for now. + let form_id = check_new_form(&response_body); + if form_id > 0 { + debug(&format!( + "New form. Forging request to set isAnonymous for id {}", + form_id + )); + + let forged_body = format!( + r#"{{"id":{},"keyValuePairs":{{"isAnonymous":true}}}}"#, + form_id + ); + let update_req = forge_from("/apps/forms/api/v1/form/update", &req, &url, &client) + .set_header("content-length", forged_body.len()) + .set_header("content-type", "application/json;charset=utf-8"); + + let res = update_req.send_body(forged_body).await.map_err(|e| { + eprintln!("error_forward_isanon: {}", e); + crash(get_lang(&req), "error_forward_isanon") + })?; + debug(&format!("(new_form) Request returned {}", res.status())); + } + Ok(client_resp.body(response_body).await.map_err(|e| { + eprintln!("error_forward_clientresp_newform: {}", e); + crash(get_lang(&req), "error_forward_clientresp_newform") + })?) + } + else { + Ok(client_resp.body(res.body().limit(PAYLOAD_LIMIT).await.map_err(|e| { + eprintln!("error_forward_clientresp_newform: {}", e); + crash(get_lang(&req), "error_forward_clientresp_std") + })?)) } - // check the response before returning it - if check_response(route, &response_body) { + + // check the response before returning it (unused) + /*if check_response(route, &response_body) { return Ok(web_redir("/")); - } - Ok(client_resp.body(response_body)) + }*/ } #[derive(Deserialize)] @@ -114,7 +132,10 @@ pub async fn forward_login( ) -> Result { // if the user is already logged in, redirect to the Forms app if is_logged_in(&req).is_some() { - return Ok(web_redir("/apps/forms/")); + return Ok(web_redir("/apps/forms").await.map_err(|e| { + eprintln!("error_redirect (1:/apps/forms/): {}", e); + crash(get_lang(&req), "error_redirect") + })?); } // check if the provided token seems valid. If not, early return. @@ -155,7 +176,10 @@ pub async fn forward_register( // if the user is already logged in, redirect to the Forms app if is_logged_in(&req).is_some() { - return Ok(web_redir("/apps/forms/")); + return Ok(web_redir("/apps/forms").await.map_err(|e| { + eprintln!("error_redirect (2:/apps/forms/): {}", e); + crash(get_lang(&req), "error_redirect") + })?); } // if the user has already generated an admin token, redirect too @@ -178,10 +202,14 @@ pub async fn forward_register( .as_str(); // sanitize the token beforehand, cookies are unsafe if check_token(&admin_token) { - return Ok(web_redir(&format!( + return Ok(web_redir( + &format!( "{}/admin/{}", - CONFIG.sncf_url, &admin_token - ))); + CONFIG.sncf_url, &admin_token) + ).await.map_err(|e| { + eprintln!("error_redirect (admin): {}", e); + crash(get_lang(&req), "error_redirect") + })?); } else { debug("Incorrect admin token given in cookies."); debug(&format!("Token: {:#?}", &admin_token)); @@ -234,9 +262,12 @@ pub async fn forward_register( .render() .map_err(|e| { eprintln!("error_tplrender (TplLink): {}", e); - crash(lang, "error_tplrender") + crash(lang.clone(), "error_tplrender") })?, - )) + ).await.map_err(|e| { + eprintln!("error_tplrender_resp (TplLink): {}", e); + crash(lang, "error_tplrender_resp") + })?) } // create a new query destined to the nextcloud instance @@ -281,5 +312,8 @@ pub async fn index(req: HttpRequest) -> Result { eprintln!("error_tplrender (TplIndex): {}", e); crash(get_lang(&req), "error_tplrender") })?, - )) + ).await.map_err(|e| { + eprintln!("error_tplrender_resp (TplIndex): {}", e); + crash(get_lang(&req), "error_tplrender_resp") + })?) } diff --git a/src/main.rs b/src/main.rs index 23ae1f5..5e0b292 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ extern crate diesel_migrations; use actix_files::Files; use actix_web::client::Client; -use actix_web::{middleware, web, App, FromRequest, HttpServer}; +use actix_web::{web, App, FromRequest, HttpServer}; use diesel::prelude::*; use diesel::r2d2::{self, ConnectionManager}; use url::Url; @@ -67,7 +67,7 @@ async fn main() -> std::io::Result<()> { .data(forward_url.clone()) /*.route("/mimolette", web::get().to(login))*/ /*.route("/login", web::post().to(forward))*/ - .wrap(middleware::Compress::default()) + /*.wrap(middleware::Compress::default())*/ .service(Files::new("/assets/", "./templates/assets/").index_file("index.html")) .route("/", web::get().to(index)) .route("/link", web::get().to(forward_register)) diff --git a/src/sniff.rs b/src/sniff.rs index 09f47d7..15151fb 100644 --- a/src/sniff.rs +++ b/src/sniff.rs @@ -32,22 +32,19 @@ fn rq_form_update(body: &web::Bytes) -> bool { // checks to be done on responses from the Nextcloud instance // if it returns true, cancels the request -pub fn check_response(_route: &str, _body: &web::Bytes) -> bool { +// NOTE: unused for now +/*pub fn check_response(_route: &str, _body: &web::Bytes) -> bool { false -} +}*/ // checks if a form has been created. // if it's the case, sets some parameters. // this part may need code quality improvements -pub fn check_new_form(route: &str, body: &web::Bytes) -> u64 { +// the body MUST come from the "create new form" route +// (this is checked upstream) +pub fn check_new_form(body: &web::Bytes) -> u64 { let req = String::from_utf8_lossy(body); - let new_form_route = "/apps/forms/api/v1/form"; - - if route != new_form_route { - return 0; - } - // finds the form ID let v: Value = serde_json::from_str(&req).unwrap_or_else(|e| { eprintln!("check_new_form: failed to parse JSON: {}", e);