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

4
.gitignore vendored
View file

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

8
Cargo.lock generated
View file

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

View file

@ -6,8 +6,10 @@ edition = "2021"
[dependencies]
diesel = { version = "=2.1.0", features = ["postgres"] }
dotenvy = "0.15.7"
maplit = "1.0.2"
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"
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,
robot INTEGER NOT NULL DEFAULT 0,
spider INTEGER NOT NULL DEFAULT 0,
swing_copter INTEGER NOT NULL DEFAULT 0,
explosion INTEGER NOT NULL DEFAULT 0,
special INTEGER NOT NULL DEFAULT 0,
glow INTEGER NOT NULL DEFAULT 0,

View file

@ -1,10 +1,8 @@
# 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._
_ONLY 2.2 is supported._
this project is based off of (stolen from) the [crystal-gauntlet](https://git.oat.zone/oat/crystal-gauntlet) server
## why?
@ -28,7 +26,7 @@ _these features are implemented_
### testing
- run `cargo run run`
- run `cargo run`
### building
@ -36,5 +34,6 @@ _these features are implemented_
## todo
- add login endpoint....... NOW!
- 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)
- ___fix the fucking get users for usernames!!!!___
- 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 robot: i32,
pub spider: i32,
pub swing_copter: i32,
pub explosion: i32,
pub special: i32,
pub glow: i32,

View file

@ -47,7 +47,6 @@ diesel::table! {
wave -> Int4,
robot -> Int4,
spider -> Int4,
swing_copter -> Int4,
explosion -> Int4,
special -> 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;

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::result::Error;
use crate::CONFIG;
use crate::helpers;
use crate::db;
@ -15,9 +16,13 @@ pub struct FormRegisterAccount {
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> {
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()) {
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 clean;
pub mod accounts;
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(lazy_cell)]
#[macro_use] extern crate maplit;
#[macro_use] extern crate rocket;
mod db;
@ -11,16 +13,25 @@ use helpers::*;
mod endpoints;
use endpoints::*;
mod config;
use config::*;
#[get("/")]
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]
fn rocket() -> _ {
rocket::build().mount("/", routes![
index,
endpoints::accounts::register_account::register_account
])
rocket::build()
.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::users::get_users::get_users
])
}