diff --git a/logs/ew b/logs/ew new file mode 100644 index 0000000..5759d1e Binary files /dev/null and b/logs/ew differ diff --git a/logs/ew- b/logs/ew- new file mode 100644 index 0000000..69270e3 Binary files /dev/null and b/logs/ew- differ diff --git a/src/main.rs b/src/main.rs index 7235d22..4e0d7be 100644 --- a/src/main.rs +++ b/src/main.rs @@ -227,6 +227,9 @@ async fn webui_user(req: HttpRequest) -> HttpResponse { router::webui::user(req) #[get("/webui/logout")] async fn webui_logout(req: HttpRequest) -> HttpResponse { router::webui::logout(req) } +#[post("/api/webui/import")] +async fn webui_import(req: HttpRequest, body: String) -> HttpResponse { router::webui::import(req, body) } + fn unhandled(req: HttpRequest) -> HttpResponse { router::webui::main(req) } @@ -266,6 +269,7 @@ async fn main() -> std::io::Result<()> { }) .service(css) .service(js) + .service(webui_import) .service(webui_logout) .service(webui_user) .service(webui_login) diff --git a/src/router/gree.rs b/src/router/gree.rs index b52e14c..2b60a3c 100644 --- a/src/router/gree.rs +++ b/src/router/gree.rs @@ -104,6 +104,14 @@ fn get_new_uuid() -> String { id } +pub fn import_user(uid: i64) -> String { + let token = get_new_uuid(); + lock_and_exec( + "INSERT INTO users (cert, uuid, user_id) VALUES (?1, ?2, ?3)", + params!("", token, uid) + ); + token +} fn update_cert(uid: i64, cert: &str) { lock_and_exec("UPDATE users SET cert=?1 WHERE user_id=?2", params!(cert, uid)); } @@ -187,7 +195,6 @@ fn decrypt_transfer_password(password: &str) -> String { } - pub fn initialize(req: HttpRequest, body: String) -> HttpResponse { let body = json::parse(&body).unwrap(); let token = create_acc(&body["token"].to_string()); diff --git a/src/router/userdata/mod.rs b/src/router/userdata/mod.rs index b198344..acf2490 100644 --- a/src/router/userdata/mod.rs +++ b/src/router/userdata/mod.rs @@ -434,6 +434,50 @@ pub fn webui_login(uid: i64, password: &str) -> Result { Ok(new_token) } +pub fn webui_import_user(user: JsonValue) -> Result { + let mut user = user; + create_webui_store(); + create_migration_store(); + create_token_store(); + let uid = user["userdata"]["user"]["id"].as_i64().unwrap(); + if acc_exists(uid) { + return Err(String::from("User already exists")); + } + if user["missions"].is_empty() { + user["missions"] = json::parse(include_str!("chat_missions.json")).unwrap(); + } + if user["sif_cards"].is_empty() { + user["sif_cards"] = array![]; + } + + lock_and_exec("INSERT INTO users (user_id, userdata, userhome, missions, loginbonus, sifcards, friends) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", params!( + uid, + json::stringify(user["userdata"].clone()), + json::stringify(user["home"].clone()), + json::stringify(user["missions"].clone()), + format!(r#"{{"last_rewarded": 0, "bonus_list": [], "start_time": {}}}"#, global::timestamp()), + json::stringify(user["sif_cards"].clone()), + r#"{"friend_user_id_list":[],"request_user_id_list":[],"pending_user_id_list":[]}"# + )); + + let token; + if !user["jp"].is_empty() { + token = crate::router::gree::import_user(uid); + } else { + token = format!("{}", Uuid::new_v4()); + } + + lock_and_exec("INSERT INTO tokens (user_id, token) VALUES (?1, ?2)", params!(uid, token)); + let mig = crate::router::user::uid_to_code(uid.to_string()); + + save_acc_transfer(&mig, &user["password"].to_string()); + + Ok(object!{ + uid: uid, + migration_token: mig + }) +} + pub fn webui_get_user(token: &str) -> Option { let uid = lock_and_select("SELECT user_id FROM webui WHERE token=?1", params!(token)).unwrap_or(String::new()); if uid == String::new() || token == "" { diff --git a/src/router/webui.rs b/src/router/webui.rs index db9bd5b..2b2c9bb 100644 --- a/src/router/webui.rs +++ b/src/router/webui.rs @@ -41,6 +41,26 @@ pub fn login(_req: HttpRequest, body: String) -> HttpResponse { .body(json::stringify(resp)) } +pub fn import(_req: HttpRequest, body: String) -> HttpResponse { + let body = json::parse(&body).unwrap(); + + let result = userdata::webui_import_user(body); + + if result.is_err() { + return error(&result.unwrap_err()); + } + let result = result.unwrap(); + + let resp = object!{ + result: "OK", + uid: result["uid"].clone(), + migration_token: result["migration_token"].clone() + }; + HttpResponse::Ok() + .insert_header(ContentType::json()) + .body(json::stringify(resp)) +} + pub fn user(req: HttpRequest) -> HttpResponse { let token = get_login_token(&req); if token.is_none() { @@ -90,7 +110,7 @@ pub fn main(req: HttpRequest) -> HttpResponse { } } } - if req.path() != "/" && req.path() != "/home/" { + if req.path() != "/" && req.path() != "/home/" && req.path() != "/import/" { return HttpResponse::Found() .insert_header(("Location", "/")) .body(""); diff --git a/webui/src/import/Import.css b/webui/src/import/Import.css new file mode 100644 index 0000000..2168936 --- /dev/null +++ b/webui/src/import/Import.css @@ -0,0 +1,95 @@ +body { + background-color: #616161; +} + +#login-form { + width: 400px; + max-width: 100%; + margin: 50px auto; + background-color: green; + border-radius: 10px; + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); + font-family: "Poppins", sans-serif; +} + +#login-form h1 { + text-align: center; + margin: 0; + padding: 20px 0; + font-size: 28px; + font-weight: bold; + color: white; +} + +#login-form form { + padding: 20px; + background-color: white; + border-radius: 10px; + font-family: "Poppins", sans-serif; +} + +#login-form form label { + display: block; + margin-bottom: 8px; + font-size: 14px; + color: black; + font-family: "Poppins", sans-serif; +} + +#login-form form input[type="file"], +#login-form form input[type="password"] { + width: 100%; + padding: 12px; + border: 1px solid lightgray; + border-radius: 5px; + font-size: 16px; + box-sizing: border-box; + margin-bottom: 20px; +} + +#login-form form input[type="submit"] { + width: 100%; + padding: 12px; + background-color: dodgerblue; + border: none; + color: white; + font-size: 16px; + font-weight: bold; + border-radius: 5px; + cursor: pointer; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: background-color 0.3s ease; +} + +#login-form form input[type="submit"]:hover { + background-color: deepskyblue; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); +} + +#sub_div p { + color: red; + grid-template-columns: auto auto auto; +} + +#sub_div { + padding-top: 10px; +} + +#sub_div button { + width: 40%; + padding: 12px; + background-color: blue; + border: none; + color: white; + font-size: 16px; + font-weight: bold; + border-radius: 5px; + cursor: pointer; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: background-color 0.3s ease; +} + +#sub_div button:hover { + background-color: green; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); +} diff --git a/webui/src/import/Import.jsx b/webui/src/import/Import.jsx new file mode 100644 index 0000000..d4e514e --- /dev/null +++ b/webui/src/import/Import.jsx @@ -0,0 +1,84 @@ +import { useState } from 'react' +import './Import.css' +import Request from '../Request.jsx' + +function Login() { + const error = useState(new URL(window.location).searchParams.get("message") || ""); + const status = useState(""); + const uid = useState((window.localStorage && window.localStorage.getItem("ew_uid")) || ""); + let file=[], file1=[], file2=[], file3=[], password; + let has_imported = false; + + const handleSubmit = async (event) => { + event.preventDefault(); + if (!file[0] || !file1[0] || has_imported || !password) return; + try { + has_imported = true; + let data = { + userdata: JSON.parse(await file[0].text()), + home: JSON.parse(await file1[0].text()), + missions: file2[0] ? JSON.parse(await file2[0].text()) : undefined, + sif_cards: file3[0] ? JSON.parse(await file3[0].text()) : undefined, + password: password, + jp: true + }; + if (!data.userdata || !data.userdata.user || !data.userdata.user.id) { + error[1]("Incorrect user data file format"); + return; + } + if (!data.home || !data.home.home || !data.home.home.information_list) { + error[1]("Incorrect home data file format"); + return; + } + if (!Array.isArray(data.missions) && data.missions) { + error[1]("Incorrect mission data file format"); + return; + } + if (!Array.isArray(data.sif_cards) && data.sif_cards) { + error[1]("Incorrect sif card data file format"); + return; + } + let resp = await Request( + "/api/webui/import", + data + ); + if (resp.result == "OK") { + status[1](

Account imported!

User id: {resp.uid}

Migration token: {resp.migration_token}

); + } else { + error[1](resp.message); + } + } catch(e) { + error[1](e.message); + } + }; + + return ( +
+

Transfer

+
+ {

{ status[0] }

} + + {file = event.target.files}} accept="application/json"/> + + + {file1 = event.target.files}} accept="application/json"/> + + + {file2 = event.target.files}} accept="application/json"/> + + + {file3 = event.target.files}} accept="application/json"/> + + + {password = event.target.value}} /> + + +
+ { error[0] ?

Error: { error[0] }. Please reload the page and try again.

:

} +
+
+
+ ); +} + +export default Login; diff --git a/webui/src/index.css b/webui/src/index.css deleted file mode 100644 index 6119ad9..0000000 --- a/webui/src/index.css +++ /dev/null @@ -1,68 +0,0 @@ -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} diff --git a/webui/src/login/Login.css b/webui/src/login/Login.css index ce64481..2152217 100644 --- a/webui/src/login/Login.css +++ b/webui/src/login/Login.css @@ -66,6 +66,30 @@ body { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); } -#error { - color: red; +#sub_div p { + color: red; + grid-template-columns: auto auto auto; +} + +#sub_div { + padding-top: 10px; +} + +#sub_div button { + width: 40%; + padding: 12px; + background-color: blue; + border: none; + color: white; + font-size: 16px; + font-weight: bold; + border-radius: 5px; + cursor: pointer; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: background-color 0.3s ease; +} + +#sub_div button:hover { + background-color: green; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3); } diff --git a/webui/src/login/Login.jsx b/webui/src/login/Login.jsx index 1bf29a2..c703506 100644 --- a/webui/src/login/Login.jsx +++ b/webui/src/login/Login.jsx @@ -24,6 +24,11 @@ function Login() { error[1](resp.message); } }; + + const import_user = (e) => { + e.preventDefault(); + window.location.href = "/import/"; + } return (
@@ -34,7 +39,10 @@ function Login() { {password = event.target.value}} /> - { error[0] &&

Error: { error[0] }

} +
+ + { error[0] ?

Error: { error[0] }

:

} +
); diff --git a/webui/src/main.jsx b/webui/src/main.jsx index c14aef8..74e0193 100644 --- a/webui/src/main.jsx +++ b/webui/src/main.jsx @@ -2,7 +2,7 @@ import React from 'react' import ReactDOM from 'react-dom/client' import Login from './login/Login.jsx' import Home from './home/Home.jsx' -//import './index.css' +import Import from './import/Import.jsx' let Elem; switch (window.location.pathname) { @@ -12,6 +12,9 @@ switch (window.location.pathname) { case "/home/": Elem = Home; break; + case "/import/": + Elem = Import; + break; default: window.location.pathname = "/"; }