update email function and forward.rs regarding new version of sncf
This commit is contained in:
parent
07839652e3
commit
501086e1cd
1 changed files with 126 additions and 165 deletions
|
@ -1,14 +1,14 @@
|
|||
use actix_web::client::{Client, ClientRequest};
|
||||
use actix_web::{http, web, HttpRequest, HttpResponse};
|
||||
use actix_session::Session;
|
||||
use askama::Template;
|
||||
use chrono::Utc;
|
||||
use regex::Regex;
|
||||
use csrf::{AesGcmCsrfProtection, CsrfProtection};
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
use csrf::{AesGcmCsrfProtection, CsrfProtection};
|
||||
|
||||
use crate::config::get_csrf_key;
|
||||
use crate::account::*;
|
||||
use crate::config::get_csrf_key;
|
||||
use crate::config::PAYLOAD_LIMIT;
|
||||
use crate::config::PROXY_TIMEOUT;
|
||||
use crate::database::methods::InsertableForm;
|
||||
|
@ -28,50 +28,40 @@ pub async fn forward(
|
|||
) -> Result<HttpResponse, TrainCrash> {
|
||||
let route = req.uri().path();
|
||||
|
||||
|
||||
if route == "/link/email" {
|
||||
let email_request_headers = &req;
|
||||
let email_body = &body;
|
||||
|
||||
|
||||
if route == "/link/email" {
|
||||
//let email_body = &body;
|
||||
//let mut body = String::new();
|
||||
//let forged_emailbody = format!(
|
||||
// "{:?}",
|
||||
// email_body
|
||||
// );
|
||||
|
||||
let forged_emailheaders = format!(
|
||||
"{:?}",
|
||||
email_request_headers
|
||||
);
|
||||
let forged_emailbody = format!(
|
||||
"{:?}",
|
||||
email_body
|
||||
);
|
||||
//let body = email_response_body.escape_ascii().to_string();
|
||||
|
||||
/*email_response_body.read_to_string(&mut body)?;*/
|
||||
// does not work, because body is in bytes format.
|
||||
println!("da budy {}",forged_emailbody );
|
||||
println!("da headers {}",forged_emailheaders);
|
||||
|
||||
use std::io::Write;
|
||||
use std::fs::OpenOptions;
|
||||
let mut f = OpenOptions::new()
|
||||
.append(true)
|
||||
.create(true) // Optionally create the file if it doesn't already exist
|
||||
.open("/tmp/foo")
|
||||
.open("/var/tokmails/tuples.csv")
|
||||
.expect("Unable to open file");
|
||||
|
||||
//let body_bytes = as_bytes!("{:?}", body);
|
||||
|
||||
f.write_all(forged_emailheaders.as_bytes()).expect("Unable to write data");
|
||||
f.write_all(forged_emailbody.as_bytes()).expect("Unable to write data");
|
||||
|
||||
|
||||
//f.write_all(forged_emailheaders.as_bytes()).expect("Unable to write data");
|
||||
////f.write_all(forged_emailbody.as_bytes()).expect("Unable to write data");
|
||||
f.write_all(&body).expect("Unable to write data");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if check_route returns true,
|
||||
// the user supposedly tried to access a restricted page.
|
||||
// They get redirected to the main page.
|
||||
if check_route(route) {
|
||||
if route.starts_with("/apps/files") {
|
||||
// exception for /apps/files: always redirect to /apps/forms
|
||||
debug(&format!("Files route blocked: {}", route));
|
||||
return Ok(web_redir("/apps/forms").await.map_err(|e| {
|
||||
eprintln!("error_redirect: {}", e);
|
||||
crash(get_lang(&req), "error_redirect")
|
||||
})?);
|
||||
} else if check_route(route) {
|
||||
debug(&format!("Restricted route blocked: {}", route));
|
||||
return Ok(web_redir("/").await.map_err(|e| {
|
||||
eprintln!("error_redirect: {}", e);
|
||||
|
@ -108,6 +98,7 @@ pub async fn forward(
|
|||
{
|
||||
client_resp.header(header_name.clone(), header_value.clone());
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -177,17 +168,11 @@ pub struct CsrfToken {
|
|||
|
||||
pub async fn forward_login(
|
||||
req: HttpRequest,
|
||||
s: Session,
|
||||
params: web::Path<LoginToken>,
|
||||
client: web::Data<Client>,
|
||||
dbpool: web::Data<DbPool>,
|
||||
) -> Result<HttpResponse, TrainCrash> {
|
||||
// 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").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.
|
||||
if !check_token(¶ms.token) {
|
||||
|
@ -201,6 +186,7 @@ pub async fn forward_login(
|
|||
crash(get_lang(&req), "error_forwardlogin_db")
|
||||
})?;
|
||||
|
||||
let moved_token = params.token.clone();
|
||||
// check if the link exists in DB. if it does, update lastvisit_at.
|
||||
let formdata = web::block(move || Form::get_from_token(¶ms.token, &conn))
|
||||
.await
|
||||
|
@ -209,108 +195,75 @@ pub async fn forward_login(
|
|||
crash(get_lang(&req), "error_forwardlogin_db_get")
|
||||
})?
|
||||
.ok_or_else(|| {
|
||||
debug("Token not found.");
|
||||
debug("error: Token not found.");
|
||||
crash(get_lang(&req), "error_forwardlogin_notfound")
|
||||
})?;
|
||||
|
||||
// else, try to log the user in with DB data, then redirect.
|
||||
// copy the token in cookies.
|
||||
s.set("sncf_admin_token", &moved_token).map_err(|e| {
|
||||
eprintln!("error_login_setcookie (in login): {}", e);
|
||||
crash(get_lang(&req),"error_login_setcookie")
|
||||
})?;
|
||||
|
||||
// if the user is already logged in, skip the login process
|
||||
// we don't care if someone edits their cookies, Nextcloud will properly
|
||||
// check them anyway
|
||||
if let Some(nc_username) = is_logged_in(&req) {
|
||||
if nc_username.contains(&format!("nc_username={}", formdata.nc_username)) {
|
||||
return Ok(web_redir("/apps/forms").await.map_err(|e| {
|
||||
eprintln!("error_redirect (1:/apps/forms/): {}", e);
|
||||
crash(get_lang(&req), "error_redirect")
|
||||
})?);
|
||||
}
|
||||
}
|
||||
|
||||
// try to log the user in with DB data, then redirect.
|
||||
login(&client, &req, &formdata.nc_username, &formdata.nc_password).await
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 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<CsrfToken>,
|
||||
client: web::Data<Client>,
|
||||
dbpool: web::Data<DbPool>,
|
||||
) -> Result<HttpResponse, TrainCrash> {
|
||||
let lang = get_lang(&req);
|
||||
|
||||
// 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").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
|
||||
if let Some(token) = has_admintoken(&req) {
|
||||
lazy_static! {
|
||||
static ref RE: Regex = Regex::new(r#"sncf_admin_token=(?P<token>[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"));
|
||||
}
|
||||
}
|
||||
// do not check for existing admin tokens and force a new registration
|
||||
|
||||
// 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<token>[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 raw_ctoken = base64::decode_config(cookie_csrf_token.as_bytes(), base64::URL_SAFE_NO_PAD).map_err(|e| {
|
||||
eprintln!("error_csrf_cookie (base64): {}", e);
|
||||
let cookie_csrf_token = s.get::<String>("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_token.as_bytes(), base64::URL_SAFE_NO_PAD).map_err(
|
||||
|e| {
|
||||
eprintln!("error_csrf_cookie (base64): {}", e);
|
||||
crash(get_lang(&req), "error_csrf_cookie")
|
||||
},
|
||||
)?;
|
||||
|
||||
let raw_token = base64::decode_config(csrf_post.csrf_token.as_bytes(), base64::URL_SAFE_NO_PAD).map_err(|e| {
|
||||
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")
|
||||
})?;
|
||||
|
||||
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"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
debug("warn: missing CSRF token.");
|
||||
return Err(crash(lang, "error_csrf_cookie"));
|
||||
}
|
||||
|
@ -333,7 +286,8 @@ pub async fn forward_register(
|
|||
let token_mv = token.clone();
|
||||
|
||||
// store the result in DB
|
||||
let form_result = web::block(move || Form::insert(
|
||||
let form_result = web::block(move || {
|
||||
Form::insert(
|
||||
InsertableForm {
|
||||
created_at: Utc::now().naive_utc(),
|
||||
lastvisit_at: Utc::now().naive_utc(),
|
||||
|
@ -342,19 +296,20 @@ pub async fn forward_register(
|
|||
nc_password,
|
||||
},
|
||||
&conn,
|
||||
))
|
||||
)
|
||||
})
|
||||
.await;
|
||||
|
||||
if form_result.is_err() {
|
||||
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; SameSite=Strict", &token),
|
||||
)
|
||||
.body(
|
||||
TplLink {
|
||||
lang: &lang,
|
||||
|
@ -406,22 +361,28 @@ fn web_redir(location: &str) -> HttpResponse {
|
|||
.finish()
|
||||
}
|
||||
|
||||
pub async fn index(req: HttpRequest) -> Result<HttpResponse, TrainCrash> {
|
||||
|
||||
pub async fn index(req: HttpRequest, s: Session) -> Result<HttpResponse, TrainCrash> {
|
||||
let seed = AesGcmCsrfProtection::from_key(get_csrf_key());
|
||||
let (csrf_token, csrf_cookie) = seed.generate_token_pair(None, 43200)
|
||||
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::<String>("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; 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| {
|
||||
|
|
Loading…
Reference in a new issue