diff --git a/src/forward.rs b/src/forward.rs index 8ce2650..1572b45 100644 --- a/src/forward.rs +++ b/src/forward.rs @@ -1,9 +1,9 @@ use actix_web::client::{Client, ClientRequest}; use actix_web::{http, web, HttpRequest, HttpResponse}; +use actix_session::Session; use askama::Template; use chrono::Utc; use csrf::{AesGcmCsrfProtection, CsrfProtection}; -use regex::Regex; use std::time::Duration; use url::Url; @@ -180,8 +180,10 @@ pub async fn forward_login( // creates a NC account using a random name and password. // the account gets associated with a token in sqlite DB. +// POST /link route pub async fn forward_register( req: HttpRequest, + s: Session, csrf_post: web::Form, client: web::Data, dbpool: web::Data, @@ -196,62 +198,30 @@ pub async fn forward_register( })?); } + let cookie_admin_token = s.get::("sncf_admin_token").map_err(|e| { + eprintln!("error_forwardregister_tokenparse: {}", e); + crash(get_lang(&req), "error_forwardregister_tokenparse") + })?; // if the user has already generated an admin token, redirect too - if let Some(token) = has_admintoken(&req) { - lazy_static! { - static ref RE: Regex = Regex::new(r#"sncf_admin_token=(?P[0-9A-Za-z_\-]*)"#) - .expect("Error while parsing the sncf_admin_token regex"); - } - let admin_token = RE - .captures(&token) - .ok_or_else(|| { - eprintln!("error_forwardregister_tokenparse (no capture)"); - crash(get_lang(&req), "error_forwardregister_tokenparse") - })? - .name("token") - .ok_or_else(|| { - eprintln!("error_forwardregister_tokenparse (no capture named token)"); - crash(get_lang(&req), "error_forwardregister_tokenparse") - })? - .as_str(); - // sanitize the token beforehand, cookies are unsafe - if check_token(&admin_token) { - return Ok( - web_redir(&format!("{}/admin/{}", 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)); - return Err(crash(lang, "error_dirtyhacker")); - } + if let Some(admin_token) = cookie_admin_token { + return Ok( + web_redir(&format!("{}/admin/{}", CONFIG.sncf_url, &admin_token)) + .await + .map_err(|e| { + eprintln!("error_redirect (admin): {}", e); + crash(get_lang(&req), "error_redirect") + })?, + ); } // check if the csrf token is OK - if let Some(cookie_token) = has_csrftoken(&req) { - lazy_static! { - static ref RE: Regex = Regex::new(r#"sncf_csrf_cookie=(?P[0-9A-Za-z_\-]*)"#) - .expect("Error while parsing the sncf_csrf_cookie regex"); - } - let cookie_csrf_token = RE - .captures(&cookie_token) - .ok_or_else(|| { - eprintln!("error_csrf_cookie: no capture"); - crash(get_lang(&req), "error_csrf_cookie") - })? - .name("token") - .ok_or_else(|| { - eprintln!("error_csrf_cookie: no capture named token"); - crash(get_lang(&req), "error_csrf_cookie") - })? - .as_str(); - + let cookie_csrf_token = s.get::("sncf_csrf_token").map_err(|e| { + eprintln!("error_csrf_cookie: {}", e); + crash(get_lang(&req), "error_csrf_cookie") + })?; + if let Some(cookie_token) = cookie_csrf_token { let raw_ctoken = - base64::decode_config(cookie_csrf_token.as_bytes(), base64::URL_SAFE_NO_PAD).map_err( + base64::decode_config(cookie_token.as_bytes(), base64::URL_SAFE_NO_PAD).map_err( |e| { eprintln!("error_csrf_cookie (base64): {}", e); crash(get_lang(&req), "error_csrf_cookie") @@ -260,14 +230,14 @@ pub async fn forward_register( let raw_token = base64::decode_config(csrf_post.csrf_token.as_bytes(), base64::URL_SAFE_NO_PAD) - .map_err(|e| { - eprintln!("error_csrf_token (base64): {}", e); - crash(get_lang(&req), "error_csrf_token") - })?; + .map_err(|e| { + eprintln!("error_csrf_token (base64): {}", e); + crash(get_lang(&req), "error_csrf_token") + })?; let seed = AesGcmCsrfProtection::from_key(get_csrf_key()); - let parsed_token = seed.parse_token(&raw_token).expect("token not parsed"); - let parsed_cookie = seed.parse_cookie(&raw_ctoken).expect("cookie not parsed"); + let parsed_token = seed.parse_token(&raw_token).expect("error: token not parsed"); + let parsed_cookie = seed.parse_cookie(&raw_ctoken).expect("error: cookie not parsed"); if !seed.verify_token_pair(&parsed_token, &parsed_cookie) { debug("warn: CSRF token doesn't match."); return Err(crash(lang, "error_csrf_token")); @@ -313,23 +283,23 @@ pub async fn forward_register( return Err(crash(lang, "error_forwardregister_db")); } + s.set("sncf_admin_token", &token).map_err(|e| { + eprintln!("error_login_setcookie (in register): {}", e); + crash(lang.clone(), "error_login_setcookie") + })?; Ok(HttpResponse::Ok() .content_type("text/html") - .set_header( - "Set-Cookie", - format!("sncf_admin_token={}; HttpOnly; Secure; SameSite=Strict", &token), - ) .body( TplLink { lang: &lang, admin_token: &token, config: &CONFIG, - } - .render() - .map_err(|e| { - eprintln!("error_tplrender (TplLink): {}", e); - crash(lang.clone(), "error_tplrender") - })?, + } + .render() + .map_err(|e| { + eprintln!("error_tplrender (TplLink): {}", e); + crash(lang.clone(), "error_tplrender") + })?, ) .await .map_err(|e| { @@ -370,25 +340,28 @@ fn web_redir(location: &str) -> HttpResponse { .finish() } -pub async fn index(req: HttpRequest) -> Result { +pub async fn index(req: HttpRequest, s: Session) -> Result { let seed = AesGcmCsrfProtection::from_key(get_csrf_key()); let (csrf_token, csrf_cookie) = seed .generate_token_pair(None, 43200) .expect("couldn't generate token/cookie pair"); + + s.set("sncf_csrf_token", &base64::encode_config(&csrf_cookie.value(), base64::URL_SAFE_NO_PAD)).map_err(|e| { + eprintln!("error_login_setcookie (in index): {}", e); + crash(get_lang(&req), "error_login_setcookie") + })?; + let cookie_admin_token = s.get::("sncf_admin_token").map_err(|e| { + eprintln!("error_forwardregister_tokenparse (index): {}", e); + crash(get_lang(&req), "error_forwardregister_tokenparse") + })?; Ok(HttpResponse::Ok() .content_type("text/html") - .set_header( - "Set-Cookie", - format!( - "sncf_csrf_cookie={}; HttpOnly; Secure; SameSite=Strict", - base64::encode_config(&csrf_cookie.value(), base64::URL_SAFE_NO_PAD) - ), - ) .body( TplIndex { lang: &get_lang(&req), csrf_token: &base64::encode_config(&csrf_token.value(), base64::URL_SAFE_NO_PAD), + sncf_admin_token: cookie_admin_token, } .render() .map_err(|e| {