Implement NPPS4 integration

This commit is contained in:
Ethan O'Brien 2024-06-04 11:42:40 -05:00
parent a1e400c1ec
commit cb3a62caa5
4 changed files with 61 additions and 20 deletions

View file

@ -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"

View file

@ -25,7 +25,7 @@ fn unhandled(req: HttpRequest, body: String) -> Option<JsonValue> {
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 ) => {

View file

@ -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<JsonValue> {
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<JsonValue> {
})
}
pub fn sif_migrate(req: HttpRequest, body: String) -> Option<JsonValue> {
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<JsonValue> {
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<JsonValue> {
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::<i32>().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<JsonValue> {
"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<JsonValue> {

View file

@ -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<u8> {
let mut rng = rand::thread_rng();