Compare commits

..

3 commits

14 changed files with 170 additions and 24 deletions

View file

@ -9,6 +9,7 @@ CREATE TABLE accounts (
username VARCHAR(20) NOT NULL COLLATE case_insensitive UNIQUE, username VARCHAR(20) NOT NULL COLLATE case_insensitive UNIQUE,
gjp2 TEXT NOT NULL, -- argon2 hashed (rubrub uses bcrypt but oh well) gjp2 TEXT NOT NULL, -- argon2 hashed (rubrub uses bcrypt but oh well)
password TEXT NOT NULL, -- argon2 hashed (rubrub uses bcrypt but oh well)
email VARCHAR(254) NOT NULL, email VARCHAR(254) NOT NULL,
-- todo: swap to proper rank system -- todo: swap to proper rank system

View file

@ -0,0 +1 @@
DROP TABLE levels;

View file

@ -0,0 +1,42 @@
CREATE TABLE levels (
id SERIAL PRIMARY KEY,
created_at TEXT NOT NULL DEFAULT (TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS')),
modified_at TEXT NOT NULL DEFAULT (TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS')),
name VARCHAR(20) NOT NULL,
user_id INTEGER NOT NULL references users(id),
description VARCHAR(140) NOT NULL DEFAULT '',
original INTEGER,
game_version INTEGER NOT NULL,
binary_version INTEGER NOT NULL,
password TEXT,
requested_stars INTEGER,
unlisted INTEGER NOT NULL DEFAULT 0,
version INTEGER NOT NULL DEFAULT 0,
extra_data BYTEA NOT NULL,
level_info BYTEA NOT NULL,
editor_time INTEGER NOT NULL,
editor_time_copies INTEGER NOT NULL,
song_id INTEGER NOT NULL,
length INTEGER NOT NULL,
objects INTEGER NOT NULL,
coins INTEGER NOT NULL DEFAULT 0,
has_ldm INTEGER NOT NULL DEFAULT 0,
two_player INTEGER NOT NULL DEFAULT 0,
downloads INTEGER NOT NULL DEFAULT 0,
likes INTEGER NOT NULL DEFAULT 0,
difficulty INTEGER,
community_difficulty INTEGER,
demon_difficulty INTEGER,
stars INTEGER,
featured INTEGER NOT NULL DEFAULT 0,
epic INTEGER NOT NULL DEFAULT 0,
rated_coins INTEGER NOT NULL DEFAULT 0
);

View file

@ -34,4 +34,6 @@ _these features are implemented_
## todo ## todo
- green name users (fuck green names!!)
- move authorization logic to (./src/helpers/accounts.rs)[./src/helpers/accounts.rs] - move authorization logic to (./src/helpers/accounts.rs)[./src/helpers/accounts.rs]
- maybe swap to timestamp type instead of `(TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS.MS'))` (thats REALLY ugly!!)

View file

@ -7,6 +7,7 @@ pub struct Account {
pub id: i32, pub id: i32,
pub username: String, pub username: String,
pub password: String,
pub gjp2: String, pub gjp2: String,
pub email: String, pub email: String,
@ -29,7 +30,8 @@ pub struct Account {
pub struct NewAccount { pub struct NewAccount {
pub username: String, pub username: String,
pub gjp2: String, pub gjp2: String,
pub email: String pub password: String,
pub email: String,
} }
#[derive(Queryable, Serialize)] #[derive(Queryable, Serialize)]
@ -80,3 +82,43 @@ pub struct NewUser {
pub username: String, pub username: String,
pub registered: i32 pub registered: i32
} }
#[derive(Queryable, Serialize)]
pub struct Level {
pub id: i32,
pub created_at: String,
pub modified_at: String,
pub name: String,
pub user_id: i32,
pub description: String,
pub original: Option<i32>,
pub game_version: i32,
pub binary_version: i32,
pub password: Option<String>,
pub requested_stars: Option<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,
pub downloads: i32,
pub likes: i32,
pub difficulty: Option<i32>,
pub community_difficulty: Option<i32>,
pub demon_difficulty: Option<i32>,
pub stars: Option<i32>,
pub featured: i32,
pub epic: i32,
pub rated_coins: i32
}

View file

@ -6,6 +6,7 @@ diesel::table! {
#[max_length = 20] #[max_length = 20]
username -> Varchar, username -> Varchar,
gjp2 -> Text, gjp2 -> Text,
password -> Text,
#[max_length = 254] #[max_length = 254]
email -> Varchar, email -> Varchar,
is_admin -> Int4, is_admin -> Int4,
@ -22,6 +23,45 @@ diesel::table! {
} }
} }
diesel::table! {
levels (id) {
id -> Int4,
created_at -> Text,
modified_at -> Text,
#[max_length = 20]
name -> Varchar,
user_id -> Int4,
#[max_length = 140]
description -> Varchar,
original -> Nullable<Int4>,
game_version -> Int4,
binary_version -> Int4,
password -> Nullable<Text>,
requested_stars -> Nullable<Int4>,
unlisted -> Int4,
version -> Int4,
extra_data -> Bytea,
level_info -> Bytea,
editor_time -> Int4,
editor_time_copies -> Int4,
song_id -> Int4,
length -> Int4,
objects -> Int4,
coins -> Int4,
has_ldm -> Int4,
two_player -> Int4,
downloads -> Int4,
likes -> Int4,
difficulty -> Nullable<Int4>,
community_difficulty -> Nullable<Int4>,
demon_difficulty -> Nullable<Int4>,
stars -> Nullable<Int4>,
featured -> Int4,
epic -> Int4,
rated_coins -> Int4,
}
}
diesel::table! { diesel::table! {
users (id) { users (id) {
id -> Int4, id -> Int4,
@ -57,9 +97,11 @@ diesel::table! {
} }
} }
diesel::joinable!(levels -> users (user_id));
diesel::joinable!(users -> accounts (account_id)); diesel::joinable!(users -> accounts (account_id));
diesel::allow_tables_to_appear_in_same_query!( diesel::allow_tables_to_appear_in_same_query!(
accounts, accounts,
levels,
users, users,
); );

View file

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

View file

@ -34,18 +34,18 @@ pub fn login_account(input: Form<FromLoginAccount>) -> status::Custom<&'static s
{ {
use crate::schema::accounts::dsl::*; use crate::schema::accounts::dsl::*;
let account_id_gjp2_result = accounts let account_id_password_result = accounts
.select((id, gjp2)) .select((id, password))
.filter(username.eq(input.userName.clone())) .filter(username.eq(input.userName.clone()))
.get_result::<(i32, String)>(connection); .get_result::<(i32, String)>(connection);
match account_id_gjp2_result { match account_id_password_result {
Ok(account_id_gjp2) => { Ok(account_id_password) => {
let user_id = helpers::accounts::get_user_id_from_account_id(account_id_gjp2.0); let user_id = helpers::accounts::get_user_id_from_account_id(account_id_password.0);
match verify_password(helpers::gjp::get_gjp2(input.password.clone()).as_bytes(), account_id_gjp2.1.as_str()) { match verify_password(input.password.clone().as_bytes(), account_id_password.1.as_str()) {
Ok(_) => return status::Custom(Status::Ok, Ok(_) => return status::Custom(Status::Ok,
Box::leak(format!("{},{}", account_id_gjp2.0, user_id).into_boxed_str()) Box::leak(format!("{},{}", account_id_password.0, user_id).into_boxed_str())
), ),
Err(_) => return status::Custom(Status::Ok, "-11") Err(_) => return status::Custom(Status::Ok, "-11")
}; };

View file

@ -5,6 +5,8 @@ use rocket::response::status;
use diesel::prelude::*; use diesel::prelude::*;
use diesel::result::Error; use diesel::result::Error;
use password_auth::generate_hash;
use crate::CONFIG; use crate::CONFIG;
use crate::helpers; use crate::helpers;
use crate::db; use crate::db;
@ -60,7 +62,8 @@ pub fn register_account(input: Form<FormRegisterAccount>) -> status::Custom<&'st
let new_account = NewAccount { let new_account = NewAccount {
username: input.userName.clone(), username: input.userName.clone(),
gjp2: helpers::gjp::get_gjp2_hashed(input.password.clone()), password: generate_hash(input.password.clone()),
gjp2: generate_hash(helpers::encryption::get_gjp2(input.password.clone())),
email: input.email.clone() email: input.email.clone()
}; };
inserted_account = diesel::insert_into(accounts) inserted_account = diesel::insert_into(accounts)

0
src/endpoints/levels.rs Normal file
View file

View file

View file

@ -1,4 +1,4 @@
pub mod accounts; pub mod accounts;
pub mod clean; pub mod clean;
pub mod encryption;
pub mod format; pub mod format;
pub mod gjp;

24
src/helpers/encryption.rs Normal file
View file

@ -0,0 +1,24 @@
use sha::sha1::Sha1;
use sha::utils::{Digest, DigestExt};
use password_auth::generate_hash;
pub fn cyclic_xor(data: &[u8], key: &[u8]) -> Vec<u8> {
data.iter()
.zip(key.iter().cycle())
.map(|(&byte, &key_byte)| byte ^ key_byte)
.collect()
}
pub fn cyclic_xor_string(string: &str, key: &str) -> String {
let data = string.as_bytes();
let key_bytes = key.as_bytes();
let result_bytes = cyclic_xor(data, key_bytes);
let result_str = String::from_utf8(result_bytes).expect("invalid UTF-8 sequence (how did this happen?)");
return String::from(result_str);
}
pub fn get_gjp2(password: String) -> String {
return Sha1::default().digest(String::from(password + "mI29fmAnxgTs").as_bytes()).to_hex();
}

View file

@ -1,12 +0,0 @@
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))
}