206 lines
6.6 KiB
Rust
206 lines
6.6 KiB
Rust
use chrono::{DateTime, Local, TimeZone, Utc};
|
|
use lazy_static::lazy_static;
|
|
use urlencoding::encode;
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
|
|
use isahc::{cookies::CookieJar, prelude::*, Request};
|
|
use std::sync::RwLock;
|
|
|
|
struct CookieHold {
|
|
pub jar: CookieJar,
|
|
}
|
|
|
|
lazy_static! {
|
|
/// Stores a client with a persistent cookie store
|
|
static ref SESSION_COOKIE: RwLock<CookieHold> = RwLock::new(CookieHold { jar: CookieJar::new()});
|
|
/// Stores the last time a request was made, in seconds since UNIX epoch
|
|
static ref SESSION_TIME: RwLock<u64> = RwLock::new(0);
|
|
}
|
|
|
|
/// Makes a request to the online classroom, and returns the html string
|
|
pub async fn request(url: String) -> Result<String, String> {
|
|
let classroom_url = std::env::var("CLASSROOM_URL").expect("CLASSROOM_URL env var is not set!");
|
|
|
|
ensure_session().await?;
|
|
|
|
// Get the stored client
|
|
let jar = SESSION_COOKIE.read().unwrap().jar.clone();
|
|
|
|
let uri = format!("{}{}", classroom_url, url);
|
|
|
|
// Do the request
|
|
let response = Request::get(uri)
|
|
.cookie_jar(jar.clone())
|
|
.body(())
|
|
.or_else(|err| Err(format!("Error creating request: {:?}", err)))?
|
|
.send();
|
|
|
|
let mut response = match response {
|
|
Ok(r) => r,
|
|
Err(err) => return Err(format!("Error sending request: {:?}", err)),
|
|
};
|
|
|
|
match response.text() {
|
|
Ok(t) => {
|
|
// Get current time and date in iso
|
|
let now: DateTime<Local> = Local::now();
|
|
let now = now.to_rfc3339();
|
|
|
|
// Write html to file
|
|
let r = std::fs::write(format!("request-logs/{}.html", now), &t);
|
|
if let Err(err) = r {
|
|
eprintln!("Error writing request html to file: {:?}", err)
|
|
}
|
|
|
|
Ok(t)
|
|
}
|
|
Err(err) => Err(format!("Error getting text from response: {:?}", err)),
|
|
}
|
|
}
|
|
|
|
/// Handles request for creating a user.
|
|
///
|
|
/// Returns `Ok("")` if the request was redirected (i.e. the user was created successfully
|
|
///
|
|
/// Returns `Ok(html)` if the request was not redirected (i.e. the user was not created successfully)
|
|
///
|
|
/// Returns `Err(err)` if there was an error
|
|
pub async fn create_user_request(url: String, body: String) -> Result<String, String> {
|
|
let classroom_url = std::env::var("CLASSROOM_URL").expect("CLASSROOM_URL env var is not set!");
|
|
|
|
ensure_session().await?;
|
|
|
|
// Get the stored client
|
|
let jar = SESSION_COOKIE.read().unwrap().jar.clone();
|
|
|
|
let uri = format!("{}{}", classroom_url, url);
|
|
|
|
// Do the request
|
|
let response = Request::post(uri)
|
|
.header("Content-Type", "multipart/form-data; boundary=---------------------------83919643214156711801978607619")
|
|
.cookie_jar(jar)
|
|
.body(body)
|
|
.or_else(|err| Err(format!("Error creating request: {:?}", err)))?
|
|
.send();
|
|
|
|
let mut response = match response {
|
|
Ok(r) => r,
|
|
Err(err) => return Err(format!("Error sending request: {:?}", err)),
|
|
};
|
|
|
|
if response.status() == isahc::http::StatusCode::FOUND {
|
|
println!("Redirected!");
|
|
return Ok("".into());
|
|
}
|
|
|
|
match response.text() {
|
|
Ok(t) => {
|
|
// Get current time and date in iso
|
|
let now: DateTime<Local> = Local::now();
|
|
let now = now.to_rfc3339();
|
|
|
|
// Write html to file
|
|
let r = std::fs::write(format!("request-logs/{}.html", now), &t);
|
|
if let Err(err) = r {
|
|
eprintln!("Error writing request html to file: {:?}", err)
|
|
}
|
|
|
|
Ok(t)
|
|
},
|
|
Err(err) => Err(format!("Error getting text from response: {:?}", err)),
|
|
}
|
|
}
|
|
|
|
pub async fn register_courses_request(url: String, body: String) -> Result<String, String> {
|
|
let classroom_url = std::env::var("CLASSROOM_URL").expect("CLASSROOM_URL env var is not set!");
|
|
|
|
ensure_session().await?;
|
|
|
|
// Get the stored client
|
|
let jar = SESSION_COOKIE.read().unwrap().jar.clone();
|
|
|
|
let uri = format!("{}{}", classroom_url, url);
|
|
|
|
let response = Request::post(uri)
|
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
|
.cookie_jar(jar)
|
|
.body(body)
|
|
.or_else(|err| Err(format!("Error creating request: {:?}", err)))?
|
|
.send();
|
|
|
|
let mut response = match response {
|
|
Ok(r) => r,
|
|
Err(err) => return Err(format!("Error sending request: {:?}", err)),
|
|
};
|
|
|
|
match response.text() {
|
|
Ok(t) => {
|
|
// Get current time and date in iso
|
|
let now: DateTime<Local> = Local::now();
|
|
let now = now.to_rfc3339();
|
|
|
|
// Write html to file
|
|
let r = std::fs::write(format!("request-logs/{}.html", now), &t);
|
|
if let Err(err) = r {
|
|
eprintln!("Error writing request html to file: {:?}", err)
|
|
}
|
|
|
|
Ok(t)
|
|
},
|
|
Err(err) => Err(format!("Error getting text from response: {:?}", err)),
|
|
}
|
|
}
|
|
|
|
/// Makes sure that the session cookie is set, and that it is valid
|
|
pub async fn ensure_session() -> Result<(), String> {
|
|
let last_usage_time = SESSION_TIME.read().unwrap().clone();
|
|
|
|
// Get current time in seconds
|
|
let current_time = SystemTime::now()
|
|
.duration_since(UNIX_EPOCH)
|
|
.expect("Time went backwards")
|
|
.as_secs();
|
|
|
|
let time_passed = current_time - last_usage_time;
|
|
|
|
// Default PHP session timeout is 1440 seconds. Use a 1400 seconds timeout to be safe
|
|
if time_passed > 1400 {
|
|
login().await?;
|
|
|
|
let mut time_ptr = SESSION_TIME.write().unwrap();
|
|
*time_ptr = current_time;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Logins to the online classroom, and sets the session cookie
|
|
async fn login() -> Result<(), String> {
|
|
let classroom_url = std::env::var("CLASSROOM_URL").expect("CLASSROOM_URL env var is not set!");
|
|
let classroom_user =
|
|
std::env::var("CLASSROOM_USER").expect("CLASSROOM_USER env var is not set!");
|
|
let classroom_password =
|
|
std::env::var("CLASSROOM_PASSWORD").expect("CLASSROOM_PASSWORD env var is not set!");
|
|
|
|
let jar = CookieJar::new();
|
|
|
|
let response = Request::post(format!("{}/index.php", classroom_url))
|
|
.header("Content-Type", "application/x-www-form-urlencoded")
|
|
.cookie_jar(jar.clone())
|
|
.body(format!(
|
|
"login={}&password={}&submitAuth=&_qf__formLogin=",
|
|
encode(classroom_user.as_str()),
|
|
encode(classroom_password.as_str()),
|
|
))
|
|
.unwrap()
|
|
.send();
|
|
|
|
match response {
|
|
Ok(_) => {
|
|
SESSION_COOKIE.write().unwrap().jar = jar.clone();
|
|
Ok(())
|
|
}
|
|
Err(error) => Err(format!("Error connecting to online classroom: {:?}", error)),
|
|
}
|
|
}
|