use color_eyre::eyre::eyre; use color_eyre::Result; use regex::Regex; use reqwest::multipart::Form; use reqwest::{Client, Url}; use reqwest_cookie_store::CookieStoreMutex; use std::env; use std::sync::Arc; const DEFAULT_BASE_URL: &str = "https://echo360.org.uk"; #[tokio::main] async fn main() -> Result<()> { color_eyre::install()?; #[cfg(feature = "dotenvy")] dotenvy::dotenv()?; let jar = Arc::new(CookieStoreMutex::default()); let client = Client::builder().cookie_provider(jar.clone()).build()?; let base_url = Url::parse(DEFAULT_BASE_URL)?; let domain = base_url.domain().unwrap(); // get the csrf token client.get(base_url.clone()).send().await?; let csrf_token = jar .lock() .unwrap() .get(domain, "/", "PLAY_SESSION") .map(|cookie| { let cookie_value = cookie.value().to_string(); cookie_value .split("&") .nth(1) .map(|part| part.split("=").last()) .flatten() .map(|x| x.to_string()) }) .flatten() .ok_or(eyre!("No csrf token found"))?; // authenticate client .post(format!("{base_url}login")) .query(&[("csrfToken", csrf_token)]) .multipart( Form::new() .text("email", env::var("ECHO360_EMAIL")?) .text("password", env::var("ECHO360_PASSWORD")?), ) .send() .await?; // get institution id let insitution_id = jar .lock() .unwrap() .get(domain, "/", "PLAY_SESSION") .map(|cookie| { let cookie_value = cookie.value().to_string(); cookie_value .split("&") .nth(1) .map(|part| part.split("=").last()) .flatten() .map(|x| x.to_string()) }) .flatten() .ok_or(eyre!("No institution id found"))?; println!("Institution ID: {}", insitution_id); // get authenticated user's name let name = { let html = client .get(format!("{base_url}courses")) .send() .await? .text() .await?; let first_name = Regex::new(r#"\\"firstName\\":\\"(\w+)\\""#)? .captures(&html) .unwrap() .get(1) .unwrap() .as_str(); let last_name = Regex::new(r#"\\"lastName\\":\\"(\w+)\\""#)? .captures(&html) .unwrap() .get(1) .unwrap() .as_str(); format!("{} {}", first_name, last_name) }; println!("Name: {}", name); Ok(()) }