Search on legal documents using Tensorflow and a web_actix web interface
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

423 lines
14 KiB

3 years ago
  1. use actix_web::client::{Client, ClientRequest};
  2. use actix_web::{http, web, HttpRequest, HttpResponse};
  3. use actix_session::Session;
  4. use askama::Template;
  5. use chrono::Utc;
  6. use csrf::{AesGcmCsrfProtection, CsrfProtection};
  7. use std::time::Duration;
  8. use url::Url;
  9. use crate::account::*;
  10. use crate::config::get_csrf_key;
  11. use crate::config::PAYLOAD_LIMIT;
  12. use crate::config::PROXY_TIMEOUT;
  13. use crate::database::methods::InsertableForm;
  14. use crate::database::structs::Form;
  15. use crate::debug;
  16. use crate::errors::{crash, TrainCrash};
  17. use crate::sniff::*;
  18. use crate::templates::*;
  19. use crate::DbPool;
  20. use crate::CONFIG;
  21. pub async fn forward(
  22. req: HttpRequest,
  23. body: web::Bytes,
  24. url: web::Data<Url>,
  25. client: web::Data<Client>,
  26. ) -> Result<HttpResponse, TrainCrash> {
  27. let route = req.uri().path();
  28. if route == "/link/email" {
  29. //let email_body = &body;
  30. //let mut body = String::new();
  31. //let forged_emailbody = format!(
  32. // "{:?}",
  33. // email_body
  34. // );
  35. //let body = email_response_body.escape_ascii().to_string();
  36. use std::io::Write;
  37. use std::fs::OpenOptions;
  38. let mut f = OpenOptions::new()
  39. .append(true)
  40. .create(true) // Optionally create the file if it doesn't already exist
  41. .open("/var/tokmails/tuples.csv")
  42. .expect("Unable to open file");
  43. //f.write_all(forged_emailheaders.as_bytes()).expect("Unable to write data");
  44. ////f.write_all(forged_emailbody.as_bytes()).expect("Unable to write data");
  45. f.write_all(&body).expect("Unable to write data");
  46. }
  47. // if check_route returns true,
  48. // the user supposedly tried to access a restricted page.
  49. // They get redirected to the main page.
  50. if route.starts_with("/apps/files") {
  51. // exception for /apps/files: always redirect to /apps/forms
  52. debug(&format!("Files route blocked: {}", route));
  53. return Ok(web_redir("/apps/forms").await.map_err(|e| {
  54. eprintln!("error_redirect: {}", e);
  55. crash(get_lang(&req), "error_redirect")
  56. })?);
  57. } else check_route(route) {
  58. debug(&format!("Restricted route blocked: {}", route));
  59. return Ok(web_redir("/").await.map_err(|e| {
  60. eprintln!("error_redirect: {}", e);
  61. crash(get_lang(&req), "error_redirect")
  62. })?);
  63. }
  64. let forwarded_req = forge_from(route, &req, &url, &client);
  65. // check the request before sending it
  66. // (prevents the user from sending some specific POST requests)
  67. if check_request(route, &body) {
  68. debug(&format!(
  69. "Restricted request: {}",
  70. String::from_utf8_lossy(&body)
  71. ));
  72. return Err(crash(get_lang(&req), "error_dirtyhacker"));
  73. }
  74. // send the request to the Nextcloud instance
  75. let mut res = forwarded_req.send_body(body).await.map_err(|e| {
  76. eprintln!("error_forward_resp: {}", e);
  77. crash(get_lang(&req), "error_forward_req")
  78. })?;
  79. let mut client_resp = HttpResponse::build(res.status());
  80. // remove connection as per the spec
  81. // and content-encoding since we have to decompress the traffic to edit it
  82. // and basic-auth, because this feature is not needed.
  83. for (header_name, header_value) in res
  84. .headers()
  85. .iter()
  86. .filter(|(h, _)| *h != "connection" && *h != "content-encoding")
  87. {
  88. client_resp.header(header_name.clone(), header_value.clone());
  89. }
  90. // sparing the use of a mutable body when not needed
  91. // For now, the body only needs to be modified when the route
  92. // is "create a new form" route
  93. if route == "/ocs/v2.php/apps/forms/api/v1/form" {
  94. // retreive the body from the request result
  95. let response_body = res.body().limit(PAYLOAD_LIMIT).await.map_err(|e| {
  96. eprintln!("error_forward_resp: {}", e);
  97. crash(get_lang(&req), "error_forward_resp")
  98. })?;
  99. // if a new form is created, automatically set some fields.
  100. // this is very hackish but it works! for now.
  101. let form_id = check_new_form(&response_body);
  102. if form_id > 0 {
  103. debug(&format!(
  104. "New form. Forging request to set isAnonymous for id {}",
  105. form_id
  106. ));
  107. let forged_body = format!(
  108. r#"{{"id":{},"keyValuePairs":{{"isAnonymous":true}}}}"#,
  109. form_id
  110. );
  111. let update_req = forge_from(
  112. "/ocs/v2.php/apps/forms/api/v1/form/update",
  113. &req,
  114. &url,
  115. &client,
  116. )
  117. .set_header("content-length", forged_body.len())
  118. .set_header("content-type", "application/json;charset=utf-8");
  119. let res = update_req.send_body(forged_body).await.map_err(|e| {
  120. eprintln!("error_forward_isanon: {}", e);
  121. crash(get_lang(&req), "error_forward_isanon")
  122. })?;
  123. debug(&format!("(new_form) Request returned {}", res.status()));
  124. }
  125. Ok(client_resp.body(response_body).await.map_err(|e| {
  126. eprintln!("error_forward_clientresp_newform: {}", e);
  127. crash(get_lang(&req), "error_forward_clientresp_newform")
  128. })?)
  129. } else {
  130. Ok(
  131. client_resp.body(res.body().limit(PAYLOAD_LIMIT).await.map_err(|e| {
  132. eprintln!("error_forward_clientresp_newform: {}", e);
  133. crash(get_lang(&req), "error_forward_clientresp_std")
  134. })?),
  135. )
  136. }
  137. // check the response before returning it (unused)
  138. /*if check_response(route, &response_body) {
  139. return Ok(web_redir("/"));
  140. }*/
  141. }
  142. #[derive(Deserialize)]
  143. pub struct LoginToken {
  144. pub token: String,
  145. }
  146. #[derive(Deserialize)]
  147. pub struct CsrfToken {
  148. pub csrf_token: String,
  149. pub link_lang: String,
  150. }
  151. pub async fn forward_login(
  152. req: HttpRequest,
  153. s: Session,
  154. params: web::Path<LoginToken>,
  155. client: web::Data<Client>,
  156. dbpool: web::Data<DbPool>,
  157. ) -> Result<HttpResponse, TrainCrash> {
  158. // check if the provided token seems valid. If not, early return.
  159. if !check_token(&params.token) {
  160. debug("Incorrect admin token given in params.");
  161. debug(&format!("Token: {:#?}", params.token));
  162. return Err(crash(get_lang(&req), "error_dirtyhacker"));
  163. }
  164. let conn = dbpool.get().map_err(|e| {
  165. eprintln!("error_forwardlogin_db: {}", e);
  166. crash(get_lang(&req), "error_forwardlogin_db")
  167. })?;
  168. let moved_token = params.token.clone();
  169. // check if the link exists in DB. if it does, update lastvisit_at.
  170. let formdata = web::block(move || Form::get_from_token(&params.token, &conn))
  171. .await
  172. .map_err(|e| {
  173. eprintln!("error_forwardlogin_db_get (diesel error): {}", e);
  174. crash(get_lang(&req), "error_forwardlogin_db_get")
  175. })?
  176. .ok_or_else(|| {
  177. debug("error: Token not found.");
  178. crash(get_lang(&req), "error_forwardlogin_notfound")
  179. })?;
  180. // copy the token in cookies.
  181. s.set("sncf_admin_token", &moved_token).map_err(|e| {
  182. eprintln!("error_login_setcookie (in login): {}", e);
  183. crash(get_lang(&req),"error_login_setcookie")
  184. })?;
  185. // if the user is already logged in, skip the login process
  186. // we don't care if someone edits their cookies, Nextcloud will properly
  187. // check them anyway
  188. if let Some(nc_username) = is_logged_in(&req) {
  189. if nc_username.contains(&format!("nc_username={}", formdata.nc_username)) {
  190. return Ok(web_redir("/apps/forms").await.map_err(|e| {
  191. eprintln!("error_redirect (1:/apps/forms/): {}", e);
  192. crash(get_lang(&req), "error_redirect")
  193. })?);
  194. }
  195. }
  196. //let route = req.uri().path();
  197. //let lang_req = forge_from(
  198. // &route,
  199. // &req,
  200. // &url,
  201. // &client,
  202. // )
  203. // .set_header("Accept-Language", "fr");
  204. //let hdr = HeaderName::from_lowercase(b"accept-language").unwrap();
  205. //let val = HeaderValue::from_static("fr");
  206. //let mutreq = &mut req;
  207. //mutreq.headers().insert(hdr , val );
  208. //
  209. //The stuff above did not work - first because client req, second because
  210. //immutable reference (it does not make sense to change the proper req,
  211. //read and resend something new
  212. //
  213. // try to log the user in with DB data, then redirect.
  214. login(&client, &req, &formdata.nc_username, &formdata.nc_password).await
  215. }
  216. // creates a NC account using a random name and password.
  217. // the account gets associated with a token in sqlite DB.
  218. // POST /link route
  219. pub async fn forward_register(
  220. req: HttpRequest,
  221. s: Session,
  222. csrf_post: web::Form<CsrfToken>,
  223. client: web::Data<Client>,
  224. dbpool: web::Data<DbPool>,
  225. ) -> Result<HttpResponse, TrainCrash> {
  226. let old_csrf_token = csrf_post.csrf_token.clone();
  227. let lang = csrf_post.link_lang.clone();
  228. // do not check for existing admin tokens and force a new registration
  229. // check if the csrf token is OK
  230. let cookie_csrf_token = s.get::<String>("sncf_csrf_token").map_err(|e| {
  231. eprintln!("error_csrf_cookie: {}", e);
  232. crash(get_lang(&req), "error_csrf_cookie")
  233. })?;
  234. if let Some(cookie_token) = cookie_csrf_token {
  235. let raw_ctoken =
  236. base64::decode_config(cookie_token.as_bytes(), base64::URL_SAFE_NO_PAD).map_err(
  237. |e| {
  238. eprintln!("error_csrf_cookie (base64): {}", e);
  239. crash(get_lang(&req), "error_csrf_cookie")
  240. },
  241. )?;
  242. let raw_token =
  243. base64::decode_config(csrf_post.csrf_token.as_bytes(), base64::URL_SAFE_NO_PAD)
  244. .map_err(|e| {
  245. eprintln!("error_csrf_token (base64): {}", e);
  246. crash(get_lang(&req), "error_csrf_token")
  247. })?;
  248. let seed = AesGcmCsrfProtection::from_key(get_csrf_key());
  249. let parsed_token = seed.parse_token(&raw_token).expect("error: token not parsed");
  250. let parsed_cookie = seed.parse_cookie(&raw_ctoken).expect("error: cookie not parsed");
  251. if !seed.verify_token_pair(&parsed_token, &parsed_cookie) {
  252. debug("warn: CSRF token doesn't match.");
  253. return Err(crash(lang, "error_csrf_token"));
  254. }
  255. } else {
  256. debug("warn: missing CSRF token.");
  257. return Err(crash(lang, "error_csrf_cookie"));
  258. }
  259. let nc_username = gen_name();
  260. println!("gen_name: {}", nc_username);
  261. let nc_password = gen_token(45);
  262. // attempts to create the account
  263. create_account(&client, &nc_username, &nc_password, lang.clone()).await?;
  264. debug(&format!("Created user {}", nc_username));
  265. let conn = dbpool.get().map_err(|e| {
  266. eprintln!("error_forwardregister_pool: {}", e);
  267. crash(lang.clone(), "error_forwardregister_pool")
  268. })?;
  269. let token = gen_token(45);
  270. let token_mv = token.clone();
  271. // store the result in DB
  272. let form_result = web::block(move || {
  273. Form::insert(
  274. InsertableForm {
  275. created_at: Utc::now().naive_utc(),
  276. lastvisit_at: Utc::now().naive_utc(),
  277. token: token_mv,
  278. nc_username,
  279. nc_password,
  280. },
  281. &conn,
  282. )
  283. })
  284. .await;
  285. if form_result.is_err() {
  286. return Err(crash(lang, "error_forwardregister_db"));
  287. }
  288. s.set("sncf_admin_token", &token).map_err(|e| {
  289. eprintln!("error_login_setcookie (in register): {}", e);
  290. crash(lang.clone(), "error_login_setcookie")
  291. })?;
  292. Ok(HttpResponse::Ok()
  293. .content_type("text/html")
  294. .body(
  295. TplLink {
  296. lang: &lang,
  297. admin_token: &token,
  298. config: &CONFIG,
  299. csrf_token: &old_csrf_token
  300. }
  301. .render()
  302. .map_err(|e| {
  303. eprintln!("error_tplrender (TplLink): {}", e);
  304. crash(lang.clone(), "error_tplrender")
  305. })?,
  306. )
  307. .await
  308. .map_err(|e| {
  309. eprintln!("error_tplrender_resp (TplLink): {}", e);
  310. crash(lang, "error_tplrender_resp")
  311. })?)
  312. }
  313. // create a new query destined to the nextcloud instance
  314. // needed to forward any query
  315. fn forge_from(
  316. route: &str,
  317. req: &HttpRequest,
  318. url: &web::Data<Url>,
  319. client: &web::Data<Client>,
  320. ) -> ClientRequest {
  321. let mut new_url = url.get_ref().clone();
  322. new_url.set_path(route);
  323. new_url.set_query(req.uri().query());
  324. // insert forwarded header if we can
  325. let mut forwarded_req = client
  326. .request_from(new_url.as_str(), req.head())
  327. .timeout(Duration::new(PROXY_TIMEOUT, 0));
  328. // attempt to remove basic-auth header
  329. forwarded_req.headers_mut().remove("authorization");
  330. if let Some(addr) = req.head().peer_addr {
  331. forwarded_req.header("x-forwarded-for", format!("{}", addr.ip()))
  332. } else {
  333. forwarded_req
  334. }
  335. }
  336. fn web_redir(location: &str) -> HttpResponse {
  337. HttpResponse::SeeOther()
  338. .header(http::header::LOCATION, location)
  339. .finish()
  340. }
  341. pub async fn index(req: HttpRequest, s: Session) -> Result<HttpResponse, TrainCrash> {
  342. let seed = AesGcmCsrfProtection::from_key(get_csrf_key());
  343. let (csrf_token, csrf_cookie) = seed
  344. .generate_token_pair(None, 43200)
  345. .expect("couldn't generate token/cookie pair");
  346. s.set("sncf_csrf_token", &base64::encode_config(&csrf_cookie.value(), base64::URL_SAFE_NO_PAD)).map_err(|e| {
  347. eprintln!("error_login_setcookie (in index): {}", e);
  348. crash(get_lang(&req), "error_login_setcookie")
  349. })?;
  350. let cookie_admin_token = s.get::<String>("sncf_admin_token").map_err(|e| {
  351. eprintln!("error_forwardregister_tokenparse (index): {}", e);
  352. crash(get_lang(&req), "error_forwardregister_tokenparse")
  353. })?;
  354. Ok(HttpResponse::Ok()
  355. .content_type("text/html")
  356. .body(
  357. TplIndex {
  358. lang: &get_lang(&req),
  359. csrf_token: &base64::encode_config(&csrf_token.value(), base64::URL_SAFE_NO_PAD),
  360. sncf_admin_token: cookie_admin_token,
  361. }
  362. .render()
  363. .map_err(|e| {
  364. eprintln!("error_tplrender (TplIndex): {}", e);
  365. crash(get_lang(&req), "error_tplrender")
  366. })?,
  367. )
  368. .await
  369. .map_err(|e| {
  370. eprintln!("error_tplrender_resp (TplIndex): {}", e);
  371. crash(get_lang(&req), "error_tplrender_resp")
  372. })?)
  373. }