Compare commits

...

7 commits

Author SHA1 Message Date
2d15914d1a
update todo 2023-08-29 03:00:06 -07:00
82aae16766
user search (i think) 2023-08-29 02:54:30 -07:00
80c884f489
add some formatting shit 2023-08-29 01:10:33 -07:00
4358ec6483
add return statement 2023-08-28 17:31:25 -07:00
6bae7ef997
make append_path work, update todo 2023-08-28 17:26:33 -07:00
fa1d23cb3e
basic config system 2023-08-28 16:30:10 -07:00
77ad597963
login endpoint is real!! 2023-08-27 21:39:54 -07:00
19 changed files with 265 additions and 21 deletions

2
.gitignore vendored
View file

@ -1,2 +1,4 @@
/target /target
.env .env
config.toml

8
Cargo.lock generated
View file

@ -408,11 +408,13 @@ version = "0.0.0"
dependencies = [ dependencies = [
"diesel", "diesel",
"dotenvy", "dotenvy",
"maplit",
"password-auth", "password-auth",
"regex", "regex",
"rocket", "rocket",
"serde", "serde",
"sha", "sha",
"toml",
] ]
[[package]] [[package]]
@ -654,6 +656,12 @@ dependencies = [
"tracing-subscriber", "tracing-subscriber",
] ]
[[package]]
name = "maplit"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
[[package]] [[package]]
name = "matchers" name = "matchers"
version = "0.1.0" version = "0.1.0"

View file

@ -6,8 +6,10 @@ edition = "2021"
[dependencies] [dependencies]
diesel = { version = "=2.1.0", features = ["postgres"] } diesel = { version = "=2.1.0", features = ["postgres"] }
dotenvy = "0.15.7" dotenvy = "0.15.7"
maplit = "1.0.2"
password-auth = "0.3.0" password-auth = "0.3.0"
regex = "1.9.4" regex = "1.9.4"
rocket = "=0.5.0-rc.3" rocket = "=0.5.0-rc.3"
serde = { version = "1.0.188", features = ["derive"] } serde = { version = "1.0.188", features = ["derive"] }
sha = "1.0.3" sha = "1.0.3"
toml = "0.7.6"

19
config.example.toml Normal file
View file

@ -0,0 +1,19 @@
[general]
# if this path is encountered during path traversal,
# it will be removed. this is useful for instances
# where your absolute domain path is not long enough
# to replace boomlings.com, because you can then point
# it at a different, longer path to fill the gap
#
# example:
# boomlings.com/database/
# example.com/aaaaaaaaaa/
# ^^^^^^^^^^^
# leaving as "/" will disable this
append_path = "/"
# where can your server be accessible?
port = 8000
[accounts]
# allow new accounts to be created
allow_registration = true

View file

