commit
d10db5d31b
|
@ -2,4 +2,5 @@
|
|||
.vscode
|
||||
users.json
|
||||
message.zsh
|
||||
TODO.md
|
||||
users_db/
|
||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -1,3 +1,19 @@
|
|||
## 0.6.0
|
||||
- Remove deprecated API
|
||||
- `/api/register` & `/api/login` now use JSON data
|
||||
- Changing user info now uses Enum (Name, Pin, or Pronouns)
|
||||
|
||||
### 0.5.2
|
||||
- When changing a username, it now deletes the previous user instead of creating a new one
|
||||
- Database functions should now use some error handling
|
||||
- Functions use `db_read_user()` instead of reading in the whole database
|
||||
|
||||
### 0.5.1
|
||||
- `/api/logout` API to delete session token
|
||||
- Add basic support for different message types
|
||||
- Messages now use unix timestamps
|
||||
- Backend finds timestamp
|
||||
|
||||
## 0.5.0
|
||||
- Most actions should now fail on a NULL token
|
||||
- Cookie should now expire after a week
|
||||
|
|
|
@ -228,9 +228,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "crypto-mac"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4857fd85a0c34b3c3297875b747c1e02e06b6a0ea32dd892d8192b9ce0813ea6"
|
||||
checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"subtle",
|
||||
|
@ -301,9 +301,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.4.1"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77b705829d1e87f762c2df6da140b26af5839e1033aa84aa5f56bb688e4e1bdb"
|
||||
checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
@ -572,9 +572,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.97"
|
||||
version = "0.2.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6"
|
||||
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
|
@ -807,7 +807,7 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
|||
|
||||
[[package]]
|
||||
name = "pogchat"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"chrono",
|
||||
|
@ -1062,7 +1062,7 @@ checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
|
|||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.73",
|
||||
"syn 1.0.74",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1148,9 +1148,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.73"
|
||||
version = "1.0.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7"
|
||||
checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.27",
|
||||
"quote 1.0.9",
|
||||
|
@ -1178,9 +1178,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.2.0"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342"
|
||||
checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
@ -1259,9 +1259,9 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
|||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8326b2c654932e3e4f9196e69d08fdf7cfd718e1dc6f66b347e6024a0c961402"
|
||||
checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"subtle",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pogchat"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
authors = ["Erin Nova <erin@the-system.eu.org>"]
|
||||
edition = "2018"
|
||||
|
||||
|
|
129
README.md
129
README.md
|
@ -1,54 +1,95 @@
|
|||
# Chat Registration System
|
||||
|
||||
The basic backend code needed to register & login to a chat system (to be built).
|
||||
Send it the unhashed username and pin, and it'll store it in the database with the pin hashed with SHA1.
|
||||
A simple chat system for built for maya's livestream.
|
||||
Provides a simple API for user authentication, and chat functions.
|
||||
Frontend & backend code stored here.
|
||||
|
||||
## API Documentation
|
||||
## Auth API Documentation
|
||||
|
||||
`POST /api/register {"name":"<username>","pin":"<pin>","pronouns":"<pronouns>"}` Register a user if they don't already exist
|
||||
Most API functions will return JSON in the following format:
|
||||
|
||||
`POST /api/register/<name>/<pin>/<pronouns>` Register the username with the pin provided if it doesn't already exist
|
||||
Returns status & reason json.
|
||||
`status`: either `ok` if action succeeded, or `fail` otherwise.
|
||||
|
||||
`GET /api/users/<name>` Check if the user exists
|
||||
Returns either
|
||||
`reason`: More info about why the action failed.
|
||||
|
||||
`{
|
||||
"status": "fail",
|
||||
"reason": "user not found",
|
||||
}`
|
||||
### Register & Login:
|
||||
|
||||
or
|
||||
`POST /api/register` with JSON body values of: `name`, `pin`, `pronouns`.
|
||||
|
||||
`{
|
||||
"status": "ok",
|
||||
"user": {
|
||||
"name": "<name>",
|
||||
"pronouns": "<pronouns>",
|
||||
Will return JSON with `status` and `reason`.
|
||||
|
||||
`POST /api/login` with JSON body values of: `name`, `pin`.
|
||||
|
||||
Will return JSON with `status` and `reason`.
|
||||
|
||||
Will set a private cookie named `token` which is used for authentication.
|
||||
|
||||
### Change User Information
|
||||
|
||||
User information such as name, pin, and pronouns, can be changed currently one at a time.
|
||||
|
||||
`POST /api/change` with JSON body values of: `name`, `changed_event`, `new_event`.
|
||||
|
||||
`name` the user's current username. used for authentication.
|
||||
|
||||
`changed_event` which event to change. value can be one of: `Name`, `Pin`, `Pronouns`.
|
||||
|
||||
`new_event` the new value for the changed event.
|
||||
|
||||
User is authenticated via token.
|
||||
|
||||
### Check if User is Still Logged in
|
||||
|
||||
Instead of having to save the pin and re-login every time to check wether they're logged in, you can just check via the token.
|
||||
|
||||
`GET /api/token/<name>` where `<name>` is the current username.
|
||||
|
||||
Will return JSON with `status` and `reason`.
|
||||
|
||||
### Logout
|
||||
|
||||
This API will remove the cookie from the client, as well as invalidating the token serverside.
|
||||
|
||||
`POST /api/logout` with JSON body values of: `name`.
|
||||
|
||||
Will use the current token as authentication.
|
||||
|
||||
Will return JSON with `status` and `reason`.
|
||||
|
||||
### Get Info About A User
|
||||
|
||||
This API will return info about a user on success.
|
||||
|
||||
`GET /api/users/<name>`
|
||||
|
||||
On success returns JSON in format:
|
||||
|
||||
`status`: `ok`
|
||||
`user`:
|
||||
`name`: user's name
|
||||
`pronouns`: user's pronouns
|
||||
`role`: the users role, one of either `Normal`, `Moderator`, or `Admin
|
||||
|
||||
eg:
|
||||
|
||||
```
|
||||
{
|
||||
status: "ok",
|
||||
user: {
|
||||
name: "example",
|
||||
pronouns: "they/them",
|
||||
role: "Normal",
|
||||
},
|
||||
}`
|
||||
}
|
||||
```
|
||||
|
||||
`GET /api/token/<name>` Check if the current token matches the user provided
|
||||
## Chat API Documentation
|
||||
|
||||
`GET /api/users/<name>/<pin>` Check if the user exists, and if the pin provided matches
|
||||
Returns status & reason json.
|
||||
`POST /api/message/send {"name":"username","body":"message body"}` Post a message with JSON body values of: `name` & `body`
|
||||
|
||||
`POST /api/users/change {"name":"<username>","pin":"<pin>","changed_event":"name/pin/pronouns","new_event":"<new name/pin/pronouns>"` Change a users details via a json post.
|
||||
Will return JSON with `status` and `reason`.
|
||||
|
||||
eg. `POST /api/users/change {"name":"example","pin":"10","changed_event":"name","new_event":"test"` to change the user "example"'s name to "test"
|
||||
|
||||
DEPRECATED `POST /api/users/change/<name>/<pin>/<new-name>/<new-pin>` Change a users pin/name
|
||||
Returns status & reason json.
|
||||
|
||||
`POST /api/logout {"name":"<username>"}` to logout a user if the token matches
|
||||
|
||||
|
||||
## Chat Documentation
|
||||
|
||||
`POST /api/message/send {"name":"username","body":"message body","date":"yyyy-mm-dd"}` Post a json message.
|
||||
Returns status & reason json.
|
||||
|
||||
`GET /api/message/messages.json` Get a json file of all the messages
|
||||
`GET /api/message/messages.json` Returns a json file of all the messages
|
||||
|
||||
## Chat Planning
|
||||
|
||||
|
@ -65,10 +106,10 @@ 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
|
||||
- [x] Use unix timestamp for date
|
||||
- [ ] Create `chat::delete_message()`
|
||||
- [x] Switch to using sled database to store users
|
||||
- [ ] Error handling
|
||||
- [x] Error handling
|
||||
- [x] Token generation & storage
|
||||
- [x] Sets cookie
|
||||
- [x] Store token in json
|
||||
|
@ -79,11 +120,15 @@ Whenever user sends a message, client will send message & token and backend will
|
|||
- [x] Fail on NULL token
|
||||
- [x] Pronouns
|
||||
- [x] Set pronouns
|
||||
- [ ] Change pronouns
|
||||
- [ ] Multiple sets of pronouns
|
||||
- [x] Change pronouns
|
||||
- [x] make changed_event Enum, use token instead of pin
|
||||
- [ ] Some form of plural support?
|
||||
- [ ] User management (banning, etc.)
|
||||
- [x] User roles (admin, mod, etc.)
|
||||
- [ ] Commands to affect users
|
||||
- [ ] Blacklist words from chat/names
|
||||
- [ ] More advanced chat features
|
||||
- [ ] Different types of message events? eg. default, announcement, command
|
||||
- [x] Different types of message events? eg. default, announcement, command
|
||||
- [ ] Types will display differently? eg. announcements pinned to top?
|
||||
- [ ] Have different commands?
|
||||
- [ ] Emote support?
|
||||
|
|
|
@ -1 +1 @@
|
|||
http POST 'http://localhost:8000/api/message/send' name=erin body="nyaa uwu" date="2021-07-21"
|
||||
http POST 'http://localhost:8000/api/mod' name=erin action=Ban target=sarah
|
||||
|
|
524
src/auth.rs
524
src/auth.rs
|
@ -1,66 +1,33 @@
|
|||
extern crate log;
|
||||
use crate::file_io::{db_add, db_write, db_read};
|
||||
use rocket::http::{Cookie, Cookies, SameSite};
|
||||
use crate::user::User;
|
||||
use crate::file_io::*;
|
||||
use rocket::http::{Cookie, Cookies};
|
||||
use crate::user::*;
|
||||
use rocket_contrib::json::{Json, JsonValue};
|
||||
use random_string::generate;
|
||||
extern crate sha1;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[get("/")]
|
||||
pub fn index() -> &'static str {
|
||||
"API Info:
|
||||
|
||||
`POST /api/register/<name>/<pin>/<pronouns>` Register the username with the pin provided if it doesn't already exist
|
||||
|
||||
`GET /api/users/<name>` Check if the user exists
|
||||
|
||||
`GET /api/users/<name>/<pin>` Check if the user exists, and if the pin provided matches
|
||||
|
||||
`POST /api/users/change/<name>/<pin>/<new-name>/<new-pin>` Change a users name and/or pin
|
||||
|
||||
`GET /api/about/name/<name>` Get the name of a user
|
||||
|
||||
`GET /api/about/pronouns/<name>` Get the pronouns of a user"
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct RegisterEvent {
|
||||
pub name: String,
|
||||
pub pin: String,
|
||||
pub pronouns: String,
|
||||
}
|
||||
|
||||
// Post request to register a user and pin
|
||||
#[post("/register", format = "json", data = "<info>")]
|
||||
pub fn register_user(info: Json<RegisterEvent>) -> JsonValue {
|
||||
let users: Vec<User> = db_read(); // Create an array of users out of parsed json
|
||||
for i in &users {
|
||||
// loop through elements of the vector
|
||||
if i.name == info.name.to_lowercase() {
|
||||
warn!("Cannot create user {}! User is already in system.", i.name);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "user already exists",
|
||||
});
|
||||
#[post("/register", format = "json", data = "<data>")]
|
||||
pub fn register(data: Json<RegisterEvent>) -> JsonValue {
|
||||
// check if the user exists
|
||||
if let Some(user) = db_read_user(&data.name).ok().flatten() {
|
||||
warn!("Cannot create user {}! User is already in system.", data.name);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "user already exists",
|
||||
});
|
||||
} else {
|
||||
let pin_hashed = sha1::Sha1::from(&data.pin).digest().to_string(); // hash the pin
|
||||
|
||||
let new_user: User = User {
|
||||
name: data.name.to_string().to_lowercase(),
|
||||
pin_hashed,
|
||||
pronouns: data.pronouns.to_string().to_lowercase(),
|
||||
session_token: "NULL".to_string(),
|
||||
role: UserType::Normal,
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
let pin_hashed = sha1::Sha1::from(&info.pin.to_string()).digest().to_string(); // hash the pin
|
||||
|
||||
let new_user: User = User {
|
||||
name: info.name.to_string().to_lowercase(),
|
||||
pin_hashed: pin_hashed,
|
||||
pronouns: info.pronouns.to_string().to_lowercase(),
|
||||
session_token: "NULL".to_string(),
|
||||
}; // append the user to the vec
|
||||
|
||||
/*
|
||||
// append to the json file
|
||||
match append_json(&new_user) {
|
||||
Err(why) => panic!("couldn't append json: {}", why),
|
||||
Ok(()) => info!("Succesfully appended to json"),
|
||||
};*/
|
||||
db_add(&new_user);
|
||||
|
||||
info!(
|
||||
|
@ -72,25 +39,20 @@ pub fn register_user(info: Json<RegisterEvent>) -> JsonValue {
|
|||
"status": "ok",
|
||||
"reason": format!("user {} registered", new_user.name.to_string().to_lowercase()),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn create_token(name: String, mut users: Vec<User>) -> String {
|
||||
fn create_token(name: String, mut user: User) -> String {
|
||||
let charset = "1234567890abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
for i in 0..users.len() {
|
||||
if users[i].name == name {
|
||||
users[i].session_token = generate(12, charset);
|
||||
/*
|
||||
match write_json(&users) {
|
||||
Err(why) => panic!("coudln't write to file: {}", why),
|
||||
Ok(()) => info!("succesfully wrote to file"),
|
||||
};*/
|
||||
db_write(&users);
|
||||
info!("succesfully created token for user {}", name);
|
||||
let token = users[i].session_token.clone();
|
||||
return token;
|
||||
};
|
||||
if user.name == name {
|
||||
user.session_token = generate(12, charset);
|
||||
db_add(&user);
|
||||
info!("succesfully created token for user {}", name);
|
||||
let token = user.session_token.clone();
|
||||
return token;
|
||||
};
|
||||
|
||||
warn!("something bad happened while creating a token and idk what");
|
||||
return "NULL".to_string();
|
||||
}
|
||||
|
@ -98,159 +60,141 @@ fn create_token(name: String, mut users: Vec<User>) -> String {
|
|||
// Check if user is properly logged in
|
||||
#[get("/token/<name>")]
|
||||
pub fn check_token(name: String, mut cookies: Cookies) -> JsonValue {
|
||||
let users: Vec<User> = 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!");
|
||||
// check if the user is in the system
|
||||
if let Some(user) = db_read_user(&name).ok().flatten() {
|
||||
// get the token from the cookie
|
||||
let token = match cookies.get_private("token") {
|
||||
None => {
|
||||
warn!("couldn't get token cookie!");
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "NULL token",
|
||||
"reason": "could not read cookie",
|
||||
});
|
||||
} 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",
|
||||
});
|
||||
}
|
||||
},
|
||||
Some(token) => token,
|
||||
};
|
||||
|
||||
// check the token value
|
||||
if token.value() == "NULL" {
|
||||
warn!("NULL token!");
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "NULL token",
|
||||
});
|
||||
} else if token.value() == user.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",
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("user {} not found", name);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "user not found",
|
||||
});
|
||||
}
|
||||
|
||||
// logout event struct
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct LogoutEvent {
|
||||
pub name: String,
|
||||
}
|
||||
}
|
||||
|
||||
// Logout API
|
||||
#[post("/logout", format = "json", data = "<info>")]
|
||||
pub fn logout(info: Json<LogoutEvent>, mut cookies: Cookies) -> JsonValue {
|
||||
let mut users: Vec<User> = 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!");
|
||||
if let Some(mut user) = db_read_user(&info.name.to_lowercase()).ok().flatten() {
|
||||
let token = match cookies.get_private("token") {
|
||||
None => {
|
||||
warn!("couldn't get token cookie!");
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "NULL token",
|
||||
"reason": "could not read cookie",
|
||||
});
|
||||
} 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",
|
||||
});
|
||||
}
|
||||
},
|
||||
Some(token) => token,
|
||||
};
|
||||
if token.value() == "NULL" {
|
||||
warn!("NULL token!");
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "NULL token",
|
||||
});
|
||||
} else if token.value() == user.session_token {
|
||||
cookies.remove_private(Cookie::named("token"));
|
||||
user.session_token = "NULL".to_string();
|
||||
db_add(&user);
|
||||
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",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
warn!("failed to log out user {}, user not found", info.name);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "user not found",
|
||||
});
|
||||
}
|
||||
warn!("logged out user {}, user not found", info.name);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "user not found",
|
||||
});
|
||||
}
|
||||
|
||||
// Check if pin matches user
|
||||
#[get("/users/<name>/<pin>")]
|
||||
pub fn login(mut cookies: Cookies, name: String, pin: i32) -> JsonValue {
|
||||
let users: Vec<User> = db_read();
|
||||
let hashed_pin_input = sha1::Sha1::from(&pin.to_string()).digest().to_string();
|
||||
for i in &users {
|
||||
// loop through the vector
|
||||
if i.name == name.to_lowercase() {
|
||||
if i.pin_hashed == hashed_pin_input {
|
||||
info!("pin correct for user {}", i.name);
|
||||
#[post("/login", format = "json", data = "<data>")]
|
||||
pub fn login(data: Json<LoginEvent>, mut cookies: Cookies) -> JsonValue {
|
||||
if let Some(user) = db_read_user(&data.name.to_lowercase()).ok().flatten() {
|
||||
let hashed_pin_input = sha1::Sha1::from(&data.pin.to_string()).digest().to_string();
|
||||
|
||||
// Create token for user & set a cookie
|
||||
let token = create_token(i.name.clone(), users);
|
||||
let cookie = Cookie::build("token", token)
|
||||
.path("/")
|
||||
.same_site(SameSite::Strict)
|
||||
.secure(true)
|
||||
.finish();
|
||||
cookies.remove_private(Cookie::named("token"));
|
||||
cookies.add_private(cookie);
|
||||
info!("set the token cookie");
|
||||
if user.pin_hashed == hashed_pin_input { // check if pin hash matches
|
||||
info!("pin correct for user {}", &user.name);
|
||||
|
||||
return json!({
|
||||
"status": "ok",
|
||||
"reason": "pin matches",
|
||||
});
|
||||
} else {
|
||||
cookies.remove_private(Cookie::named("token"));
|
||||
info!("removed private cookie");
|
||||
warn!("pin incorrect for user {}", i.name);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "incorrect pin",
|
||||
});
|
||||
};
|
||||
// Create token for user & set a cookie
|
||||
let token = create_token(user.name.clone(), user);
|
||||
let cookie = Cookie::build("token", token)
|
||||
.path("/")
|
||||
.finish();
|
||||
cookies.remove_private(Cookie::named("token"));
|
||||
cookies.add_private(cookie);
|
||||
info!("set the token cookie");
|
||||
|
||||
return json!({
|
||||
"status": "ok",
|
||||
"reason": "pin matches",
|
||||
});
|
||||
} else {
|
||||
cookies.remove_private(Cookie::named("token"));
|
||||
info!("removed private cookie");
|
||||
warn!("pin incorrect for user {}", user.name);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "incorrect pin",
|
||||
});
|
||||
};
|
||||
} else {
|
||||
cookies.remove_private(Cookie::named("token"));
|
||||
info!("removed private cookie");
|
||||
warn!(
|
||||
"cannot check pin for user {} as they do not exist",
|
||||
data.name.to_string().to_lowercase()
|
||||
);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": format!("user {} doesn't exist", data.name.to_string().to_lowercase()),
|
||||
});
|
||||
}
|
||||
cookies.remove_private(Cookie::named("token"));
|
||||
info!("removed private cookie");
|
||||
warn!(
|
||||
"cannot check pin for user {} as they do not exist",
|
||||
name.to_string().to_lowercase()
|
||||
);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": format!("user {} doesn't exist", name.to_string().to_lowercase()),
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ChangeEvent {
|
||||
pub name: String,
|
||||
pub pin: String,
|
||||
pub changed_event: String,
|
||||
pub new_event: String,
|
||||
}
|
||||
|
||||
// Change info about a user
|
||||
#[post("/users/change", format = "json", data = "<input>")]
|
||||
#[post("/change", format = "json", data = "<input>")]
|
||||
pub fn change_info(input: Json<ChangeEvent>, mut cookies: Cookies) -> JsonValue {
|
||||
// read in the users & hash the pin
|
||||
let mut users: Vec<User> = db_read();
|
||||
|
@ -274,134 +218,61 @@ pub fn change_info(input: Json<ChangeEvent>, mut cookies: Cookies) -> JsonValue
|
|||
});
|
||||
}
|
||||
|
||||
// loop through the users
|
||||
for i in 0..users.len() {
|
||||
if input.name.to_lowercase() == users[i].name { // if user found...
|
||||
if token.value() == users[i].session_token { // & if token matches:
|
||||
if input.changed_event == "name" {
|
||||
// find the user
|
||||
if let Some(mut user) = db_read_user(&input.name).ok().flatten() {
|
||||
if token.value() == user.session_token { // & if token matches:
|
||||
match input.changed_event {
|
||||
ChangeEventType::Name => {
|
||||
// remove the user first
|
||||
db_remove(&user);
|
||||
// change the name
|
||||
users[i].name = input.new_event.clone();
|
||||
user.name = input.new_event.clone();
|
||||
info!("changed name of {} to {}", input.name, input.new_event);
|
||||
db_write(&users);
|
||||
db_add(&user);
|
||||
return json!({
|
||||
"status": "ok",
|
||||
"reason": format!("changed name of {} to {}", input.name, input.new_event),
|
||||
});
|
||||
} else if input.changed_event == "pin" {
|
||||
},
|
||||
ChangeEventType::Pin => {
|
||||
// change the pin
|
||||
let new_hashed_pin = sha1::Sha1::from(&input.new_event).digest().to_string();
|
||||
users[i].pin_hashed = new_hashed_pin.clone();
|
||||
db_write(&users);
|
||||
user.pin_hashed = new_hashed_pin.clone();
|
||||
db_add(&user);
|
||||
info!("changed pin of {}", input.name);
|
||||
return json!({
|
||||
"status": "ok",
|
||||
"reason": "changed pin",
|
||||
});
|
||||
} else if input.changed_event == "pronouns" {
|
||||
},
|
||||
ChangeEventType::Pronouns => {
|
||||
// change the pronouns
|
||||
users[i].pronouns = input.new_event.clone();
|
||||
user.pronouns = input.new_event.clone();
|
||||
info!("changed pronouns of {} to {}", input.name, input.new_event);
|
||||
db_write(&users);
|
||||
db_add(&user);
|
||||
return json!({
|
||||
"status": "ok",
|
||||
"reason": "successfully changed pronouns",
|
||||
});
|
||||
};
|
||||
} else {
|
||||
warn!("incorrect pin for user {}", input.name);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "incorrect pin",
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
};
|
||||
warn!("couldn't change users info, user does not exist");
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "user doesn't exist",
|
||||
});
|
||||
}
|
||||
|
||||
// Change a users pin/name
|
||||
#[post("/users/change/<name>/<pin>/<new_name>/<new_pin>")]
|
||||
pub fn change(name: String, pin: i32, new_name: String, new_pin: i32) -> JsonValue {
|
||||
let mut users: Vec<User> = db_read();
|
||||
|
||||
let hashed_pin_input = sha1::Sha1::from(&pin.to_string()).digest().to_string();
|
||||
|
||||
// Loop over elements in vector
|
||||
for i in 0..users.len() {
|
||||
if users[i].name == name.to_lowercase() {
|
||||
// make sure name exists
|
||||
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
|
||||
users[i].pin_hashed = sha1::Sha1::from(&new_pin.to_string()).digest().to_string();
|
||||
/*
|
||||
match write_json(&users) {
|
||||
Err(why) => panic!("Cannot write to json! {}", why),
|
||||
Ok(()) => info!("succesfully wrote to json file"),
|
||||
}*/
|
||||
db_write(&users);
|
||||
info!("Changed pin of {}", name.to_string().to_lowercase());
|
||||
return json!({
|
||||
"status": "ok",
|
||||
"reason": format!("changed {}'s pin", name.to_string().to_lowercase()),
|
||||
});
|
||||
} else {
|
||||
// check if new name already exists
|
||||
for n in &users {
|
||||
if n.name == new_name.to_lowercase() {
|
||||
warn!(
|
||||
"Could not change name of {} to {}, as new name is already taken.",
|
||||
name.to_lowercase(),
|
||||
new_name.to_lowercase()
|
||||
);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": format!("new name {} is already taken", new_name.to_lowercase()),
|
||||
});
|
||||
}
|
||||
}
|
||||
users[i].name = new_name.to_string().to_lowercase();
|
||||
users[i].pin_hashed =
|
||||
sha1::Sha1::from(&new_pin.to_string()).digest().to_string();
|
||||
/*
|
||||
match write_json(&users) {
|
||||
Err(why) => panic!("couldn't write to json file! {}", why),
|
||||
Ok(()) => info!("succesfully wrote to json file"),
|
||||
}*/
|
||||
db_write(&users);
|
||||
info!(
|
||||
"Changed name of {} to {}. New pin hash is {}",
|
||||
name.to_string(),
|
||||
users[i].name.to_string(),
|
||||
users[i].pin_hashed.to_string()
|
||||
);
|
||||
return json!({
|
||||
"status": "ok",
|
||||
"reason": "successfully changed name and/or pin",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
warn!("Incorrect token for user {}!", name.to_string());
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "incorrect token for user",
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("incorrect pin for user {}", input.name);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "incorrect pin",
|
||||
});
|
||||
};
|
||||
} else {
|
||||
warn!("couldn't change users info, user does not exist");
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "user doesn't exist",
|
||||
});
|
||||
}
|
||||
warn!(
|
||||
"User {} not found, could not change pin and/or name.",
|
||||
name.to_string()
|
||||
);
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": format!("user {} not found", name.to_string().to_lowercase()),
|
||||
"reason": "idk",
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -419,6 +290,7 @@ pub fn get_user(name: String) -> JsonValue {
|
|||
"user": {
|
||||
"name": user.name,
|
||||
"pronouns": user.pronouns,
|
||||
"role": user.role,
|
||||
},
|
||||
}),
|
||||
None => json!({
|
||||
|
@ -427,3 +299,59 @@ pub fn get_user(name: String) -> JsonValue {
|
|||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/* User Management */
|
||||
#[post("/mod", format = "json", data = "<data>")]
|
||||
pub fn moderation_actions(data: Json<ModerationAction>, mut cookies: Cookies) -> JsonValue {
|
||||
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 let Some(user) = db_read_user(&data.name.to_lowercase()).ok().flatten() {
|
||||
if token.value() == "NULL" { // fail if token is NULL
|
||||
warn!("NULL token!");
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "NULL token",
|
||||
});
|
||||
} else if user.session_token == token.value() { // if token matches
|
||||
if user.role == UserType::Normal {
|
||||
match data.action {
|
||||
ModActions::Kick => {
|
||||
info!("kicked user {}", data.target)
|
||||
},
|
||||
ModActions::Ban => info!("banned user {}", data.target),
|
||||
_ => info!("F"),
|
||||
};
|
||||
return json!({
|
||||
"status": "ok",
|
||||
"reason": "completed action",
|
||||
});
|
||||
} else {
|
||||
warn!("user does not have sufficient permissions to perform that action!");
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "insufficient permissions",
|
||||
});
|
||||
};
|
||||
} else {
|
||||
warn!("token does not match!");
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "token does not match",
|
||||
})
|
||||
};
|
||||
} else {
|
||||
warn!("user not found");
|
||||
return json!({
|
||||
"status": "fail",
|
||||
"reason": "user not found"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
52
src/chat.rs
52
src/chat.rs
|
@ -4,7 +4,7 @@ use once_cell::sync::Lazy;
|
|||
use std::sync::Mutex;
|
||||
use crate::file_io::db_read;
|
||||
use rocket::http::{Cookie, Cookies};
|
||||
use crate::message::{Message, MessageInput};
|
||||
use crate::message::{Message, MessageInput, MessageType};
|
||||
use rocket_contrib::json::{Json, JsonValue};
|
||||
use chrono::prelude::*;
|
||||
use uuid::Uuid;
|
||||
|
@ -23,35 +23,24 @@ pub fn fetch_messages() -> Json<Vec<Message>> {
|
|||
|
||||
// Create full message object and write to file
|
||||
fn create_message(message: Json<MessageInput>, file: &str, user: &User) -> JsonValue {
|
||||
let event_type = match message.body.chars().nth(0).unwrap() {
|
||||
'/' => MessageType::Command,
|
||||
':' => MessageType::Emote,
|
||||
_ => MessageType::Normal,
|
||||
};
|
||||
|
||||
// create full message object
|
||||
// append message to file
|
||||
|
||||
// Create proper datetime format out of string
|
||||
let date_split: Vec<&str> = message.date.split("-").collect();
|
||||
|
||||
let year: i32 = match date_split[0].trim().parse() { // extract year
|
||||
Err(why) => panic!("could not extract year from given date: {}", why),
|
||||
Ok(year) => year,
|
||||
};
|
||||
|
||||
let month: u32 = match date_split[1].trim().parse() { // extract month
|
||||
Err(why) => panic!("could not extract month from given date: {}", why),
|
||||
Ok(month) => month,
|
||||
};
|
||||
|
||||
let day: u32 = match date_split[2].trim().parse() { // extract day
|
||||
Err(why) => panic!("could not extract day from given date: {}", why),
|
||||
Ok(month) => month,
|
||||
};
|
||||
|
||||
let date: DateTime<Utc> = Utc.ymd(year, month, day).and_hms(9, 10, 11);
|
||||
let message_obj: Message = Message {
|
||||
id: Uuid::new_v4(),
|
||||
event_type,
|
||||
user: user.name.to_owned(),
|
||||
body: message.body.to_string(),
|
||||
created_at: date,
|
||||
created_at: Utc::now(),
|
||||
};
|
||||
info!("created mesage: {:?}", message_obj);
|
||||
info!("Date is: {}", message_obj.created_at.to_rfc2822());
|
||||
|
||||
// append message to file
|
||||
let mut messages = MESSAGES.lock().unwrap();
|
||||
messages.push(message_obj.to_owned());
|
||||
return json!({
|
||||
|
@ -107,3 +96,20 @@ pub fn send_message(message: Json<MessageInput<'_>>, mut cookies: Cookies) -> Js
|
|||
};
|
||||
check_token(token, message)
|
||||
}
|
||||
|
||||
// Delete a message
|
||||
/*
|
||||
#[post("/message/delete", format = "json", data = "<message>")]
|
||||
pub fn delete_message(message: Json<MessageInput<'_>>, mut cookies: Cookies) -> JsonValue {
|
||||
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,
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
|
138
src/file_io.rs
138
src/file_io.rs
|
@ -1,123 +1,7 @@
|
|||
use std::fs::{File, OpenOptions};
|
||||
use std::io::prelude::*;
|
||||
use std::io::{self, BufRead};
|
||||
use std::path::Path;
|
||||
extern crate log;
|
||||
use crate::user::User;
|
||||
use serde_json::Result;
|
||||
|
||||
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
{
|
||||
let file = File::open(filename)?;
|
||||
Ok(io::BufReader::new(file).lines())
|
||||
}
|
||||
|
||||
// Function to read json from file into the vector
|
||||
pub fn read_json() -> Vec<User> {
|
||||
// Create path to file
|
||||
let path = Path::new("users.json");
|
||||
let display = path.display();
|
||||
|
||||
let mut users: Vec<User> = Vec::new(); // Create an empty vector of users
|
||||
|
||||
// Read through the lines and append them to the array
|
||||
if let Ok(lines) = read_lines(&path) {
|
||||
for line in lines {
|
||||
if let Ok(user) = line {
|
||||
info!("read {} from json file {}", display, &user);
|
||||
// Parse line from file into a data structure
|
||||
let user: User = serde_json::from_str(&user).unwrap();
|
||||
users.push(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
// Function to append the last value of the users vector to the file
|
||||
pub fn append_json(user: &User) -> Result<()> {
|
||||
// Create a file to write to
|
||||
let path = Path::new("users.json");
|
||||
let display = path.display();
|
||||
|
||||
let mut file = match OpenOptions::new()
|
||||
.write(true)
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(&path)
|
||||
{
|
||||
Err(why) => panic!("couldn't create {}: {}", display, why),
|
||||
Ok(file) => file,
|
||||
};
|
||||
|
||||
// Serialize the last user value
|
||||
let user_json = serde_json::to_string(&user)?;
|
||||
|
||||
// Write to the file
|
||||
match file.write_all(user_json.as_bytes()) {
|
||||
Err(why) => panic!("couldn't write to {}: {}", display, why),
|
||||
Ok(_) => info!("succesfully wrote to {}", display),
|
||||
};
|
||||
// Add newline
|
||||
match file.write_all("\n".as_bytes()) {
|
||||
Err(why) => panic!("couldn't write to {}: {}", display, why),
|
||||
Ok(_) => info!("succesfully wrote newline to {}", display),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Function to write whole vector of users to file
|
||||
pub fn write_json(users_list: &Vec<User>) -> Result<()> {
|
||||
// Create a file to write to
|
||||
let path = Path::new("users.json");
|
||||
let display = path.display();
|
||||
|
||||
let mut file = match OpenOptions::new().write(true).create(true).open(&path) {
|
||||
Err(why) => panic!("couldn't create {}: {}", display, why),
|
||||
Ok(file) => file,
|
||||
};
|
||||
|
||||
let mut users_json = String::new();
|
||||
for i in 0..users_list.len() {
|
||||
// Serialize the users
|
||||
users_json += &serde_json::to_string(&users_list[i])?;
|
||||
if i != users_list.len()-1 {
|
||||
// don't append newline if it's the last element
|
||||
users_json += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Write to the file
|
||||
match file.write_all(users_json.as_bytes()) {
|
||||
Err(why) => panic!("couldn't write to {}: {}", display, why),
|
||||
Ok(_) => info!("succesfully wrote to {}", display),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// test sled funtion
|
||||
pub fn test_sled() {
|
||||
// create test user
|
||||
let user = User {
|
||||
name: "erin".to_string(),
|
||||
pin_hashed: "nyaa".to_string(),
|
||||
pronouns: "she/her".to_string(),
|
||||
session_token: "NULL".to_string(),
|
||||
};
|
||||
// open database
|
||||
let db: sled::Db = sled::open("my_db").unwrap();
|
||||
let bytes = bincode::serialize(&user).unwrap();
|
||||
db.insert(&user.name, bytes).unwrap();
|
||||
match db.get(user.name).unwrap() {
|
||||
Some(bytes) => {
|
||||
let read_user: User = bincode::deserialize(&bytes).unwrap();
|
||||
println!("username: {}, pronouns: {}", read_user.name, read_user.pronouns);
|
||||
},
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
type MyErrorType = Box<dyn std::error::Error>;
|
||||
|
||||
// add a user to the database
|
||||
pub fn db_add(user: &User) {
|
||||
|
@ -138,6 +22,12 @@ pub fn db_write(users_list: &Vec<User>) {
|
|||
info!("wrote all users to db");
|
||||
}
|
||||
|
||||
// remove a user from the database
|
||||
pub fn db_remove(user: &User) {
|
||||
let db: sled::Db = sled::open("users_db").unwrap();
|
||||
db.remove(&user.name);
|
||||
}
|
||||
|
||||
// read all users from the database
|
||||
pub fn db_read() -> Vec<User> {
|
||||
let db: sled::Db = sled::open("users_db").unwrap();
|
||||
|
@ -149,3 +39,17 @@ pub fn db_read() -> Vec<User> {
|
|||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
// read one user from the database
|
||||
pub fn db_read_user(user: &str) -> std::result::Result<Option<User>, MyErrorType> {
|
||||
let db: sled::Db = sled::open("users_db")?;
|
||||
let entry = db.get(user)?;
|
||||
if let Some(user_entry) = entry {
|
||||
let read_user: User = bincode::deserialize(&user_entry)?;
|
||||
info!("read user {} from db", read_user.name);
|
||||
Ok(Some(read_user))
|
||||
} else {
|
||||
warn!("user {} not found in db!", user);
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,16 +28,15 @@ fn main() {
|
|||
.mount(
|
||||
"/api",
|
||||
routes![
|
||||
auth::index,
|
||||
auth::get_user,
|
||||
auth::register_user,
|
||||
auth::register,
|
||||
auth::login,
|
||||
auth::change,
|
||||
chat::send_message,
|
||||
chat::fetch_messages,
|
||||
auth::change_info,
|
||||
auth::check_token,
|
||||
auth::logout
|
||||
auth::logout,
|
||||
auth::moderation_actions
|
||||
],
|
||||
)
|
||||
.mount("/", StaticFiles::from("frontend"))
|
||||
|
|
|
@ -7,12 +7,21 @@ use uuid::Uuid;
|
|||
pub struct MessageInput<'r> {
|
||||
pub name: &'r str,
|
||||
pub body: &'r str,
|
||||
pub date: &'r str,
|
||||
pub date: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub enum MessageType {
|
||||
Normal,
|
||||
Announcement,
|
||||
Emote,
|
||||
Command,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
pub struct Message {
|
||||
pub id: Uuid,
|
||||
pub event_type: MessageType,
|
||||
pub user: String,
|
||||
pub body: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
|
|
75
src/user.rs
75
src/user.rs
|
@ -1,11 +1,76 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/* User Data */
|
||||
// enum of different user types
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub enum UserType {
|
||||
Normal,
|
||||
Moderator,
|
||||
Admin,
|
||||
}
|
||||
|
||||
// Struct to store basic user data
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct User {
|
||||
pub name: String,
|
||||
pub pin_hashed: String,
|
||||
pub pronouns: String,
|
||||
#[serde(rename = "sessionToken")]
|
||||
pub session_token: String,
|
||||
pub name: String, // unique username
|
||||
pub pin_hashed: String, // sha1 hash of the pin
|
||||
pub pronouns: String, // user's pronouns
|
||||
pub session_token: String, // generated session token
|
||||
pub role: UserType, // type/role of user
|
||||
}
|
||||
|
||||
/* Moderation Data */
|
||||
// enum of different moderator actions
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub enum ModActions {
|
||||
Kick, // Log the user out of their current session
|
||||
Ban, // Remove the user
|
||||
Demote, // Demote a user to a lower role
|
||||
Premote, // Premote a user to a higher role
|
||||
}
|
||||
|
||||
// struct to use for json input
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ModerationAction {
|
||||
pub name: String, // name of the moderator
|
||||
pub action: ModActions, // what action to take
|
||||
pub target: String, // who to take the action on
|
||||
}
|
||||
|
||||
/* Miscellaneous Events */
|
||||
// logout event struct
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct LogoutEvent {
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
// register event struct
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct RegisterEvent {
|
||||
pub name: String,
|
||||
pub pin: String,
|
||||
pub pronouns: String,
|
||||
}
|
||||
|
||||
// login event struct
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct LoginEvent {
|
||||
pub name: String,
|
||||
pub pin: String,
|
||||
}
|
||||
|
||||
// change event type
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub enum ChangeEventType {
|
||||
Name,
|
||||
Pin,
|
||||
Pronouns,
|
||||
}
|
||||
|
||||
// change info event struct
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct ChangeEvent {
|
||||
pub name: String, // name of the user
|
||||
pub changed_event: ChangeEventType, // which event to change
|
||||
pub new_event: String, // the new value for the event
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue