diff --git a/Cargo.toml b/Cargo.toml index a03910e..1f5321b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" actix-web = { version = "4.5.1", features = [ "openssl" ] } rusqlite = { version = "0.30.0", features = ["bundled"] } openssl = { version = "0.10", features = ["vendored"] } +reqwest = { version = "0.11", features = ["blocking"] } base64 = "0.21.5" json = "0.12.4" rand = "0.8.5" diff --git a/src/main.rs b/src/main.rs index 5ce0113..e331477 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ fn unhandled(req: HttpRequest, body: String) -> Option { None } -fn api_req(req: HttpRequest, body: String) -> HttpResponse { +async fn api_req(req: HttpRequest, body: String) -> HttpResponse { let headers = req.headers().clone(); if !req.path().starts_with("/api") && !req.path().starts_with("/v1.0") { return router::webui::main(req); @@ -89,7 +89,7 @@ fn api_req(req: HttpRequest, body: String) -> HttpResponse { "/api/card/evolve" => router::card::evolve(req, body), "/api/shop/buy" => router::shop::buy(req, body), "/api/user/getregisteredplatformlist" => router::user::getregisteredplatformlist(req, body), - "/api/user/sif/migrate" => router::user::sif_migrate(req, body), + "/api/user/sif/migrate" => router::user::sif_migrate(req, body).await, "/api/user/ss/migrate" => router::user::sifas_migrate(req, body), "/api/exchange" => router::exchange::exchange_post(req, body), "/api/item/use" => router::items::use_item_req(req, body), @@ -147,7 +147,7 @@ async fn request(req: HttpRequest, body: String) -> HttpResponse { "/api/webui/import" => router::webui::import(req, body), "/api/webui/set_time" => router::webui::set_time(req, body), "/api/webui/admin" => router::webui::admin_post(req, body), - _ => api_req(req, body) + _ => api_req(req, body).await } } else { match req.path() { @@ -163,7 +163,7 @@ async fn request(req: HttpRequest, body: String) -> HttpResponse { "/webui/logout" => router::webui::logout(req), "/api/webui/admin" => router::webui::admin(req), "/api/webui/export" => router::webui::export(req), - _ => api_req(req, body) + _ => api_req(req, body).await } } } @@ -197,8 +197,6 @@ async fn main() -> std::io::Result<()> { rv.await } - - #[macro_export] macro_rules! include_file { ( $s:expr ) => { diff --git a/src/router/user.rs b/src/router/user.rs index d546aa4..44928dc 100644 --- a/src/router/user.rs +++ b/src/router/user.rs @@ -1,5 +1,6 @@ use json::{array, object, JsonValue}; use actix_web::{HttpRequest}; +use sha1::{Sha1, Digest}; use crate::encryption; use crate::router::{userdata, global, items}; @@ -286,7 +287,7 @@ pub fn sif(req: HttpRequest) -> Option { let mut cards = userdata::get_acc_sif(&key); // prevent duplicate data in the database - if user["user"]["sif_user_id"].as_i64().unwrap() == 111111111 { + if user["user"]["sif_user_id"].as_i64().unwrap_or(0) == 111111111 { cards = json::parse(&include_file!("src/router/userdata/full_sif.json")).unwrap(); } @@ -308,13 +309,62 @@ pub fn sifas_migrate(_req: HttpRequest, _body: String) -> Option { }) } -pub fn sif_migrate(req: HttpRequest, body: String) -> Option { +fn _a_sha1(t: &str) -> String { + let mut hasher = Sha1::new(); + hasher.update(t.as_bytes()); + let result = hasher.finalize(); + format!("{:X}", result) +} + +fn generate_passcode_sha1(transfer_id: String, transfer_code: String) -> String { + let id_sha1 = _a_sha1(&transfer_id); + _a_sha1(&format!("{}{}", id_sha1, transfer_code)) +} + +async fn npps4_req(sha_id: String) -> Option { + let client = reqwest::Client::new(); + // TODO - ability to configure in admin webui? + let hostname = "http://127.0.0.1:51376"; + let url = format!("{}/ewexport?sha1={}", hostname, sha_id); + println!("Polling NPPS4 at {}", hostname); + let response = client.get(url); + let response_body = response.send().await.ok()?.text().await.ok()?; + Some(json::parse(&response_body).ok()?) +} + +fn clean_sif_data(current: &JsonValue) -> JsonValue { + let mut rv = array![]; + for data in current.members() { + rv.push(object!{ + master_card_id: data["id"].clone(), + evolve: if data["idolized"].as_bool().unwrap_or(false) { 1 } else { 0 }, + sign_flag: if data["signed"].as_bool().unwrap_or(false) { 1 } else { 0 } + }).unwrap(); + } + rv +} + +pub async fn sif_migrate(req: HttpRequest, body: String) -> Option { let key = global::get_login(req.headers(), &body); let mut user = userdata::get_acc(&key); - user["user"]["sif_user_id"] = 111111111.into(); + let body = json::parse(&encryption::decrypt_packet(&body).unwrap()).unwrap(); + + let id = generate_passcode_sha1(body["sif_user_id"].to_string(), body["password"].to_string()); + let user_info = npps4_req(id).await; + if user_info.is_none() { + return Some(object!{ + sif_migrate_status: 38 + }); + } + let user_info = user_info.unwrap(); + + //TODO - give rewards? Titles? + + user["user"]["sif_user_id"] = body["sif_user_id"].to_string().parse::().unwrap().into(); //sif2 client sends this as a string... items::give_gift_basic(8, 4293000525, 1, &mut user, &mut array![], &mut array![], &mut array![]); items::give_gift_basic(8, 4293000521, 1, &mut user, &mut array![], &mut array![], &mut array![]); + userdata::save_acc_sif(&key, clean_sif_data(&user_info["units"])); userdata::save_acc(&key, user.clone()); Some(object!{ @@ -323,17 +373,6 @@ pub fn sif_migrate(req: HttpRequest, body: String) -> Option { "master_title_ids": user["master_title_ids"].clone() }) - - /* - // Error response - let resp = object!{ - "code": 0, - "server_time": global::timestamp(), - "data": { - "sif_migrate_status": 38 - } - }; - */ } pub fn getregisteredplatformlist(_req: HttpRequest, _body: String) -> Option { diff --git a/src/router/userdata/mod.rs b/src/router/userdata/mod.rs index 0da1ae7..5fc32b0 100644 --- a/src/router/userdata/mod.rs +++ b/src/router/userdata/mod.rs @@ -296,6 +296,9 @@ pub fn save_server_data(auth_key: &str, data: JsonValue) { pub fn save_acc_chats(auth_key: &str, data: JsonValue) { save_data(auth_key, "chats", data); } +pub fn save_acc_sif(auth_key: &str, data: JsonValue) { + save_data(auth_key, "sifcards", data); +} fn generate_salt() -> Vec { let mut rng = rand::thread_rng();