From 2828640ed748199ed08ebe0fbb18d8a996ac187d Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Sat, 9 Nov 2024 02:42:43 -0300 Subject: [PATCH 1/8] feat: add intercom user id --- src/main/events/index.ts | 3 ++- src/preload/index.ts | 1 + src/renderer/src/components/sidebar/sidebar.tsx | 17 ++++++++++------- src/renderer/src/declaration.d.ts | 1 + 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/events/index.ts b/src/main/events/index.ts index 932b80e4..eff62531 100644 --- a/src/main/events/index.ts +++ b/src/main/events/index.ts @@ -1,4 +1,4 @@ -import { appVersion, defaultDownloadsPath } from "@main/constants"; +import { appVersion, defaultDownloadsPath, isStaging } from "@main/constants"; import { ipcMain } from "electron"; import "./catalogue/get-catalogue"; @@ -72,5 +72,6 @@ import "./misc/show-item-in-folder"; ipcMain.handle("ping", () => "pong"); ipcMain.handle("getVersion", () => appVersion); +ipcMain.handle("isStaging", () => isStaging); ipcMain.handle("isPortableVersion", () => isPortableVersion()); ipcMain.handle("getDefaultDownloadsPath", () => defaultDownloadsPath); diff --git a/src/preload/index.ts b/src/preload/index.ts index d8d142ca..0166ba2a 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -198,6 +198,7 @@ contextBridge.exposeInMainWorld("electron", { ping: () => ipcRenderer.invoke("ping"), getVersion: () => ipcRenderer.invoke("getVersion"), getDefaultDownloadsPath: () => ipcRenderer.invoke("getDefaultDownloadsPath"), + isStaging: () => ipcRenderer.invoke("isStaging"), isPortableVersion: () => ipcRenderer.invoke("isPortableVersion"), openExternal: (src: string) => ipcRenderer.invoke("openExternal", src), openCheckout: () => ipcRenderer.invoke("openCheckout"), diff --git a/src/renderer/src/components/sidebar/sidebar.tsx b/src/renderer/src/components/sidebar/sidebar.tsx index 75bd1b78..787cf66a 100644 --- a/src/renderer/src/components/sidebar/sidebar.tsx +++ b/src/renderer/src/components/sidebar/sidebar.tsx @@ -54,13 +54,16 @@ export function Sidebar() { useEffect(() => { if (userDetails) { - update({ - name: userDetails.displayName, - Username: userDetails.username, - email: userDetails.email ?? undefined, - Email: userDetails.email, - "Subscription expiration date": userDetails?.subscription?.expiresAt, - "Payment status": userDetails?.subscription?.status, + window.electron.isStaging().then((isStaging) => { + update({ + user_id: userDetails.id + (isStaging ? "-staging" : ""), + name: userDetails.displayName, + Username: userDetails.username, + email: userDetails.email ?? undefined, + Email: userDetails.email, + "Subscription expiration date": userDetails?.subscription?.expiresAt, + "Payment status": userDetails?.subscription?.status, + }); }); } }, [userDetails, hasActiveSubscription]); diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts index 4065b64c..a1965b6a 100644 --- a/src/renderer/src/declaration.d.ts +++ b/src/renderer/src/declaration.d.ts @@ -162,6 +162,7 @@ declare global { openExternal: (src: string) => Promise; openCheckout: () => Promise; getVersion: () => Promise; + isStaging: () => Promise; ping: () => string; getDefaultDownloadsPath: () => Promise; isPortableVersion: () => Promise; From 6e6469d90f8302686b700c667b7fc98ee37029e3 Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Sun, 10 Nov 2024 20:55:23 -0300 Subject: [PATCH 2/8] fix: format ignore case --- src/shared/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/index.ts b/src/shared/index.ts index 173867df..cc35d241 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -46,7 +46,7 @@ export const removeSymbolsFromName = (name: string) => export const removeSpecialEditionFromName = (name: string) => name.replace( - /(The |Digital )?(GOTY|Deluxe|Standard|Ultimate|Definitive|Enhanced|Collector's|Premium|Digital|Limited|Game of the Year|Reloaded|[0-9]{4}) Edition/g, + /(The |Digital )?(GOTY|Deluxe|Standard|Ultimate|Definitive|Enhanced|Collector's|Premium|Digital|Limited|Game of the Year|Reloaded|[0-9]{4}) Edition/gi, "" ); @@ -73,7 +73,7 @@ export const formatName = pipe( replaceUnderscoreWithSpace, replaceDotsWithSpace, replaceNbspWithSpace, - (str) => str.replace(/DIRECTOR'S CUT/g, ""), + (str) => str.replace(/DIRECTOR'S CUT/gi, ""), removeSymbolsFromName, removeDuplicateSpaces, (str) => str.trim() From 8cfe5b4d3419b225d7a429927a51b59ce6e28cc6 Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Mon, 11 Nov 2024 10:35:33 -0300 Subject: [PATCH 3/8] fix: add friend's pass to format name --- src/shared/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/index.ts b/src/shared/index.ts index cc35d241..699cc4d8 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -74,6 +74,7 @@ export const formatName = pipe( replaceDotsWithSpace, replaceNbspWithSpace, (str) => str.replace(/DIRECTOR'S CUT/gi, ""), + (str) => str.replace(/Friend's Pass/gi, ""), removeSymbolsFromName, removeDuplicateSpaces, (str) => str.trim() From 730ea4f2b9c10b7b14a18599184d86d96ef1985a Mon Sep 17 00:00:00 2001 From: Zamitto <167933696+zamitto@users.noreply.github.com> Date: Wed, 27 Nov 2024 13:17:40 -0300 Subject: [PATCH 4/8] fix: subscription date validation --- .../events/torrenting/start-game-download.ts | 13 ------- src/main/services/hydra-analytics.ts | 34 ------------------- src/main/services/hydra-api.ts | 7 ++-- src/renderer/src/hooks/use-user-details.ts | 7 ++-- .../cloud-sync-files-modal.tsx | 2 +- 5 files changed, 7 insertions(+), 56 deletions(-) delete mode 100644 src/main/services/hydra-analytics.ts diff --git a/src/main/events/torrenting/start-game-download.ts b/src/main/events/torrenting/start-game-download.ts index 17099450..ce16e97b 100644 --- a/src/main/events/torrenting/start-game-download.ts +++ b/src/main/events/torrenting/start-game-download.ts @@ -1,5 +1,4 @@ import { registerEvent } from "../register-event"; -import parseTorrent from "parse-torrent"; import type { StartGameDownloadPayload } from "@types"; import { DownloadManager, HydraApi, logger } from "@main/services"; @@ -9,7 +8,6 @@ import { createGame } from "@main/services/library-sync"; import { steamUrlBuilder } from "@shared"; import { dataSource } from "@main/data-source"; import { DownloadQueue, Game } from "@main/entity"; -import { HydraAnalytics } from "@main/services/hydra-analytics"; const startGameDownload = async ( _event: Electron.IpcMainInvokeEvent, @@ -91,17 +89,6 @@ const startGameDownload = async ( logger.error("Failed to create game download", err); }); - if (uri.startsWith("magnet:")) { - try { - const { infoHash } = await parseTorrent(payload.uri); - if (infoHash) { - HydraAnalytics.postDownload(infoHash).catch(() => {}); - } - } catch (err) { - logger.error("Failed to parse torrent", err); - } - } - await DownloadManager.cancelDownload(updatedGame!.id); await DownloadManager.startDownload(updatedGame!); diff --git a/src/main/services/hydra-analytics.ts b/src/main/services/hydra-analytics.ts deleted file mode 100644 index f4a6b24c..00000000 --- a/src/main/services/hydra-analytics.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { userSubscriptionRepository } from "@main/repository"; -import axios from "axios"; -import { appVersion } from "@main/constants"; - -export class HydraAnalytics { - private static instance = axios.create({ - baseURL: import.meta.env.MAIN_VITE_ANALYTICS_API_URL, - headers: { "User-Agent": `Hydra Launcher v${appVersion}` }, - }); - - private static async hasActiveSubscription() { - const userSubscription = await userSubscriptionRepository.findOne({ - where: { id: 1 }, - }); - - return ( - userSubscription?.expiresAt && userSubscription.expiresAt > new Date() - ); - } - - static async postDownload(hash: string) { - const hasSubscription = await this.hasActiveSubscription(); - - return this.instance - .post("/track", { - event: "download", - attributes: { - hash, - hasSubscription, - }, - }) - .then((response) => response.data); - } -} diff --git a/src/main/services/hydra-api.ts b/src/main/services/hydra-api.ts index b2125ac4..f642f43b 100644 --- a/src/main/services/hydra-api.ts +++ b/src/main/services/hydra-api.ts @@ -12,6 +12,7 @@ import { UserNotLoggedInError, SubscriptionRequiredError } from "@shared"; import { omit } from "lodash-es"; import { appVersion } from "@main/constants"; import { getUserData } from "./user/get-user-data"; +import { isFuture, isToday } from "date-fns"; interface HydraApiOptions { needsAuth?: boolean; @@ -45,10 +46,8 @@ export class HydraApi { } private static hasActiveSubscription() { - return ( - this.userAuth.subscription?.expiresAt && - this.userAuth.subscription.expiresAt > new Date() - ); + const expiresAt = this.userAuth.subscription?.expiresAt; + return expiresAt && (isFuture(expiresAt) || isToday(expiresAt)); } static async handleExternalAuth(uri: string) { diff --git a/src/renderer/src/hooks/use-user-details.ts b/src/renderer/src/hooks/use-user-details.ts index ab4408cc..feca478c 100644 --- a/src/renderer/src/hooks/use-user-details.ts +++ b/src/renderer/src/hooks/use-user-details.ts @@ -14,6 +14,7 @@ import type { UserDetails, } from "@types"; import { UserFriendModalTab } from "@renderer/pages/shared-modals/user-friend-modal"; +import { isFuture, isToday } from "date-fns"; export function useUserDetails() { const dispatch = useAppDispatch(); @@ -128,10 +129,8 @@ export function useUserDetails() { const unblockUser = (userId: string) => window.electron.unblockUser(userId); const hasActiveSubscription = useMemo(() => { - return ( - userDetails?.subscription?.expiresAt && - new Date(userDetails.subscription.expiresAt) > new Date() - ); + const expiresAt = userDetails?.subscription?.expiresAt; + return expiresAt && (isFuture(expiresAt) || isToday(expiresAt)); }, [userDetails]); return { diff --git a/src/renderer/src/pages/game-details/cloud-sync-files-modal/cloud-sync-files-modal.tsx b/src/renderer/src/pages/game-details/cloud-sync-files-modal/cloud-sync-files-modal.tsx index c70f69b7..6fd277e7 100644 --- a/src/renderer/src/pages/game-details/cloud-sync-files-modal/cloud-sync-files-modal.tsx +++ b/src/renderer/src/pages/game-details/cloud-sync-files-modal/cloud-sync-files-modal.tsx @@ -75,7 +75,7 @@ export function CloudSyncFilesModal({ showSuccessToast(t("custom_backup_location_set")); getGameBackupPreview(); } - }, [objectId, setValue, shop, showSuccessToast, getGameBackupPreview]); + }, [objectId, setValue, shop, showSuccessToast, getGameBackupPreview, t]); const handleFileMappingMethodClick = useCallback( (mappingOption: FileMappingMethod) => { From 7f600a0cbfc55e39c17e31404ce7244cbcc2542b Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Mon, 2 Dec 2024 17:10:13 +0000 Subject: [PATCH 5/8] feat: adding csp update --- .env.example | 1 - .github/workflows/build.yml | 10 ------- src/main/events/index.ts | 3 +- src/preload/index.ts | 3 +- src/renderer/index.html | 6 +++- src/renderer/src/app.tsx | 29 +++++++++++++------ src/renderer/src/components/modal/modal.tsx | 1 + .../src/components/sidebar/sidebar.tsx | 26 ++++------------- src/renderer/src/declaration.d.ts | 3 +- src/renderer/src/vite-env.d.ts | 8 ----- 10 files changed, 37 insertions(+), 53 deletions(-) diff --git a/.env.example b/.env.example index 991a06ff..b12e9517 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,3 @@ MAIN_VITE_API_URL=API_URL MAIN_VITE_AUTH_URL=AUTH_URL MAIN_VITE_STEAMGRIDDB_API_KEY=YOUR_API_KEY -RENDERER_VITE_INTERCOM_APP_ID=YOUR_APP_ID diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 89392011..0f650fc5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,16 +22,6 @@ jobs: with: node-version: 20.18.0 - - name: Configure AWS credentials - uses: aws-actions/configure-aws-credentials@v2 - with: - aws-access-key-id: ${{ secrets.R2_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.R2_SECRET_ACCESS_KEY }} - aws-region: ${{ env.AWS_REGION }} - - - name: Push build to R2 - run: aws s3 sync ./docs s3://${{ vars.BUILDS_BUCKET_NAME }} - - name: Install dependencies run: yarn diff --git a/src/main/events/index.ts b/src/main/events/index.ts index eff62531..932b80e4 100644 --- a/src/main/events/index.ts +++ b/src/main/events/index.ts @@ -1,4 +1,4 @@ -import { appVersion, defaultDownloadsPath, isStaging } from "@main/constants"; +import { appVersion, defaultDownloadsPath } from "@main/constants"; import { ipcMain } from "electron"; import "./catalogue/get-catalogue"; @@ -72,6 +72,5 @@ import "./misc/show-item-in-folder"; ipcMain.handle("ping", () => "pong"); ipcMain.handle("getVersion", () => appVersion); -ipcMain.handle("isStaging", () => isStaging); ipcMain.handle("isPortableVersion", () => isPortableVersion()); ipcMain.handle("getDefaultDownloadsPath", () => defaultDownloadsPath); diff --git a/src/preload/index.ts b/src/preload/index.ts index 0166ba2a..17f4b3e9 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -15,6 +15,7 @@ import type { import type { CatalogueCategory } from "@shared"; import type { AxiosProgressEvent } from "axios"; import { GameAchievement } from "@main/entity"; +import { isStaging } from "@main/constants"; contextBridge.exposeInMainWorld("electron", { /* Torrenting */ @@ -198,7 +199,7 @@ contextBridge.exposeInMainWorld("electron", { ping: () => ipcRenderer.invoke("ping"), getVersion: () => ipcRenderer.invoke("getVersion"), getDefaultDownloadsPath: () => ipcRenderer.invoke("getDefaultDownloadsPath"), - isStaging: () => ipcRenderer.invoke("isStaging"), + isStaging, isPortableVersion: () => ipcRenderer.invoke("isPortableVersion"), openExternal: (src: string) => ipcRenderer.invoke("openExternal", src), openCheckout: () => ipcRenderer.invoke("openCheckout"), diff --git a/src/renderer/index.html b/src/renderer/index.html index bfc3a206..c3ce2e83 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -6,8 +6,12 @@ Hydra +
diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index 5a479879..e40d2d27 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -2,8 +2,6 @@ import { useCallback, useContext, useEffect, useRef } from "react"; import { Sidebar, BottomPanel, Header, Toast } from "@renderer/components"; -import Intercom from "@intercom/messenger-js-sdk"; - import { useAppDispatch, useAppSelector, @@ -36,10 +34,6 @@ export interface AppProps { children: React.ReactNode; } -Intercom({ - app_id: import.meta.env.RENDERER_VITE_INTERCOM_APP_ID, -}); - export function App() { const contentRef = useRef(null); const { updateLibrary, library } = useLibrary(); @@ -68,6 +62,25 @@ export function App() { clearUserDetails, } = useUserDetails(); + useEffect(() => { + if (userDetails) { + const $existingScript = document.getElementById("user-details"); + + const content = `window.userDetails = ${JSON.stringify(userDetails)};`; + + if ($existingScript) { + $existingScript.textContent = content; + } else { + const $script = document.createElement("script"); + $script.id = "user-details"; + $script.type = "text/javascript"; + $script.textContent = content; + + document.head.appendChild($script); + } + } + }, [userDetails]); + const dispatch = useAppDispatch(); const navigate = useNavigate(); @@ -215,9 +228,7 @@ export function App() { useEffect(() => { new MutationObserver(() => { - const modal = document.body.querySelector( - "[role=dialog]:not([data-intercom-frame='true'])" - ); + const modal = document.body.querySelector("[data-hydra-dialog]"); dispatch(toggleDraggingDisabled(Boolean(modal))); }).observe(document.body, { diff --git a/src/renderer/src/components/modal/modal.tsx b/src/renderer/src/components/modal/modal.tsx index eb2894de..af15feb5 100644 --- a/src/renderer/src/components/modal/modal.tsx +++ b/src/renderer/src/components/modal/modal.tsx @@ -107,6 +107,7 @@ export function Modal({ aria-labelledby={title} aria-describedby={description} ref={modalContentRef} + data-hydra-dialog >
diff --git a/src/renderer/src/components/sidebar/sidebar.tsx b/src/renderer/src/components/sidebar/sidebar.tsx index 787cf66a..f487681c 100644 --- a/src/renderer/src/components/sidebar/sidebar.tsx +++ b/src/renderer/src/components/sidebar/sidebar.tsx @@ -22,8 +22,6 @@ import { SidebarProfile } from "./sidebar-profile"; import { sortBy } from "lodash-es"; import { CommentDiscussionIcon } from "@primer/octicons-react"; -import { show, update } from "@intercom/messenger-js-sdk"; - const SIDEBAR_MIN_WIDTH = 200; const SIDEBAR_INITIAL_WIDTH = 250; const SIDEBAR_MAX_WIDTH = 450; @@ -50,23 +48,7 @@ export function Sidebar() { return sortBy(library, (game) => game.title); }, [library]); - const { userDetails, hasActiveSubscription } = useUserDetails(); - - useEffect(() => { - if (userDetails) { - window.electron.isStaging().then((isStaging) => { - update({ - user_id: userDetails.id + (isStaging ? "-staging" : ""), - name: userDetails.displayName, - Username: userDetails.username, - email: userDetails.email ?? undefined, - Email: userDetails.email, - "Subscription expiration date": userDetails?.subscription?.expiresAt, - "Payment status": userDetails?.subscription?.status, - }); - }); - } - }, [userDetails, hasActiveSubscription]); + const { hasActiveSubscription } = useUserDetails(); const { lastPacket, progress } = useDownload(); @@ -269,7 +251,11 @@ export function Sidebar() {
{hasActiveSubscription && ( -