diff --git a/src/main/events/auth/get-session-hash.ts b/src/main/events/auth/get-session-hash.ts index c81e0965..02edebdc 100644 --- a/src/main/events/auth/get-session-hash.ts +++ b/src/main/events/auth/get-session-hash.ts @@ -3,7 +3,6 @@ import jwt from "jsonwebtoken"; import { registerEvent } from "../register-event"; import { db, levelKeys } from "@main/level"; import type { Auth } from "@types"; -import { Crypto } from "@main/services"; const getSessionHash = async (_event: Electron.IpcMainInvokeEvent) => { const auth = await db.get(levelKeys.auth, { @@ -11,9 +10,7 @@ const getSessionHash = async (_event: Electron.IpcMainInvokeEvent) => { }); if (!auth) return null; - const payload = jwt.decode( - Crypto.decrypt(auth.accessToken) - ) as jwt.JwtPayload; + const payload = jwt.decode(auth.accessToken) as jwt.JwtPayload; if (!payload) return null; diff --git a/src/main/events/misc/open-checkout.ts b/src/main/events/misc/open-checkout.ts index 76316a6e..75b93f9d 100644 --- a/src/main/events/misc/open-checkout.ts +++ b/src/main/events/misc/open-checkout.ts @@ -1,6 +1,6 @@ import { shell } from "electron"; import { registerEvent } from "../register-event"; -import { Crypto, HydraApi } from "@main/services"; +import { HydraApi } from "@main/services"; import { db, levelKeys } from "@main/level"; import type { Auth } from "@types"; @@ -14,7 +14,7 @@ const openCheckout = async (_event: Electron.IpcMainInvokeEvent) => { } const paymentToken = await HydraApi.post("/auth/payment", { - refreshToken: Crypto.decrypt(auth.refreshToken), + refreshToken: auth.refreshToken, }).then((response) => response.accessToken); const params = new URLSearchParams({ diff --git a/src/main/events/user-preferences/get-user-preferences.ts b/src/main/events/user-preferences/get-user-preferences.ts index b40d6780..ba01d077 100644 --- a/src/main/events/user-preferences/get-user-preferences.ts +++ b/src/main/events/user-preferences/get-user-preferences.ts @@ -1,21 +1,10 @@ import { registerEvent } from "../register-event"; import { db, levelKeys } from "@main/level"; -import { Crypto } from "@main/services"; import type { UserPreferences } from "@types"; const getUserPreferences = async () => - db - .get(levelKeys.userPreferences, { - valueEncoding: "json", - }) - .then((userPreferences) => { - if (userPreferences?.realDebridApiToken) { - userPreferences.realDebridApiToken = Crypto.decrypt( - userPreferences.realDebridApiToken - ); - } - - return userPreferences; - }); + db.get(levelKeys.userPreferences, { + valueEncoding: "json", + }); registerEvent("getUserPreferences", getUserPreferences); diff --git a/src/main/main.ts b/src/main/main.ts index f7ad596d..8205deef 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -1,10 +1,4 @@ -import { - Crypto, - DownloadManager, - logger, - Ludusavi, - startMainLoop, -} from "./services"; +import { DownloadManager, logger, Ludusavi, startMainLoop } from "./services"; import { RealDebridClient } from "./services/download/real-debrid"; import { HydraApi } from "./services/hydra-api"; import { uploadGamesBatch } from "./services/library-sync"; @@ -27,9 +21,7 @@ const loadState = async (userPreferences: UserPreferences | null) => { Aria2.spawn(); if (userPreferences?.realDebridApiToken) { - RealDebridClient.authorize( - Crypto.decrypt(userPreferences.realDebridApiToken) - ); + RealDebridClient.authorize(userPreferences.realDebridApiToken); } Ludusavi.addManifestToLudusaviConfig(); @@ -106,9 +98,7 @@ const migrateFromSqlite = async () => { await db.put(levelKeys.userPreferences, { ...rest, - realDebridApiToken: realDebridApiToken - ? Crypto.encrypt(realDebridApiToken) - : null, + realDebridApiToken, preferQuitInsteadOfHiding: rest.preferQuitInsteadOfHiding === 1, runAtStartup: rest.runAtStartup === 1, startMinimized: rest.startMinimized === 1, @@ -171,8 +161,8 @@ const migrateFromSqlite = async () => { await db.put( levelKeys.auth, { - accessToken: Crypto.encrypt(users[0].accessToken), - refreshToken: Crypto.encrypt(users[0].refreshToken), + accessToken: users[0].accessToken, + refreshToken: users[0].refreshToken, tokenExpirationTimestamp: users[0].tokenExpirationTimestamp, }, { diff --git a/src/main/services/crypto.ts b/src/main/services/crypto.ts deleted file mode 100644 index 63a50668..00000000 --- a/src/main/services/crypto.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { safeStorage } from "electron"; -import { logger } from "./logger"; - -export class Crypto { - public static encrypt(str: string) { - if (safeStorage.isEncryptionAvailable()) { - return safeStorage.encryptString(str).toString("base64"); - } else { - logger.warn( - "Encrypt method returned raw string because encryption is not available" - ); - - return str; - } - } - - public static decrypt(b64: string) { - if (safeStorage.isEncryptionAvailable()) { - return safeStorage.decryptString(Buffer.from(b64, "base64")); - } else { - logger.warn( - "Decrypt method returned raw string because encryption is not available" - ); - - return b64; - } - } -} diff --git a/src/main/services/hydra-api.ts b/src/main/services/hydra-api.ts index 4d5623a0..1c67f729 100644 --- a/src/main/services/hydra-api.ts +++ b/src/main/services/hydra-api.ts @@ -12,7 +12,6 @@ import { isFuture, isToday } from "date-fns"; import { db } from "@main/level"; import { levelKeys } from "@main/level/sublevels"; import type { Auth, User } from "@types"; -import { Crypto } from "./crypto"; interface HydraApiOptions { needsAuth?: boolean; @@ -32,7 +31,9 @@ export class HydraApi { private static readonly EXPIRATION_OFFSET_IN_MS = 1000 * 60 * 5; // 5 minutes private static readonly ADD_LOG_INTERCEPTOR = true; - private static secondsToMilliseconds = (seconds: number) => seconds * 1000; + private static secondsToMilliseconds(seconds: number) { + return seconds * 1000; + } private static userAuth: HydraApiUserAuth = { authToken: "", @@ -80,8 +81,8 @@ export class HydraApi { db.put( levelKeys.auth, { - accessToken: Crypto.encrypt(accessToken), - refreshToken: Crypto.encrypt(refreshToken), + accessToken, + refreshToken, tokenExpirationTimestamp, }, { valueEncoding: "json" } @@ -194,12 +195,8 @@ export class HydraApi { const user = result.at(1) as User | undefined; this.userAuth = { - authToken: userAuth?.accessToken - ? Crypto.decrypt(userAuth.accessToken) - : "", - refreshToken: userAuth?.refreshToken - ? Crypto.decrypt(userAuth.refreshToken) - : "", + authToken: userAuth?.accessToken ?? "", + refreshToken: userAuth?.refreshToken ?? "", expirationTimestamp: userAuth?.tokenExpirationTimestamp ?? 0, subscription: user?.subscription ? { expiresAt: user.subscription?.expiresAt } @@ -248,7 +245,7 @@ export class HydraApi { levelKeys.auth, { ...auth, - accessToken: Crypto.encrypt(accessToken), + accessToken, tokenExpirationTimestamp, }, { valueEncoding: "json" } diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index 3934144a..3d31284d 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -234,7 +234,7 @@ export class WindowManager { if (is.dev && process.env["ELECTRON_RENDERER_URL"]) { editorWindow.loadURL( - `${process.env["ELECTRON_RENDERER_URL"]}#/editor?themeId=${themeId}` + `${process.env["ELECTRON_RENDERER_URL"]}#/theme-editor?themeId=${themeId}` ); } else { editorWindow.loadFile(path.join(__dirname, "../renderer/index.html"), { diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index 8a681b7e..a9ec7923 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -30,7 +30,6 @@ import { HydraCloudModal } from "./pages/shared-modals/hydra-cloud/hydra-cloud-m import { injectCustomCss } from "./helpers"; import "./app.scss"; -import { Theme } from "@types"; export interface AppProps { children: React.ReactNode; @@ -214,22 +213,22 @@ export function App() { const id = crypto.randomUUID(); const channel = new BroadcastChannel(`download_sources:sync:${id}`); - channel.onmessage = (event: MessageEvent) => { + channel.onmessage = async (event: MessageEvent) => { const newRepacksCount = event.data; window.electron.publishNewRepacksNotification(newRepacksCount); updateRepacks(); - downloadSourcesTable.toArray().then((downloadSources) => { - downloadSources - .filter((source) => !source.fingerprint) - .forEach((downloadSource) => { - window.electron - .putDownloadSource(downloadSource.objectIds) - .then(({ fingerprint }) => { - downloadSourcesTable.update(downloadSource.id, { fingerprint }); - }); - }); - }); + const downloadSources = await downloadSourcesTable.toArray(); + + downloadSources + .filter((source) => !source.fingerprint) + .forEach(async (downloadSource) => { + const { fingerprint } = await window.electron.putDownloadSource( + downloadSource.objectIds + ); + + downloadSourcesTable.update(downloadSource.id, { fingerprint }); + }); }; downloadSourcesWorker.postMessage(["SYNC_DOWNLOAD_SOURCES", id]); @@ -237,9 +236,9 @@ export function App() { useEffect(() => { const loadAndApplyTheme = async () => { - const activeTheme: Theme = await window.electron.getActiveCustomTheme(); + const activeTheme = await window.electron.getActiveCustomTheme(); - if (activeTheme.code) { + if (activeTheme?.code) { injectCustomCss(activeTheme.code); } }; diff --git a/src/renderer/src/main.tsx b/src/renderer/src/main.tsx index 509d744d..80c4317c 100644 --- a/src/renderer/src/main.tsx +++ b/src/renderer/src/main.tsx @@ -33,7 +33,9 @@ const Profile = React.lazy(() => import("./pages/profile/profile")); const Achievements = React.lazy( () => import("./pages/achievements/achievements") ); -const Editor = React.lazy(() => import("./pages/editor/editor")); +const ThemeEditor = React.lazy( + () => import("./pages/theme-editor/theme-editor") +); import * as Sentry from "@sentry/react"; @@ -107,8 +109,8 @@ ReactDOM.createRoot(document.getElementById("root")!).render( } + path="/theme-editor" + element={} /> diff --git a/src/renderer/src/pages/downloads/delete-game-modal.tsx b/src/renderer/src/pages/downloads/delete-game-modal.tsx index e9486652..7f4a530e 100644 --- a/src/renderer/src/pages/downloads/delete-game-modal.tsx +++ b/src/renderer/src/pages/downloads/delete-game-modal.tsx @@ -12,7 +12,7 @@ export function DeleteGameModal({ onClose, visible, deleteGame, -}: DeleteGameModalProps) { +}: Readonly) { const { t } = useTranslation("downloads"); const handleDeleteGame = () => { diff --git a/src/renderer/src/pages/editor/editor.scss b/src/renderer/src/pages/theme-editor/theme-editor.scss similarity index 88% rename from src/renderer/src/pages/editor/editor.scss rename to src/renderer/src/pages/theme-editor/theme-editor.scss index d522c8c5..1f436417 100644 --- a/src/renderer/src/pages/editor/editor.scss +++ b/src/renderer/src/pages/theme-editor/theme-editor.scss @@ -1,22 +1,25 @@ -@use "../../scss/globals.scss" as globals; +@use "../../scss/globals.scss"; -.editor { +.theme-editor { display: flex; flex-direction: column; height: 100%; width: 100%; &__header { - height: 35px; display: flex; align-items: center; - padding: 10px; + padding: calc(globals.$spacing-unit * 2); background-color: globals.$dark-background-color; font-size: 8px; z-index: 50; -webkit-app-region: drag; gap: 8px; + &--darwin { + padding-top: calc(globals.$spacing-unit * 6); + } + h1 { margin: 0; line-height: 1; diff --git a/src/renderer/src/pages/editor/editor.tsx b/src/renderer/src/pages/theme-editor/theme-editor.tsx similarity index 80% rename from src/renderer/src/pages/editor/editor.tsx rename to src/renderer/src/pages/theme-editor/theme-editor.tsx index 95210b2f..b69b8261 100644 --- a/src/renderer/src/pages/editor/editor.tsx +++ b/src/renderer/src/pages/theme-editor/theme-editor.tsx @@ -1,5 +1,5 @@ -import { useEffect, useState } from "react"; -import "./editor.scss"; +import { useCallback, useEffect, useState } from "react"; +import "./theme-editor.scss"; import Editor from "@monaco-editor/react"; import { Theme } from "@types"; import { useSearchParams } from "react-router-dom"; @@ -10,8 +10,9 @@ import { ProjectRoadmapIcon, } from "@primer/octicons-react"; import { useTranslation } from "react-i18next"; +import cn from "classnames"; -const EditorPage = () => { +export default function ThemeEditor() { const [searchParams] = useSearchParams(); const [theme, setTheme] = useState(null); const [code, setCode] = useState(""); @@ -37,29 +38,7 @@ const EditorPage = () => { } }, [themeId]); - useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if ((event.ctrlKey || event.metaKey) && event.key === "s") { - event.preventDefault(); - handleSave(); - } - }; - - window.addEventListener("keydown", handleKeyDown); - - return () => { - window.removeEventListener("keydown", handleKeyDown); - }; - }, [code, theme]); - - const handleEditorChange = (value: string | undefined) => { - if (value !== undefined) { - setCode(value); - setHasUnsavedChanges(true); - } - }; - - const handleSave = async () => { + const handleSave = useCallback(async () => { if (theme) { const updatedTheme = { ...theme, @@ -74,13 +53,41 @@ const EditorPage = () => { window.electron.injectCSS(code); } } + }, [code, theme]); + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if ((event.ctrlKey || event.metaKey) && event.key === "s") { + event.preventDefault(); + handleSave(); + } + }; + + window.addEventListener("keydown", handleKeyDown); + + return () => { + window.removeEventListener("keydown", handleKeyDown); + }; + }, [code, handleSave, theme]); + + const handleEditorChange = (value: string | undefined) => { + if (value !== undefined) { + setCode(value); + setHasUnsavedChanges(true); + } }; return ( -
-
+
+

{theme?.name}

- {hasUnsavedChanges &&
} + {hasUnsavedChanges && ( +
+ )}
{activeTab === "code" && ( @@ -100,15 +107,15 @@ const EditorPage = () => { )} {activeTab === "info" && ( -
+
entao mano eu ate fiz isso aqui mas tava feio dms ai deu vergonha e removi kkkk
)} -
-
-
+
+
+
); -}; - -export default EditorPage; +}