1
0
Fork 0
mirror of https://git.42l.fr/neil/sncf.git synced 2024-05-04 06:53:12 +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 rand::RngCore;
use regex::Regex; use regex::Regex;
use std::time::Duration; use std::time::Duration;
use std::collections::HashMap;
use percent_encoding::percent_decode_str;
use crate::config::PROXY_TIMEOUT; use crate::config::{PROXY_TIMEOUT, USER_AGENT, ADJ_LIST, NAME_LIST};
use crate::config::{ADJ_LIST, NAME_LIST};
use crate::debug; use crate::debug;
use crate::errors::{crash, TrainCrash}; use crate::errors::{crash, TrainCrash};
use crate::templates::get_lang; use crate::templates::get_lang;
@ -142,11 +143,11 @@ pub async fn login(
) -> Result<HttpResponse, TrainCrash> { ) -> Result<HttpResponse, TrainCrash> {
debug(&format!("Sending forged login for user {}", user)); debug(&format!("Sending forged login for user {}", user));
// 1. GET /login // 1. GET /csrftoken
let mut login_get = client let mut login_get = client
.get(format!("{}/{}", CONFIG.nextcloud_url, "login")) .get(format!("{}/{}", CONFIG.nextcloud_url, "csrftoken"))
.timeout(Duration::new(PROXY_TIMEOUT, 0)) .timeout(Duration::new(PROXY_TIMEOUT, 0))
.header("User-Agent", "Actix-web") .header("User-Agent", USER_AGENT)
.send() .send()
.await .await
.map_err(|e| { .map_err(|e| {
@ -156,22 +157,63 @@ pub async fn login(
// rewrite cookie headers from GET to POST // rewrite cookie headers from GET to POST
let mut str_cookiepair = String::new(); let mut str_cookiepair = String::new();
for h_value in login_get.headers().get_all("set-cookie") {
str_cookiepair = format!( // remove duplicate oc<id> cookie (nextcloud bug)
"{}; {}", // leading to sncf being unable to forge logins
str_cookiepair, let cookie_set = login_get.headers().get_all("set-cookie");
h_value.clone().to_str().map_err(|e| { let mut cookie_map: HashMap<String, String> = HashMap::new();
eprintln!("error_login_cookiepair: {}", e); for c in cookie_set {
crash(get_lang(&req), "error_login_cookiepair") // 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 // load requesttoken regex
lazy_static! { 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"); .expect("Error while parsing the requesttoken regex");
} }
let post_body = login_get.body().await.map_err(|e| { let post_body = login_get.body().await.map_err(|e| {
eprintln!("error_login_get_body: {}", e); eprintln!("error_login_get_body: {}", e);
@ -186,18 +228,18 @@ pub async fn login(
eprintln!("error_login_regex (no capture)"); eprintln!("error_login_regex (no capture)");
crash(get_lang(&req), "error_login_regex") crash(get_lang(&req), "error_login_regex")
})? })?
.name("token") .name("token")
.ok_or_else(|| { .ok_or_else(|| {
eprintln!("error_login_regex (no capture named token)"); eprintln!("error_login_regex (no capture named token)");
crash(get_lang(&req), "error_login_regex") crash(get_lang(&req), "error_login_regex")
})? })?
.as_str(); .as_str();
// 2. POST /login // 2. POST /login
let mut login_post = client let mut login_post = client
.post(format!("{}/{}", CONFIG.nextcloud_url, "login")) .post(format!("{}/{}", CONFIG.nextcloud_url, "login"))
.timeout(Duration::new(PROXY_TIMEOUT, 0)) .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) // include all NC cookies in one cookie (cookie pair)
login_post = login_post.header("Cookie", str_cookiepair); login_post = login_post.header("Cookie", str_cookiepair);
@ -211,7 +253,7 @@ pub async fn login(
timezone_offset: "2", timezone_offset: "2",
requesttoken, requesttoken,
}) })
.await .await
.map_err(|e| { .map_err(|e| {
eprintln!("error_login_post: {}", e); eprintln!("error_login_post: {}", e);
crash(get_lang(&req), "error_login_post") 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 // 3. set the same cookies in the user's browser
let mut user_response = HttpResponse::SeeOther(); let mut user_response = HttpResponse::SeeOther();
for item in response_post.headers().clone().get_all("set-cookie") { for item in response_post.headers().clone().get_all("set-cookie") {
user_response.header( user_response.header(
"Set-Cookie", "Set-Cookie",