implement-websockets
~erin 2021-07-26 14:09:10 -04:00
parent b3fa390c72
commit 92f4eb8ec1
Signed by: erin
GPG Key ID: DA70E064A8C70F44
6 changed files with 452 additions and 104 deletions

334
Cargo.lock generated
View File

@ -128,6 +128,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
version = "0.1.10" version = "0.1.10"
@ -320,6 +326,22 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding 2.1.0",
]
[[package]] [[package]]
name = "fs2" name = "fs2"
version = "0.4.3" version = "0.4.3"
@ -365,6 +387,55 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "futures-core"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af51b1b4a7fdff033703db39de8802c673eb91855f2e0d47dcf3bf2c0ef01f99"
[[package]]
name = "futures-macro"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c54913bae956fb8df7f4dc6fc90362aa72e69148e3f39041fbe8742d21e0ac57"
dependencies = [
"autocfg",
"proc-macro-hack",
"proc-macro2 1.0.27",
"quote 1.0.9",
"syn 1.0.74",
]
[[package]]
name = "futures-sink"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f30aaa67363d119812743aa5f33c201a7a66329f97d1a887022971feea4b53"
[[package]]
name = "futures-task"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe54a98670017f3be909561f6ad13e810d9a51f3f061b902062ca3da80799f2"
[[package]]
name = "futures-util"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67eb846bfd58e44a8481a00049e82c43e0ccb5d61f8dc071057cb19249dd4d78"
dependencies = [
"autocfg",
"futures-core",
"futures-macro",
"futures-sink",
"futures-task",
"pin-project-lite",
"pin-utils",
"proc-macro-hack",
"proc-macro-nested",
"slab",
]
[[package]] [[package]]
name = "fxhash" name = "fxhash"
version = "0.2.1" version = "0.2.1"
@ -446,6 +517,17 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "http"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]] [[package]]
name = "httparse" name = "httparse"
version = "1.4.1" version = "1.4.1"
@ -474,7 +556,7 @@ dependencies = [
"traitobject", "traitobject",
"typeable", "typeable",
"unicase", "unicase",
"url", "url 1.7.2",
] ]
[[package]] [[package]]
@ -488,6 +570,17 @@ dependencies = [
"unicode-normalization", "unicode-normalization",
] ]
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.7.0" version = "1.7.0"
@ -576,6 +669,28 @@ version = "0.2.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
[[package]]
name = "lila-chat"
version = "0.6.0"
dependencies = [
"bincode",
"chrono",
"env_logger",
"futures-util",
"log 0.4.14",
"once_cell",
"random-string",
"rocket",
"rocket_contrib",
"serde",
"serde_json",
"sha1",
"sled",
"tokio",
"tokio-tungstenite",
"uuid",
]
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.4" version = "0.4.4"
@ -646,12 +761,25 @@ dependencies = [
"kernel32-sys", "kernel32-sys",
"libc", "libc",
"log 0.4.14", "log 0.4.14",
"miow", "miow 0.2.2",
"net2", "net2",
"slab", "slab",
"winapi 0.2.8", "winapi 0.2.8",
] ]
[[package]]
name = "mio"
version = "0.7.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
dependencies = [
"libc",
"log 0.4.14",
"miow 0.3.7",
"ntapi",
"winapi 0.3.9",
]
[[package]] [[package]]
name = "mio-extras" name = "mio-extras"
version = "2.0.6" version = "2.0.6"
@ -660,7 +788,7 @@ checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
dependencies = [ dependencies = [
"lazycell", "lazycell",
"log 0.4.14", "log 0.4.14",
"mio", "mio 0.6.23",
"slab", "slab",
] ]
@ -676,6 +804,15 @@ dependencies = [
"ws2_32-sys", "ws2_32-sys",
] ]
[[package]]
name = "miow"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [
"winapi 0.3.9",
]
[[package]] [[package]]
name = "net2" name = "net2"
version = "0.2.37" version = "0.2.37"
@ -699,12 +836,21 @@ dependencies = [
"fsevent-sys", "fsevent-sys",
"inotify", "inotify",
"libc", "libc",
"mio", "mio 0.6.23",
"mio-extras", "mio-extras",
"walkdir", "walkdir",
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "ntapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44"
dependencies = [
"winapi 0.3.9",
]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.44" version = "0.1.44"
@ -806,24 +952,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]] [[package]]
name = "pogchat" name = "pin-project"
version = "0.6.0" version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08"
dependencies = [ dependencies = [
"bincode", "pin-project-internal",
"chrono",
"env_logger",
"log 0.4.14",
"once_cell",
"random-string",
"rocket",
"rocket_contrib",
"serde",
"serde_json",
"sha1",
"sled",
"uuid",
] ]
[[package]]
name = "pin-project-internal"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389"
dependencies = [
"proc-macro2 1.0.27",
"quote 1.0.9",
"syn 1.0.74",
]
[[package]]
name = "pin-project-lite"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]] [[package]]
name = "polyval" name = "polyval"
version = "0.4.5" version = "0.4.5"
@ -841,6 +1000,18 @@ version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]]
name = "proc-macro-hack"
version = "0.5.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
[[package]]
name = "proc-macro-nested"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "0.4.30" version = "0.4.30"
@ -1076,6 +1247,19 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "sha-1"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81"
dependencies = [
"block-buffer",
"cfg-if 1.0.0",
"cpufeatures",
"digest",
"opaque-debug",
]
[[package]] [[package]]
name = "sha1" name = "sha1"
version = "0.6.0" version = "0.6.0"
@ -1095,6 +1279,15 @@ dependencies = [
"opaque-debug", "opaque-debug",
] ]
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "slab" name = "slab"
version = "0.4.3" version = "0.4.3"
@ -1166,6 +1359,26 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "thiserror"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
dependencies = [
"proc-macro2 1.0.27",
"quote 1.0.9",
"syn 1.0.74",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.43" version = "0.1.43"
@ -1191,6 +1404,50 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b7b349f11a7047e6d1276853e612d152f5e8a352c61917887cc2169e2366b4c"
dependencies = [
"autocfg",
"bytes",
"libc",
"memchr",
"mio 0.7.13",
"num_cpus",
"once_cell",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"tokio-macros",
"winapi 0.3.9",
]
[[package]]
name = "tokio-macros"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110"
dependencies = [
"proc-macro2 1.0.27",
"quote 1.0.9",
"syn 1.0.74",
]
[[package]]
name = "tokio-tungstenite"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "511de3f85caf1c98983545490c3d09685fa8eb634e57eec22bb4db271f46cbd8"
dependencies = [
"futures-util",
"log 0.4.14",
"pin-project",
"tokio",
"tungstenite",
]
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.4.10" version = "0.4.10"
@ -1206,6 +1463,25 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" checksum = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
[[package]]
name = "tungstenite"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0b2d8558abd2e276b0a8df5c05a2ec762609344191e5fd23e292c910e9165b5"
dependencies = [
"base64 0.13.0",
"byteorder",
"bytes",
"http",
"httparse",
"log 0.4.14",
"rand",
"sha-1",
"thiserror",
"url 2.2.2",
"utf-8",
]
[[package]] [[package]]
name = "typeable" name = "typeable"
version = "0.1.2" version = "0.1.2"
@ -1273,11 +1549,29 @@ version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
dependencies = [ dependencies = [
"idna", "idna 0.1.5",
"matches", "matches",
"percent-encoding 1.0.1", "percent-encoding 1.0.1",
] ]
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna 0.2.3",
"matches",
"percent-encoding 2.1.0",
]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "0.8.2" version = "0.8.2"

