diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d13b2c4 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,19 @@ +## 0.5.0 +- Most actions should now fail on a NULL token +- Cookie should now expire after a week +- Use sled database instead of json file to store users + +## 0.4.0 +- Serve frontend code +- Set cookie for token +- Basic messaging functionality +- Return JSON for all http requests +- License added (CNPLv6+) + +## 0.3.0 +- Add todo and other info to README +- Add chat core + +## 0.2.0 +- Basic functionality added +- Program is split into multiple files diff --git a/Cargo.toml b/Cargo.toml index 320e7f1..26d401a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pogchat" -version = "0.4.0" +version = "0.5.0" authors = ["Erin Nova "] edition = "2018" diff --git a/README.md b/README.md index 3dcaf2b..8babc33 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,9 @@ or }, }` -`GET /api/users//` Check if the user exists, and if the pin provided matches +`GET /api/token/` Check if the current token matches the user provided + +DEPRECATED `GET /api/users//` Check if the user exists, and if the pin provided matches Returns status & reason json. `POST /api/users/change {"name":"","pin":"","changed_event":"name/pin/pronouns","new_event":""` Change a users details via a json post. @@ -59,13 +61,18 @@ Whenever user sends a message, client will send message & token and backend will - [x] Basic messaging system - [x] Finish up `chat::create_message()` - [x] Create `chat::fetch_messages()` + - [ ] Use unix timestamp for date - [ ] Create `chat::delete_message()` - [x] Switch to using sled database to store users + - [ ] Error handling - [x] Token generation & storage - [x] Sets cookie - [x] Store token in json - [x] Have cookie expire - [x] Remove old cookie + - [x] Use token for most stuff + - [ ] Logout API + - [x] Fail on NULL token - [x] Pronouns - [x] Set pronouns - [ ] Change pronouns diff --git a/src/auth.rs b/src/auth.rs index 09e1007..bdc9b4a 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -88,6 +88,50 @@ fn create_token(name: String, mut users: Vec) -> String { return "NULL".to_string(); } +// Check if user is properly logged in +#[get("/token/")] +pub fn check_token(name: String, mut cookies: Cookies) -> JsonValue { + let users: Vec = db_read(); + for i in &users { + if i.name == name.to_lowercase() { + 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() == i.session_token { + info!("user {} has correct session token", name); + return json!({ + "status": "ok", + "reason": "correct token", + }); + } else { + info!("user {} has incorrect token!", name); + return json!({ + "status": "fail", + "reason": "incorrect token", + }); + } + } + } + warn!("user {} not found", 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 { @@ -146,16 +190,35 @@ pub struct Event { // Change info about a user #[post("/users/change", format = "json", data = "")] -pub fn change_info(input: Json) -> JsonValue { +pub fn change_info(input: Json, mut cookies: Cookies) -> JsonValue { println!("{:?}", input); // 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") { + 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", + }); + } // loop through the users for i in 0..users.len() { if input.name.to_lowercase() == users[i].name { // if user found... - if hashed_pin == users[i].pin_hashed { // & if pin matches: + if token.value() == users[i].session_token { // & if token matches: if input.changed_event == "name" { // change the name users[i].name = input.new_event.clone(); @@ -212,8 +275,8 @@ pub fn change(name: String, pin: i32, new_name: String, new_pin: i32) -> JsonVal for i in 0..users.len() { if users[i].name == name.to_lowercase() { // make sure name exists - if users[i].pin_hashed == hashed_pin_input { - // check if pin is correct + if hashed_pin_input == users[i].pin_hashed { + // check if token is correct // Check wether to change name or name+pin if users[i].name == new_name.to_lowercase() { // check if new name already exists @@ -265,10 +328,10 @@ pub fn change(name: String, pin: i32, new_name: String, new_pin: i32) -> JsonVal }); } } else { - warn!("Incorrect pin given for user {}!", name.to_string()); + warn!("Incorrect token for user {}!", name.to_string()); return json!({ "status": "fail", - "reason": "incorrect pin for user", + "reason": "incorrect token for user", }); } } diff --git a/src/chat.rs b/src/chat.rs index ee2b1c8..1163453 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -67,7 +67,13 @@ fn check_token(token: Cookie, message: Json>) -> JsonValue { for i in &users { // loop through elements if i.name == message.name.to_lowercase() { // if it finds the user in the file - if i.session_token == token.value() { // if token matches + if token == "NULL" { + warn!("NULL token!"); + return json!({ + "status": "fail", + "reason": "NULL token", + }); + } else if i.session_token == token.value() { // if token matches info!("user exists and given token matches"); return create_message(message, "messages.json", i); } else { diff --git a/src/main.rs b/src/main.rs index a3db2e1..6f01d34 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,7 +35,8 @@ fn main() { auth::change, chat::send_message, chat::fetch_messages, - auth::change_info + auth::change_info, + auth::check_token ], ) .mount("/", StaticFiles::from("frontend"))