reuploading levels

This commit is contained in:
Reid 2023-09-20 18:46:37 -07:00
parent fd88a4e374
commit 4d8a41ba47
Signed by: reidlab
GPG key ID: 6C9EAA3364F962C8
20 changed files with 604 additions and 22 deletions

323
Cargo.lock generated
View file

@ -172,6 +172,22 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "core-foundation"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.9" version = "0.2.9"
@ -399,6 +415,30 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
dependencies = [
"percent-encoding",
]
[[package]] [[package]]
name = "fsevent-sys" name = "fsevent-sys"
version = "4.1.0" version = "4.1.0"
@ -485,9 +525,12 @@ dependencies = [
"password-auth", "password-auth",
"rand", "rand",
"regex", "regex",
"reqwest",
"rocket", "rocket",
"rocket_dyn_templates", "rocket_dyn_templates",
"roxmltree",
"serde", "serde",
"serde_json",
"sha", "sha",
"toml", "toml",
] ]
@ -643,6 +686,29 @@ dependencies = [
"want", "want",
] ]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]]
name = "idna"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
dependencies = [
"unicode-bidi",
"unicode-normalization",
]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.9.3" version = "1.9.3"
@ -690,6 +756,12 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "ipnet"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
[[package]] [[package]]
name = "is-terminal" name = "is-terminal"
version = "0.4.9" version = "0.4.9"
@ -853,6 +925,24 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "native-tls"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]] [[package]]
name = "normpath" name = "normpath"
version = "1.1.1" version = "1.1.1"
@ -906,6 +996,50 @@ version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "openssl"
version = "0.10.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
dependencies = [
"bitflags 2.4.0",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]] [[package]]
name = "overload" name = "overload"
version = "0.1.1" version = "0.1.1"
@ -1044,6 +1178,12 @@ 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 = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.17" version = "0.2.17"
@ -1193,6 +1333,43 @@ version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "reqwest"
version = "0.11.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
dependencies = [
"base64",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2",
"http",
"http-body",
"hyper",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-native-tls",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"winreg",
]
[[package]] [[package]]
name = "rocket" name = "rocket"
version = "0.5.0-rc.3" version = "0.5.0-rc.3"
@ -1287,6 +1464,15 @@ dependencies = [
"uncased", "uncased",
] ]
[[package]]
name = "roxmltree"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8f595a457b6b8c6cda66a48503e92ee8d19342f905948f29c383200ec9eb1d8"
dependencies = [
"xmlparser",
]
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.9" version = "0.38.9"
@ -1321,6 +1507,15 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "schannel"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
dependencies = [
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "scoped-tls" name = "scoped-tls"
version = "1.0.1" version = "1.0.1"
@ -1333,6 +1528,29 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.188" version = "1.0.188"
@ -1355,9 +1573,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.105" version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@ -1373,6 +1591,18 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
dependencies = [
"form_urlencoded",
"itoa",
"ryu",
"serde",
]
[[package]] [[package]]
name = "sha" name = "sha"
version = "1.0.3" version = "1.0.3"
@ -1548,6 +1778,21 @@ dependencies = [
"time-core", "time-core",
] ]
[[package]]
name = "tinyvec"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.27.0" version = "1.27.0"
@ -1577,6 +1822,16 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]] [[package]]
name = "tokio-stream" name = "tokio-stream"
version = "0.1.12" version = "0.1.12"
@ -1741,18 +1996,44 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "unicode-bidi"
version = "0.3.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.11" version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
[[package]]
name = "unicode-normalization"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
dependencies = [
"tinyvec",
]
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
version = "0.2.4" version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "url"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
]
[[package]] [[package]]
name = "valuable" name = "valuable"
version = "0.1.0" version = "0.1.0"
@ -1821,6 +2102,18 @@ dependencies = [
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.87" version = "0.2.87"
@ -1850,6 +2143,16 @@ version = "0.2.87"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
[[package]]
name = "web-sys"
version = "0.3.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"
@ -2031,6 +2334,22 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "xmlparser"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d25c75bf9ea12c4040a97f829154768bbbce366287e2dc044af160cd79a13fd"
[[package]] [[package]]
name = "yansi" name = "yansi"
version = "0.5.1" version = "0.5.1"

View file

@ -12,8 +12,11 @@ maplit = "1.0.2"
password-auth = "0.3.0" password-auth = "0.3.0"
rand = "0.8.5" rand = "0.8.5"
regex = "1.9.4" regex = "1.9.4"
reqwest = { version = "0.11.20", features = ["blocking"] }
rocket = "=0.5.0-rc.3" rocket = "=0.5.0-rc.3"
rocket_dyn_templates = { version = "0.1.0-rc.3", features = ["handlebars"] } rocket_dyn_templates = { version = "0.1.0-rc.3", features = ["handlebars"] }
roxmltree = "0.18.0"
serde = { version = "1.0.188", features = ["derive"] } serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.107"
sha = "1.0.3" sha = "1.0.3"
toml = "0.7.6" toml = "0.7.6"

View file

@ -28,4 +28,6 @@ data_folder = "data"
# max amount of objects in a level # max amount of objects in a level
max_objects = 80_000 max_objects = 80_000
# object ids to block # object ids to block
blocklist = [ 31 ] # start position blocklist = [ 31 ] # start position
# if reuploading levels is allowed
reupload = true

View file

@ -24,12 +24,11 @@ CREATE TABLE levels (
song_id INTEGER NOT NULL, song_id INTEGER NOT NULL,
length INTEGER NOT NULL, length INTEGER NOT NULL,
length_real DOUBLE PRECISION NOT NULL, objects INTEGER NOT NULL,
objects INTEGER NOT NULL, coins INTEGER NOT NULL DEFAULT 0,
coins INTEGER NOT NULL DEFAULT 0, has_ldm INTEGER NOT NULL DEFAULT 0,
has_ldm INTEGER NOT NULL DEFAULT 0, two_player INTEGER NOT NULL DEFAULT 0,
two_player INTEGER NOT NULL DEFAULT 0,
downloads INTEGER NOT NULL DEFAULT 0, downloads INTEGER NOT NULL DEFAULT 0,
likes INTEGER NOT NULL DEFAULT 0, likes INTEGER NOT NULL DEFAULT 0,

View file

@ -9,6 +9,8 @@
line-height: 1; line-height: 1;
font-weight: 400; font-weight: 400;
color-scheme: light dark;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;

View file

@ -34,7 +34,6 @@ _these features are implemented_
## todo ## todo
- __we're doing song uploading/rework and level reuploading next__
- swap to chrono instead of `(TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS'))` (thats REALLY ugly!!) this would also make the `28` (upload) and `29` (update) responses work on downloadlevel and the `4` (recent) on getlevels - swap to chrono instead of `(TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS'))` (thats REALLY ugly!!) this would also make the `28` (upload) and `29` (update) responses work on downloadlevel and the `4` (recent) on getlevels
- 2.2 friends only unlisted - 2.2 friends only unlisted
- add more old endpoints + better support for older versions - add more old endpoints + better support for older versions
@ -43,4 +42,9 @@ _these features are implemented_
- moderation utilities - moderation utilities
- ip actions - ip actions
- better song support - better song support
- return "-1" instead of panicking for stuff - return "-1" instead of panicking for stuff
- authentication caching (ip? redis?)
- idfk where to put this but i need to rant about this. why cant you have `get` and `post` in the same function for rocket. like??? why??
- use log instead of println
- find what the fuck level info is. gddocs just says "a random gzip string" like bro what
- unscuff parsing

View file

@ -1,5 +1,7 @@
use serde::Deserialize; use serde::Deserialize;
use std::fs; use std::fs;
use std::sync::LazyLock; use std::sync::LazyLock;
#[derive(Deserialize)] #[derive(Deserialize)]
@ -30,7 +32,8 @@ pub struct ConfigDB {
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct ConfigLevels { pub struct ConfigLevels {
pub max_objects: i32, pub max_objects: i32,
pub blocklist: Vec<i32> pub blocklist: Vec<i32>,
pub reupload: bool
} }
impl Config { impl Config {

View file

@ -108,7 +108,6 @@ pub struct Level {
pub editor_time_copies: i32, pub editor_time_copies: i32,
pub song_id: i32, pub song_id: i32,
pub length: i32, pub length: i32,
pub length_real: f64,
pub objects: i32, pub objects: i32,
pub coins: i32, pub coins: i32,
pub has_ldm: i32, pub has_ldm: i32,
@ -143,7 +142,6 @@ pub struct NewLevel {
pub editor_time_copies: i32, pub editor_time_copies: i32,
pub song_id: i32, pub song_id: i32,
pub length: i32, pub length: i32,
pub length_real: f64,
pub objects: i32, pub objects: i32,
pub coins: i32, pub coins: i32,
pub has_ldm: i32, pub has_ldm: i32,

View file

@ -46,7 +46,6 @@ diesel::table! {
editor_time_copies -> Int4, editor_time_copies -> Int4,
song_id -> Int4, song_id -> Int4,
length -> Int4, length -> Int4,
length_real -> Float8,
objects -> Int4, objects -> Int4,
coins -> Int4, coins -> Int4,
has_ldm -> Int4, has_ldm -> Int4,

View file

@ -93,7 +93,7 @@ pub fn download_level(input: Form<FormDownloadLevel>) -> status::Custom<&'static
let xor_pass: String; let xor_pass: String;
if input.gameVersion.unwrap_or(19) >= 20 { if input.gameVersion.unwrap_or(19) >= 20 {
xor_pass = helpers::encryption::cyclic_xor_string(&level.password.clone().unwrap_or(String::from("0")), "26364") xor_pass = general_purpose::URL_SAFE.encode(helpers::encryption::cyclic_xor_string(&level.password.clone().unwrap_or(String::from("0")), "26364"))
} else { } else {
xor_pass = level.password.clone().unwrap_or(String::from("0")); xor_pass = level.password.clone().unwrap_or(String::from("0"));
} }

View file

@ -45,7 +45,6 @@ pub fn get_levels(input: Form<FormGetLevels>) -> status::Custom<&'static str> {
let connection = &mut db::establish_connection_pg(); let connection = &mut db::establish_connection_pg();
use crate::schema::{levels, users}; use crate::schema::{levels, users};
use crate::models::{Level, User}; use crate::models::{Level, User};
let mut can_see_unlisted = false; let mut can_see_unlisted = false;

View file

@ -183,7 +183,6 @@ pub fn upload_level(input: Form<FormUploadLevel>) -> status::Custom<&'static str
editor_time_copies: input.wt2.unwrap_or(0), editor_time_copies: input.wt2.unwrap_or(0),
song_id: song_id_val, song_id: song_id_val,
length: level_length_val, length: level_length_val,
length_real: level_length_secs,
objects: objects_val as i32, objects: objects_val as i32,
coins: coins_val as i32, coins: coins_val as i32,
has_ldm: input.ldm.unwrap_or(0).clamp(0, 1), has_ldm: input.ldm.unwrap_or(0).clamp(0, 1),

View file

@ -3,4 +3,5 @@ pub mod clean;
pub mod difficulty; pub mod difficulty;
pub mod encryption; pub mod encryption;
pub mod format; pub mod format;
pub mod levels; pub mod levels;
pub mod reupload;

View file

@ -5,6 +5,8 @@ use base64::{Engine as _, engine::general_purpose};
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use roxmltree::Document;
use std::collections::HashMap; use std::collections::HashMap;
pub static DEFAULT_EXTRA_STRING: LazyLock<String> = LazyLock::new(|| { pub static DEFAULT_EXTRA_STRING: LazyLock<String> = LazyLock::new(|| {
@ -13,6 +15,12 @@ pub static DEFAULT_EXTRA_STRING: LazyLock<String> = LazyLock::new(|| {
return string; return string;
}); });
pub static DEFAULT_LEVEL_INFO: LazyLock<String> = LazyLock::new(|| {
let string = String::from("");
return string;
});
macro_rules! object_prop_bool { macro_rules! object_prop_bool {
($key:expr, $name:ident) => { ($key:expr, $name:ident) => {
pub fn $name(&self) -> bool { pub fn $name(&self) -> bool {
@ -167,6 +175,21 @@ pub fn parse(raw_level_data: &str) -> Vec<HashMap<String, String>> {
.collect() .collect()
} }
pub fn gmd_parse(gmd_file: &str) -> HashMap<String, String> {
let doc = Document::parse(gmd_file).expect("failed to parse gmd file");
let root = doc.root_element();
let mut result = Vec::new();
for child in root.children().filter(|node| node.node_type() != roxmltree::NodeType::Text) {
if let Some(child_text) = child.children().next() {
result.push(child_text.text().unwrap_or("").to_string());
}
}
return array_to_hash(result);
}
pub fn decode(level_data: String) -> Vec<HashMap<String, String>> { pub fn decode(level_data: String) -> Vec<HashMap<String, String>> {
let decoded_bytes = general_purpose::URL_SAFE.decode(level_data).expect("couldnt decode b64"); let decoded_bytes = general_purpose::URL_SAFE.decode(level_data).expect("couldnt decode b64");

59
src/helpers/reupload.rs Normal file
View file

@ -0,0 +1,59 @@
use std::sync::RwLock;
use diesel::prelude::*;
use crate::db;
pub const REUPLOAD_USER_NAME: &str = "reupload";
pub static REUPLOAD_ACCOUNT_ID: RwLock<i32> = RwLock::new(0);
pub fn init() {
let connection = &mut db::establish_connection_pg();
use crate::schema::{accounts, users};
use crate::models::{Account, NewAccount, User, NewUser};
match accounts::table
.filter(accounts::username.eq(REUPLOAD_USER_NAME))
.select(accounts::id)
.get_result::<i32, >(connection) {
Ok(reupload_acc_id) => {
let mut write_lock = REUPLOAD_ACCOUNT_ID.write().expect("poisoned lock!!");
*write_lock = reupload_acc_id;
println!("reupload account found, id: {}", reupload_acc_id);
},
Err(_) => {
let new_account = NewAccount {
username: REUPLOAD_USER_NAME.to_string(),
gjp2: "!".to_string(),
password: "!".to_string(),
email: "".to_string()
};
let inserted_account = diesel::insert_into(accounts::table)
.values(&new_account)
.get_result::<Account, >(connection)
.expect("Fatal error saving the new account");
let reupload_acc_id = inserted_account.id;
let new_user = NewUser {
account_id: inserted_account.id,
username: REUPLOAD_USER_NAME.to_string(),
registered: 1
};
diesel::insert_into(users::table)
.values(&new_user)
.get_result::<User, >(connection)
.expect("Fatal error saving the new user");
let mut write_lock = REUPLOAD_ACCOUNT_ID.write().expect("poisoned lock!!");
*write_lock = reupload_acc_id;
println!("created reupload account, id: {}", reupload_acc_id);
}
}
}

View file

@ -34,6 +34,10 @@ async fn files(file: PathBuf) -> Option<NamedFile> {
#[launch] #[launch]
fn rocket() -> _ { fn rocket() -> _ {
// init stuff
crate::helpers::reupload::init();
// data directories
// this is a bit scuffed // this is a bit scuffed
fs::create_dir_all(&CONFIG.db.data_folder).expect("failed to create data directory!"); 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"); fs::create_dir_all(format!("{}/levels", &CONFIG.db.data_folder)).expect("failed to create data directory for levels");
@ -46,13 +50,16 @@ fn rocket() -> _ {
.merge(("limits", Limits::new().limit("forms", 10.megabytes())))) .merge(("limits", Limits::new().limit("forms", 10.megabytes()))))
// actual website // actual website
.mount("/", routes![ .mount("/", routes![
template_endpoints::index::index template_endpoints::index::index,
template_endpoints::reupload::post_reupload,
template_endpoints::reupload::get_reupload
]) ])
// assets // assets
.mount("/", routes![ .mount("/", routes![
files files
]) ])
// GEOMETRY DASH https://www.youtube.com/watch?v=_pLrtsf5yfE // https://www.youtube.com/watch?v=_pLrtsf5yfE
.mount(CONFIG.general.append_path.as_str(), routes![ .mount(CONFIG.general.append_path.as_str(), routes![
endpoints::accounts::login_account::login_account, endpoints::accounts::login_account::login_account,
endpoints::accounts::register_account::register_account, endpoints::accounts::register_account::register_account,

View file

@ -1 +1,2 @@
pub mod index; pub mod index;
pub mod reupload;

View file

@ -0,0 +1,130 @@
use rocket_dyn_templates::{Template, context};
use rocket::form::Form;
use reqwest;
use serde::Deserialize;
use serde_json;
use std::fs;
use base64::{Engine as _, engine::general_purpose};
use diesel::prelude::*;
use crate::helpers;
use crate::db;
#[derive(Deserialize)]
struct LevelResults {
records: Vec<LevelRecord>
}
#[derive(Deserialize, Debug)]
struct LevelRecord {
level_string_available: bool,
real_date: String,
length: Option<i32>,
id: i32
}
#[derive(FromForm)]
pub struct FormReupload {
level_id: i32
}
#[post("/tools/reupload", data = "<input>")]
pub async fn post_reupload(input: Form<FormReupload>) -> Template {
let connection = &mut db::establish_connection_pg();
let disabled = !crate::CONFIG.levels.reupload;
let error: Option<String> = None;
if !disabled {
let remote_level_id = input.level_id;
let resp = reqwest::get(format!("https://history.geometrydash.eu/api/v1/level/{}", remote_level_id)).await.expect("failed to fetch level from remote server");
if !resp.status().is_success() {
return Template::render("reupload", context! {
error: Some(format!("Recieved status code: {}", resp.status()))
})
}
let text = resp.text().await.expect("failed to parse response as text");
let data: LevelResults = serde_json::from_str(&text).expect("failed to parse response as json");
let level: LevelRecord = match data.records
.into_iter()
.filter(|record| record.level_string_available)
.max_by_key(|record| record.real_date.clone())
.map(|record| record) {
Some(level) => level,
None => {
return Template::render("reupload", context! {
error: Some(String::from("No level string available"))
})
}
};
let gmd_file = reqwest::get(format!("https://history.geometrydash.eu/level/{}/{}/download/", remote_level_id, level.id)).await.expect("failed to fetch gmd file from remote server");
let level_data = helpers::levels::gmd_parse(&gmd_file.text().await.expect("failed to parse gmd file as text"));
use crate::schema::levels::dsl::*;
use crate::models::{Level, NewLevel};
println!("{:?}", level_data.get("k3"));
let new_level = NewLevel {
name: level_data.get("k2").expect("level name not found").to_string(),
user_id: crate::helpers::reupload::REUPLOAD_ACCOUNT_ID.read().expect("poisoned lock!!").to_string().parse::<i32>().expect("reupload account id not int (shouldnt ever happen)"),
description: String::from_utf8(general_purpose::URL_SAFE.decode(general_purpose::URL_SAFE.decode(level_data.get("k3").expect("level description not found")).expect("couldnt decode base64")).expect("couldnt decode base64")).expect("invalid utf-8 sequence (how)"),
original: None,
game_version: level_data.get("k17").expect("level game version not found").to_string().parse::<i32>().expect("level game version not int"),
binary_version: level_data.get("k50").unwrap_or(&String::from("0")).to_string().parse::<i32>().expect("level binary version not int"),
password: Some(level_data.get("k41").expect("level password not found").to_string()),
requested_stars: level_data.get("k66").expect("level requested stars not found").to_string().parse::<i32>().expect("level requested stars not int"),
unlisted: 0,
version: level_data.get("k16").expect("level version not found").to_string().parse::<i32>().expect("level version not int"),
extra_data: level_data.get("extra_string").unwrap_or(&crate::helpers::levels::DEFAULT_EXTRA_STRING).to_string().into_bytes(),
level_info: crate::helpers::levels::DEFAULT_LEVEL_INFO.to_string().into_bytes(),
editor_time: level_data.get("k80").unwrap_or(&String::from("0")).parse::<i32>().expect("level editor time not int"),
editor_time_copies: level_data.get("k81").unwrap_or(&String::from("0")).parse::<i32>().expect("level editor time copies not int"),
song_id: if level_data.get("k8").unwrap_or(&String::from("0")).parse::<i32>().expect("level song id not int") == 0 {
level_data.get("k45").expect("level song id doesnt fucking exist").parse::<i32>().expect("level song id not int")
} else {
level_data.get("k8").expect("level song id doesnt fucking exist").parse::<i32>().expect("level song id not int")
},
length: level.length.expect("level length doesnt fucking exist"),
objects: level_data.get("k48").expect("level object count doesnt exist").parse::<i32>().expect("object count not int"),
coins: level_data.get("k64").unwrap_or(&String::from("0")).parse::<i32>().expect("coins not int"),
has_ldm: level_data.get("k72").unwrap_or(&String::from("0")).parse::<i32>().expect("ldm not int"),
two_player: level_data.get("k43").unwrap_or(&String::from("0")).parse::<i32>().expect("two player not int")
};
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(level_data.get("k4").expect("no level data?!").as_bytes()).expect("user provided invalid level string")).expect("couldnt write level to file");
return Template::render("reupload", context! {
level_id: inserted_level.id
})
}
Template::render("reupload", context! {
disabled: disabled
})
}
#[get("/tools/reupload")]
pub fn get_reupload() -> Template {
let disabled = !crate::CONFIG.levels.reupload;
Template::render("reupload", context! {
disabled: disabled
})
}

View file

@ -23,6 +23,7 @@
<br> <br>
<el> <el>
<li>The <a href="https://git.reidlab.online/reidlab/gdps-server">Git repository</a></li> <li>The <a href="https://git.reidlab.online/reidlab/gdps-server">Git repository</a></li>
<li><a href="/tools/reupload">Level reuploading</a></li>
</el> </el>
</p> </p>
</div> </div>

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="/style.css" />
<title>Level Reupload</title>
</head>
<body style="max-width: 800px; margin: auto; padding-top: 1em;">
<h1>Level Reupload</h1>
{{#if error}}
<div>Error while uploading: {{ error }}</div><br />
{{/if}}
{{#if level_id}}
<div>Uploaded successfully! Level ID: <b>{{ level_id }}</b></div><br />
{{/if}}
{{#if disabled}}
<b>Reuploading levels has been disabled.</b><br><br>
{{/if}}
<form action="/tools/reupload" method="post">
ID: <input type="text" id="level_id" name="level_id" {{#if disabled}}disabled{{/if}}>
<input type="submit" value="Submit" {{#if disabled}}disabled{{/if}}>
</form>
<br>
<i>Only vanilla servers are supported.</i>
</body>
</html>