View File

@ -24,3 +24,6 @@ once_cell = "1.8.0"
random-string = "1.0" random-string = "1.0"
sled = "0.34.6" sled = "0.34.6"
bincode = "1.3.3" bincode = "1.3.3"
tokio = { version = "1.9.0", features = ["full"] }
futures-util = "0.3.16"
tokio-tungstenite = "0.15.0"

View File

@ -1,10 +1,10 @@
extern crate log; extern crate log;
use uuid::Uuid;
use crate::file_io::*; use crate::file_io::*;
use rocket::http::{Cookie, Cookies};
use crate::user::*; use crate::user::*;
use rocket_contrib::json::{Json, JsonValue};
use random_string::generate; use random_string::generate;
use rocket::http::{Cookie, Cookies};
use rocket_contrib::json::{Json, JsonValue};
use uuid::Uuid;
extern crate sha1; extern crate sha1;
// Post request to register a user and pin // Post request to register a user and pin
@ -12,14 +12,17 @@ extern crate sha1;
pub fn register(data: Json<RegisterEvent>) -> JsonValue { pub fn register(data: Json<RegisterEvent>) -> JsonValue {
// check if the user exists // check if the user exists
if let Some(_user) = db_read_user(&data.name.to_lowercase()).ok().flatten() { if let Some(_user) = db_read_user(&data.name.to_lowercase()).ok().flatten() {
warn!("Cannot create user {}! User is already in system.", data.name); warn!(
"Cannot create user {}! User is already in system.",
data.name
);
return json!({ return json!({
"status": "fail", "status": "fail",
"reason": "user already exists", "reason": "user already exists",
}); });
} else { } else {
let pin_hashed = sha1::Sha1::from(&data.pin).digest().to_string(); // hash the pin let pin_hashed = sha1::Sha1::from(&data.pin).digest().to_string(); // hash the pin
let mut new_user: User = User { let mut new_user: User = User {
name: data.name.to_string().to_lowercase(), name: data.name.to_string().to_lowercase(),
pin_hashed, pin_hashed,
@ -29,20 +32,21 @@ pub fn register(data: Json<RegisterEvent>) -> JsonValue {
id: Uuid::new_v4(), id: Uuid::new_v4(),
}; };
if new_user.name == "admin".to_string() { // if name is admin, make them an admin if new_user.name == "admin".to_string() {
// if name is admin, make them an admin
new_user.role = UserType::Admin; new_user.role = UserType::Admin;
} }
db_add(&new_user); db_add(&new_user);
info!( info!(
"succesfully created user {} with pin hash {}", "succesfully created user {} with pin hash {}",
new_user.name.to_string(), new_user.name.to_string(),
new_user.pin_hashed new_user.pin_hashed
); );
return json!({ return json!({
"status": "ok", "status": "ok",
"reason": format!("user {} registered", new_user.name.to_string().to_lowercase()), "reason": format!("user {} registered", new_user.name.to_string().to_lowercase()),
}); });
} }
} }
@ -69,7 +73,7 @@ pub fn check_token(name: String, mut cookies: Cookies) -> JsonValue {
"status": "fail", "status": "fail",
"reason": "could not read cookie", "reason": "could not read cookie",
}); });
}, }
Some(token) => token, Some(token) => token,
}; };
@ -94,11 +98,11 @@ pub fn check_token(name: String, mut cookies: Cookies) -> JsonValue {
}); });
} }
} else { } else {
warn!("user {} not found", name); warn!("user {} not found", name);
return json!({ return json!({
"status": "fail", "status": "fail",
"reason": "user not found", "reason": "user not found",
}); });
} }
} }
@ -113,7 +117,7 @@ pub fn logout(info: Json<LogoutEvent>, mut cookies: Cookies) -> JsonValue {
"status": "fail", "status": "fail",
"reason": "could not read cookie", "reason": "could not read cookie",
}); });
}, }
Some(token) => token, Some(token) => token,
}; };
if token.value() == "NULL" { if token.value() == "NULL" {
@ -153,14 +157,13 @@ pub fn login(data: Json<LoginEvent>, mut cookies: Cookies) -> JsonValue {
if let Some(user) = db_read_user(&data.name.to_lowercase()).ok().flatten() { 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(); let hashed_pin_input = sha1::Sha1::from(&data.pin.to_string()).digest().to_string();
if user.pin_hashed == hashed_pin_input { // check if pin hash matches if user.pin_hashed == hashed_pin_input {
// check if pin hash matches
info!("pin correct for user {}", &user.name); info!("pin correct for user {}", &user.name);
// Create token for user & set a cookie // Create token for user & set a cookie
let token = create_token(user); let token = create_token(user);
let cookie = Cookie::build("token", token) let cookie = Cookie::build("token", token).path("/").finish();
.path("/")
.finish();
cookies.remove_private(Cookie::named("token")); cookies.remove_private(Cookie::named("token"));
cookies.add_private(cookie); cookies.add_private(cookie);
info!("set the token cookie"); info!("set the token cookie");
@ -203,7 +206,7 @@ pub fn change_info(input: Json<ChangeEvent>, mut cookies: Cookies) -> JsonValue
"status": "fail", "status": "fail",
"reason": "could not read cookie", "reason": "could not read cookie",
}); });
}, }
Some(token) => token, Some(token) => token,
}; };
if token.value() == "NULL" { if token.value() == "NULL" {
@ -216,7 +219,8 @@ pub fn change_info(input: Json<ChangeEvent>, mut cookies: Cookies) -> JsonValue
// find the user // find the user
if let Some(mut user) = db_read_user(&input.name.to_lowercase()).ok().flatten() { if let Some(mut user) = db_read_user(&input.name.to_lowercase()).ok().flatten() {
if token.value() == user.session_token { // & if token matches: if token.value() == user.session_token {
// & if token matches:
match input.changed_event { match input.changed_event {
ChangeEventType::Name => { ChangeEventType::Name => {
// remove the user first // remove the user first
@ -229,7 +233,7 @@ pub fn change_info(input: Json<ChangeEvent>, mut cookies: Cookies) -> JsonValue
"status": "ok", "status": "ok",
"reason": format!("changed name of {} to {}", input.name, input.new_event), "reason": format!("changed name of {} to {}", input.name, input.new_event),
}); });
}, }
ChangeEventType::Pin => { ChangeEventType::Pin => {
// change the pin // change the pin
let new_hashed_pin = sha1::Sha1::from(&input.new_event).digest().to_string(); let new_hashed_pin = sha1::Sha1::from(&input.new_event).digest().to_string();
@ -240,7 +244,7 @@ pub fn change_info(input: Json<ChangeEvent>, mut cookies: Cookies) -> JsonValue
"status": "ok", "status": "ok",
"reason": "changed pin", "reason": "changed pin",
}); });
}, }
ChangeEventType::Pronouns => { ChangeEventType::Pronouns => {
// change the pronouns // change the pronouns
user.pronouns = input.new_event.clone(); user.pronouns = input.new_event.clone();
@ -250,7 +254,7 @@ pub fn change_info(input: Json<ChangeEvent>, mut cookies: Cookies) -> JsonValue
"status": "ok", "status": "ok",
"reason": "successfully changed pronouns", "reason": "successfully changed pronouns",
}); });
}, }
}; };
} else { } else {
warn!("incorrect pin for user {}", input.name); warn!("incorrect pin for user {}", input.name);
@ -258,7 +262,7 @@ pub fn change_info(input: Json<ChangeEvent>, mut cookies: Cookies) -> JsonValue
"status": "fail", "status": "fail",
"reason": "incorrect pin", "reason": "incorrect pin",
}); });
}; };
} else { } else {
warn!("couldn't change users info, user does not exist"); warn!("couldn't change users info, user does not exist");
return json!({ return json!({
@ -290,7 +294,8 @@ pub fn get_user(name: String) -> JsonValue {
// Make a user into a moderator // Make a user into a moderator
fn premote(name: &str) -> JsonValue { fn premote(name: &str) -> JsonValue {
if let Some(mut user) = db_read_user(&name.to_lowercase()).ok().flatten() { if let Some(mut user) = db_read_user(&name.to_lowercase()).ok().flatten() {
if user.role != UserType::Admin { // make sure mods can't demote admins ;3 if user.role != UserType::Admin {
// make sure mods can't demote admins ;3
user.role = UserType::Moderator; user.role = UserType::Moderator;
db_remove(&user); db_remove(&user);
db_add(&user); db_add(&user);
@ -318,7 +323,8 @@ fn premote(name: &str) -> JsonValue {
// Make a user into a normal user // Make a user into a normal user
fn demote(name: &str) -> JsonValue { fn demote(name: &str) -> JsonValue {
if let Some(mut user) = db_read_user(&name.to_lowercase()).ok().flatten() { if let Some(mut user) = db_read_user(&name.to_lowercase()).ok().flatten() {
if user.role != UserType::Admin { // make sure mods can't demote admins ;3 if user.role != UserType::Admin {
// make sure mods can't demote admins ;3
user.role = UserType::Normal; user.role = UserType::Normal;
db_remove(&user); db_remove(&user);
db_add(&user); db_add(&user);
@ -346,7 +352,8 @@ fn demote(name: &str) -> JsonValue {
// Kick a user (temporarilly log them out for a certain amount of time) // Kick a user (temporarilly log them out for a certain amount of time)
fn kick(name: &str) -> JsonValue { fn kick(name: &str) -> JsonValue {
if let Some(mut user) = db_read_user(&name.to_lowercase()).ok().flatten() { if let Some(mut user) = db_read_user(&name.to_lowercase()).ok().flatten() {
if user.role != UserType::Admin { // make sure mods can't kick admins if user.role != UserType::Admin {
// make sure mods can't kick admins
user.session_token = "NULL".to_string(); user.session_token = "NULL".to_string();
db_remove(&user); db_remove(&user);
db_add(&user); db_add(&user);
@ -369,13 +376,13 @@ fn kick(name: &str) -> JsonValue {
"reason": "user not found", "reason": "user not found",
}); });
} }
} }
// Ban a user (remove their account) // Ban a user (remove their account)
fn ban(name: &str) -> JsonValue { fn ban(name: &str) -> JsonValue {
if let Some(mut user) = db_read_user(&name.to_lowercase()).ok().flatten() { if let Some(mut user) = db_read_user(&name.to_lowercase()).ok().flatten() {
if user.role != UserType::Admin { // make sure mods can't kick admins if user.role != UserType::Admin {
// make sure mods can't kick admins
db_remove(&user); db_remove(&user);
info!("succesfully banned user {}", &user.name); info!("succesfully banned user {}", &user.name);
return json!({ return json!({
@ -396,7 +403,6 @@ fn ban(name: &str) -> JsonValue {
"reason": "user not found", "reason": "user not found",
}); });
} }
} }
/* User Management */ /* User Management */
@ -409,19 +415,21 @@ pub fn moderation_actions(data: Json<ModerationAction>, mut cookies: Cookies) ->
"status": "fail", "status": "fail",
"reason": "could not read cookie", "reason": "could not read cookie",
}); });
}, }
Some(token) => token, Some(token) => token,
}; };
if let Some(user) = db_read_user(&data.name.to_lowercase()).ok().flatten() { if let Some(user) = db_read_user(&data.name.to_lowercase()).ok().flatten() {
if token.value() == "NULL" { // fail if token is NULL if token.value() == "NULL" {
// fail if token is NULL
warn!("NULL token!"); warn!("NULL token!");
return json!({ return json!({
"status": "fail", "status": "fail",
"reason": "NULL token", "reason": "NULL token",
}); });
} else if user.session_token == token.value() { // if token matches } else if user.session_token == token.value() {
// if token matches
if user.role == UserType::Moderator || user.role == UserType::Admin { if user.role == UserType::Moderator || user.role == UserType::Admin {
match data.action { match data.action {
ModActions::Kick => kick(&data.target), ModActions::Kick => kick(&data.target),
ModActions::Ban => ban(&data.target), ModActions::Ban => ban(&data.target),
ModActions::Demote => demote(&data.target), ModActions::Demote => demote(&data.target),
@ -441,7 +449,7 @@ pub fn moderation_actions(data: Json<ModerationAction>, mut cookies: Cookies) ->
return json!({ return json!({
"status": "fail", "status": "fail",
"reason": "token does not match", "reason": "token does not match",
}) });
}; };
} else { } else {
warn!("user not found"); warn!("user not found");

View File

@ -1,14 +1,17 @@
/* Contains Rocket code for chat/message functionality */ /* Contains Rocket code for chat/message functionality */
extern crate log; extern crate log;
use once_cell::sync::Lazy;
use std::sync::Mutex;
use crate::file_io::db_read_user; use crate::file_io::db_read_user;
use rocket::http::{Cookie, Cookies};
use crate::message::{Message, MessageInput, MessageType}; use crate::message::{Message, MessageInput, MessageType};
use rocket_contrib::json::{Json, JsonValue};
use chrono::prelude::*;
use uuid::Uuid;
use crate::user::User; use crate::user::User;
use chrono::prelude::*;
use futures_util::StreamExt;
use once_cell::sync::Lazy;
use rocket::http::{Cookie, Cookies};
use rocket_contrib::json::{Json, JsonValue};
use std::sync::Mutex;
use tokio::net::{TcpListener, TcpStream};
use tokio::sync::broadcast;
use uuid::Uuid;
static MESSAGES: Lazy<Mutex<Vec<Message>>> = Lazy::new(|| Mutex::new(Vec::new())); static MESSAGES: Lazy<Mutex<Vec<Message>>> = Lazy::new(|| Mutex::new(Vec::new()));
@ -21,6 +24,15 @@ pub fn fetch_messages() -> Json<Vec<Message>> {
Json(messages) Json(messages)
} }
async fn send_message_to_websocket() {
let (tx, mut rx1) = broadcast::channel(16);
let mut rx2 = tx.subscribe();
tokio::spawn(async move {
info!("message: {}", rx1.recv().await.unwrap());
});
tx.send(10).unwrap();
}
// Create full message object and write to file // Create full message object and write to file
fn create_message(message: Json<MessageInput>, user: &User) -> JsonValue { fn create_message(message: Json<MessageInput>, user: &User) -> JsonValue {
let event_type = match message.body.chars().nth(0).unwrap() { let event_type = match message.body.chars().nth(0).unwrap() {
@ -28,7 +40,7 @@ fn create_message(message: Json<MessageInput>, user: &User) -> JsonValue {
':' => MessageType::Emote, ':' => MessageType::Emote,
_ => MessageType::Normal, _ => MessageType::Normal,
}; };
if (message.body == "") | (message.body == " ") { if (message.body == "") | (message.body == " ") {
warn!("blank message given"); warn!("blank message given");
return json!({ return json!({
@ -48,9 +60,13 @@ fn create_message(message: Json<MessageInput>, user: &User) -> JsonValue {
info!("created mesage: {:?}", message_obj); info!("created mesage: {:?}", message_obj);
info!("Date is: {}", message_obj.created_at.to_rfc2822()); info!("Date is: {}", message_obj.created_at.to_rfc2822());
std::thread::spawn(|| send_message_to_websocket());
/*
// append message to file // append message to file
let mut messages = MESSAGES.lock().unwrap(); let mut messages = MESSAGES.lock().unwrap();
messages.push(message_obj.to_owned()); messages.push(message_obj.to_owned());
*/
return json!({ return json!({
"status": "ok", "status": "ok",
"reason": "message created", "reason": "message created",
@ -67,7 +83,8 @@ fn check_token(token: Cookie, message: Json<MessageInput<'_>>) -> JsonValue {
"status": "fail", "status": "fail",
"reason": "NULL token", "reason": "NULL token",
}); });
} else if user.session_token == token.value() { // if token matches } else if user.session_token == token.value() {
// if token matches
info!("user exists and given token matches"); info!("user exists and given token matches");
return create_message(message, &user); return create_message(message, &user);
} else { } else {
@ -75,7 +92,7 @@ fn check_token(token: Cookie, message: Json<MessageInput<'_>>) -> JsonValue {
return json!({ return json!({
"status": "fail", "status": "fail",
"reason": "token does not match", "reason": "token does not match",
}) });
}; };
}; };
warn!("user not found"); warn!("user not found");
@ -95,25 +112,31 @@ pub fn send_message(message: Json<MessageInput<'_>>, mut cookies: Cookies) -> Js
"status": "fail", "status": "fail",
"reason": "could not read cookie", "reason": "could not read cookie",
}); });
}, }
Some(token) => token, Some(token) => token,
}; };
check_token(token, message) check_token(token, message)
} }
// Delete a message // Websocket Stuff //
/*
#[post("/message/delete", format = "json", data = "<message>")] pub async fn accept_connection(stream: TcpStream) {
pub fn delete_message(message: Json<MessageInput<'_>>, mut cookies: Cookies) -> JsonValue { let addr = stream
let token = match cookies.get_private("token") { .peer_addr()
None => { .expect("connected streams should have a peer address");
warn!("couldn't get token cookie!"); info!("Peer address: {}", addr);
return json!({
"status": "fail", let ws_stream = tokio_tungstenite::accept_async(stream)
"reason": "could not read cookie", .await
}); .expect("Error during the websocket handshake occurred");
},
Some(token) => token, info!("New WebSocket connection: {}", addr);
};
let (tx, mut rx1) = broadcast::channel::<usize>(16);
let mut rx2 = tx.subscribe();
loop {
let message = rx2.recv().await.unwrap();
info!("message recieved: {}", message);
}
} }
*/

View File

@ -6,9 +6,11 @@ extern crate log;
extern crate rocket; extern crate rocket;
#[macro_use] #[macro_use]
extern crate rocket_contrib; extern crate rocket_contrib;
use rocket_contrib::serve::StaticFiles; use chat::accept_connection;
use rocket::fairing::AdHoc; use rocket::fairing::AdHoc;
use rocket_contrib::serve::StaticFiles;
use std::io::Error;
use tokio::net::{TcpListener, TcpStream};
mod auth; mod auth;
mod chat; mod chat;
@ -16,14 +18,32 @@ mod file_io;
mod message; mod message;
mod user; mod user;
#[tokio::main]
async fn startup_websocket() -> Result<(), Error> {
let addr = "127.0.0.1:1312".to_string();
// Create the event loop and TCP listener we'll accept connections on.
let try_socket = TcpListener::bind(&addr).await;
let listener = try_socket.expect("Failed to bind");
info!("Listening on: {}", addr);
while let Ok((stream, _)) = listener.accept().await {
tokio::spawn(accept_connection(stream));
}
Ok(())
}
fn main() { fn main() {
env_logger::init(); env_logger::init();
info!("Started up rocket");
// Start thread for tungstenite websockets
std::thread::spawn(|| startup_websocket());
let cors_fairing = AdHoc::on_response("CORS", |_, res| { let cors_fairing = AdHoc::on_response("CORS", |_, res| {
res.set_raw_header("Access-Control-Allow-Origin", "http://localhost:8000"); res.set_raw_header("Access-Control-Allow-Origin", "http://localhost:8000");
}); });
info!("Built CORS fairing"); info!("Built CORS fairing");
info!("Started up rocket");
rocket::ignite() rocket::ignite()
.mount( .mount(
"/api", "/api",

View File

@ -13,11 +13,11 @@ pub enum UserType {
// Struct to store basic user data // Struct to store basic user data
#[derive(Clone, Serialize, Deserialize, Debug)] #[derive(Clone, Serialize, Deserialize, Debug)]
pub struct User { pub struct User {
pub name: String, // unique username pub name: String, // unique username
pub pin_hashed: String, // sha1 hash of the pin pub pin_hashed: String, // sha1 hash of the pin
pub pronouns: String, // user's pronouns pub pronouns: String, // user's pronouns
pub session_token: String, // generated session token pub session_token: String, // generated session token
pub role: UserType, // type/role of user pub role: UserType, // type/role of user
pub id: Uuid, pub id: Uuid,
} }
@ -25,18 +25,18 @@ pub struct User {
// enum of different moderator actions // enum of different moderator actions
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub enum ModActions { pub enum ModActions {
Kick, // Log the user out of their current session Kick, // Log the user out of their current session
Ban, // Remove the user Ban, // Remove the user
Demote, // Demote a user to a lower role Demote, // Demote a user to a lower role
Premote, // Premote a user to a higher role Premote, // Premote a user to a higher role
} }
// struct to use for json input // struct to use for json input
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct ModerationAction { pub struct ModerationAction {
pub name: String, // name of the moderator pub name: String, // name of the moderator
pub action: ModActions, // what action to take pub action: ModActions, // what action to take
pub target: String, // who to take the action on pub target: String, // who to take the action on
} }
/* Miscellaneous Events */ /* Miscellaneous Events */
@ -72,7 +72,7 @@ pub enum ChangeEventType {
// change info event struct // change info event struct
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
pub struct ChangeEvent { pub struct ChangeEvent {
pub name: String, // name of the user pub name: String, // name of the user
pub changed_event: ChangeEventType, // which event to change pub changed_event: ChangeEventType, // which event to change
pub new_event: String, // the new value for the event pub new_event: String, // the new value for the event
} }