login is functional now

This commit is contained in:
HorizonCode 2024-01-11 12:59:52 +01:00
parent 05b9ddd5a1
commit d0937f626d
10 changed files with 1509 additions and 110 deletions

61
main.js
View File

@ -3,6 +3,7 @@ const { app, BrowserWindow, Menu, ipcMain } = require("electron");
const path = require("path"); const path = require("path");
const serve = require("electron-serve"); const serve = require("electron-serve");
const loadURL = serve({ directory: "public" }); const loadURL = serve({ directory: "public" });
const config = require("./src/config/config");
const { setupTitlebar, attachTitlebarToWindow } = require( const { setupTitlebar, attachTitlebarToWindow } = require(
"custom-electron-titlebar/main", "custom-electron-titlebar/main",
); );
@ -19,7 +20,10 @@ function registerIPCPipes() {
ipcMain.handle("ezpplauncher:login", async (e, args) => { ipcMain.handle("ezpplauncher:login", async (e, args) => {
const fetchResult = await fetch("https://ez-pp.farm/login/check", { const fetchResult = await fetch("https://ez-pp.farm/login/check", {
method: "POST", method: "POST",
body: JSON.stringify({ username: args.username, password: args.password }), body: JSON.stringify({
username: args.username,
password: args.password,
}),
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
@ -27,12 +31,61 @@ function registerIPCPipes() {
if (fetchResult.ok) { if (fetchResult.ok) {
const result = await fetchResult.json(); const result = await fetchResult.json();
if (result.code == 200) return result; if ("user" in result) {
if (args.saveCredentials) {
config.set("username", args.username);
config.set("password", args.password);
}
config.remove("guest");
}
return result;
} }
return { return {
code: 403, code: 500,
message: "Invalid username or password.", message: "Something went wrong while logging you in.",
};
});
ipcMain.handle("ezpplauncher:autologin", async (e) => {
const username = config.get("username");
const password = config.get("password");
const guest = config.get("guest");
if (guest) return { code: 200, message: "Login as guest", guest: true };
if (username == undefined || password == undefined) {
return { code: 200, message: "No autologin" };
} }
const fetchResult = await fetch("https://ez-pp.farm/login/check", {
method: "POST",
body: JSON.stringify({
username: username,
password: password,
}),
headers: {
"Content-Type": "application/json",
},
});
if (fetchResult.ok) {
const result = await fetchResult.json();
return result;
}
return {
code: 500,
message: "Something went wrong while logging you in.",
};
});
ipcMain.handle("ezpplauncher:guestlogin", (e) => {
config.remove("username");
config.remove("password");
config.set("guest", "1");
});
ipcMain.handle("ezpplauncher:logout", (e) => {
config.remove("username");
config.remove("password");
config.remove("guest");
return true;
}); });
} }

1331
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
}, },
"scripts": { "scripts": {
"build": "rollup -c --bundleConfigAsCjs", "build": "rollup -c --bundleConfigAsCjs",
"rebuild": "electron-rebuild",
"dev": "rollup -c -w --bundleConfigAsCjs", "dev": "rollup -c -w --bundleConfigAsCjs",
"start": "sirv public --no-clear", "start": "sirv public --no-clear",
"electron": "wait-on http://localhost:8080 && electron .", "electron": "wait-on http://localhost:8080 && electron .",
@ -33,7 +34,10 @@
"check": "svelte-check --tsconfig ./tsconfig.json" "check": "svelte-check --tsconfig ./tsconfig.json"
}, },
"dependencies": { "dependencies": {
"@electron/rebuild": "^3.5.0",
"@types/better-sqlite3": "^7.6.8",
"axios": "^1.6.5", "axios": "^1.6.5",
"better-sqlite3": "^9.2.2",
"custom-electron-titlebar": "^4.2.7", "custom-electron-titlebar": "^4.2.7",
"electron-serve": "^1.1.0", "electron-serve": "^1.1.0",
"svelte-french-toast": "^1.2.0" "svelte-french-toast": "^1.2.0"

View File

@ -15,6 +15,24 @@ window.addEventListener("login-attempt", async (e) => {
const loginResult = await ipcRenderer.invoke("ezpplauncher:login", { const loginResult = await ipcRenderer.invoke("ezpplauncher:login", {
username: e.detail.username, username: e.detail.username,
password: e.detail.password, password: e.detail.password,
saveCredentials: e.detail.saveCredentials,
}); });
window.dispatchEvent(new CustomEvent("login-result", { detail: loginResult })); window.dispatchEvent(
}) new CustomEvent("login-result", { detail: loginResult }),
);
});
window.addEventListener("autologin-attempt", async (e) => {
const loginResult = await ipcRenderer.invoke("ezpplauncher:autologin");
window.dispatchEvent(
new CustomEvent("login-result", { detail: loginResult }),
);
});
window.addEventListener("logout", async (e) => {
await ipcRenderer.invoke("ezpplauncher:logout");
});
window.addEventListener("guest-login", async (e) => {
await ipcRenderer.invoke("ezpplauncher:guestlogin");
});

View File

@ -31,6 +31,12 @@
loggedIn = newUser != undefined; loggedIn = newUser != undefined;
user = newUser; user = newUser;
}); });
const logout = () => {
window.dispatchEvent(new CustomEvent("logout"));
currentUser.set(undefined);
currentPage.set(Page.Login);
};
</script> </script>
<Toaster></Toaster> <Toaster></Toaster>
@ -52,7 +58,7 @@
id="avatar-menu" id="avatar-menu"
/> />
</div> </div>
<Dropdown placement="bottom" triggeredBy="#avatar-menu"> <Dropdown placement="bottom-start" triggeredBy="#avatar-menu">
<DropdownHeader> <DropdownHeader>
<span class="block text-sm">{loggedIn ? user?.name : "Guest"}</span> <span class="block text-sm">{loggedIn ? user?.name : "Guest"}</span>
<span <span
@ -79,10 +85,7 @@
{#if loggedIn} {#if loggedIn}
<DropdownItem <DropdownItem
class="flex flex-row gap-2 border-0 dark:!bg-gray-700 dark:active:!bg-gray-900 dark:hover:!bg-gray-800 transition-colors" class="flex flex-row gap-2 border-0 dark:!bg-gray-700 dark:active:!bg-gray-900 dark:hover:!bg-gray-800 transition-colors"
on:click={() => { on:click={logout}
currentUser.set(undefined);
currentPage.set(Page.Login);
}}
> >
<ArrowRightFromBracketSolid <ArrowRightFromBracketSolid
class="select-none outline-none border-none" class="select-none outline-none border-none"

45
src/config/config.js Normal file
View File

@ -0,0 +1,45 @@
const sqlite = require("better-sqlite3");
const path = require("path");
const fs = require("fs");
const configFolder = path.join(
process.platform == "win32"
? process.env["LOCALAPPDATA"]
: process.env["HOME"],
"EZPPLauncher",
);
if (!fs.existsSync(configFolder)) fs.mkdirSync(configFolder);
const dbFile = path.join(configFolder, "ezpplauncher.db");
const db = sqlite(dbFile);
db.pragma("journal_mode = WAL");
db.exec(
"CREATE TABLE IF NOT EXISTS config (configKey VARCHAR PRIMARY KEY, configValue VARCHAR);",
);
const set = (key, value) => {
db.prepare(
`INSERT OR REPLACE INTO config (configKey, configValue) VALUES (?, ?)`,
).run(key, value);
};
const remove = (key) => {
db.prepare(`DELETE FROM config WHERE configKey = ?`).run(key);
};
const get = (
key,
) => {
const result = db.prepare(
"SELECT configKey key, configValue val FROM config WHERE key = ?",
).get(key);
return result ? result.val ?? undefined : undefined;
};
module.exports = {
get,
set,
remove,
};

View File

@ -1,24 +1,44 @@
<script lang="ts"> <script lang="ts">
import { Button } from "flowbite-svelte"; import { Button, Checkbox } from "flowbite-svelte";
import Progressbar from "../lib/Progressbar.svelte"; import Progressbar from "../lib/Progressbar.svelte";
let progressbarFix = true;
let launching = false;
let patch = true;
setTimeout(() => {
progressbarFix = false;
}, 1000);
</script> </script>
<main class="h-[265px] my-auto flex flex-col justify-center items-center p-5"> <main
class="h-[265px] my-auto flex flex-col justify-center items-center p-5 animate-fadeIn"
>
<div <div
class="container flex flex-col items-center justify-center gap-5 rounded-lg p-3" class="container flex flex-col items-center justify-center gap-3 rounded-lg p-3"
> >
<Button color="light" size="xl" class="dark:active:!bg-gray-900" <Button
>Launch</Button color="light"
size="xl"
class="dark:active:!bg-gray-900 {launching
? ''
: 'active:scale-95 '}transition-transform duration-75"
disabled={launching}
on:click={() => (launching = !launching)}>Launch</Button
>
<Checkbox disabled={launching} bind:checked={patch}>Patch</Checkbox>
<div
class="w-full flex flex-col justify-center items-center gap-2 mt-2 {launching
? 'animate-fadeIn '
: 'animate-fadeOut '}{progressbarFix ? '!opacity-0' : 'opacity-0'}"
> >
<div class="w-full flex flex-col justify-center items-center gap-2">
<p class="m-0 p-0 dark:text-gray-100">Waiting</p>
<Progressbar <Progressbar
animate={true} animate={true}
progress={null} progress={null}
labelInside={true} labelInside={true}
size="h-6" size="h-3"
labelInsideClass="bg-primary-600 drop-shadow-xl text-gray-100 text-base font-medium text-center p-1 leading-none rounded-full" labelInsideClass="bg-primary-600 drop-shadow-xl text-gray-100 text-base font-medium text-center p-1 leading-none rounded-full"
/> />
<p class="m-0 p-0 dark:text-gray-400 font-light">Waiting...</p>
</div> </div>
</div> </div>
</main> </main>

