diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index cb2444f..bae49d5 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -6,19 +6,21 @@ services: build: dockerfile: "./Dockerfile" environment: - PORT: 8081 + PORT: 8080 DIRECTORY: /data/ HTTPS: false NPPS4_ADDRESS: "http://127.0.0.1:51376" + MAXTIME: 1717045200 # A day before global EOS + HIDDEN: false # Will disable the webui - #Everything below is for the "Help" page - ANDROID_GLOBAL: "link.to/patched/android/global.apk" - ANDROID_JAPAN: "link.to/patched/android/japan.apk" - IOS_GLOBAL: "link.to/ios/global.ipa" - IOS_JAPAN: "link.to/ios/japan.ipa" - ASSET_URL: "link.to/client/assets/" + # Everything below is for the "Help" page + #ANDROID_GLOBAL: "link.to/patched/android/global.apk" + #ANDROID_JAPAN: "link.to/patched/android/japan.apk" + #IOS_GLOBAL: "link.to/ios/global.ipa" + #IOS_JAPAN: "link.to/ios/japan.ipa" + #ASSET_URL: "link.to/client/assets/" ports: - - 8081:8081 + - 8080:8080 volumes: - ./data:/data restart: unless-stopped diff --git a/docker/start.sh b/docker/start.sh index c6421c0..7a938e1 100755 --- a/docker/start.sh +++ b/docker/start.sh @@ -11,4 +11,6 @@ hidden=$([ "$HIDDEN" = "true" ] && echo "--hidden" || echo "") maxTime="${MAXTIME:-0}" -/root/ew/ew --path $directory --port $port --npps4 $npps4 $hidden $https --global-android "$ANDROID_GLOBAL" --japan-android "$ANDROID_JAPAN" --global-ios "$IOS_GLOBAL" --japan-ios "$IOS_JAPAN" --assets-url "$ASSET_URL" --max-time $maxTime +purge=$([ "$PURGE" = "true" ] && echo "--purge" || echo "") + +/root/ew/ew --path $directory --port $port --npps4 $npps4 $purge $hidden $https --global-android "$ANDROID_GLOBAL" --japan-android "$ANDROID_JAPAN" --global-ios "$IOS_GLOBAL" --japan-ios "$IOS_JAPAN" --assets-url "$ASSET_URL" --max-time $maxTime diff --git a/src/main.rs b/src/main.rs index 9ec85ee..f643211 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,7 +64,10 @@ pub struct Args { max_time: u64, #[arg(long, default_value_t = false, help = "Disable webui, act completely like the original server")] - hidden: bool + hidden: bool, + + #[arg(long, default_value_t = false, help = "Purge dead user accounts on startup")] + purge: bool } #[actix_web::main] @@ -72,6 +75,12 @@ async fn main() -> std::io::Result<()> { let args = get_args(); let port = args.port; + if args.purge { + println!("Purging accounts..."); + let ct = crate::router::userdata::purge_accounts(); + println!("Purged {} accounts", ct); + } + let rv = HttpServer::new(|| App::new() .wrap_fn(|req, srv| { println!("Request: {}", req.path()); diff --git a/src/router/gree.rs b/src/router/gree.rs index d60fe16..9995898 100644 --- a/src/router/gree.rs +++ b/src/router/gree.rs @@ -70,6 +70,15 @@ fn verify_signature(signature: &[u8], message: &[u8], public_key: &[u8]) -> bool verifier.verify(signature).is_ok() } + +pub fn delete_uuid(user_id: i64) { + DATABASE.lock_and_exec("DELETE FROM users WHERE user_id=?1", params!(user_id)); +} + +pub fn vacuum_database() { + DATABASE.lock_and_exec("VACUUM", params!()); +} + pub fn get_uuid(headers: &HeaderMap, body: &str) -> String { let body = encryption::decrypt_packet(body).unwrap(); let blank_header = HeaderValue::from_static(""); diff --git a/src/router/userdata/mod.rs b/src/router/userdata/mod.rs index 1ce74c8..95013f7 100644 --- a/src/router/userdata/mod.rs +++ b/src/router/userdata/mod.rs @@ -610,3 +610,38 @@ pub fn export_user(token: &str) -> Option { sifcards: json::stringify(get_acc_sif(&login_token)) }) } + +pub fn purge_accounts() -> usize { + // If the user has no cards, its safe to assume its a dead account (imo). In the (rare) event this function is ran after a user started and before the account has characters, the server should create them a new account, and let them start the tutorial over. + let dead_uids = DATABASE.lock_and_select_all(" + SELECT user_id + FROM userdata + WHERE (userdata LIKE ?1 AND userdata LIKE ?2 AND friend_request_disabled=1) + OR (userdata LIKE ?3 AND friend_request_disabled=1)", + params!( + "%\"card_list\":[]%", + "%Tutorial in progress%", + "%tutorial_step\":60%" //For some reason, a majority of dead accounts in the tutorial are here.... + )).unwrap(); + for uid in dead_uids.members() { + let user_id = uid.as_i64().unwrap(); + println!("Removing dead UID: {}", user_id); + crate::router::gree::delete_uuid(user_id); + DATABASE.lock_and_exec("DELETE FROM userdata WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM userhome WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM missions WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM loginbonus WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM sifcards WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM friends WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM chats WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM event WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM eventloginbonus WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM server_data WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM webui WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM tokens WHERE user_id=?1", params!(user_id)); + DATABASE.lock_and_exec("DELETE FROM migration WHERE token=?1", params!(crate::router::user::uid_to_code(user_id.to_string()))); + } + DATABASE.lock_and_exec("VACUUM", params!()); + crate::router::gree::vacuum_database(); + dead_uids.len() +}