1
0
Fork 0
mirror of https://git.42l.fr/neil/sncf.git synced 2024-04-25 02:50:27 +02:00

fixing the login forgery process to work around nextcloud issue

This commit is contained in:
neil 2021-03-24 19:49:27 +01:00
parent 3b82283cfd
commit 31bf380e12

View file

@ -6,9 +6,10 @@ use rand::Rng;
use rand::RngCore;
use regex::Regex;
use std::time::Duration;
use std::collections::HashMap;
use percent_encoding::percent_decode_str;
use crate::config::PROXY_TIMEOUT;
use crate::config::{ADJ_LIST, NAME_LIST};
use crate::config::{PROXY_TIMEOUT, USER_AGENT, ADJ_LIST, NAME_LIST};
use crate::debug;
use crate::errors::{crash, TrainCrash};
use crate::templates::get_lang;
@ -142,11 +143,11 @@ pub async fn login(
) -> Result<HttpResponse, TrainCrash> {
debug(&format!("Sending forged login for user {}", user));
// 1. GET /login
// 1. GET /csrftoken
let mut login_get = client
.get(format!("{}/{}", CONFIG.nextcloud_url, "login"))
.get(format!("{}/{}", CONFIG.nextcloud_url, "csrftoken"))
.timeout(Duration::new(PROXY_TIMEOUT, 0))
.header("User-Agent", "Actix-web")
.header("User-Agent", USER_AGENT)
.send()
.await
.map_err(|e| {
@ -156,22 +157,63 @@ pub async fn login(
// rewrite cookie headers from GET to POST
let mut str_cookiepair = String::new();
for h_value in login_get.headers().get_all("set-cookie") {
str_cookiepair = format!(
"{}; {}",
str_cookiepair,
h_value.clone().to_str().map_err(|e| {
eprintln!("error_login_cookiepair: {}", e);
crash(get_lang(&req), "error_login_cookiepair")
})?
);
// remove duplicate oc<id> cookie (nextcloud bug)
// leading to sncf being unable to forge logins
let cookie_set = login_get.headers().get_all("set-cookie");
let mut cookie_map: HashMap<String, String> = HashMap::new();
for c in cookie_set {
// get str version of cookie header
let c_str = c.to_str().map_err(|e| {
eprintln!("error_login_cookiepair (1): {}", e);
crash(get_lang(&req), "error_login_cookiepair")
})?;
// percent decode
let c_str = percent_decode_str(c_str).decode_utf8_lossy();
//then remove values after ';'
let c_str_arr = c_str.split(';').collect::<Vec<&str>>();
let c_str = c_str_arr.first()
.expect("error: cookiepair split does not have a first value. shouldn't happen.");
// split cookie key and cookie value
// split_once would work best but it's nightly-only for now
let c_str_arr = c_str.split('=').collect::<Vec<&str>>();
let c_key = c_str_arr.first()
.expect("error: cookie key split does not have a first value, shouldn't happen.");
let c_value = c_str.replace(&format!("{}=", c_key), "");
if c_key != c_str {
// if the key already exists in hashmap, replace its value
// else, insert it
if let Some(c_sel) = cookie_map.get_mut(*c_key) {
*c_sel = c_value;
}
else {
cookie_map.insert(c_key.to_string(), c_value);
}
}
else {
eprintln!("error_login_cookiepair (2)");
return Err(crash(get_lang(&req), "error_login_cookiepair"));
}
}
for (cookie_k, cookie_v) in cookie_map {
str_cookiepair.push_str(&format!("{}={}; ", cookie_k, cookie_v));
}
println!("SET-COOKIE: {}", str_cookiepair);
// load requesttoken regex
lazy_static! {
static ref RE: Regex = Regex::new(r#"requesttoken="(?P<token>.*)""#)
static ref RE: Regex = Regex::new(r#"\{"token":"(?P<token>[^"]*)"\}"#)
.expect("Error while parsing the requesttoken regex");
}
}
let post_body = login_get.body().await.map_err(|e| {
eprintln!("error_login_get_body: {}", e);
@ -186,18 +228,18 @@ pub async fn login(
eprintln!("error_login_regex (no capture)");
crash(get_lang(&req), "error_login_regex")
})?
.name("token")
.name("token")
.ok_or_else(|| {
eprintln!("error_login_regex (no capture named token)");
crash(get_lang(&req), "error_login_regex")
})?
.as_str();
.as_str();
// 2. POST /login
let mut login_post = client
.post(format!("{}/{}", CONFIG.nextcloud_url, "login"))
.timeout(Duration::new(PROXY_TIMEOUT, 0))
.header("User-Agent", "Actix-web");
.header("User-Agent", USER_AGENT);
// include all NC cookies in one cookie (cookie pair)
login_post = login_post.header("Cookie", str_cookiepair);
@ -211,7 +253,7 @@ pub async fn login(
timezone_offset: "2",
requesttoken,
})
.await
.await
.map_err(|e| {
eprintln!("error_login_post: {}", e);
crash(get_lang(&req), "error_login_post")
@ -219,6 +261,7 @@ pub async fn login(
// 3. set the same cookies in the user's browser
let mut user_response = HttpResponse::SeeOther();
for item in response_post.headers().clone().get_all("set-cookie") {
user_response.header(
"Set-Cookie",