diff --git a/README.md b/README.md index 8babc33..6cd6bdd 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ eg. `POST /api/users/change {"name":"example","pin":"10","changed_event":"name", DEPRECATED `POST /api/users/change////` Change a users pin/name Returns status & reason json. +`POST /api/logout {"name":""}` to logout a user if the token matches + ## Chat Documentation @@ -71,7 +73,7 @@ Whenever user sends a message, client will send message & token and backend will - [x] Have cookie expire - [x] Remove old cookie - [x] Use token for most stuff - - [ ] Logout API + - [x] Logout API - [x] Fail on NULL token - [x] Pronouns - [x] Set pronouns diff --git a/src/auth.rs b/src/auth.rs index bdc9b4a..5a11db3 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1,6 +1,6 @@ extern crate log; use crate::file_io::{db_add, db_write, db_read}; -use rocket::http::{Cookie, Cookies}; +use rocket::http::{Cookie, Cookies, SameSite}; use crate::user::User; use rocket_contrib::json::{Json, JsonValue}; use random_string::generate; @@ -132,6 +132,58 @@ pub fn check_token(name: String, mut cookies: Cookies) -> JsonValue { }); } +// logout event struct +#[derive(Deserialize, Debug)] +pub struct LogoutEvent { + pub name: String, +} + +// Logout API +#[post("/logout", format = "json", data = "")] +pub fn logout(info: Json, mut cookies: Cookies) -> JsonValue { + let mut users: Vec = db_read(); + for i in 0..users.len() { + if info.name.to_lowercase() == users[i].name { + let token = match cookies.get_private("token") { + None => { + warn!("couldn't get token cookie!"); + return json!({ + "status": "fail", + "reason": "could not read cookie", + }); + }, + Some(token) => token, + }; + if token.value() == "NULL" { + warn!("NULL token!"); + return json!({ + "status": "fail", + "reason": "NULL token", + }); + } else if token.value() == users[i].session_token { + cookies.remove_private(Cookie::named("token")); + users[i].session_token = "NULL".to_string(); + info!("logged out user {}", info.name); + return json!({ + "status": "ok", + "reason": "logged out", + }); + } else { + warn!("token does not match! cannot logout"); + return json!({ + "status": "fail", + "reason": "token does not match", + }); + } + } + } + warn!("logged out user {}, user not found", info.name); + return json!({ + "status": "fail", + "reason": "user not found", + }); +} + // Check if pin matches user #[get("/users//")] pub fn check_pin(mut cookies: Cookies, name: String, pin: i32) -> JsonValue { @@ -147,7 +199,6 @@ pub fn check_pin(mut cookies: Cookies, name: String, pin: i32) -> JsonValue { let token = create_token(i.name.clone(), users); let cookie = Cookie::build("token", token) .path("/") - .secure(true) .finish(); cookies.remove_private(Cookie::named("token")); cookies.add_private(cookie); @@ -181,7 +232,7 @@ pub fn check_pin(mut cookies: Cookies, name: String, pin: i32) -> JsonValue { } #[derive(Deserialize, Debug)] -pub struct Event { +pub struct ChangeEvent { pub name: String, pub pin: String, pub changed_event: String, @@ -190,11 +241,9 @@ pub struct Event { // Change info about a user #[post("/users/change", format = "json", data = "")] -pub fn change_info(input: Json, mut cookies: Cookies) -> JsonValue { - println!("{:?}", input); +pub fn change_info(input: Json, mut cookies: Cookies) -> JsonValue { // read in the users & hash the pin let mut users: Vec = db_read(); - let hashed_pin = sha1::Sha1::from(&input.pin).digest().to_string(); // get token from cookie let token = match cookies.get_private("token") { diff --git a/src/chat.rs b/src/chat.rs index 79e1d71..7d1d3f4 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -80,7 +80,7 @@ fn check_token(token: Cookie, message: Json>) -> JsonValue { warn!("token does not match!"); return json!({ "status": "fail", - "reason": "token does not match" + "reason": "token does not match", }) }; }; @@ -95,6 +95,15 @@ fn check_token(token: Cookie, message: Json>) -> JsonValue { // Receive a basic message #[post("/message/send", format = "json", data = "")] pub fn send_message(message: Json>, mut cookies: Cookies) -> JsonValue { - let token = cookies.get_private("token").unwrap(); + let token = match cookies.get_private("token") { + None => { + warn!("couldn't get token cookie!"); + return json!({ + "status": "fail", + "reason": "could not read cookie", + }); + }, + Some(token) => token, + }; check_token(token, message) } diff --git a/src/main.rs b/src/main.rs index 6f01d34..42a9a1c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,7 @@ fn main() { env_logger::init(); info!("Started up rocket"); let cors_fairing = AdHoc::on_response("CORS", |_, res| { - res.set_raw_header("Access-Control-Allow-Origin", "*"); + res.set_raw_header("Access-Control-Allow-Origin", "http://localhost:8000"); }); info!("Built CORS fairing"); @@ -36,7 +36,8 @@ fn main() { chat::send_message, chat::fetch_messages, auth::change_info, - auth::check_token + auth::check_token, + auth::logout ], ) .mount("/", StaticFiles::from("frontend"))