From fa50d909412945f2d577646e02d6d6d9f2cdb4ee Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Tue, 26 Dec 2023 22:41:05 +0100 Subject: [PATCH 1/4] [chore] disable download oculus version with Meta login + Add possibility to store token with password --- assets/jsons/patreons.json | 90 ++++++-- assets/jsons/translations/de.json | 18 +- assets/jsons/translations/en.json | 18 +- assets/jsons/translations/es.json | 18 +- assets/jsons/translations/fr.json | 18 +- assets/jsons/translations/ja.json | 20 +- assets/jsons/translations/ru.json | 18 +- assets/jsons/translations/zh-tw.json | 18 +- assets/jsons/translations/zh.json | 18 +- package-lock.json | 22 ++ package.json | 2 + .../bs-oculus-downloader.service.ts | 1 + .../enter-meta-token-modal.component.tsx | 196 +++++++++++++++--- .../pages/settings-page.component.tsx | 3 +- .../bs-downloader.service.ts | 8 +- .../oculus-downloader.service.ts | 48 ++--- .../services/configuration.service.ts | 10 +- src/shared/helpers/oculus.helpers.ts | 14 +- 18 files changed, 418 insertions(+), 122 deletions(-) diff --git a/assets/jsons/patreons.json b/assets/jsons/patreons.json index 4f579763..4a876ea3 100644 --- a/assets/jsons/patreons.json +++ b/assets/jsons/patreons.json @@ -1,21 +1,71 @@ [ - {"username": "Shidorien"}, - {"username": "iPixelGalaxy"}, - {"username": "Emyte", "type": "gold"}, - {"username": "GoodOldNervy"}, - {"username": "Naysy"}, - {"username": "Falmil"}, - {"username": "K1Lc4m"}, - {"username": "Anonymously42", "type": "diamond", "link": "https://www.twitch.tv/anonymously42tv"}, - {"username": "Burt", "type": "gold"}, - {"username": "Ilnahro"}, - {"username": "Phil", "type": "gold"}, - {"username": "Protocrush", "type": "gold"}, - {"username": "ServerMensch", "type": "gold"}, - {"username": "Karlito", "type": "gold"}, - {"username": "Cathery", "type": "gold"}, - {"username": ".sharkey"}, - {"username": "Z3t4"}, - {"username": "blot455", "type": "diamond"}, - {"username": "Lumberjack462", "type": "diamond", "link": "https://www.youtube.com/@lumberjack462"} -] + { + "username": "Shidorien" + }, + { + "username": "iPixelGalaxy" + }, + { + "username": "Emyte", + "type": "gold" + }, + { + "username": "GoodOldNervy" + }, + { + "username": "Naysy" + }, + { + "username": "Falmil" + }, + { + "username": "K1Lc4m" + }, + { + "username": "Anonymously42", + "type": "diamond", + "link": "https://www.twitch.tv/anonymously42tv" + }, + { + "username": "Burt", + "type": "gold" + }, + { + "username": "Ilnahro" + }, + { + "username": "Phil", + "type": "gold" + }, + { + "username": "Protocrush", + "type": "gold" + }, + { + "username": "ServerMensch", + "type": "gold" + }, + { + "username": "Karlito", + "type": "gold" + }, + { + "username": "Cathery", + "type": "gold" + }, + { + "username": ".sharkey" + }, + { + "username": "Z3t4" + }, + { + "username": "blot455", + "type": "diamond" + }, + { + "username": "Lumberjack462", + "type": "diamond", + "link": "https://www.youtube.com/@lumberjack462" + } +] \ No newline at end of file diff --git a/assets/jsons/translations/de.json b/assets/jsons/translations/de.json index d4acba37..4a631259 100644 --- a/assets/jsons/translations/de.json +++ b/assets/jsons/translations/de.json @@ -707,12 +707,20 @@ "understood": "Verstanden" }, "enter-meta-token": { - "title": "Meta-Token", + "title": "Oculus 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." + "info-enter-token": "Um Beat Saber herunterzuladen, ist Ihr Oculus-Anmeldetoken erforderlich.", + "how-obtain-token": "Wie erhalte ich mein Oculus Token?", + "oculus-token": "Oculus Token", + "token-is-invalid": "Das Token ist ungültig.", + "save-my-token": "Mein Token speichern", + "have-token-saved": "Ich habe bereits ein Token gespeichert", + "save-token-info": "Dies wird Ihr Token zur einfacheren Wiederverwendung speichern. Sie müssen ein Passwort erstellen, um Ihr Token zu verschlüsseln und zu speichern. Wenn Sie Ihr Passwort vergessen, müssen Sie nur Ihr Token erneut angeben.", + "password": "Passwort", + "password-too-short": "Passwort zu kurz", + "info-enter-password": "Um Beat Saber herunterzuladen, ist Ihr Oculus-Anmeldetoken erforderlich. Geben Sie das Passwort ein, mit dem Ihr Oculus-Token gespeichert wurde.", + "info-disabled-btn-password": "Der mit dem angegebenen Passwort entschlüsselte Token ist ungültig. Stellen Sie sicher, dass das Passwort dasselbe ist wie das zum Speichern des Tokens verwendete.", + "enter-oculus-token": "Ein Oculus-Token eingeben" }, "valid-btn": "Validieren" } diff --git a/assets/jsons/translations/en.json b/assets/jsons/translations/en.json index 02527bae..625c0405 100644 --- a/assets/jsons/translations/en.json +++ b/assets/jsons/translations/en.json @@ -707,12 +707,20 @@ "understood": "Understood" }, "enter-meta-token": { - "title": "Meta Token", + "title": "Oculus 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." + "info-enter-token": "To download Beat Saber, your Oculus login token is required.", + "how-obtain-token": "How do I obtain my Oculus Token?", + "oculus-token": "Oculus Token", + "token-is-invalid": "The Token is invalid.", + "save-my-token": "Save my token", + "have-token-saved": "I already have a token saved", + "save-token-info": "This will save your token for easier reuse. You will need to create a password to encrypt your token for storage purposes. If you ever forget your password, you just need to provide your token again.", + "password": "Password", + "password-too-short": "Password too short", + "info-enter-password": "To download Beat Saber, your Oculus login token is required. Enter the password used to save your Oculus token.", + "info-disabled-btn-password": "The token decrypted with the provided password is invalid. Make sure the password is the same as the one used to save the token.", + "enter-oculus-token": "Enter an Oculus token" }, "valid-btn": "Validate" } diff --git a/assets/jsons/translations/es.json b/assets/jsons/translations/es.json index 865c54a5..67441fa6 100644 --- a/assets/jsons/translations/es.json +++ b/assets/jsons/translations/es.json @@ -706,12 +706,20 @@ "understood": "Entendido" }, "enter-meta-token": { - "title": "Token de Meta", + "title": "Token de Oculus", "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." + "info-enter-token": "Para descargar Beat Saber, se requiere tu token de inicio de sesión de Oculus.", + "how-obtain-token": "¿Cómo obtengo mi Token de Oculus?", + "oculus-token": "Token de Oculus", + "token-is-invalid": "El token es inválido.", + "save-my-token": "Guardar mi token", + "have-token-saved": "Ya tengo un token guardado", + "save-token-info": "Esto guardará tu token para reutilizarlo más fácilmente. Necesitarás crear una contraseña para encriptar tu token para su almacenamiento. Si alguna vez olvidas tu contraseña, solo necesitas proporcionar tu token nuevamente.", + "password": "Contraseña", + "password-too-short": "Contraseña demasiado corta", + "info-enter-password": "Para descargar Beat Saber, se requiere tu token de inicio de sesión de Oculus. Introduce la contraseña utilizada para guardar tu token de Oculus.", + "info-disabled-btn-password": "El token descifrado con la contraseña proporcionada es inválido. Asegúrate de que la contraseña sea la misma que la utilizada para guardar el token.", + "enter-oculus-token": "Introducir un token de Oculus" }, "valid-btn": "Validar" } diff --git a/assets/jsons/translations/fr.json b/assets/jsons/translations/fr.json index e60ef015..7631e256 100644 --- a/assets/jsons/translations/fr.json +++ b/assets/jsons/translations/fr.json @@ -703,12 +703,20 @@ "understood": "J'ai compris" }, "enter-meta-token": { - "title": "Token Meta", + "title": "Token Oculus", "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." + "info-enter-token": "Pour télécharger Beat Saber, votre token de connexion à Oculus est nécessaire.", + "how-obtain-token": "Comment obtenir mon Token Oculus ?", + "oculus-token": "Token Oculus", + "token-is-invalid": "Le Token est invalide.", + "save-my-token": "Sauvegarder mon token", + "have-token-saved": "J'ai déjà un token sauvegardé", + "save-token-info": "Ceci enregistrera votre token pour le réutiliser plus facilement. Vous devrez créer un mot de passe pour crypter votre token à des fins de stockage. Si jamais vous oubliez votre mot de passe, il vous suffit de fournir à nouveau votre token.", + "password": "Mot de passe", + "password-too-short": "Mot de passe trop court", + "info-enter-password": "Pour télécharger Beat Saber, votre token de connexion à Oculus est nécessaire. Entrez le mot de passe utilisé pour sauvegarder votre token Oculus.", + "info-disabled-btn-password": "Le token déchiffré à l'aide du mot de passe fourni est invalide. Assurez-vous que le mot de passe est le même que celui utilisé pour sauvegarder le token.", + "enter-oculus-token": "Entrer un token Oculus" }, "valid-btn": "Valider" } diff --git a/assets/jsons/translations/ja.json b/assets/jsons/translations/ja.json index 85393775..65132a6a 100644 --- a/assets/jsons/translations/ja.json +++ b/assets/jsons/translations/ja.json @@ -707,14 +707,22 @@ "understood": "分かった" }, "enter-meta-token": { - "title": "Metaトークン", + "title": "Oculusトークン", "body": { - "need-token": "Beat Saberをダウンロードするには、Metaのログイントークンが必要です。", - "how-obtain-token": "Metaトークンはどうやって入手すればいいですか?", - "input-label": "Metaトークン", - "token-is-invalid": "トークンが無効です。" + "info-enter-token": "Beat Saberをダウンロードするには、あなたのオキュラスログイントークンが必要です。", + "how-obtain-token": "オキュラストークンはどうやって取得するの?", + "oculus-token": "オキュラストークン", + "token-is-invalid": "トークンが無効です。", + "save-my-token": "私のトークンを保存する", + "have-token-saved": "すでにトークンを保存しています", + "save-token-info": "これにより、トークンを簡単に再利用するために保存します。保管のためにトークンを暗号化するパスワードを作成する必要があります。パスワードを忘れた場合は、トークンを再度提供するだけです。", + "password": "パスワード", + "password-too-short": "パスワードが短すぎます", + "info-enter-password": "Beat Saberをダウンロードするには、あなたのオキュラスログイントークンが必要です。オキュラストークンを保存するために使用したパスワードを入力してください。", + "info-disabled-btn-password": "提供されたパスワードで復号化されたトークンは無効です。トークンを保存するために使用されたパスワードと同じであることを確認してください。", + "enter-oculus-token": "オキュラストークンを入力する" }, - "valid-btn": "検証" + "valid-btn": "確認" } }, "maps": { diff --git a/assets/jsons/translations/ru.json b/assets/jsons/translations/ru.json index 93b8c0bf..f1e289e6 100644 --- a/assets/jsons/translations/ru.json +++ b/assets/jsons/translations/ru.json @@ -707,12 +707,20 @@ "understood": "Понял" }, "enter-meta-token": { - "title": "Мета Токен", + "title": "Токен Oculus", "body": { - "need-token": "Для загрузки Beat Saber требуется ваш токен входа в Meta.", - "how-obtain-token": "Как получить мой Мета Токен?", - "input-label": "Мета Токен", - "token-is-invalid": "Токен недействителен." + "info-enter-token": "Для загрузки Beat Saber требуется ваш токен входа в Oculus.", + "how-obtain-token": "Как получить мой токен Oculus?", + "oculus-token": "Токен Oculus", + "token-is-invalid": "Токен недействителен.", + "save-my-token": "Сохранить мой токен", + "have-token-saved": "У меня уже есть сохраненный токен", + "save-token-info": "Это сохранит ваш токен для удобства повторного использования. Вам необходимо создать пароль для шифрования вашего токена для хранения. Если вы забудете пароль, вам просто нужно будет снова предоставить свой токен.", + "password": "Пароль", + "password-too-short": "Слишком короткий пароль", + "info-enter-password": "Для загрузки Beat Saber требуется ваш токен входа в Oculus. Введите пароль, используемый для сохранения вашего токена Oculus.", + "info-disabled-btn-password": "Токен, расшифрованный с использованием предоставленного пароля, недействителен. Убедитесь, что пароль совпадает с тем, который использовался для сохранения токена.", + "enter-oculus-token": "Введите токен Oculus" }, "valid-btn": "Подтвердить" } diff --git a/assets/jsons/translations/zh-tw.json b/assets/jsons/translations/zh-tw.json index cca5aa27..cf2e71b2 100644 --- a/assets/jsons/translations/zh-tw.json +++ b/assets/jsons/translations/zh-tw.json @@ -708,12 +708,20 @@ "understood": "明白了" }, "enter-meta-token": { - "title": "Meta 令牌", + "title": "Oculus令牌", "body": { - "need-token": "要下載 BeatSaber,需要你的 Meta 登錄令牌。", - "how-obtain-token": "如何獲取我的 Meta 令牌?", - "input-label": "Meta 令牌", - "token-is-invalid": "令牌無效。" + "info-enter-token": "下載Beat Saber需要您的Oculus登錄令牌。", + "how-obtain-token": "我如何獲得我的Oculus令牌?", + "oculus-token": "Oculus令牌", + "token-is-invalid": "令牌無效。", + "save-my-token": "保存我的令牌", + "have-token-saved": "我已經保存了一個令牌", + "save-token-info": "這將保存您的令牌以便更容易地重新使用。您需要創建一個密碼來加密您的令牌以進行存儲。如果您忘記了密碼,只需再次提供您的令牌即可。", + "password": "密碼", + "password-too-short": "密碼太短", + "info-enter-password": "下載Beat Saber需要您的Oculus登錄令牌。請輸入用於保存您的Oculus令牌的密碼。", + "info-disabled-btn-password": "使用提供的密碼解密的令牌無效。確保密碼與保存令牌時使用的密碼相同。", + "enter-oculus-token": "輸入Oculus令牌" }, "valid-btn": "驗證" } diff --git a/assets/jsons/translations/zh.json b/assets/jsons/translations/zh.json index 8db38707..2e806fc0 100644 --- a/assets/jsons/translations/zh.json +++ b/assets/jsons/translations/zh.json @@ -708,12 +708,20 @@ "understood": "明白了" }, "enter-meta-token": { - "title": "Meta 令牌", + "title": "Oculus令牌", "body": { - "need-token": "要下载 BeatSaber,需要你的 Meta 登录令牌。", - "how-obtain-token": "如何获取我的 Meta 令牌?", - "input-label": "Meta 令牌", - "token-is-invalid": "令牌无效。" + "info-enter-token": "下载Beat Saber需要您的Oculus登录令牌。", + "how-obtain-token": "我如何获得我的Oculus令牌?", + "oculus-token": "Oculus令牌", + "token-is-invalid": "令牌无效。", + "save-my-token": "保存我的令牌", + "have-token-saved": "我已经保存了一个令牌", + "save-token-info": "这将保存您的令牌以便更容易地重新使用。您需要创建一个密码来加密您的令牌以进行存储。如果您忘记了密码,只需再次提供您的令牌即可。", + "password": "密码", + "password-too-short": "密码太短", + "info-enter-password": "下载Beat Saber需要您的Oculus登录令牌。请输入用于保存您的Oculus令牌的密码。", + "info-disabled-btn-password": "使用提供的密码解密的令牌无效。确保密码与保存令牌时使用的密码相同。", + "enter-oculus-token": "输入Oculus令牌" }, "valid-btn": "验证" } diff --git a/package-lock.json b/package-lock.json index 88acdeb7..d9494b8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,8 +11,10 @@ "@electron/fuses": "^1.6.2", "@node-steam/vdf": "^2.2.0", "@tippyjs/react": "^4.2.6", + "@types/crypto-js": "^4.2.1", "archiver": "^6.0.1", "color": "^4.2.3", + "crypto-js": "^4.2.0", "dateformat": "^5.0.3", "dot-prop": "^8.0.2", "electron-debug": "^3.2.0", @@ -2524,6 +2526,11 @@ "@types/node": "*" } }, + "node_modules/@types/crypto-js": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.1.tgz", + "integrity": "sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==" + }, "node_modules/@types/dateformat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/dateformat/-/dateformat-5.0.0.tgz", @@ -5711,6 +5718,11 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, "node_modules/css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", @@ -21062,6 +21074,11 @@ "@types/node": "*" } }, + "@types/crypto-js": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.1.tgz", + "integrity": "sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==" + }, "@types/dateformat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/dateformat/-/dateformat-5.0.0.tgz", @@ -23585,6 +23602,11 @@ "which": "^2.0.1" } }, + "crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, "css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", diff --git a/package.json b/package.json index 6e1b815a..6ac26fbe 100644 --- a/package.json +++ b/package.json @@ -236,8 +236,10 @@ "@electron/fuses": "^1.6.2", "@node-steam/vdf": "^2.2.0", "@tippyjs/react": "^4.2.6", + "@types/crypto-js": "^4.2.1", "archiver": "^6.0.1", "color": "^4.2.3", + "crypto-js": "^4.2.0", "dateformat": "^5.0.3", "dot-prop": "^8.0.2", "electron-debug": "^3.2.0", 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 7fc43a3b..3b974a0c 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 @@ -129,6 +129,7 @@ export class BsOculusDownloaderService { return tokenObs$.pipe( switchMap(token => { + isOculusTokenValid(token, log.info); // Log token validity if(!downloadInfo.isVerification){ return this.createDownloadVersion(downloadInfo.bsVersion).then(({version, dest}) => ({token, version, dest})) } 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 index 796f05ef..f7c8be4f 100644 --- 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 @@ -5,55 +5,203 @@ import BeatWaiting from "../../../../../../assets/images/apngs/beat-impatient.pn import { useTranslation } from "renderer/hooks/use-translation.hook"; import { useState } from "react"; import { isOculusTokenValid } from "shared/helpers/oculus.helpers"; +import crypto from "crypto-js"; +import { BsmCheckbox } from "renderer/components/shared/bsm-checkbox.component"; +import Tippy from "@tippyjs/react"; +import { tryit } from "shared/helpers/error.helpers"; import { logRenderError } from "renderer"; +import { useService } from "renderer/hooks/use-service.hook"; +import { ConfigurationService } from "renderer/services/configuration.service"; + +const OCULUS_TOKEN_STORAGE_KEY = "meta-token"; export const EnterMetaTokenModal: ModalComponent = ({resolver}) => { const t = useTranslation(); - const [token, setToken] = useState(""); - const [showToken, setShowToken] = useState(false); + const config = useService(ConfigurationService); - const submit = () => { + const [passwordView, setPasswordView] = useState(() => !!config.get(OCULUS_TOKEN_STORAGE_KEY)); + + const submit = (token: string) => { 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")}

- + {passwordView ? ( + setPasswordView(() => false)}/> + ) : ( + setPasswordView(() => true)}/> + )} + + ); +} -

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

