mirror of
https://github.com/Zagrios/bs-manager.git
synced 2026-07-03 14:08:25 +02:00
[feature] add the possibility to enter oculus token manually
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -159,6 +159,7 @@ export interface DownloadInfo {
|
||||
bsVersion: BSVersion;
|
||||
isVerification?: boolean;
|
||||
stay?: boolean;
|
||||
token?: string;
|
||||
}
|
||||
|
||||
export interface DownloadSteamInfo extends DownloadInfo {
|
||||
|
||||
+59
@@ -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<string> = ({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 (
|
||||
<form className="flex flex-col w-80 gap-4">
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">{t("modals.enter-meta-token.title")}</h1>
|
||||
|
||||
<BsmImage className="h-20 w-20 mx-auto" image={BeatWaiting}/>
|
||||
|
||||
<p>{t("modals.enter-meta-token.body.need-token")}</p>
|
||||
|
||||
<a href="https://github.com/Zagrios/bs-manager/wiki/How-to-obtain-your-Oculus-Token" target="_blank" className="underline">{t("modals.enter-meta-token.body.how-obtain-token")}</a>
|
||||
|
||||
<div>
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<label className="font-bold cursor-pointer tracking-wide inline-block" htmlFor="meta_token">{t("modals.enter-meta-token.body.input-label")}</label>
|
||||
{!isTokenValid && token.length > 0 && (
|
||||
<span className="text-orange-700 dark:text-orange-400 text-xs whitespace-normal min-w-0">{t("modals.enter-meta-token.body.token-is-invalid")}</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="bg-light-main-color-1 dark:bg-main-color-1 rounded-md flex box-border h-9">
|
||||
<input className="grow px-1 py-[2px] outline-none bg-transparent" onChange={e => setToken(e.target.value)} value={token} type={showToken ? "text" : "password"} name="meta_token" id="meta_token" placeholder="OCAStr43sdx2..." />
|
||||
<BsmButton className="shrink-0 m-1 rounded-md p-0.5 !bg-light-main-color-3 dark:!bg-main-color-3" icon={showToken ? "eye-cross" : "eye"} withBar={false} onClick={() => setShowToken(prev => !prev)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row gap-2">
|
||||
<BsmButton className="rounded-md flex justify-center items-center transition-all h-9 w-full" typeColor="cancel" text="misc.cancel" withBar={false} onClick={cancel}/>
|
||||
<BsmButton className="rounded-md flex justify-center items-center transition-all h-9 w-full" typeColor="primary" text="modals.enter-meta-token.valid-btn" withBar={false} onClick={submit} disabled={!isTokenValid}/>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
);
|
||||
}
|
||||
+19
-2
@@ -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<boolean> = ({ resolver }) => {
|
||||
type ReturnType = { method: MetaAuthMethod.META, stay: boolean } | { method: MetaAuthMethod.MANUAL };
|
||||
|
||||
export const LoginToMetaModal: ModalComponent<ReturnType> = ({ 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 (
|
||||
<form className="flex flex-col justify-center items-center w-96 gap-4">
|
||||
<h1 className="text-3xl uppercase tracking-wide w-full text-center">{t("modals.connect-to-meta.title")}</h1>
|
||||
@@ -32,6 +39,16 @@ export const LoginToMetaModal: ModalComponent<boolean> = ({ resolver }) => {
|
||||
</div>
|
||||
|
||||
<BsmButton className="rounded-md flex justify-center items-center transition-all h-10 w-full" typeColor="primary" text="modals.connect-to-meta.connect-to-meta" withBar={false} onClick={submit}/>
|
||||
|
||||
<Tippy className="!bg-neutral-900" arrow={false} content={t("modals.connect-to-meta.body.enter-token-manually-tooltip")} >
|
||||
<p className="text-sm italic underline text-center -translate-y-1 leading-3 cursor-pointer" onClick={enterTokenManually}>{t("modals.connect-to-meta.body.enter-token-manually")}</p>
|
||||
</Tippy>
|
||||
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export enum MetaAuthMethod {
|
||||
MANUAL = "manual",
|
||||
META = "meta"
|
||||
}
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user