Compare commits
No commits in common. "af1e423b56af4d24d517025e20e1f4b2dd58062b" and "dfcd9e8921c1f9076cd5e5517327ae002b9b6a58" have entirely different histories.
af1e423b56
...
dfcd9e8921
12 changed files with 15 additions and 198 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,6 +1,4 @@
|
||||||
/target
|
/target
|
||||||
|
|
||||||
/data
|
|
||||||
|
|
||||||
.env
|
.env
|
||||||
config.toml
|
config.toml
|
|
@ -17,7 +17,3 @@ port = 8000
|
||||||
[accounts]
|
[accounts]
|
||||||
# allow new accounts to be created
|
# allow new accounts to be created
|
||||||
allow_registration = true
|
allow_registration = true
|
||||||
|
|
||||||
[db]
|
|
||||||
# path for your data to be stored
|
|
||||||
data_folder = "data"
|
|
|
@ -30,12 +30,11 @@ _these features are implemented_
|
||||||
|
|
||||||
### building
|
### building
|
||||||
|
|
||||||
- run `cargo build --release`
|
- run `cargo build`
|
||||||
|
|
||||||
## todo
|
## todo
|
||||||
|
|
||||||
- <small>green name users...</small>
|
- probably work on the code warnings we get hehe
|
||||||
- patch uploadlevel to use 2.2 unlisted(honsetly idk what this is)
|
- <small>green name users...</small> (add udid auth to auth function, use userName instead of accountID in uploading levels, and it goes on and on and on <small>and on...</small>)
|
||||||
- clean up uploadlevel
|
|
||||||
- add level parsing
|
- add level parsing
|
||||||
- maybe swap to chrono instead of `(TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS'))` (thats REALLY ugly!!)
|
- maybe swap to timestamp type instead of `(TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS'))` (thats REALLY ugly!!)
|
|
@ -5,8 +5,7 @@ use std::sync::LazyLock;
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub general: ConfigGeneral,
|
pub general: ConfigGeneral,
|
||||||
pub accounts: ConfigAccounts,
|
pub accounts: ConfigAccounts
|
||||||
pub db: ConfigDB
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
@ -20,11 +19,6 @@ pub struct ConfigAccounts {
|
||||||
pub allow_registration: bool
|
pub allow_registration: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
pub struct ConfigDB {
|
|
||||||
pub data_folder: String
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn load_from_file(file_path: &str) -> Self {
|
pub fn load_from_file(file_path: &str) -> Self {
|
||||||
let toml_str = fs::read_to_string(file_path).expect("Error finding toml config:");
|
let toml_str = fs::read_to_string(file_path).expect("Error finding toml config:");
|
||||||
|
|
|
@ -122,28 +122,3 @@ pub struct Level {
|
||||||
pub epic: i32,
|
pub epic: i32,
|
||||||
pub rated_coins: i32
|
pub rated_coins: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Insertable, Deserialize)]
|
|
||||||
#[diesel(table_name = levels)]
|
|
||||||
pub struct NewLevel {
|
|
||||||
pub name: String,
|
|
||||||
pub user_id: i32,
|
|
||||||
pub description: String,
|
|
||||||
pub original: i32,
|
|
||||||
pub game_version: i32,
|
|
||||||
pub binary_version: i32,
|
|
||||||
pub password: Option<String>,
|
|
||||||
pub requested_stars: i32,
|
|
||||||
pub unlisted: i32,
|
|
||||||
pub version: i32,
|
|
||||||
pub extra_data: Vec<u8>,
|
|
||||||
pub level_info: Vec<u8>,
|
|
||||||
pub editor_time: i32,
|
|
||||||
pub editor_time_copies: i32,
|
|
||||||
pub song_id: i32,
|
|
||||||
pub length: i32,
|
|
||||||
pub objects: i32,
|
|
||||||
pub coins: i32,
|
|
||||||
pub has_ldm: i32,
|
|
||||||
pub two_player: i32
|
|
||||||
}
|
|
|
@ -20,7 +20,7 @@ pub struct FromLoginAccount {
|
||||||
pub fn login_account(input: Form<FromLoginAccount>) -> status::Custom<&'static str> {
|
pub fn login_account(input: Form<FromLoginAccount>) -> status::Custom<&'static str> {
|
||||||
let connection = &mut db::establish_connection_pg();
|
let connection = &mut db::establish_connection_pg();
|
||||||
|
|
||||||
if input.userName != helpers::clean::clean_no_space(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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ pub fn register_account(input: Form<FormRegisterAccount>) -> status::Custom<&'st
|
||||||
return status::Custom(Status::Ok, "-1")
|
return status::Custom(Status::Ok, "-1")
|
||||||
}
|
}
|
||||||
|
|
||||||
if input.userName != helpers::clean::clean_no_space(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")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,6 @@ use rocket::response::status;
|
||||||
|
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
|
||||||
use base64::{Engine as _, engine::general_purpose};
|
|
||||||
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
use crate::helpers;
|
use crate::helpers;
|
||||||
use crate::db;
|
use crate::db;
|
||||||
|
|
||||||
|
@ -16,27 +12,9 @@ use crate::db;
|
||||||
pub struct FormUploadLevel {
|
pub struct FormUploadLevel {
|
||||||
accountID: i32,
|
accountID: i32,
|
||||||
|
|
||||||
|
password: Option<String>,
|
||||||
gjp: Option<String>,
|
gjp: Option<String>,
|
||||||
gjp2: Option<String>,
|
gjp2: Option<String>,
|
||||||
|
|
||||||
password: Option<String>,
|
|
||||||
songID: i32,
|
|
||||||
audioTrack: i32,
|
|
||||||
levelName: String,
|
|
||||||
levelDesc: String,
|
|
||||||
levelID: i32,
|
|
||||||
levelVersion: i32,
|
|
||||||
levelInfo: String,
|
|
||||||
levelString: String,
|
|
||||||
gameVersion: i32,
|
|
||||||
extraString: Option<String>,
|
|
||||||
requestedStars: Option<i32>,
|
|
||||||
binaryVersion: Option<i32>,
|
|
||||||
unlisted: Option<i32>,
|
|
||||||
original: Option<i32>,
|
|
||||||
wt: Option<i32>,
|
|
||||||
wt2: Option<i32>,
|
|
||||||
ldm: Option<i32>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/uploadGJLevel21.php", data = "<input>")]
|
#[post("/uploadGJLevel21.php", data = "<input>")]
|
||||||
|
@ -44,121 +22,15 @@ pub fn upload_level(input: Form<FormUploadLevel>) -> status::Custom<&'static str
|
||||||
let connection = &mut db::establish_connection_pg();
|
let connection = &mut db::establish_connection_pg();
|
||||||
|
|
||||||
// account verification
|
// account verification
|
||||||
let (user_id_val, _account_id_val): (i32, i32);
|
let (user_id_val, account_id_val): (i32, i32);
|
||||||
|
|
||||||
// password argument is used for the level, so
|
match helpers::accounts::auth(input.accountID.clone(), input.password.clone(), input.gjp.clone(), input.gjp2.clone()) {
|
||||||
match helpers::accounts::auth(input.accountID.clone(), None, input.gjp.clone(), input.gjp2.clone()) {
|
|
||||||
Ok((user_id, account_id)) => {
|
Ok((user_id, account_id)) => {
|
||||||
user_id_val = user_id;
|
user_id_val = user_id;
|
||||||
_account_id_val = account_id;
|
account_id_val = account_id;
|
||||||
},
|
},
|
||||||
Err(_) => return status::Custom(Status::Ok, "-1")
|
Err(_) => return status::Custom(Status::Ok, "-1")
|
||||||
};
|
};
|
||||||
|
|
||||||
let description_val;
|
|
||||||
if input.gameVersion >= 20 {
|
|
||||||
description_val = String::from_utf8(general_purpose::URL_SAFE.decode(input.levelDesc.clone()).expect("couldn't decode base64")).expect("invalid UTF-8 sequence (how)")
|
|
||||||
} else {
|
|
||||||
description_val = input.levelDesc.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
let song_id_val = if input.songID == 0 {
|
|
||||||
input.audioTrack
|
|
||||||
} else {
|
|
||||||
input.songID
|
|
||||||
};
|
|
||||||
|
|
||||||
let extra_string;
|
|
||||||
match input.extraString.clone() {
|
|
||||||
Some(extra_string_val) => { extra_string = extra_string_val },
|
|
||||||
None => { extra_string = helpers::levels::DEFAULT_EXTRA_STRING.to_owned() }
|
|
||||||
}
|
|
||||||
|
|
||||||
// db shit
|
|
||||||
use crate::models::{Level, NewLevel};
|
|
||||||
|
|
||||||
{
|
|
||||||
use crate::schema::levels::dsl::*;
|
|
||||||
|
|
||||||
if levels
|
|
||||||
.filter(id.eq(input.levelID))
|
|
||||||
.count()
|
|
||||||
.get_result::<i64>(connection)
|
|
||||||
.expect("couldnt get count of levels") > 0 {
|
|
||||||
// update level
|
|
||||||
let level_user_id = levels
|
|
||||||
.filter(id.eq(input.levelID))
|
|
||||||
.select(user_id)
|
|
||||||
.get_result::<i32>(connection)
|
|
||||||
.expect("couldnt query levels");
|
|
||||||
|
|
||||||
if level_user_id != user_id_val {
|
|
||||||
return status::Custom(Status::Ok, "-1")
|
|
||||||
}
|
|
||||||
|
|
||||||
let updated_level = diesel::update(levels)
|
|
||||||
.filter(id.eq(input.levelID))
|
|
||||||
.set((
|
|
||||||
description.eq(description_val.chars().take(140).collect::<String>()),
|
|
||||||
password.eq(input.password.clone()),
|
|
||||||
requested_stars.eq(match input.requestedStars {
|
|
||||||
Some(requested_stars_val) => requested_stars_val.clamp(0, 10),
|
|
||||||
None => 0
|
|
||||||
}),
|
|
||||||
version.eq(input.levelVersion),
|
|
||||||
extra_data.eq(extra_string.as_bytes().to_owned()),
|
|
||||||
level_info.eq(input.levelInfo.clone().into_bytes()),
|
|
||||||
editor_time.eq(input.wt.unwrap_or(0)),
|
|
||||||
editor_time_copies.eq(input.wt2.unwrap_or(0)),
|
|
||||||
song_id.eq(song_id_val),
|
|
||||||
length.eq(0), // unimplemeneted
|
|
||||||
objects.eq(0), // unimplemented
|
|
||||||
coins.eq(0), // unimplemented
|
|
||||||
has_ldm.eq(input.ldm.unwrap_or(0)),
|
|
||||||
two_player.eq(0) // unimplemented
|
|
||||||
))
|
|
||||||
.get_result::<Level, >(connection)
|
|
||||||
.expect("failed to update level");
|
|
||||||
|
|
||||||
fs::write(format!("{}/levels/{}.lvl", crate::CONFIG.db.data_folder, updated_level.id), general_purpose::URL_SAFE.decode(input.levelString.clone()).expect("user provided invalid level string")).expect("couldnt write level to file");
|
|
||||||
|
|
||||||
return status::Custom(Status::Ok, Box::leak(input.levelID.to_string().into_boxed_str()))
|
|
||||||
} else {
|
|
||||||
// upload level
|
|
||||||
let new_level = NewLevel {
|
|
||||||
name: helpers::clean::clean_basic(&input.levelName).chars().take(20).collect(),
|
|
||||||
user_id: user_id_val,
|
|
||||||
description: description_val.chars().take(140).collect(),
|
|
||||||
original: input.original.unwrap_or(0),
|
|
||||||
game_version: input.gameVersion,
|
|
||||||
binary_version: input.binaryVersion.unwrap_or(0),
|
|
||||||
password: input.password.clone(),
|
|
||||||
requested_stars: match input.requestedStars {
|
|
||||||
Some(requested_stars_val) => requested_stars_val.clamp(0, 10),
|
|
||||||
None => 0
|
|
||||||
},
|
|
||||||
unlisted: input.unlisted.unwrap_or(0),
|
|
||||||
version: input.levelVersion,
|
|
||||||
extra_data: extra_string.as_bytes().to_owned(),
|
|
||||||
level_info: input.levelInfo.clone().into_bytes(),
|
|
||||||
editor_time: input.wt.unwrap_or(0),
|
|
||||||
editor_time_copies: input.wt2.unwrap_or(0),
|
|
||||||
song_id: song_id_val,
|
|
||||||
length: 0, // not implemeneted
|
|
||||||
objects: 0, // not implemeneted
|
|
||||||
coins: 0, // not implemeneted
|
|
||||||
has_ldm: input.ldm.unwrap_or(0),
|
|
||||||
two_player: 0 // not implemented
|
|
||||||
};
|
|
||||||
|
|
||||||
let inserted_level = diesel::insert_into(levels)
|
|
||||||
.values(&new_level)
|
|
||||||
.get_result::<Level, >(connection)
|
|
||||||
.expect("failed to insert level");
|
|
||||||
|
|
||||||
fs::write(format!("{}/levels/{}.lvl", crate::CONFIG.db.data_folder, inserted_level.id), general_purpose::URL_SAFE.decode(input.levelString.clone()).expect("user provided invalid level string")).expect("couldnt write level to file");
|
|
||||||
|
|
||||||
return status::Custom(Status::Ok, "1")
|
return status::Custom(Status::Ok, "1")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
|
@ -2,4 +2,3 @@ pub mod accounts;
|
||||||
pub mod clean;
|
pub mod clean;
|
||||||
pub mod encryption;
|
pub mod encryption;
|
||||||
pub mod format;
|
pub mod format;
|
||||||
pub mod levels;
|
|
|
@ -1,11 +1,6 @@
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
pub fn clean_no_space(string: &str) -> String {
|
pub fn clean(string: &str) -> String {
|
||||||
let regex = Regex::new(r"[^a-zA-z0-9_-]").unwrap();
|
let regex = Regex::new(r"[^a-zA-z0-9_-]").unwrap();
|
||||||
return regex.replace_all(string, "").to_string();
|
return regex.replace_all(string, "").to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clean_basic(string: &str) -> String {
|
|
||||||
let regex = Regex::new(r"[^A-Za-z0-9\-_ ]").unwrap();
|
|
||||||
return regex.replace_all(string, "").to_string();
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
use std::sync::LazyLock;
|
|
||||||
|
|
||||||
pub static DEFAULT_EXTRA_STRING: LazyLock<String> = LazyLock::new(|| {
|
|
||||||
let string = String::from("29_29_29_40_29_29_29_29_29_29_29_29_29_29_29_29");
|
|
||||||
|
|
||||||
return string;
|
|
||||||
});
|
|
|
@ -4,8 +4,6 @@
|
||||||
#[macro_use] extern crate maplit;
|
#[macro_use] extern crate maplit;
|
||||||
#[macro_use] extern crate rocket;
|
#[macro_use] extern crate rocket;
|
||||||
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
mod db;
|
mod db;
|
||||||
use db::*;
|
use db::*;
|
||||||
|
|
||||||
|
@ -25,8 +23,6 @@ fn index() -> String {
|
||||||
|
|
||||||
#[launch]
|
#[launch]
|
||||||
fn rocket() -> _ {
|
fn rocket() -> _ {
|
||||||
fs::create_dir_all(&CONFIG.db.data_folder).expect("failed to create data directory!");
|
|
||||||
fs::create_dir_all(format!("{}/levels", &CONFIG.db.data_folder)).expect("failed to create data directory for levels");
|
|
||||||
rocket::build()
|
rocket::build()
|
||||||
.configure(rocket::Config::figment().merge(("port", CONFIG.general.port)))
|
.configure(rocket::Config::figment().merge(("port", CONFIG.general.port)))
|
||||||
.mount("/", routes![
|
.mount("/", routes![
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue