From 237e4031632f9df3325cb2b3986a3d6016d445ee Mon Sep 17 00:00:00 2001 From: Ethan O'Brien <77750390+ethanaobrien@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:18:24 -0500 Subject: [PATCH] Re-write user data handler --- src/router/global.rs | 27 +- src/router/login.rs | 8 +- src/router/start.rs | 3 +- src/router/user.rs | 4 +- src/router/userdata/mod.rs | 552 ++++++++++++++++--------------------- 5 files changed, 263 insertions(+), 331 deletions(-) diff --git a/src/router/global.rs b/src/router/global.rs index 6a3d159..4227016 100644 --- a/src/router/global.rs +++ b/src/router/global.rs @@ -16,18 +16,33 @@ pub const ASSET_VERSION_JP: &str = "4c921d2443335e574a82e04ec9ea243c"; pub const ASSET_HASH_ANDROID_JP: &str = "67f8f261c16b3cca63e520a25aad6c1c"; pub const ASSET_HASH_IOS_JP: &str = "b8975be8300013a168d061d3fdcd4a16"; + +fn get_uuid(input: &str) -> Option { + let key = "sk1bdzb310n0s9tl"; + let key_index = match input.find(key) { + Some(index) => index + key.len(), + None => return None, + }; + let after = &input[key_index..]; + + let uuid_length = 36; + if after.len() >= uuid_length { + let uuid = &after[..uuid_length]; + return Some(uuid.to_string()); + } + + None +} pub fn get_login(headers: &HeaderMap, body: &str) -> String { let blank_header = HeaderValue::from_static(""); let login = headers.get("a6573cbe").unwrap_or(&blank_header).to_str().unwrap_or(""); let decoded = general_purpose::STANDARD.decode(login).unwrap_or(vec![]); - match String::from_utf8(decoded) { - Ok(a6573cbe) => { - let parts: Vec<&str> = a6573cbe.split('-').collect(); - let token = parts[1..parts.len() - 1].join("-"); - return token.to_string(); + match get_uuid(&String::from_utf8_lossy(&decoded).to_string()) { + Some(token) => { + return token; }, - Err(_) => { + None => { let rv = gree::get_uuid(headers, body); assert!(rv != String::new()); return rv; diff --git a/src/router/login.rs b/src/router/login.rs index fb173ac..110b43e 100644 --- a/src/router/login.rs +++ b/src/router/login.rs @@ -9,12 +9,8 @@ use crate::router::userdata; pub fn dummy(req: HttpRequest, body: String) -> HttpResponse { //let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap(); let key = global::get_login(req.headers(), &body); - let mut user = userdata::get_acc(&key); + let user = userdata::get_acc(&key); - user["user"]["last_login_time"] = global::timestamp().into(); - userdata::save_acc(&key, user.clone()); - - println!("Signin from uid: {}", user["user"]["id"].clone()); let resp = object!{ "code": 0, "server_time": global::timestamp(), @@ -28,7 +24,7 @@ pub fn dummy(req: HttpRequest, body: String) -> HttpResponse { pub fn bonus(req: HttpRequest, body: String) -> HttpResponse { //let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap(); let key = global::get_login(req.headers(), &body); - let user = userdata::get_acc_home(&key); + let user = userdata::get_acc(&key); let resp = object!{ "code": 0, diff --git a/src/router/start.rs b/src/router/start.rs index e8f1403..5dd0f8c 100644 --- a/src/router/start.rs +++ b/src/router/start.rs @@ -46,7 +46,8 @@ pub fn start(req: HttpRequest, body: String) -> HttpResponse { println!("Warning! Asset version is not what was expected. (Did the app update?)"); } let mut user = userdata::get_acc(&key); - //println!("{} - {}", key, user["user"]["id"].to_string()); + + println!("Signin from uid: {}", user["user"]["id"].clone()); user["user"]["last_login_time"] = global::timestamp().into(); user["stamina"]["last_updated_time"] = global::timestamp().into(); diff --git a/src/router/user.rs b/src/router/user.rs index 7075f80..e53a545 100644 --- a/src/router/user.rs +++ b/src/router/user.rs @@ -162,7 +162,7 @@ pub fn verify_migration_code(_req: HttpRequest, body: String) -> HttpResponse { "server_time": global::timestamp(), "data": { "user_id": uid, - "uuid": format!("ecd0d830-{}-25ec5f34f7f8", user["login_token"].to_string()), + "uuid": user["login_token"].to_string(), "charge": data_user["gem"]["charge"].clone(), "free": data_user["gem"]["free"].clone() } @@ -189,7 +189,7 @@ pub fn request_migration_code(_req: HttpRequest, body: String) -> HttpResponse { "code": 0, "server_time": global::timestamp(), "data": { - "twxuid": format!("ecd0d830-{}-25ec5f34f7f8", user["login_token"].to_string()) + "twxuid": user["login_token"].to_string() } }; global::send(resp) diff --git a/src/router/userdata/mod.rs b/src/router/userdata/mod.rs index 80a16ea..669fe7a 100644 --- a/src/router/userdata/mod.rs +++ b/src/router/userdata/mod.rs @@ -1,9 +1,10 @@ -use rusqlite::{Connection, params}; +use rusqlite::{Connection, params, ToSql}; use std::sync::{Mutex, MutexGuard}; use lazy_static::lazy_static; -use json::{JsonValue, array, object}; +use json::{JsonValue, object}; use crate::router::global; use math::round; +use rand::Rng; lazy_static! { pub static ref ENGINE: Mutex> = Mutex::new(None); @@ -15,137 +16,7 @@ fn init(engine: &mut MutexGuard<'_, Option>) { engine.replace(conn); } -fn create_token_store(conn: &Connection) { - match conn.prepare("SELECT jsondata FROM tokens") { - Ok(_) => {} - Err(_) => { - conn.execute( - "CREATE TABLE tokens ( - jsondata TEXT NOT NULL - )", - (), - ).unwrap(); - init_data(conn, "tokens", object!{}); - } - } -} -fn create_uid_store(conn: &Connection) { - match conn.prepare("SELECT jsondata FROM uids") { - Ok(_) => {} - Err(_) => { - conn.execute( - "CREATE TABLE uids ( - jsondata TEXT NOT NULL - )", - (), - ).unwrap(); - init_data(conn, "uids", array![]); - } - } -} - -fn create_migration_store(conn: &Connection) { - match conn.prepare("SELECT jsondata FROM migrationdata") { - Ok(_) => {} - Err(_) => { - conn.execute( - "CREATE TABLE migrationdata ( - jsondata TEXT NOT NULL - )", - (), - ).unwrap(); - init_data(conn, "migrationdata", object!{}); - } - } -} -fn acc_exists(conn: &Connection, key: i64) -> bool { - conn.prepare(&format!("SELECT jsondata FROM _{}_", key)).is_ok() -} -fn store_data(conn: &Connection, key: &str, value: JsonValue) { - conn.execute( - &format!("UPDATE {} SET jsondata=?1", key), - params!(json::stringify(value)) - ).unwrap(); -} -fn init_data(conn: &Connection, key: &str, value: JsonValue) { - conn.execute( - &format!("INSERT INTO {} (jsondata) VALUES (?1)", key), - params!(json::stringify(value)) - ).unwrap(); -} - -use rand::Rng; -fn get_uids(conn: &Connection) -> JsonValue { - let mut stmt = conn.prepare("SELECT jsondata FROM uids").unwrap(); - let result: Result = stmt.query_row([], |row| row.get(0)); - json::parse(&result.unwrap()).unwrap() -} -fn get_tokens(conn: &Connection) -> JsonValue { - let mut stmt = conn.prepare("SELECT jsondata FROM tokens").unwrap(); - let result: Result = stmt.query_row([], |row| row.get(0)); - json::parse(&result.unwrap()).unwrap() -} - -fn generate_uid(conn: &Connection) -> i64 { - create_uid_store(conn); - let mut rng = rand::thread_rng(); - let random_number = rng.gen_range(100_000_000_000_000..=999_999_999_999_999); - let mut existing_ids = get_uids(conn); - //the chances of this...? - if existing_ids.contains(random_number) { - return generate_uid(conn); - } - existing_ids.push(random_number).unwrap(); - store_data(conn, "uids", existing_ids); - - random_number -} - -fn create_acc(conn: &Connection, uid: i64, login: &str) { - let key = &uid.to_string(); - conn.execute( - &format!("CREATE TABLE _{}_ ( - jsondata TEXT NOT NULL - )", key), - (), - ).unwrap(); - let mut data = object!{ - userdata: json::parse(include_str!("new_user.json")).unwrap(), - home: json::parse(include_str!("new_user_home.json")).unwrap(), - missions: json::parse(include_str!("chat_missions.json")).unwrap() - }; - data["userdata"]["user"]["id"] = uid.into(); - data["userdata"]["stamina"]["last_updated_time"] = global::timestamp().into(); - - init_data(conn, &format!("_{}_", key), data); - - create_token_store(conn); - let mut tokens = get_tokens(conn); - tokens[login] = uid.into(); - store_data(conn, "tokens", tokens); -} - -fn get_uid(conn: &Connection, uid: &str) -> i64 { - create_token_store(conn); - let tokens = get_tokens(conn); - if tokens[uid].is_null() { - return 0; - } - return tokens[uid].as_i64().unwrap(); -} - -fn get_login_token(conn: &Connection, uid: i64) -> String { - create_token_store(conn); - let tokens = get_tokens(conn); - for (_i, data) in tokens.entries().enumerate() { - if uid == data.1.as_i64().unwrap() { - return data.0.to_string(); - } - } - String::new() -} - -fn get_data(a6573cbe: &str) -> JsonValue { +fn lock_and_exec(command: &str, args: &[&dyn ToSql]) { loop { match ENGINE.lock() { Ok(mut result) => { @@ -153,25 +24,54 @@ fn get_data(a6573cbe: &str) -> JsonValue { init(&mut result); } let conn = result.as_ref().unwrap(); - let uid = get_uid(conn, &a6573cbe); - - let key: i64; - if uid == 0 { - key = generate_uid(conn); - create_acc(conn, key, &a6573cbe); - } else { - key = uid; + conn.execute(command, args).unwrap(); + return; + } + Err(_) => { + std::thread::sleep(std::time::Duration::from_millis(15)); + } + } + } +} +fn lock_and_select(command: &str) -> Result { + loop { + match ENGINE.lock() { + Ok(mut result) => { + if result.is_none() { + init(&mut result); } - - if !acc_exists(conn, key) { - create_acc(conn, key, &a6573cbe); + let conn = result.as_ref().unwrap(); + let mut stmt = conn.prepare(command)?; + return stmt.query_row([], |row| row.get(0)); + } + Err(_) => { + std::thread::sleep(std::time::Duration::from_millis(15)); + } + } + } +} +fn create_store(test_cmd: &str, table: &str, init_cmd: &str, init_args: &[&dyn ToSql]) { + loop { + match ENGINE.lock() { + Ok(mut result) => { + if result.is_none() { + init(&mut result); } - let mut stmt = conn.prepare(&format!("SELECT jsondata FROM _{}_", key)).unwrap(); - let result: Result = stmt.query_row([], |row| row.get(0)); - - let rv = json::parse(&result.unwrap()).unwrap(); - - return rv + let conn = result.as_ref().unwrap(); + match conn.prepare(test_cmd) { + Ok(_) => {} + Err(_) => { + conn.execute( + table, + (), + ).unwrap(); + conn.execute( + init_cmd, + init_args + ).unwrap(); + } + } + return; } Err(_) => { std::thread::sleep(std::time::Duration::from_millis(15)); @@ -180,8 +80,122 @@ fn get_data(a6573cbe: &str) -> JsonValue { } } -pub fn get_acc(a6573cbe: &str) -> JsonValue { - let mut user = get_data(a6573cbe)["userdata"].clone(); +fn create_token_store() { + create_store("SELECT jsondata FROM tokens", "CREATE TABLE tokens ( + jsondata TEXT NOT NULL + )", "INSERT INTO tokens (jsondata) VALUES (?1)", params!("{}")); +} +fn create_uid_store() { + create_store("SELECT jsondata FROM uids", "CREATE TABLE uids ( + jsondata TEXT NOT NULL + )", "INSERT INTO uids (jsondata) VALUES (?1)", params!("[]")); +} +fn create_migration_store() { + create_store("SELECT jsondata FROM migrationdata", "CREATE TABLE migrationdata ( + jsondata TEXT NOT NULL + )", "INSERT INTO migrationdata (jsondata) VALUES (?1)", params!("{}")); +} + +fn acc_exists(key: i64) -> bool { + lock_and_select(&format!("SELECT userdata FROM _{}_", key)).is_ok() +} +fn store_data(key: &str, value: JsonValue) { + lock_and_exec(&format!("UPDATE {} SET jsondata=?1", key), params!(json::stringify(value))); +} +fn get_key(auth_key: &str) -> i64 { + let uid = get_uid(&auth_key); + let key = if uid == 0 { + generate_uid() + } else { + uid + }; + + if !acc_exists(key) { + create_acc(key, &auth_key); + } + + key +} +fn get_uids() -> JsonValue { + let data = lock_and_select("SELECT jsondata FROM uids"); + json::parse(&data.unwrap()).unwrap() +} +fn get_tokens() -> JsonValue { + let data = lock_and_select("SELECT jsondata FROM tokens"); + json::parse(&data.unwrap()).unwrap() +} + +fn generate_uid() -> i64 { + create_uid_store(); + let mut rng = rand::thread_rng(); + let random_number = rng.gen_range(100_000_000_000_000..=999_999_999_999_999); + let mut existing_ids = get_uids(); + //the chances of this...? + if existing_ids.contains(random_number) { + return generate_uid(); + } + existing_ids.push(random_number).unwrap(); + store_data("uids", existing_ids); + + random_number +} + +fn create_acc(uid: i64, login: &str) { + let key = &uid.to_string(); + + let mut new_user = json::parse(include_str!("new_user.json")).unwrap(); + new_user["user"]["id"] = uid.into(); + new_user["stamina"]["last_updated_time"] = global::timestamp().into(); + + create_store(&format!("SELECT userhome FROM _{}_", key), &format!("CREATE TABLE _{}_ ( + userdata TEXT NOT NULL, + userhome TEXT NOT NULL, + missions TEXT NOT NULL + )", key), + &format!("INSERT INTO _{}_ (userdata, userhome, missions) VALUES (?1, ?2, ?3)", key), + params!( + json::stringify(new_user), + include_str!("new_user_home.json"), + include_str!("chat_missions.json") + ) + ); + + create_token_store(); + let mut tokens = get_tokens(); + tokens[login] = uid.into(); + store_data("tokens", tokens); +} + +fn get_uid(uid: &str) -> i64 { + create_token_store(); + let tokens = get_tokens(); + if tokens[uid].is_null() { + return 0; + } + return tokens[uid].as_i64().unwrap(); +} + +fn get_login_token(uid: i64) -> String { + create_token_store(); + let tokens = get_tokens(); + for (_i, data) in tokens.entries().enumerate() { + if uid == data.1.as_i64().unwrap() { + return data.0.to_string(); + } + } + String::new() +} + +fn get_data(auth_key: &str, row: &str) -> JsonValue { + let key = get_key(&auth_key); + + let result = lock_and_select(&format!("SELECT {} FROM _{}_", row, key)); + + json::parse(&result.unwrap()).unwrap() +} + +pub fn get_acc(auth_key: &str) -> JsonValue { + let mut user = get_data(auth_key, "userdata"); let max = 100; //todo let speed = 300; //5 mins let since_last = global::timestamp() - user["stamina"]["last_updated_time"].as_u64().unwrap(); @@ -198,192 +212,98 @@ pub fn get_acc(a6573cbe: &str) -> JsonValue { return user; } -pub fn get_acc_home(a6573cbe: &str) -> JsonValue { - return get_data(a6573cbe)["home"].clone(); +pub fn get_acc_home(auth_key: &str) -> JsonValue { + get_data(auth_key, "userhome") } -pub fn get_acc_missions(a6573cbe: &str) -> JsonValue { - return get_data(a6573cbe)["missions"].clone(); +pub fn get_acc_missions(auth_key: &str) -> JsonValue { + get_data(auth_key, "missions") } -pub fn save_data(a6573cbe: &str, data: JsonValue, id: &str) { - loop { - match ENGINE.lock() { - Ok(mut result) => { - if result.is_none() { - init(&mut result); - } - let conn = result.as_ref().unwrap(); - let uid = get_uid(conn, &a6573cbe); - - let key: i64; - if uid == 0 { - key = generate_uid(conn); - create_acc(conn, key, &a6573cbe); - } else { - key = uid; - } - - if !acc_exists(conn, key) { - create_acc(conn, key, &a6573cbe); - } - let mut stmt = conn.prepare(&format!("SELECT jsondata FROM _{}_", key)).unwrap(); - let result: Result = stmt.query_row([], |row| row.get(0)); - - let mut rv = json::parse(&result.unwrap()).unwrap(); - - rv[id] = data; - store_data(conn, &format!("_{}_", key), rv); - break; - } - Err(_) => { - std::thread::sleep(std::time::Duration::from_millis(15)); - } - } - } +pub fn save_data(auth_key: &str, row: &str, data: JsonValue) { + let key = get_key(&auth_key); + + lock_and_exec(&format!("UPDATE _{}_ SET {}=?1", key, row), params!(json::stringify(data))); } -pub fn save_acc(a6573cbe: &str, data: JsonValue) { - save_data(a6573cbe, data, "userdata"); +pub fn save_acc(auth_key: &str, data: JsonValue) { + save_data(auth_key, "userdata", data); } -pub fn save_acc_home(a6573cbe: &str, data: JsonValue) { - save_data(a6573cbe, data, "home"); +pub fn save_acc_home(auth_key: &str, data: JsonValue) { + save_data(auth_key, "userhome", data); } -pub fn save_acc_missions(a6573cbe: &str, data: JsonValue) { - save_data(a6573cbe, data, "missions"); +pub fn save_acc_missions(auth_key: &str, data: JsonValue) { + save_data(auth_key, "missions", data); } pub fn get_acc_transfer(uid: i64, token: &str, password: &str) -> JsonValue { - loop { - match ENGINE.lock() { - Ok(mut result) => { - if result.is_none() { - init(&mut result); - } - let conn = result.as_ref().unwrap(); - create_migration_store(conn); - - let mut stmt = conn.prepare("SELECT jsondata FROM migrationdata").unwrap(); - let result: Result = stmt.query_row([], |row| row.get(0)); - - let data = json::parse(&result.unwrap()).unwrap(); - - if data[token].is_empty() { - return object!{success: false}; - } - if data[token].to_string() == password.to_string() { - let login_token = get_login_token(conn, uid); - if login_token == String::new() { - return object!{success: false}; - } - return object!{success: true, login_token: login_token}; - } - - return object!{success: false}; - } - Err(_) => { - std::thread::sleep(std::time::Duration::from_millis(15)); - } - } + create_migration_store(); + + let result = lock_and_select("SELECT jsondata FROM migrationdata"); + let data = json::parse(&result.unwrap()).unwrap(); + + if data[token].is_empty() { + return object!{success: false}; } + if data[token].to_string() == password.to_string() { + let login_token = get_login_token(uid); + if login_token == String::new() { + return object!{success: false}; + } + return object!{success: true, login_token: login_token}; + } + + return object!{success: false}; } pub fn save_acc_transfer(token: &str, password: &str) { - loop { - match ENGINE.lock() { - Ok(mut result) => { - if result.is_none() { - init(&mut result); - } - let conn = result.as_ref().unwrap(); - create_migration_store(conn); - - let mut stmt = conn.prepare("SELECT jsondata FROM migrationdata").unwrap(); - let result: Result = stmt.query_row([], |row| row.get(0)); - - let mut data = json::parse(&result.unwrap()).unwrap(); - - data[token] = password.into(); - - store_data(conn, "migrationdata", data); - break; - } - Err(_) => { - std::thread::sleep(std::time::Duration::from_millis(15)); - } - } - } + create_migration_store(); + + let result = lock_and_select("SELECT jsondata FROM migrationdata"); + let mut data = json::parse(&result.unwrap()).unwrap(); + + data[token] = password.into(); + + store_data("migrationdata", data); } pub fn get_name_and_rank(uid: i64) -> JsonValue { - loop { - match ENGINE.lock() { - Ok(mut result) => { - if result.is_none() { - init(&mut result); - } - let conn = result.as_ref().unwrap(); - create_migration_store(conn); - let login_token = get_login_token(conn, uid); - if login_token == String::new() { - return object!{ - user_name: "", - user_rank: 1 - } - } - let uid = get_uid(conn, &login_token); - if uid == 0 || !acc_exists(conn, uid) { - return object!{ - user_name: "", - user_rank: 1 - } - } - let mut stmt = conn.prepare(&format!("SELECT jsondata FROM _{}_", uid)).unwrap(); - let result: Result = stmt.query_row([], |row| row.get(0)); - - let data = json::parse(&result.unwrap()).unwrap(); - - return object!{ - user_name: data["userdata"]["user"]["name"].clone(), - user_rank: 1 //todo - } - } - Err(_) => { - std::thread::sleep(std::time::Duration::from_millis(15)); - } + create_migration_store(); + let login_token = get_login_token(uid); + if login_token == String::new() { + return object!{ + user_name: "", + user_rank: 1 } } + let uid = get_uid(&login_token); + if uid == 0 || !acc_exists(uid) { + return object!{ + user_name: "", + user_rank: 1 + } + } + let result = lock_and_select(&format!("SELECT userdata FROM _{}_", uid)); + let data = json::parse(&result.unwrap()).unwrap(); + + return object!{ + user_name: data["user"]["name"].clone(), + user_rank: 1 //todo + } } pub fn get_acc_from_uid(uid: i64) -> JsonValue { - loop { - match ENGINE.lock() { - Ok(mut result) => { - if result.is_none() { - init(&mut result); - } - let conn = result.as_ref().unwrap(); - create_migration_store(conn); - let login_token = get_login_token(conn, uid); - if login_token == String::new() { - return object!{ - user_name: "", - user_rank: 1 - } - } - let uid = get_uid(conn, &login_token); - if uid == 0 || !acc_exists(conn, uid) { - return object!{"error": true} - } - let mut stmt = conn.prepare(&format!("SELECT jsondata FROM _{}_", uid)).unwrap(); - let result: Result = stmt.query_row([], |row| row.get(0)); - - let data = json::parse(&result.unwrap()).unwrap(); - - return data["userdata"].clone(); - } - Err(_) => { - std::thread::sleep(std::time::Duration::from_millis(15)); - } + create_migration_store(); + let login_token = get_login_token(uid); + if login_token == String::new() { + return object!{ + user_name: "", + user_rank: 1 } } + let uid = get_uid(&login_token); + if uid == 0 || !acc_exists(uid) { + return object!{"error": true} + } + let result = lock_and_select(&format!("SELECT userdata FROM _{}_", uid)); + json::parse(&result.unwrap()).unwrap() }