use std::fs; use std::path::Path; use rocket; use rocket::fs::{FileServer, NamedFile, relative}; use rocket::http::{CookieJar, Cookie, Status}; use rocket::request::{FromRequest, Outcome}; use rocket::{Request, routes, uri}; use rocket_cors::{AllowedHeaders, AllowedOrigins, Cors}; use rocket::serde::json::Json; use crate::{data, file}; use crate::data::deserialize; use crate::file::PATH; struct Token(String); #[derive(Debug)] enum ApiTokenError { Missing, } #[derive(serde::Deserialize)] #[serde(crate = "rocket::serde")] struct Text<'r> { text: &'r str, } #[rocket::async_trait] impl<'r> FromRequest<'r> for Token { type Error = ApiTokenError; async fn from_request(request: &'r Request<'_>) -> rocket::request::Outcome { let token = request.headers().get_one("token"); match token { Some(token) => { // check validity Outcome::Success(Token(token.to_string())) } None => Outcome::Failure((Status::Unauthorized, ApiTokenError::Missing)), } } } fn make_cors() -> Cors { rocket_cors::CorsOptions { allowed_origins: AllowedOrigins::all(), allowed_headers: AllowedHeaders::some(&["Authorization", "Accept"]), allow_credentials: true, ..Default::default() } .to_cors() .expect("error while building CORS") } #[rocket::get("/")] fn get_text() -> String { let content = data::deserialize(fs::read_to_string(&file::PATH).expect("")); if content.is_err() { return "".to_string(); } return content.unwrap().text; } #[rocket::get("/edit")] async fn edit_get() -> Option { let path = Path::new(relative!("public")).join("edit.html"); NamedFile::open(path).await.ok() } #[rocket::post("/login")] fn login(token: Token, cookies: &CookieJar<'_>) -> String { let temp = fs::read_to_string(PATH); if temp.is_err() { return "/".to_string(); } let content = deserialize(temp.unwrap()); let token_int = token.0.parse::(); if token_int.is_err() { return "/".to_string(); } if content.is_ok() { if content.unwrap().password == token.0.parse::().unwrap() { cookies.add_private(Cookie::new("Token", token.0)); return uri!(edit_get).to_string(); } } return "/".to_string(); } #[rocket::post("/edit", format = "json", data = "")] fn edit(text: Json>, cookies: &CookieJar<'_>) -> String { let temp = fs::read_to_string(PATH); if temp.is_err() { return "/".to_string(); } let content = deserialize(temp.unwrap()); let token = cookies.get_private("Token"); if token.is_none() { return "/".to_string(); } let token_int = token.unwrap().value().parse::(); if token_int.is_err() { return "/".to_string(); } if content.is_ok() { let mut data = content.unwrap(); if data.password == token_int.unwrap() { data.text = text.text.to_string(); file::write_file(data); return "/".to_string(); } } return "/".to_string(); } #[rocket::main] pub async fn main() -> Result<(), rocket::Error> { let _rocket = rocket::build() .mount("/", FileServer::from("public/")) .mount("/", routes![login, edit_get]) .mount("/api", routes![get_text, edit]) .manage(make_cors()) .launch() .await?; Ok(()) }