@ -28,7 +28,6 @@ CREATE TABLE users (
wave INTEGER NOT NULL DEFAULT 0, wave INTEGER NOT NULL DEFAULT 0,
robot INTEGER NOT NULL DEFAULT 0, robot INTEGER NOT NULL DEFAULT 0,
spider INTEGER NOT NULL DEFAULT 0, spider INTEGER NOT NULL DEFAULT 0,
swing_copter INTEGER NOT NULL DEFAULT 0,
explosion INTEGER NOT NULL DEFAULT 0, explosion INTEGER NOT NULL DEFAULT 0,
special INTEGER NOT NULL DEFAULT 0, special INTEGER NOT NULL DEFAULT 0,
glow INTEGER NOT NULL DEFAULT 0, glow INTEGER NOT NULL DEFAULT 0,

View file

@ -1,10 +1,8 @@
# gdps-server # gdps-server
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 a [Geometry Dash](https://store.steampowered.com/app/322170/Geometry_Dash/) server reimplementation in [Rust](https://rust-lang.org)
_this project is in early stages. it is NOT production ready._ this project is based off of (stolen from) the [crystal-gauntlet](https://git.oat.zone/oat/crystal-gauntlet) server
_ONLY 2.2 is supported._
## why? ## why?
@ -28,7 +26,7 @@ _these features are implemented_
### testing ### testing
- run `cargo run run` - run `cargo run`
### building ### building
@ -36,5 +34,6 @@ _these features are implemented_
## todo ## todo
- add login endpoint....... NOW! - ___fix the fucking get users for usernames!!!!___
- 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!! (try and find a fix anyway lul) - move authorization logic to (./src/helpers/accounts.rs)[./src/helpers/accounts.rs]
- make gjp2 authentication faster (bcrypt?)

34
src/config.rs Normal file
View file

@ -0,0 +1,34 @@
use serde::Deserialize;
use std::fs;
use std::sync::LazyLock;
#[derive(Deserialize)]
pub struct Config {
pub general: ConfigGeneral,
pub accounts: ConfigAccounts
}
#[derive(Deserialize)]
pub struct ConfigGeneral {
pub append_path: String,
pub port: u16
}
#[derive(Deserialize)]
pub struct ConfigAccounts {
pub allow_registration: bool
}
impl Config {
pub fn load_from_file(file_path: &str) -> Self {
let toml_str = fs::read_to_string(file_path).expect("Error finding toml config:");
let config: Config = toml::from_str(toml_str.as_str()).expect("Error parsing toml config:");
return config;
}
}
pub static CONFIG: LazyLock<Config> = LazyLock::new(|| {
let config = Config::load_from_file("config.toml");
config
});

View file

@ -62,7 +62,6 @@ pub struct User {
pub wave: i32, pub wave: i32,
pub robot: i32, pub robot: i32,
pub spider: i32, pub spider: i32,
pub swing_copter: i32,
pub explosion: i32, pub explosion: i32,
pub special: i32, pub special: i32,
pub glow: i32, pub glow: i32,

View file

@ -47,7 +47,6 @@ diesel::table! {
wave -> Int4, wave -> Int4,
robot -> Int4, robot -> Int4,
spider -> Int4, spider -> Int4,
swing_copter -> Int4,
explosion -> Int4, explosion -> Int4,
special -> Int4, special -> Int4,
glow -> Int4, glow -> Int4,

View file

@ -1 +1,2 @@
pub mod accounts; pub mod accounts;
pub mod users;

View file

@ -1 +1,2 @@
pub mod login_account;
pub mod register_account; pub mod register_account;

View file

@ -0,0 +1,55 @@
use password_auth::verify_password;
use rocket::form::Form;
use rocket::http::Status;
use rocket::response::status;
use diesel::prelude::*;
use crate::helpers;
use crate::db;
#[derive(FromForm)]
pub struct FromLoginAccount {
userName: String,
password: String
}
#[post("/accounts/loginGJAccount.php", data = "<input>")]
pub fn login_account(input: Form<FromLoginAccount>) -> status::Custom<&'static str> {
let connection = &mut db::establish_connection_pg();
if input.userName != helpers::clean::clean(input.userName.as_ref()) {
return status::Custom(Status::Ok, "-4")
}
if input.password.len() < 6 {
return status::Custom(Status::Ok, "-8")
}
if input.userName.len() < 3 {
return status::Custom(Status::Ok, "-9")
}
{
use crate::schema::accounts::dsl::*;
let account_id_gjp2_result = accounts
.select((id, gjp2))
.filter(username.eq(input.userName.clone()))
.get_result::<(i32, String)>(connection);
match account_id_gjp2_result {
Ok(account_id_gjp2) => {
let user_id = helpers::accounts::get_user_id_from_account_id(account_id_gjp2.0);
match verify_password(helpers::gjp2::get_gjp2(input.password.clone()).as_bytes(), account_id_gjp2.1.as_str()) {
Ok(_) => return status::Custom(Status::Ok,
Box::leak(format!("{},{}", account_id_gjp2.0, user_id).into_boxed_str())
),
Err(_) => return status::Custom(Status::Ok, "-11")
};
},
Err(_) => return status::Custom(Status::Ok, "-1")
}
}
}

View file

@ -5,6 +5,7 @@ use rocket::response::status;
use diesel::prelude::*; use diesel::prelude::*;
use diesel::result::Error; use diesel::result::Error;
use crate::CONFIG;
use crate::helpers; use crate::helpers;
use crate::db; use crate::db;
@ -15,10 +16,14 @@ pub struct FormRegisterAccount {
email: String email: String
} }
#[post("/memaddrefix/accounts/registerGJAccount.php", data = "<input>")] #[post("/accounts/registerGJAccount.php", data = "<input>")]
pub fn register_account(input: Form<FormRegisterAccount>) -> status::Custom<&'static str> { pub fn register_account(input: Form<FormRegisterAccount>) -> status::Custom<&'static str> {
let connection = &mut db::establish_connection_pg(); let connection = &mut db::establish_connection_pg();
if CONFIG.accounts.allow_registration == false {
return status::Custom(Status::Ok, "-1")
}
if input.userName != helpers::clean::clean(input.userName.as_ref()) { if input.userName != helpers::clean::clean(input.userName.as_ref()) {
return status::Custom(Status::Ok, "-4") return status::Custom(Status::Ok, "-4")
} }

1
src/endpoints/users.rs Normal file
View file

@ -0,0 +1 @@
pub mod get_users;

View file

@ -0,0 +1,74 @@
use rocket::form::Form;
use rocket::http::Status;
use rocket::response::status;
use diesel::prelude::*;
use diesel::result::Error;
use crate::helpers;
use crate::db;
#[derive(FromForm)]
pub struct FormGetUsers {
page: i64,
str: String
}
#[post("/accounts/getGJUsers20.php", data = "<input>")]
pub fn get_users(input: Form<FormGetUsers>) -> status::Custom<&'static str> {
let connection = &mut db::establish_connection_pg();
// query users
use crate::schema::users::dsl::*;
use crate::models::User;
let mut query = users.into_boxed();
match input.str.parse::<i32>() {
Ok(id_value) => query = query.filter(id.eq(id_value)),
Err(_) => query = query.filter(username.like(input.str.to_owned() + "%"))
};
let results = query
.order(stars.desc())
.limit(10)
.offset(input.page * 10)
.get_result::<User, >(connection)
.expect("Fatal error loading users");
let response = helpers::format::format(hashmap! {
1 => results.username,
2 => results.id.to_string(),
3 => results.stars.to_string(),
4 => results.demons.to_string(),
8 => results.creator_points.to_string(),
9 => {
vec![
results.cube,
results.ship,
results.ball,
results.ufo,
results.wave,
results.robot
][results.icon_type as usize].to_string()
},
10 => results.color1.to_string(),
11 => results.color2.to_string(),
13 => results.coins.to_string(),
14 => results.icon_type.to_string(),
15 => results.special.to_string(),
16 => {
match results.account_id {
Some(account_id_value) => account_id_value.to_string(),
None => match results.udid {
Some(udid_value) => udid_value.to_string(),
None => panic!("user has no account_id or udid?!?!?")
}
}
}
});
println!("{}", response);
return status::Custom(Status::Ok, "1")
}

View file

@ -1,2 +1,4 @@
pub mod gjp2; pub mod accounts;
pub mod clean; pub mod clean;
pub mod format;
pub mod gjp2;

17
src/helpers/accounts.rs Normal file
View file

@ -0,0 +1,17 @@
use diesel::prelude::*;
use crate::db;
pub fn get_user_id_from_account_id(ext_id: i32) -> i32 {
use crate::schema::users::dsl::*;
let connection = &mut db::establish_connection_pg();
let user_id = users
.filter(udid.eq(ext_id.to_string()).or(account_id.eq(ext_id)))
.select(id)
.get_result::<i32>(connection)
.expect("No user associated with account?!?!?");
return user_id
}

16
src/helpers/format.rs Normal file
View file

@ -0,0 +1,16 @@
use std::collections::HashMap;
pub fn format(map: HashMap<i32, impl ToString>) -> String {
let mut result = String::new();
for (k, v) in map {
result.push_str(&format!("{}:{}", k, v.to_string()));
result.push(':');
}
if !result.is_empty() {
result.pop();
}
return result;
}

View file

@ -1,5 +1,7 @@
#![feature(decl_macro)] #![feature(decl_macro)]
#![feature(lazy_cell)]
#[macro_use] extern crate maplit;
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
mod db; mod db;
@ -11,16 +13,25 @@ use helpers::*;
mod endpoints; mod endpoints;
use endpoints::*; use endpoints::*;
mod config;
use config::*;
#[get("/")] #[get("/")]
fn index() -> String { fn index() -> String {
return String::from("index | coming soon to a localhost:8000 near u"); return String::from("gdps-server | https://git.reidlab.online/reidlab/gdps-server");
} }
#[launch] #[launch]
fn rocket() -> _ { fn rocket() -> _ {
rocket::build().mount("/", routes![ rocket::build()
index, .configure(rocket::Config::figment().merge(("port", CONFIG.general.port)))
.mount("/", routes![
index,
])
.mount(CONFIG.general.append_path.as_str(), routes![
endpoints::accounts::login_account::login_account,
endpoints::accounts::register_account::register_account,
endpoints::accounts::register_account::register_account endpoints::users::get_users::get_users
]) ])
} }