+const isPasswordValid = (password: string) => { + return password.length >= 8; +} - {t("modals.enter-meta-token.body.how-obtain-token")} - -
-
- - {!isTokenValid && token.length > 0 && ( - {t("modals.enter-meta-token.body.token-is-invalid")} - )} +const EnterPasswordView = ({onValid, onCancel, dontHaveToken}: {onValid: (token: string) => void, onCancel: () => void, dontHaveToken: () => void}) => { + + const t = useTranslation(); + + const config = useService(ConfigurationService); + + const [password, setPassword] = useState(""); + const [showPassword, setShowPassword] = useState(false); + + const getTokenFromStorage = () => { + const cryptedToken = config.get(OCULUS_TOKEN_STORAGE_KEY); + if(!cryptedToken) return null; + const { result: token, error } = tryit(() => crypto.AES.decrypt(cryptedToken, password).toString(crypto.enc.Utf8)); + + if(error){ + logRenderError(error, "Often indicate that the password is not the same as the one used to save the token."); + } + + return token; + } + + const isTokenValid = () => { + const token = getTokenFromStorage(); + return isOculusTokenValid(token); + } + + const valid = () => { + const token = getTokenFromStorage(); + onValid(token); + } + + return ( + <> +

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

+ +
+
+
+ + {!isPasswordValid(password) && password.length > 0 && ( + {t("modals.enter-meta-token.body.password-too-short")} + )} +
+
+ setPassword(e.target.value)} value={password} type={showPassword ? "text" : "password"} name="password" id="password" placeholder={t("modals.enter-meta-token.body.password")} /> + setShowPassword(prev => !prev)} /> +
-
- setToken(e.target.value)} value={token} type={showToken ? "text" : "password"} name="meta_token" id="meta_token" placeholder="OCAStr43sdx2..." /> - setShowToken(prev => !prev)} /> + +
+ {t("modals.enter-meta-token.body.enter-oculus-token")}
- - + + +
+ +
+
- - + + ); + +} + +const EnterOculusTokenView = ({onValid, onCancel, alreadyHaveToken}: {onValid: (token: string) => void, onCancel: () => void, alreadyHaveToken: () => void}) => { + + const t = useTranslation(); + + const config = useService(ConfigurationService); + + const [token, setToken] = useState(""); + const [showToken, setShowToken] = useState(false); + const [stay, setStay] = useState(false); + const [password, setPassword] = useState(""); + const [showPassword, setShowPassword] = useState(false); + + const storeToken = (token: string, password: string) => { + const cryptedToken = crypto.AES.encrypt(token, password).toString(); + config.set(OCULUS_TOKEN_STORAGE_KEY, cryptedToken); + } + + const valid = () => { + + if(stay){ + storeToken(token, password); + } else { + config.delete(OCULUS_TOKEN_STORAGE_KEY); + } + + onValid(token); + } + + const isCryptedTokenPresent = () => { + return !!config.get(OCULUS_TOKEN_STORAGE_KEY); + } + + return ( + <> +

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

+ {t("modals.enter-meta-token.body.how-obtain-token")} + +
+
+
+ + {!isOculusTokenValid(token) && 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="FRLAStr43sdx2..." /> + setShowToken(prev => !prev)} /> +
+
+ + +
+ + {t("modals.enter-meta-token.body.save-my-token")} +
+
+ +
+
+
+ + {!isPasswordValid(password) && password.length > 0 && ( + {t("modals.enter-meta-token.body.password-too-short")} + )} +
+
+ setPassword(e.target.value)} value={password} type={showPassword ? "text" : "password"} name="password" id="password" placeholder={t("modals.enter-meta-token.body.password")} /> + setShowPassword(prev => !prev)} /> +
+
+
+ + {isCryptedTokenPresent() && ( +
+ {t("modals.enter-meta-token.body.have-token-saved")} +
+ )} +
+ +
+ + +
+ + + ); + } diff --git a/src/renderer/pages/settings-page.component.tsx b/src/renderer/pages/settings-page.component.tsx index bccd2bf6..7bf12f88 100644 --- a/src/renderer/pages/settings-page.component.tsx +++ b/src/renderer/pages/settings-page.component.tsx @@ -80,6 +80,7 @@ export function SettingsPage() { const themeSelected = useObservable(themeService.theme$, "os"); const languageSelected = useObservable(i18nService.currentLanguage$, i18nService.getFallbackLanguage()); const downloadStore = useObservable(bsDownloader.defaultStore$); + const [installationFolder, setInstallationFolder] = useState(null); const [showSupporters, setShowSupporters] = useState(false); const [mapDeepLinksEnabled, setMapDeepLinksEnabled] = useState(false); @@ -236,7 +237,7 @@ export function SettingsPage() { }, { id: 2, text: "Oculus Store (PC)", value: BsStore.OCULUS, icon: }, - { id: 0, text: t("pages.settings.steam-and-oculus.download-platform.always-ask"), value: undefined, }, + { id: 0, text: t("pages.settings.steam-and-oculus.download-platform.always-ask"), value: null, }, ]} selectedItemValue={downloadStore} onItemSelected={handleChangeBsStore}/> diff --git a/src/renderer/services/bs-version-download/bs-downloader.service.ts b/src/renderer/services/bs-version-download/bs-downloader.service.ts index 200a5df8..d8cc7b68 100644 --- a/src/renderer/services/bs-version-download/bs-downloader.service.ts +++ b/src/renderer/services/bs-version-download/bs-downloader.service.ts @@ -28,7 +28,7 @@ export class BsDownloaderService extends AbstractBsDownloaderService { private readonly oculusDownloader: OculusDownloaderService; private readonly versionManager: BSVersionManagerService; - private readonly SELECTED_STORE_TO_DOWNLOAD_KET = "selectedStoreToDownload"; + private readonly SELECTED_STORE_TO_DOWNLOAD_KEY = "selectedStoreToDownload"; private constructor(){ super(); @@ -55,11 +55,11 @@ export class BsDownloaderService extends AbstractBsDownloaderService { this._isVerifying$.next(false); } - public get defaultStore(): BsStore | undefined { return this.config.get(this.SELECTED_STORE_TO_DOWNLOAD_KET); } - public get defaultStore$(): Observable { return this.config.watch(this.SELECTED_STORE_TO_DOWNLOAD_KET); } + public get defaultStore(): BsStore | undefined { return this.config.get(this.SELECTED_STORE_TO_DOWNLOAD_KEY); } + public get defaultStore$(): Observable { return this.config.watch(this.SELECTED_STORE_TO_DOWNLOAD_KEY); } public setDefaultStore(store: BsStore|undefined): void { - this.config.set(this.SELECTED_STORE_TO_DOWNLOAD_KET, store); + this.config.set(this.SELECTED_STORE_TO_DOWNLOAD_KEY, store); } public async chooseStoreToDownloadFrom(): Promise { 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 ecd9b09c..590d1497 100644 --- a/src/renderer/services/bs-version-download/oculus-downloader.service.ts +++ b/src/renderer/services/bs-version-download/oculus-downloader.service.ts @@ -87,37 +87,39 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme private async doDownloadBsVersion(bsVersion: BSVersion, isVerification: boolean): Promise { - let autoDownloadFailed = false; + const autoDownloadFailed = false; return (async () => { - const autoDownload = await lastValueFrom(this.tryAutoDownload({ bsVersion, isVerification })).then(() => true).catch((err: CustomError) => { - const doNotRestartCodes: string[] = [ - OculusDownloaderErrorCodes.ALREADY_DOWNLOADING, - OculusDownloaderErrorCodes.SOME_FILES_FAILED_TO_DOWNLOAD, - OculusDownloaderErrorCodes.VERIFY_INTEGRITY_FAILED, - OculusDownloaderErrorCodes.DOWNLOAD_CANCELLED - ]; - autoDownloadFailed = true; + // DISABLE FOR NOW, WILL MAYBE BE RE-ENABLED WHEN META AUTH IS FIXED - if(doNotRestartCodes.includes(err?.code)){ - return true; - } + // const autoDownload = await lastValueFrom(this.tryAutoDownload({ bsVersion, isVerification })).then(() => true).catch((err: CustomError) => { + // const doNotRestartCodes: string[] = [ + // OculusDownloaderErrorCodes.ALREADY_DOWNLOADING, + // OculusDownloaderErrorCodes.SOME_FILES_FAILED_TO_DOWNLOAD, + // OculusDownloaderErrorCodes.VERIFY_INTEGRITY_FAILED, + // OculusDownloaderErrorCodes.DOWNLOAD_CANCELLED + // ]; + // autoDownloadFailed = true; - return false; - }); + // if(doNotRestartCodes.includes(err?.code)){ + // return true; + // } + + // return false; + // }); - if(autoDownload){ return autoDownload; } + // if(autoDownload){ return autoDownload; } - const {exitCode, data} = await this.modals.openModal(LoginToMetaModal) + // const {exitCode, data} = await this.modals.openModal(LoginToMetaModal) - if(exitCode !== ModalExitCode.COMPLETED){ - return false - } + // if(exitCode !== ModalExitCode.COMPLETED){ + // return false + // } - if(data.method === MetaAuthMethod.META){ - return lastValueFrom(this.startDownloadBsVersion({ bsVersion, isVerification, stay: data.stay })).then(() => true); - } + // if(data.method === MetaAuthMethod.META){ + // return lastValueFrom(this.startDownloadBsVersion({ bsVersion, isVerification, stay: data.stay })).then(() => true); + // } const tokenRes = await this.modals.openModal(EnterMetaTokenModal); @@ -129,8 +131,6 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme })().then(res => { - console.log("aaa", res); - if(autoDownloadFailed || !res){ return bsVersion; } diff --git a/src/renderer/services/configuration.service.ts b/src/renderer/services/configuration.service.ts index 81dc31a6..9a1a61c4 100644 --- a/src/renderer/services/configuration.service.ts +++ b/src/renderer/services/configuration.service.ts @@ -30,10 +30,14 @@ export class ConfigurationService { public get(key: string | DefaultConfigKey): Type { const rawValue = (window.sessionStorage.getItem(key) ?? window.localStorage.getItem(key)); const tryParse = tryit(() => JSON.parse(rawValue)); - if (!tryParse.result) { - return defaultConfiguration[key as DefaultConfigKey]; + + const res = (tryParse.error ? rawValue : tryParse.result) as Type; + + if(!res && Object.keys(defaultConfiguration).includes(key)){ + return defaultConfiguration[key as DefaultConfigKey] as Type; } - return (tryParse.result ?? rawValue) as Type; + + return res; } public set(key: string, value: unknown, persistant = true) { diff --git a/src/shared/helpers/oculus.helpers.ts b/src/shared/helpers/oculus.helpers.ts index 70fd416d..3176867c 100644 --- a/src/shared/helpers/oculus.helpers.ts +++ b/src/shared/helpers/oculus.helpers.ts @@ -1,6 +1,6 @@ export function isOculusTokenValid(token: string, logger?: (...args: unknown[]) => void): boolean{ - // Code taken from "https://github.com/ComputerElite/QuestAppVersionSwitcher" (TokenTools.cs) + // Part of code taken from "https://github.com/ComputerElite/QuestAppVersionSwitcher" (TokenTools.cs) logger?.("Checking if Oculus user token is valid"); @@ -12,12 +12,16 @@ export function isOculusTokenValid(token: string, logger?: (...args: unknown[]) 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."); + if(!token.startsWith("FRL")){ + logger?.("Tokens must start with 'FRL'."); return false; } if(token.includes("|")){ - logger?.("Token contains | which usually indicates an application token which is not valid for user tokens"); + logger?.("Token contains '|' which usually indicates an application token which is not valid for user tokens"); + return false; + } + if(token.includes(":")){ + logger?.("Token contains ':' wich can indicate that the user have copied the 'access_token' field with the token"); return false; } if(token.match(/OC\d{15}/)){ @@ -25,7 +29,7 @@ export function isOculusTokenValid(token: string, logger?: (...args: unknown[]) return false; } - logger?.("Oculus user token is valid"); + logger?.("Oculus user token is valid.", `token lenght : ${token.length}`); return true; From 1ba0b0beac54d5b7f57a6f33533a0bb2c32363c3 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Tue, 26 Dec 2023 22:52:44 +0100 Subject: [PATCH 2/4] [chore] remove comments --- .../oculus-downloader.service.ts | 39 ------------------- 1 file changed, 39 deletions(-) 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 590d1497..6bc8bca2 100644 --- a/src/renderer/services/bs-version-download/oculus-downloader.service.ts +++ b/src/renderer/services/bs-version-download/oculus-downloader.service.ts @@ -6,7 +6,6 @@ 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, 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"; @@ -69,14 +68,6 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme ); } - private tryAutoDownload(downloadInfo: DownloadInfo): Observable>{ - const ignoreCode = [MetaAuthErrorCodes.NO_META_AUTH_TOKEN, OculusDownloaderErrorCodes.DOWNLOAD_CANCELLED]; - return this.handleDownload( - this.ipc.sendV2>("bs-oculus-auto-download", { args: downloadInfo }), - ignoreCode - ); - } - private startDownloadBsVersion(downloadInfo: DownloadInfo): Observable>{ const ignoreCode = [MetaAuthErrorCodes.META_LOGIN_WINDOW_CLOSED_BY_USER, OculusDownloaderErrorCodes.DOWNLOAD_CANCELLED]; return this.handleDownload( @@ -91,36 +82,6 @@ export class OculusDownloaderService extends AbstractBsDownloaderService impleme return (async () => { - // DISABLE FOR NOW, WILL MAYBE BE RE-ENABLED WHEN META AUTH IS FIXED - - // const autoDownload = await lastValueFrom(this.tryAutoDownload({ bsVersion, isVerification })).then(() => true).catch((err: CustomError) => { - // const doNotRestartCodes: string[] = [ - // OculusDownloaderErrorCodes.ALREADY_DOWNLOADING, - // OculusDownloaderErrorCodes.SOME_FILES_FAILED_TO_DOWNLOAD, - // OculusDownloaderErrorCodes.VERIFY_INTEGRITY_FAILED, - // OculusDownloaderErrorCodes.DOWNLOAD_CANCELLED - // ]; - // autoDownloadFailed = true; - - // if(doNotRestartCodes.includes(err?.code)){ - // return true; - // } - - // return false; - // }); - - // if(autoDownload){ return autoDownload; } - - // const {exitCode, data} = await this.modals.openModal(LoginToMetaModal) - - // if(exitCode !== ModalExitCode.COMPLETED){ - // return false - // } - - // if(data.method === MetaAuthMethod.META){ - // return lastValueFrom(this.startDownloadBsVersion({ bsVersion, isVerification, stay: data.stay })).then(() => true); - // } - const tokenRes = await this.modals.openModal(EnterMetaTokenModal); if(tokenRes.exitCode !== ModalExitCode.COMPLETED){ From fb7f08ee2e2aeab73133fadd56775af9779decf7 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Tue, 26 Dec 2023 22:56:44 +0100 Subject: [PATCH 3/4] [chore] move types of "crypto-js" to dev dependencies --- package-lock.json | 8 +++++--- package.json | 2 +- release/app/package-lock.json | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index d9494b8b..4cd548dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "@electron/fuses": "^1.6.2", "@node-steam/vdf": "^2.2.0", "@tippyjs/react": "^4.2.6", - "@types/crypto-js": "^4.2.1", "archiver": "^6.0.1", "color": "^4.2.3", "crypto-js": "^4.2.0", @@ -62,6 +61,7 @@ "@testing-library/react": "^13.3.0", "@types/archiver": "^5.3.1", "@types/color": "^3.0.3", + "@types/crypto-js": "^4.2.1", "@types/dateformat": "^5.0.0", "@types/jest": "^27.5.2", "@types/node": "17.0.23", @@ -2529,7 +2529,8 @@ "node_modules/@types/crypto-js": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.1.tgz", - "integrity": "sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==" + "integrity": "sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==", + "dev": true }, "node_modules/@types/dateformat": { "version": "5.0.0", @@ -21077,7 +21078,8 @@ "@types/crypto-js": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.1.tgz", - "integrity": "sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==" + "integrity": "sha512-FSPGd9+OcSok3RsM0UZ/9fcvMOXJ1ENE/ZbLfOPlBWj7BgXtEAM8VYfTtT760GiLbQIMoVozwVuisjvsVwqYWw==", + "dev": true }, "@types/dateformat": { "version": "5.0.0", diff --git a/package.json b/package.json index 6ac26fbe..10dfac8d 100644 --- a/package.json +++ b/package.json @@ -172,6 +172,7 @@ "@types/use-double-click": "^1.0.1", "@types/webpack-bundle-analyzer": "^4.4.2", "@types/webpack-env": "^1.18.0", + "@types/crypto-js": "^4.2.1", "@typescript-eslint/eslint-plugin": "^5.34.0", "@typescript-eslint/parser": "^5.34.0", "autoprefixer": "^10.4.8", @@ -236,7 +237,6 @@ "@electron/fuses": "^1.6.2", "@node-steam/vdf": "^2.2.0", "@tippyjs/react": "^4.2.6", - "@types/crypto-js": "^4.2.1", "archiver": "^6.0.1", "color": "^4.2.3", "crypto-js": "^4.2.0", diff --git a/release/app/package-lock.json b/release/app/package-lock.json index 2ae5ec12..a784f062 100644 --- a/release/app/package-lock.json +++ b/release/app/package-lock.json @@ -1,12 +1,12 @@ { "name": "bs-manager", - "version": "1.4.1", + "version": "1.4.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "bs-manager", - "version": "1.4.1", + "version": "1.4.2", "hasInstallScript": true, "license": "MIT", "dependencies": { From b97e03041aeec61ad6477d10978c4c2ed40262bd Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Tue, 26 Dec 2023 23:14:43 +0100 Subject: [PATCH 4/4] [chore] reduce code duplication --- .../enter-meta-token-modal.component.tsx | 62 ++++++++++--------- 1 file changed, 33 insertions(+), 29 deletions(-) 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 index f7c8be4f..d18a694c 100644 --- 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 @@ -44,10 +44,6 @@ export const EnterMetaTokenModal: ModalComponent = ({resolver}) => { ); } -const isPasswordValid = (password: string) => { - return password.length >= 8; -} - const EnterPasswordView = ({onValid, onCancel, dontHaveToken}: {onValid: (token: string) => void, onCancel: () => void, dontHaveToken: () => void}) => { const t = useTranslation(); @@ -55,7 +51,6 @@ const EnterPasswordView = ({onValid, onCancel, dontHaveToken}: {onValid: (token: const config = useService(ConfigurationService); const [password, setPassword] = useState(""); - const [showPassword, setShowPassword] = useState(false); const getTokenFromStorage = () => { const cryptedToken = config.get(OCULUS_TOKEN_STORAGE_KEY); @@ -63,7 +58,7 @@ const EnterPasswordView = ({onValid, onCancel, dontHaveToken}: {onValid: (token: const { result: token, error } = tryit(() => crypto.AES.decrypt(cryptedToken, password).toString(crypto.enc.Utf8)); if(error){ - logRenderError(error, "Often indicate that the password is not the same as the one used to save the token."); + logRenderError(error, "Often indicate that the password is not the same as the one used to save the token. This error can occur when the use is writing the password."); } return token; @@ -85,16 +80,7 @@ const EnterPasswordView = ({onValid, onCancel, dontHaveToken}: {onValid: (token:
-
- - {!isPasswordValid(password) && password.length > 0 && ( - {t("modals.enter-meta-token.body.password-too-short")} - )} -
-
- setPassword(e.target.value)} value={password} type={showPassword ? "text" : "password"} name="password" id="password" placeholder={t("modals.enter-meta-token.body.password")} /> - setShowPassword(prev => !prev)} /> -
+ setPassword(v.password)} value={password}/>
@@ -126,7 +112,7 @@ const EnterOculusTokenView = ({onValid, onCancel, alreadyHaveToken}: {onValid: ( const [showToken, setShowToken] = useState(false); const [stay, setStay] = useState(false); const [password, setPassword] = useState(""); - const [showPassword, setShowPassword] = useState(false); + const [passwordValid, setPasswordValid] = useState(false); const storeToken = (token: string, password: string) => { const cryptedToken = crypto.AES.encrypt(token, password).toString(); @@ -170,22 +156,13 @@ const EnterOculusTokenView = ({onValid, onCancel, alreadyHaveToken}: {onValid: (
- {t("modals.enter-meta-token.body.save-my-token")} + {t("modals.enter-meta-token.body.save-my-token")}
-
- - {!isPasswordValid(password) && password.length > 0 && ( - {t("modals.enter-meta-token.body.password-too-short")} - )} -
-
- setPassword(e.target.value)} value={password} type={showPassword ? "text" : "password"} name="password" id="password" placeholder={t("modals.enter-meta-token.body.password")} /> - setShowPassword(prev => !prev)} /> -
+ {setPassword(v.password); setPasswordValid(v.valid)}} value={password}/>
@@ -198,10 +175,37 @@ const EnterOculusTokenView = ({onValid, onCancel, alreadyHaveToken}: {onValid: (
- +
); } + +const PasswordInput = ({onChange, value}: {onChange: (value : {password: string, valid: boolean}) => void, value: string}) => { + + const t = useTranslation(); + + const [showPassword, setShowPassword] = useState(false); + + const isPasswordValid = (password: string) => { + return password.length >= 8; + } + + return ( + <> +
+ + {!isPasswordValid(value) && value.length > 0 && ( + {t("modals.enter-meta-token.body.password-too-short")} + )} +
+
+ onChange({password: e.target.value, valid: isPasswordValid(e.target.value)})} value={value} type={showPassword ? "text" : "password"} name="password" id="password" placeholder={t("modals.enter-meta-token.body.password")} /> + setShowPassword(prev => !prev)} /> +
+ + ) + +}