From 4cd2fb8da0f2757ff50ce4cf408ea14fbf733055 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Sun, 12 Nov 2023 02:24:40 +0100 Subject: [PATCH] [feature] add the possibility to enter oculus token manually --- assets/jsons/translations/de.json | 14 ++++- assets/jsons/translations/en.json | 14 ++++- assets/jsons/translations/es.json | 14 ++++- assets/jsons/translations/fr.json | 14 ++++- assets/jsons/translations/ru.json | 14 ++++- .../bs-oculus-downloader.service.ts | 40 +++---------- .../bs-steam-downloader.service.ts | 1 + .../enter-meta-token-modal.component.tsx | 59 +++++++++++++++++++ .../login-to-meta-modal.component.tsx | 21 ++++++- src/renderer/index.tsx | 6 +- .../oculus-downloader.service.ts | 25 +++++--- src/shared/helpers/oculus.helpers.ts | 32 ++++++++++ 12 files changed, 208 insertions(+), 46 deletions(-) create mode 100644 src/renderer/components/modal/modal-types/bs-downgrade/enter-meta-token-modal.component.tsx create mode 100644 src/shared/helpers/oculus.helpers.ts diff --git a/assets/jsons/translations/de.json b/assets/jsons/translations/de.json index 7e7a922b..5288cbce 100644 --- a/assets/jsons/translations/de.json +++ b/assets/jsons/translations/de.json @@ -680,7 +680,9 @@ "title": "Mit Meta verbinden", "body":{ "token-needed": "Dein Meta-Verbindungstoken wird benötigt, um Beat Saber herunterzuladen.", - "need-cookie-enabled": "Beim Einloggen in Meta wird ein Anmeldefenster geöffnet und du kannst dann den Anmeldevorgang beginnen. Bitte stelle sicher, dass Cookies akzeptiert werden, sonst könnten wir deinen Token zum Starten des Downloads nicht abrufen." + "need-cookie-enabled": "Beim Einloggen in Meta wird ein Anmeldefenster geöffnet und du kannst dann den Anmeldevorgang beginnen. Bitte stelle sicher, dass Cookies akzeptiert werden, sonst könnten wir deinen Token zum Starten des Downloads nicht abrufen.", + "enter-token-manually": "Mein Anmelde-Token manuell eingeben", + "enter-token-manually-tooltip": "Dies ermöglicht es Ihnen, Ihren Anmelde-Token einzugeben, ohne sich über Meta anzumelden." }, "stay":"Angemeldet bleiben", "connect-to-meta": "Mit Meta verbinden" @@ -694,6 +696,16 @@ }, "not-remind-me": "Nicht mehr erinnern", "understood": "Verstanden" + }, + "enter-meta-token": { + "title": "Meta-Token", + "body": { + "need-token": "Um Beat Saber herunterzuladen, ist Ihr Meta-Anmelde-Token erforderlich.", + "how-obtain-token": "Wie erhalte ich mein Meta-Token?", + "input-label": "Meta-Token", + "token-is-invalid": "Das Token ist ungültig." + }, + "valid-btn": "Validieren" } }, "maps": { diff --git a/assets/jsons/translations/en.json b/assets/jsons/translations/en.json index e7ea3709..e261ead3 100644 --- a/assets/jsons/translations/en.json +++ b/assets/jsons/translations/en.json @@ -680,7 +680,9 @@ "title": "Connect to Meta", "body":{ "token-needed": "Your Meta connection token is required to download Beat Saber.", - "need-cookie-enabled": "By logging into Meta, a login window will open and you can then start the login process. Please ensure to accept cookies, otherwise, we might not be able to retrieve your token to start the download." + "need-cookie-enabled": "By logging into Meta, a login window will open and you can then start the login process. Please ensure to accept cookies, otherwise, we might not be able to retrieve your token to start the download.", + "enter-token-manually": "Enter my login token manually", + "enter-token-manually-tooltip": "This will allow you to enter your login token without going through Meta login." }, "stay":"Remember me", "connect-to-meta": "Connect to Meta" @@ -694,6 +696,16 @@ }, "not-remind-me": "Do not remind me", "understood": "Understood" + }, + "enter-meta-token": { + "title": "Meta Token", + "body": { + "need-token": "To download Beat Saber, your Meta login token is required.", + "how-obtain-token": "How do I obtain my Meta Token?", + "input-label": "Meta Token", + "token-is-invalid": "The Token is invalid." + }, + "valid-btn": "Validate" } }, "maps": { diff --git a/assets/jsons/translations/es.json b/assets/jsons/translations/es.json index 8fe67bf0..a3529851 100644 --- a/assets/jsons/translations/es.json +++ b/assets/jsons/translations/es.json @@ -679,7 +679,9 @@ "title": "Conexión a Meta", "body":{ "token-needed": "Tu token de conexión a Meta es necesario para descargar Beat Saber.", - "need-cookie-enabled": "Al conectarte a Meta, se abrirá una ventana de inicio de sesión y entonces podrás empezar el proceso de conexión. Asegúrate de aceptar las cookies, de lo contrario, podríamos no poder recuperar tu token para iniciar la descarga." + "need-cookie-enabled": "Al conectarte a Meta, se abrirá una ventana de inicio de sesión y entonces podrás empezar el proceso de conexión. Asegúrate de aceptar las cookies, de lo contrario, podríamos no poder recuperar tu token para iniciar la descarga.", + "enter-token-manually": "Ingresar mi token de inicio de sesión manualmente", + "enter-token-manually-tooltip": "Esto te permitirá ingresar tu token de inicio de sesión sin pasar por el inicio de sesión de Meta." }, "stay":"Recuérdame", "connect-to-meta": "Conectarse a Meta" @@ -693,6 +695,16 @@ }, "not-remind-me": "No volver a recordármelo", "understood": "Entendido" + }, + "enter-meta-token": { + "title": "Token de Meta", + "body": { + "need-token": "Para descargar Beat Saber, se requiere su token de inicio de sesión de Meta.", + "how-obtain-token": "¿Cómo obtengo mi Token de Meta?", + "input-label": "Token de Meta", + "token-is-invalid": "El Token es inválido." + }, + "valid-btn": "Validar" } }, "maps": { diff --git a/assets/jsons/translations/fr.json b/assets/jsons/translations/fr.json index e4c60a2d..8eeb7161 100644 --- a/assets/jsons/translations/fr.json +++ b/assets/jsons/translations/fr.json @@ -676,7 +676,9 @@ "title": "Connexion à Meta", "body":{ "token-needed": "Votre token de connexion à Meta est nécessaire pour télécharger Beat Saber.", - "need-cookie-enabled": "En vous connectant à Meta, une fenêtre de connexion s'ouvrira et vous pourrez alors débuter le processus de connexion. Veillez à bien accepter les cookies sinon quoi, il se pourrait que l'on n'arrive pas à récupérer votre token pour démarrer le téléchargement." + "need-cookie-enabled": "En vous connectant à Meta, une fenêtre de connexion s'ouvrira et vous pourrez alors débuter le processus de connexion. Veillez à bien accepter les cookies sinon quoi, il se pourrait que l'on n'arrive pas à récupérer votre token pour démarrer le téléchargement.", + "enter-token-manually": "Entrer mon token de connexion manuellement", + "enter-token-manually-tooltip": "Cela vous permettra d'entrer votre token de connexion sans passer par la connexion Meta." }, "stay":"Se souvenir de moi", "connect-to-meta": "Se connecter à Meta" @@ -690,6 +692,16 @@ }, "not-remind-me": "Ne plus me rappeler", "understood": "J'ai compris" + }, + "enter-meta-token": { + "title": "Token Meta", + "body": { + "need-token": "Pour télécharger Beat Saber, votre token de connexion à Meta est nécessaire.", + "how-obtain-token": "Comment obtenir mon Token Meta ?", + "input-label": "Token Meta", + "token-is-invalid": "Le Token est invalide." + }, + "valid-btn": "Valider" } }, "maps": { diff --git a/assets/jsons/translations/ru.json b/assets/jsons/translations/ru.json index 3a075686..d36a16a4 100644 --- a/assets/jsons/translations/ru.json +++ b/assets/jsons/translations/ru.json @@ -680,7 +680,9 @@ "title": "Подключение к Meta", "body":{ "token-needed": "Для скачивания Beat Saber необходим ваш токен подключения к Meta.", - "need-cookie-enabled": "При входе в Meta откроется окно входа, и вы сможете начать процесс входа. Пожалуйста, убедитесь, что вы приняли cookies, иначе мы можем не суметь получить ваш токен для начала загрузки." + "need-cookie-enabled": "При входе в Meta откроется окно входа, и вы сможете начать процесс входа. Пожалуйста, убедитесь, что вы приняли cookies, иначе мы можем не суметь получить ваш токен для начала загрузки.", + "enter-token-manually": "Ввести мой токен входа вручную", + "enter-token-manually-tooltip": "Это позволит вам ввести ваш токен входа без прохождения через вход в Meta." }, "stay":"Запомнить меня", "connect-to-meta": "Подключиться к Meta" @@ -694,6 +696,16 @@ }, "not-remind-me": "Больше не напоминать", "understood": "Понял" + }, + "enter-meta-token": { + "title": "Мета Токен", + "body": { + "need-token": "Для загрузки Beat Saber требуется ваш токен входа в Meta.", + "how-obtain-token": "Как получить мой Мета Токен?", + "input-label": "Мета Токен", + "token-is-invalid": "Токен недействителен." + }, + "valid-btn": "Подтвердить" } }, "maps": { diff --git a/src/main/services/bs-version-download/bs-oculus-downloader.service.ts b/src/main/services/bs-version-download/bs-oculus-downloader.service.ts index 81d335f8..fe4b1408 100644 --- a/src/main/services/bs-version-download/bs-oculus-downloader.service.ts +++ b/src/main/services/bs-version-download/bs-oculus-downloader.service.ts @@ -7,10 +7,11 @@ import { OculusDownloader } from "../../models/oculus-downloader.class"; import { Cookie, session } from "electron"; import { Progression, ensurePathNotAlreadyExist } from "../../helpers/fs.helpers"; import { BSLocalVersionService } from "../bs-local-version.service"; -import { Observable, finalize, from, map, switchMap } from "rxjs"; +import { Observable, finalize, from, map, of, switchMap } from "rxjs"; import path from "path"; import { DownloadInfo } from "./bs-steam-downloader.service"; import { BsStore } from "../../../shared/models/bs-store.enum"; +import { isOculusTokenValid } from "../../../shared/helpers/oculus.helpers"; export class BsOculusDownloaderService { @@ -37,34 +38,7 @@ export class BsOculusDownloaderService { } private isUserTokenValid(token: string): boolean{ - - // Code taken from "https://github.com/ComputerElite/QuestAppVersionSwitcher" (TokenTools.cs) - - log.info("Checking if Oculus user token is valid"); - - if(!token){ - log.info("Oculus user token is empty"); - return false; - } - if(token.includes("%")){ - log.info("Token contains %. Token most likely comes from an uri and won't work"); - return false; - } - if(!token.startsWith("OC")){ - log.info("Token does not start with OC."); - return false; - } - if(token.includes("|")){ - log.info("Token contains | which usually indicates an application token which is not valid for user tokens"); - return false; - } - if(token.match(/OC\d{15}/)){ - log.info("Token matches /OC[0-9}{15}/ which usually indicates a changed oculus store token"); - return false; - } - - return true; - + return isOculusTokenValid(token, log.info); } private isCookieValid(cookie: Cookie): boolean { @@ -147,7 +121,9 @@ export class BsOculusDownloaderService { let downloadVersion: BSVersion - return from(this.getUserTokenFromMetaAuth(downloadInfo.stay)).pipe( + const tokenObs$ = downloadInfo.token ? of(downloadInfo.token) : from(this.getUserTokenFromMetaAuth(downloadInfo.stay)); + + return tokenObs$.pipe( switchMap(token => { if(!downloadInfo.isVerification){ return this.createDownloadVersion(downloadInfo.bsVersion).then(({version, dest}) => ({token, version, dest})) @@ -169,7 +145,9 @@ export class BsOculusDownloaderService { let downloadVersion: BSVersion - return from(this.getAuthToken()).pipe( + const tokenObs$ = downloadInfo.token ? of(downloadInfo.token) : from(this.getAuthToken()); + + return tokenObs$.pipe( map(token => { if(!token){ throw new CustomError("No Meta auth token was found in cookies for auto download", "NO_META_AUTH_TOKEN"); diff --git a/src/main/services/bs-version-download/bs-steam-downloader.service.ts b/src/main/services/bs-version-download/bs-steam-downloader.service.ts index 7f32f501..60fba30a 100644 --- a/src/main/services/bs-version-download/bs-steam-downloader.service.ts +++ b/src/main/services/bs-version-download/bs-steam-downloader.service.ts @@ -159,6 +159,7 @@ export interface DownloadInfo { bsVersion: BSVersion; isVerification?: boolean; stay?: boolean; + token?: string; } export interface DownloadSteamInfo extends DownloadInfo { diff --git a/src/renderer/components/modal/modal-types/bs-downgrade/enter-meta-token-modal.component.tsx b/src/renderer/components/modal/modal-types/bs-downgrade/enter-meta-token-modal.component.tsx new file mode 100644 index 00000000..796f05ef --- /dev/null +++ b/src/renderer/components/modal/modal-types/bs-downgrade/enter-meta-token-modal.component.tsx @@ -0,0 +1,59 @@ +import { BsmButton } from "renderer/components/shared/bsm-button.component"; +import { ModalComponent, ModalExitCode } from "../../../../services/modale.service"; +import { BsmImage } from "renderer/components/shared/bsm-image.component"; +import BeatWaiting from "../../../../../../assets/images/apngs/beat-impatient.png"; +import { useTranslation } from "renderer/hooks/use-translation.hook"; +import { useState } from "react"; +import { isOculusTokenValid } from "shared/helpers/oculus.helpers"; +import { logRenderError } from "renderer"; + +export const EnterMetaTokenModal: ModalComponent = ({resolver}) => { + + const t = useTranslation(); + + const [token, setToken] = useState(""); + const [showToken, setShowToken] = useState(false); + + const submit = () => { + resolver({exitCode: ModalExitCode.COMPLETED, data: token}); + } + + const cancel = () => { + resolver({exitCode: ModalExitCode.CANCELED}); + } + + const isTokenValid = (() => { + return isOculusTokenValid(token, logRenderError); + })(); + + return ( +
+

{t("modals.enter-meta-token.title")}

+ + + +

{t("modals.enter-meta-token.body.need-token")}

+ + {t("modals.enter-meta-token.body.how-obtain-token")} + +
+
+ + {!isTokenValid && token.length > 0 && ( + {t("modals.enter-meta-token.body.token-is-invalid")} + )} +
+
+ setToken(e.target.value)} value={token} type={showToken ? "text" : "password"} name="meta_token" id="meta_token" placeholder="OCAStr43sdx2..." /> + setShowToken(prev => !prev)} /> +
+
+ +
+ + +
+ + + ); +} diff --git a/src/renderer/components/modal/modal-types/bs-downgrade/login-to-meta-modal.component.tsx b/src/renderer/components/modal/modal-types/bs-downgrade/login-to-meta-modal.component.tsx index 29c225a2..901dd2ee 100644 --- a/src/renderer/components/modal/modal-types/bs-downgrade/login-to-meta-modal.component.tsx +++ b/src/renderer/components/modal/modal-types/bs-downgrade/login-to-meta-modal.component.tsx @@ -4,17 +4,24 @@ import { BsmButton } from "renderer/components/shared/bsm-button.component"; import { useTranslation } from "renderer/hooks/use-translation.hook"; import { MetaIcon } from "renderer/components/svgs/icons/meta-icon.component"; import { BsmCheckbox } from "renderer/components/shared/bsm-checkbox.component"; +import Tippy from "@tippyjs/react"; -export const LoginToMetaModal: ModalComponent = ({ resolver }) => { +type ReturnType = { method: MetaAuthMethod.META, stay: boolean } | { method: MetaAuthMethod.MANUAL }; + +export const LoginToMetaModal: ModalComponent = ({ resolver }) => { const t = useTranslation(); const [stay, setStay] = useState(false); const submit = () => { - resolver({ exitCode: ModalExitCode.COMPLETED, data: stay }); + resolver({ exitCode: ModalExitCode.COMPLETED, data: { method: MetaAuthMethod.META, stay } }); }; + const enterTokenManually = () => { + resolver({ exitCode: ModalExitCode.COMPLETED, data: { method: MetaAuthMethod.MANUAL } }); + } + return (

{t("modals.connect-to-meta.title")}

@@ -32,6 +39,16 @@ export const LoginToMetaModal: ModalComponent = ({ resolver }) => { + + +

{t("modals.connect-to-meta.body.enter-token-manually")}

+
+ ); }; + +export enum MetaAuthMethod { + MANUAL = "manual", + META = "meta" +} diff --git a/src/renderer/index.tsx b/src/renderer/index.tsx index 35ae65e2..befd5df7 100644 --- a/src/renderer/index.tsx +++ b/src/renderer/index.tsx @@ -15,7 +15,7 @@ const ipc = IpcService.getInstance(); const themeService = ThemeService.getInstance(); window.onerror = (...data) => { - ipc.sendLazy("log-error", { args: data }); + logRenderError(data); }; document.addEventListener("DOMContentLoaded", () => { @@ -58,4 +58,8 @@ if (launcherContainer) { }); } +export function logRenderError(...params: unknown[]){ + ipc.sendLazy("log-error", { args: params }); +} + diff --git a/src/renderer/services/bs-version-download/oculus-downloader.service.ts b/src/renderer/services/bs-version-download/oculus-downloader.service.ts index 9828432e..b833f4f0 100644 --- a/src/renderer/services/bs-version-download/oculus-downloader.service.ts +++ b/src/renderer/services/bs-version-download/oculus-downloader.service.ts @@ -6,11 +6,12 @@ import { ProgressBarService } from "../progress-bar.service"; import { CustomError } from "shared/models/exceptions/custom-error.class"; import { NotificationService } from "../notification.service"; import { ModalExitCode, ModalService } from "../modale.service"; -import { LoginToMetaModal } from "renderer/components/modal/modal-types/bs-downgrade/login-to-meta-modal.component"; +import { LoginToMetaModal, MetaAuthMethod } from "renderer/components/modal/modal-types/bs-downgrade/login-to-meta-modal.component"; import { DownloaderServiceInterface } from "./bs-store-downloader.interface"; import { AbstractBsDownloaderService } from "./abstract-bs-downloader.service"; import { DownloadInfo } from "main/services/bs-version-download/bs-steam-downloader.service"; import { MetaAuthErrorCodes, OculusDownloaderErrorCodes } from "shared/models/bs-version-download/oculus-download.model"; +import { EnterMetaTokenModal } from "renderer/components/modal/modal-types/bs-downgrade/enter-meta-token-modal.component"; export class OculusDownloaderService extends AbstractBsDownloaderService implements DownloaderServiceInterface{ @@ -103,16 +104,26 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme if(autoDownload){ return autoDownload; } - const [completed, stay] = await this.modals.openModal(LoginToMetaModal).then(res => [res.exitCode === ModalExitCode.COMPLETED, res.data]); + const {exitCode, data} = await this.modals.openModal(LoginToMetaModal) - if(!completed){ - return completed; + if(exitCode !== ModalExitCode.COMPLETED){ + return false } - return lastValueFrom(this.startDownloadBsVersion({ bsVersion, isVerification, stay })).then(() => true); + if(data.method === MetaAuthMethod.META){ + return lastValueFrom(this.startDownloadBsVersion({ bsVersion, isVerification, stay: data.stay })).then(() => true); + } - })().then(() => { - if(autoDownloadFailed){ + const tokenRes = await this.modals.openModal(EnterMetaTokenModal); + + if(tokenRes.exitCode !== ModalExitCode.COMPLETED){ + return false; + } + + return lastValueFrom(this.startDownloadBsVersion({ bsVersion, isVerification, token: tokenRes.data })).then(() => true); + + })().then(res => { + if(autoDownloadFailed || !res){ return bsVersion; } diff --git a/src/shared/helpers/oculus.helpers.ts b/src/shared/helpers/oculus.helpers.ts new file mode 100644 index 00000000..70fd416d --- /dev/null +++ b/src/shared/helpers/oculus.helpers.ts @@ -0,0 +1,32 @@ +export function isOculusTokenValid(token: string, logger?: (...args: unknown[]) => void): boolean{ + + // Code taken from "https://github.com/ComputerElite/QuestAppVersionSwitcher" (TokenTools.cs) + + logger?.("Checking if Oculus user token is valid"); + + if(!token){ + logger?.("Oculus user token is empty"); + return false; + } + if(token.includes("%")){ + logger?.("Token contains %. Token most likely comes from an uri and won't work"); + return false; + } + if(!token.startsWith("OC")){ + logger?.("Token does not start with OC."); + return false; + } + if(token.includes("|")){ + logger?.("Token contains | which usually indicates an application token which is not valid for user tokens"); + return false; + } + if(token.match(/OC\d{15}/)){ + logger?.("Token matches /OC[0-9}{15}/ which usually indicates a changed oculus store token"); + return false; + } + + logger?.("Oculus user token is valid"); + + return true; + +} \ No newline at end of file