From 2ba4aa8c8ed527298563683419e6656989fea3a7 Mon Sep 17 00:00:00 2001 From: reidlab Date: Sat, 26 Aug 2023 19:49:43 -0700 Subject: [PATCH 1/2] WIP account registration --- Cargo.lock | 226 +++++++++++++++++- Cargo.toml | 9 +- diesel.toml | 2 +- .../2023-08-26-071607_accounts/down.sql | 3 + migrations/2023-08-26-071607_accounts/up.sql | 28 +++ readme.md | 12 +- src/db.rs | 14 ++ src/db/models.rs | 33 +++ src/db/schema.rs | 23 ++ src/helpers.rs | 2 + src/helpers/clean.rs | 6 + src/helpers/gjp2.rs | 12 + src/main.rs | 66 ++++- src/schema.rs | 2 - 14 files changed, 419 insertions(+), 19 deletions(-) create mode 100644 migrations/2023-08-26-071607_accounts/down.sql create mode 100644 migrations/2023-08-26-071607_accounts/up.sql create mode 100644 src/db.rs create mode 100644 src/db/models.rs create mode 100644 src/db/schema.rs create mode 100644 src/helpers.rs create mode 100644 src/helpers/clean.rs create mode 100644 src/helpers/gjp2.rs delete mode 100644 src/schema.rs diff --git a/Cargo.lock b/Cargo.lock index 8dc0cb5..e529cc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "argon2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e554a8638bdc1e4eae9984845306cc95f8a9208ba8d49c3859fd958b46774d" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + [[package]] name = "async-stream" version = "0.3.5" @@ -56,6 +68,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "binascii" version = "0.1.4" @@ -74,6 +92,36 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bswap" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3acc5ce9c60e68df21b877f13f908ef95c89f01cb6c656cf76ba95f10bc72f5" + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + [[package]] name = "byteorder" version = "1.4.3" @@ -112,6 +160,25 @@ dependencies = [ "version_check", ] +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "deranged" version = "0.3.8" @@ -185,6 +252,23 @@ dependencies = [ "syn", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "either" version = "1.9.0" @@ -323,7 +407,12 @@ name = "gdps-server" version = "0.0.0" dependencies = [ "diesel", + "dotenvy", + "password-auth", + "regex", "rocket", + "serde", + "sha", ] [[package]] @@ -339,6 +428,16 @@ dependencies = [ "windows", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -346,8 +445,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -495,6 +596,15 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "js-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -652,6 +762,29 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "password-auth" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd7eefeb5d5f281fbb19963c0e17bbf33d1dbfda324f76deb1b4889b332b9224" +dependencies = [ + "argon2", + "getrandom", + "password-hash", + "rand_core", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "pear" version = "0.2.7" @@ -800,14 +933,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.6", - "regex-syntax 0.7.4", + "regex-automata 0.3.7", + "regex-syntax 0.7.5", ] [[package]] @@ -821,13 +954,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.7.5", ] [[package]] @@ -838,9 +971,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "rocket" @@ -1000,6 +1133,15 @@ dependencies = [ "serde", ] +[[package]] +name = "sha" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4208d5a903276a9f3b797afdf6c5bc12a8da1344b053b100abf3565ecc80cb7e" +dependencies = [ + "bswap", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -1067,6 +1209,12 @@ dependencies = [ "loom", ] +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "2.0.29" @@ -1291,6 +1439,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + [[package]] name = "ubyte" version = "0.10.3" @@ -1355,6 +1509,60 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 184a059..4c56fc5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,8 +3,11 @@ name = "gdps-server" version = "0.0.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] diesel = { version = "=2.1.0", features = ["postgres"] } -rocket = "=0.5.0-rc.3" \ No newline at end of file +dotenvy = "0.15.7" +password-auth = "0.3.0" +regex = "1.9.4" +rocket = "=0.5.0-rc.3" +serde = { version = "1.0.188", features = ["derive"] } +sha = "1.0.3" diff --git a/diesel.toml b/diesel.toml index c028f4a..436f015 100644 --- a/diesel.toml +++ b/diesel.toml @@ -2,7 +2,7 @@ # see https://diesel.rs/guides/configuring-diesel-cli [print_schema] -file = "src/schema.rs" +file = "src/server/db/schema.rs" custom_type_derives = ["diesel::query_builder::QueryId"] [migrations_directory] diff --git a/migrations/2023-08-26-071607_accounts/down.sql b/migrations/2023-08-26-071607_accounts/down.sql new file mode 100644 index 0000000..5e3fce1 --- /dev/null +++ b/migrations/2023-08-26-071607_accounts/down.sql @@ -0,0 +1,3 @@ +DROP TABLE accounts; + +DROP COLLATION case_insensitive; \ No newline at end of file diff --git a/migrations/2023-08-26-071607_accounts/up.sql b/migrations/2023-08-26-071607_accounts/up.sql new file mode 100644 index 0000000..4eb423d --- /dev/null +++ b/migrations/2023-08-26-071607_accounts/up.sql @@ -0,0 +1,28 @@ +CREATE COLLATION case_insensitive ( + provider = icu, + locale = 'und-u-ks-level2', + deterministic = false +); + +CREATE TABLE accounts ( + id SERIAL PRIMARY KEY, + + username VARCHAR(20) NOT NULL COLLATE case_insensitive UNIQUE, + gjp2 TEXT NOT NULL, -- argon2 hashed (rubrub uses bcrypt but oh well) + email VARCHAR(254) NOT NULL, + + -- todo: swap to proper rank system + is_admin INTEGER NOT NULL DEFAULT 0, + + -- 0: disabled, 1: only for friends, 2: open to all + messages_enabled INTEGER NOT NULL DEFAULT 2, + comments_enabled INTEGER NOT NULL DEFAULT 0, + -- 0: disabled, 1: enabled + friend_requests_enabled INTEGER NOT NULL DEFAULT 1, -- frs enabled + + youtube_url VARCHAR(30), + twitter_url VARCHAR(20), + twitch_url VARCHAR(20), + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/readme.md b/readme.md index de7c81d..f7fd890 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,9 @@ a [Geometry Dash](https://store.steampowered.com/app/322170/Geometry_Dash/) server reimplementation in [Rust](https://rust-lang.org), focusing on 1:1 recreations of vanilla GD features -_this project is on hold until the release of 2.2 (october 2023) due to the possibly huge api changes coming up_ +_this project is in early stages. it is NOT production ready._ + +_ONLY 2.2 is supported._ ## why? @@ -26,8 +28,12 @@ _these features are implemented_ ### testing -- run `cargo run` +- run `cargo run ` ### building -- run `cargo build` \ No newline at end of file +- run `cargo build ` + +## todo + +- our passwords are a little insecure (`argon2(sha1(password + "mI29fmAnxgTs"))`) and there isnt anything we can do about this because gpj2 is forced like that!! thanks robtop!! \ No newline at end of file diff --git a/src/db.rs b/src/db.rs new file mode 100644 index 0000000..dd78ff4 --- /dev/null +++ b/src/db.rs @@ -0,0 +1,14 @@ +use diesel::prelude::*; +use dotenvy::dotenv; +use std::env; + +pub mod models; +pub mod schema; + +pub fn establish_connection_pg() -> PgConnection { + dotenv().ok(); + + let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); + PgConnection::establish(&database_url) + .unwrap_or_else(|_| panic!("Error connecting to {}", database_url)) +} \ No newline at end of file diff --git a/src/db/models.rs b/src/db/models.rs new file mode 100644 index 0000000..296a8eb --- /dev/null +++ b/src/db/models.rs @@ -0,0 +1,33 @@ +use diesel::prelude::*; +use serde::{Serialize, Deserialize}; +use super::schema::accounts; + +#[derive(Queryable, Serialize)] +pub struct Account { + pub id: i32, + + pub username: String, + pub gjp2: String, + pub email: String, + + pub is_admin: i32, + + pub messages_enabled: i32, + pub comments_enabled: i32, + + pub friend_requests_enabled: i32, + + pub youtube_url: Option, + pub twitter_url: Option, + pub twitch_url: Option, + + pub created_at: String +} + +#[derive(Insertable, Deserialize)] +#[diesel(table_name = accounts)] +pub struct NewAccount { + pub username: String, + pub gjp2: String, + pub email: String +} \ No newline at end of file diff --git a/src/db/schema.rs b/src/db/schema.rs new file mode 100644 index 0000000..14a6569 --- /dev/null +++ b/src/db/schema.rs @@ -0,0 +1,23 @@ +// @generated automatically by Diesel CLI. + +diesel::table! { + accounts (id) { + id -> Int4, + #[max_length = 20] + username -> Varchar, + gjp2 -> Text, + #[max_length = 254] + email -> Varchar, + is_admin -> Int4, + messages_enabled -> Int4, + comments_enabled -> Int4, + friend_requests_enabled -> Int4, + #[max_length = 30] + youtube_url -> Nullable, + #[max_length = 20] + twitter_url -> Nullable, + #[max_length = 20] + twitch_url -> Nullable, + created_at -> Timestamp, + } +} diff --git a/src/helpers.rs b/src/helpers.rs new file mode 100644 index 0000000..1302a7d --- /dev/null +++ b/src/helpers.rs @@ -0,0 +1,2 @@ +pub mod gjp2; +pub mod clean; \ No newline at end of file diff --git a/src/helpers/clean.rs b/src/helpers/clean.rs new file mode 100644 index 0000000..855b39a --- /dev/null +++ b/src/helpers/clean.rs @@ -0,0 +1,6 @@ +use regex::Regex; + +pub fn clean(string: &str) -> String { + let regex = Regex::new(r"[^a-zA-z0-9_-]").unwrap(); + return regex.replace_all(string, "").to_string(); +} \ No newline at end of file diff --git a/src/helpers/gjp2.rs b/src/helpers/gjp2.rs new file mode 100644 index 0000000..fc2525e --- /dev/null +++ b/src/helpers/gjp2.rs @@ -0,0 +1,12 @@ +use sha::sha1::Sha1; +use sha::utils::{Digest, DigestExt}; + +use password_auth::generate_hash; + +pub fn get_gjp2(password: String) -> String { + return Sha1::default().digest(String::from(password + "mI29fmAnxgTs").as_bytes()).to_hex(); +} + +pub fn get_gjp2_hashed(password: String) -> String { + return generate_hash(get_gjp2(password)) +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 07ba76a..a574139 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,77 @@ #![feature(decl_macro)] #[macro_use] extern crate rocket; +use rocket::form::Form; +use rocket::http::Status; +use rocket::response::status; + +use diesel::prelude::*; +use diesel::result::Error; + +mod db; +use db::*; + +mod helpers; +use helpers::*; #[get("/")] fn index() -> String { return String::from("index | coming soon to a localhost:8000 near u"); } +#[derive(FromForm)] +struct FormRegisterGJAccount { + userName: String, + password: String, + email: String +} +#[post("/memaddrefix/accounts/registerGJAccount.php", data = "")] +fn register_gj_account(input: Form) -> status::Custom<&'static str> { + use crate::schema::accounts::dsl::*; + use crate::models::NewAccount; + + let connection = &mut establish_connection_pg(); + + if input.userName != clean::clean(input.userName.as_ref()) { + return status::Custom(Status::BadRequest, "-4") + } + + if input.password.len() < 6 { + return status::Custom(Status::BadRequest, "-8") + } + + if input.userName.len() < 3 { + return status::Custom(Status::BadRequest, "-9") + } + + if input.userName.len() > 20 { + return status::Custom(Status::BadRequest, "-4") + } + + if input.userName.len() > 254 { + return status::Custom(Status::BadRequest, "-6") + } + + let account_name_usage = accounts.filter(username.eq(input.userName.clone())).count().get_result::(connection) as Result; + let account_name_used = account_name_usage.expect("Fatal database name query error") != 0; + if account_name_used { + return status::Custom(Status::Conflict, "-2") + } + + let new_account = NewAccount { + username: input.userName.clone(), + gjp2: helpers::gjp2::get_gjp2_hashed(input.password.clone()), + email: input.email.clone() + }; + diesel::insert_into(accounts) + .values(&new_account) + .execute(connection) + .expect("Fatal error saving the new account"); + + return status::Custom(Status::Created, "1") +} + #[launch] fn rocket() -> _ { - rocket::build().mount("/", routes![index]) + rocket::build().mount("/", routes![index, register_gj_account]) } \ No newline at end of file diff --git a/src/schema.rs b/src/schema.rs deleted file mode 100644 index 4dc25e2..0000000 --- a/src/schema.rs +++ /dev/null @@ -1,2 +0,0 @@ -// @generated automatically by Diesel CLI. - From 4e2318b8523eb407d4c24788727e6e6b7505806a Mon Sep 17 00:00:00 2001 From: reidlab Date: Sat, 26 Aug 2023 19:54:52 -0700 Subject: [PATCH 2/2] update to ok status (GD doesnt parse other codes) --- src/main.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index a574139..38dac15 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,29 +33,29 @@ fn register_gj_account(input: Form) -> status::Custom<&'s let connection = &mut establish_connection_pg(); if input.userName != clean::clean(input.userName.as_ref()) { - return status::Custom(Status::BadRequest, "-4") + return status::Custom(Status::Ok, "-4") } if input.password.len() < 6 { - return status::Custom(Status::BadRequest, "-8") + return status::Custom(Status::Ok, "-8") } if input.userName.len() < 3 { - return status::Custom(Status::BadRequest, "-9") + return status::Custom(Status::Ok, "-9") } if input.userName.len() > 20 { - return status::Custom(Status::BadRequest, "-4") + return status::Custom(Status::Ok, "-4") } if input.userName.len() > 254 { - return status::Custom(Status::BadRequest, "-6") + return status::Custom(Status::Ok, "-6") } let account_name_usage = accounts.filter(username.eq(input.userName.clone())).count().get_result::(connection) as Result; let account_name_used = account_name_usage.expect("Fatal database name query error") != 0; if account_name_used { - return status::Custom(Status::Conflict, "-2") + return status::Custom(Status::Ok, "-2") } let new_account = NewAccount { @@ -68,7 +68,7 @@ fn register_gj_account(input: Form) -> status::Custom<&'s .execute(connection) .expect("Fatal error saving the new account"); - return status::Custom(Status::Created, "1") + return status::Custom(Status::Ok, "1") } #[launch]