View File

@ -1,15 +1,16 @@
<script lang="ts"> <script lang="ts">
import { Input, Button, Spinner } from "flowbite-svelte"; import { Input, Button, Spinner, Checkbox } from "flowbite-svelte";
import { performLogin } from "../util/loginUtil"; import { performLogin } from "../util/loginUtil";
import type { User } from "../types/user"; import type { User } from "../types/user";
import type { Error } from "../types/error"; import type { Error } from "../types/error";
import { currentPage, currentUser } from "../storage/localStore"; import { currentPage, currentUser, startup } from "../storage/localStore";
import toast from "svelte-french-toast"; import toast from "svelte-french-toast";
import { Page } from "../consts/pages"; import { Page } from "../consts/pages";
let loading = false; let loading = false;
let username = ""; let username = "";
let password = ""; let password = "";
let saveCredentials = false;
const processLogin = async () => { const processLogin = async () => {
loading = true; loading = true;
@ -21,7 +22,8 @@
const wasSuccessful = "user" in resultData; const wasSuccessful = "user" in resultData;
if (!wasSuccessful) { if (!wasSuccessful) {
toast.error(resultData.message, { const errorResult = resultData as Error;
toast.error(errorResult.message, {
position: "bottom-center", position: "bottom-center",
className: className:
"dark:!bg-gray-800 border-1 dark:!border-gray-700 dark:!text-gray-100", "dark:!bg-gray-800 border-1 dark:!border-gray-700 dark:!text-gray-100",
@ -30,27 +32,87 @@
loading = false; loading = false;
return; return;
} }
console.log(resultData); const userResult = resultData.user as User;
currentUser.set(resultData.user as User); currentUser.set(userResult);
currentPage.set(Page.Launch); currentPage.set(Page.Launch);
toast.success(`Welcome back ${resultData.user.name}!`, { toast.success(`Welcome back, ${userResult.name}!`, {
position: "bottom-center", position: "bottom-center",
className: className:
"dark:!bg-gray-800 border-1 dark:!border-gray-700 dark:!text-gray-100", "dark:!bg-gray-800 border-1 dark:!border-gray-700 dark:!text-gray-100",
duration: 5000, duration: 3000,
}); });
}, },
{ once: true } { once: true }
); );
window.dispatchEvent( window.dispatchEvent(
new CustomEvent("login-attempt", { detail: { username, password } }) new CustomEvent("login-attempt", {
detail: { username, password, saveCredentials },
})
); );
}; };
const tryAutoLogin = async () => {
loading = true;
await new Promise((res) => setTimeout(res, 1500));
window.addEventListener(
"login-result",
(e) => {
const customEvent = e as CustomEvent;
const resultData = customEvent.detail;
const isGuest = "guest" in resultData;
const wasSuccessful = "user" in resultData;
if (isGuest) {
currentPage.set(Page.Launch);
toast.success(`Logged in as Guest`, {
position: "bottom-center",
className:
"dark:!bg-gray-800 border-1 dark:!border-gray-700 dark:!text-gray-100",
duration: 3000,
});
return;
}
if (!wasSuccessful) {
loading = false;
return;
}
const userResult = resultData.user as User;
currentUser.set(userResult);
currentPage.set(Page.Launch);
toast.success(`Welcome back, ${userResult.name}!`, {
position: "bottom-center",
className:
"dark:!bg-gray-800 border-1 dark:!border-gray-700 dark:!text-gray-100",
duration: 3000,
});
loading = false;
},
{ once: true }
);
window.dispatchEvent(new CustomEvent("autologin-attempt"));
};
const proceedAsGuest = () => {
window.dispatchEvent(new CustomEvent("guest-login"));
currentPage.set(Page.Launch);
toast.success(`Logged in as Guest`, {
position: "bottom-center",
className:
"dark:!bg-gray-800 border-1 dark:!border-gray-700 dark:!text-gray-100",
duration: 3000,
});
};
if (!$startup) {
startup.set(true);
tryAutoLogin();
}
</script> </script>
<main class="h-[265px] my-auto flex flex-col justify-center items-center p-5"> <main
class="h-[265px] my-auto flex flex-col justify-center items-center p-5 animate-fadeIn opacity-0"
>
<div <div
class="container flex flex-col items-center justify-center gap-5 rounded-lg p-3" class="container flex flex-col items-center justify-center gap-3 rounded-lg p-3"
> >
<Input <Input
type="text" type="text"
@ -66,9 +128,10 @@
disabled={loading} disabled={loading}
bind:value={password} bind:value={password}
/> />
<div class="flex flex-col justify-center items-center gap-5 mt-2"> <Checkbox bind:checked={saveCredentials}>Save credentials</Checkbox>
<div class="flex flex-col justify-center items-center gap-5 mt-1">
<Button <Button
class="dark:active:!bg-gray-900" class="dark:active:!bg-gray-900 active:scale-95 transition-transform duration-75"
color="light" color="light"
disabled={loading} disabled={loading}
on:click={processLogin} on:click={processLogin}
@ -80,11 +143,10 @@
{/if} {/if}
</Button> </Button>
<Button <Button
class="!bg-transparent border-none dark:text-gray-700 hover:!bg-gray-700/15 ring-primary active:ring-2 focus:ring-2" class="!bg-transparent font-light border-none dark:text-gray-700 hover:!bg-gray-700/15 ring-primary active:ring-2 focus:ring-2 active:scale-95 transition-transform duration-75"
color="none" color="none"
disabled={loading} disabled={loading}
on:click={() => currentPage.set(Page.Launch)} on:click={proceedAsGuest}>Continue without login</Button
>Continue without login</Button
> >
</div> </div>
</div> </div>

View File

@ -2,5 +2,6 @@ import { type Writable, writable } from "svelte/store";
import { Page } from "../consts/pages"; import { Page } from "../consts/pages";
import type { User } from "../types/user"; import type { User } from "../types/user";
export const startup = writable(false);
export const currentUser: Writable<undefined | User> = writable(undefined); export const currentUser: Writable<undefined | User> = writable(undefined);
export const currentPage = writable(Page.Login); export const currentPage = writable(Page.Login);

View File

@ -7,6 +7,20 @@ const config = {
darkMode: "media", darkMode: "media",
theme: { theme: {
extend: { extend: {
keyframes: {
fadeIn: {
"0%": { opacity: "0", transform: "translateY(5px)" },
"100%": { opacity: "1" },
},
fadeOut: {
"100%": { opacity: "0", transform: "translateY(5px)" },
"0%": { opacity: "1" },
},
},
animation: {
fadeIn: "fadeIn 1s ease forwards",
fadeOut: "fadeOut 1s ease forwards",
},
colors: { colors: {
// flowbite-svelte // flowbite-svelte
primary: { primary: {