[BE][Class] Get session cookie and store it for ~20m
This commit is contained in:
parent
5992908ce6
commit
b55e05eeb4
23
backend/src/online_classroom/json_result.rs
Normal file
23
backend/src/online_classroom/json_result.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
use rocket::serde::json::Json;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub enum JsonResult<A> {
|
||||||
|
Ok(A),
|
||||||
|
Error(JsonError),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct JsonError {
|
||||||
|
reason: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> JsonResult<A> {
|
||||||
|
pub fn error(reason: String) -> Json<JsonResult<A>> {
|
||||||
|
Json(JsonResult::Error(JsonError { reason }))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ok(data: A) -> Json<JsonResult<A>> {
|
||||||
|
Json(JsonResult::Ok(data))
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,13 @@ use reqwest::Client;
|
|||||||
use rocket::{http::Status, serde::json::Json};
|
use rocket::{http::Status, serde::json::Json};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
static SESSION_COOKIE: OnceCell<String> = OnceCell::new();
|
use self::session::ensure_session;
|
||||||
|
|
||||||
|
pub mod json_result;
|
||||||
|
mod session;
|
||||||
|
pub mod users;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub enum ConnectionResult {
|
pub enum ConnectionResult {
|
||||||
@ -22,64 +28,10 @@ fn new_error(reason: String) -> ConnectionResult {
|
|||||||
/// Tries to connect to the online classroom, and get a session cookie
|
/// Tries to connect to the online classroom, and get a session cookie
|
||||||
#[get("/classroom/connect")]
|
#[get("/classroom/connect")]
|
||||||
pub async fn connection() -> (Status, Json<ConnectionResult>) {
|
pub async fn connection() -> (Status, Json<ConnectionResult>) {
|
||||||
// Get session cookie
|
match ensure_session().await {
|
||||||
let _cookie = match get_cookie().await {
|
Ok(_) => (Status::Ok, Json(ConnectionResult::Ok())),
|
||||||
Ok(cookie) => cookie,
|
Err(err) => (Status::Ok, Json(new_error(err))),
|
||||||
Err(reason) => return (Status::InternalServerError, Json(new_error(reason))),
|
|
||||||
};
|
|
||||||
|
|
||||||
(Status::Ok, Json(ConnectionResult::Ok()))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn get_cookie<'a>() -> Result<&'a String, String> {
|
|
||||||
match SESSION_COOKIE.get() {
|
|
||||||
Some(cookie) => Ok(cookie),
|
|
||||||
None => {
|
|
||||||
// Try to create cookie
|
|
||||||
let _ = create_cookie().await?;
|
|
||||||
|
|
||||||
// Try to get cookie again
|
|
||||||
match SESSION_COOKIE.get() {
|
|
||||||
Some(cookie) => Ok(cookie),
|
|
||||||
None => Err("Error getting session cookie".into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to connect to the online classroom, and get a session cookie.
|
|
||||||
/// Stores the session coookie in a global static variable.
|
|
||||||
pub async fn create_cookie() -> Result<(), String> {
|
|
||||||
let clasroom_url = std::env::var("CLASSROOM_URL").expect("CLASSROOM_URL env var is not set!");
|
|
||||||
let clasroom_user =
|
|
||||||
std::env::var("CLASSROOM_USER").expect("CLASSROOM_USER env var is not set!");
|
|
||||||
let clasroom_password =
|
|
||||||
std::env::var("CLASSROOM_PASSWORD").expect("CLASSROOM_PASSWORD env var is not set!");
|
|
||||||
|
|
||||||
let params = [
|
|
||||||
("login", clasroom_user),
|
|
||||||
("password", clasroom_password),
|
|
||||||
("submitAuth", "".into()),
|
|
||||||
("_qf__formLogin", "".into()),
|
|
||||||
];
|
|
||||||
let client = Client::new();
|
|
||||||
let result = client
|
|
||||||
.post(format!("{}/index.php", clasroom_url))
|
|
||||||
.form(¶ms)
|
|
||||||
.send()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(response) => {
|
|
||||||
let Some(session_cookie) = response.cookies().find(|c| c.name() == "ch_sid") else {
|
|
||||||
return Err("Response succeeded, but no session cookie was foun".into());
|
|
||||||
};
|
|
||||||
|
|
||||||
match SESSION_COOKIE.set(session_cookie.value().into()) {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(error) => Err(format!("Error setting session cookie: {:?}", error)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(error) => Err(format!("Error connecting to online classroom: {:?}", error)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
75
backend/src/online_classroom/session.rs
Normal file
75
backend/src/online_classroom/session.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use reqwest::Client;
|
||||||
|
|
||||||
|
static SESSION_COOKIE: OnceCell<String> = OnceCell::new();
|
||||||
|
static SESSION_TIME: OnceCell<u64> = OnceCell::new();
|
||||||
|
|
||||||
|
/// Makes a request to the online classroom, and returns the html string
|
||||||
|
pub async fn request(url: String) -> Result<String, String> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Makes sure that the session cookie is set, and that it is valid
|
||||||
|
pub async fn ensure_session() -> Result<(), String> {
|
||||||
|
let last_usage_time = match SESSION_TIME.get() {
|
||||||
|
Some(time) => *time,
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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?;
|
||||||
|
if let Err(err) = SESSION_TIME.set(current_time) {
|
||||||
|
return Err(format!("Error setting session time: {:?}", err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Logins to the online classroom, and sets the session cookie
|
||||||
|
async fn login() -> Result<(), String> {
|
||||||
|
let clasroom_url = std::env::var("CLASSROOM_URL").expect("CLASSROOM_URL env var is not set!");
|
||||||
|
let clasroom_user =
|
||||||
|
std::env::var("CLASSROOM_USER").expect("CLASSROOM_USER env var is not set!");
|
||||||
|
let clasroom_password =
|
||||||
|
std::env::var("CLASSROOM_PASSWORD").expect("CLASSROOM_PASSWORD env var is not set!");
|
||||||
|
|
||||||
|
let params = [
|
||||||
|
("login", clasroom_user),
|
||||||
|
("password", clasroom_password),
|
||||||
|
("submitAuth", "".into()),
|
||||||
|
("_qf__formLogin", "".into()),
|
||||||
|
];
|
||||||
|
let client = Client::new();
|
||||||
|
let result = client
|
||||||
|
.post(format!("{}/index.php", clasroom_url))
|
||||||
|
.form(¶ms)
|
||||||
|
.send()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(response) => {
|
||||||
|
let Some(session_cookie) = response.cookies().find(|c| c.name() == "ch_sid") else {
|
||||||
|
return Err("Response succeeded, but no session cookie was foun".into());
|
||||||
|
};
|
||||||
|
|
||||||
|
match SESSION_COOKIE.set(session_cookie.value().into()) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(error) => Err(format!("Error setting session cookie: {:?}", error)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(error) => Err(format!("Error connecting to online classroom: {:?}", error)),
|
||||||
|
}
|
||||||
|
}
|
15
backend/src/online_classroom/users.rs
Normal file
15
backend/src/online_classroom/users.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use rocket::{http::Status, serde::json::Json};
|
||||||
|
|
||||||
|
use super::{ json_result::JsonResult};
|
||||||
|
|
||||||
|
// Instead of requesting pages and managing session & cookies manually,
|
||||||
|
// create a wrapper that:
|
||||||
|
// - Checks if the session cookie is valid
|
||||||
|
// - If not, tries to login
|
||||||
|
// - Makes the request
|
||||||
|
// - Returns the html string, or an error
|
||||||
|
|
||||||
|
#[get("/classroom/users/<full_name>")]
|
||||||
|
pub async fn get_users(full_name: String) -> (Status, Json<JsonResult<()>>) {
|
||||||
|
(Status::Ok, JsonResult::ok(()))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user