[feature] add function to get user oculus token + other small changes

This commit is contained in:
MathieuG-P
2023-09-28 20:16:02 +02:00
parent bd7d6b2f2e
commit 8bfe4caa5e
6 changed files with 125 additions and 13 deletions
+4
View File
@@ -20,6 +20,8 @@ import { APP_NAME } from "./constants";
import { BSLauncherService } from "./services/bs-launcher.service";
import { IpcRequest } from "shared/models/ipc";
import { LivShortcut } from "./services/liv/liv-shortcut.service";
import { BsOculusDownloaderService } from "./services/bs-oculus-downloader.service";
import { BSVersion } from "shared/bs-version.interface";
const isDebug = process.env.NODE_ENV === "development" || process.env.DEBUG_PROD === "true";
@@ -58,6 +60,8 @@ const createWindow = async (window: AppWindow = "launcher.html") => {
await installExtensions();
}
WindowManagerService.getInstance().openWindow(window);
BsOculusDownloaderService.getInstance().downloadVersion({} as BSVersion).then(console.log).catch(console.error);
};
const initServicesMustBeInitialized = () => {
@@ -0,0 +1,97 @@
import { BSVersion } from "../../shared/bs-version.interface";
import { WindowManagerService } from "./window-manager.service";
import { minToMs } from "../../shared/helpers/time.helpers";
import log from "electron-log";
export class BsOculusDownloaderService {
private static instance: BsOculusDownloaderService;
public static getInstance(): BsOculusDownloaderService {
if (!BsOculusDownloaderService.instance) {
BsOculusDownloaderService.instance = new BsOculusDownloaderService();
}
return BsOculusDownloaderService.instance;
}
private readonly windows: WindowManagerService;
private constructor() {
this.windows = WindowManagerService.getInstance();
}
private isUserTokenValid(token: string): boolean{
// Code take 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[0-9]{15}/)){
log.info("Token matches /OC[0-9}{15}/ which usually indicates a changed oculus store token");
return false;
}
return true;
}
public async getUserToken(): Promise<string>{
const redirectUrl = "https://developer.oculus.com/manage/";
const loginUrl = `https://auth.oculus.com/login/?redirect_uri=${encodeURIComponent(redirectUrl)}`;
const window = await this.windows.openWindow(loginUrl, { frame: true });
let timout: NodeJS.Timeout;
const promise = new Promise<string>((resolve, reject) => {
timout = setTimeout(() => {
reject(new Error("Trying to get Oculus user token timed out"));
window.close();
}, minToMs(5));
window.webContents.on("did-navigate", async (_, url) => {
if(!url.startsWith(redirectUrl)){ return; }
const token = (await window.webContents.session.cookies.get({ name: "oc_www_at" })).at(0)?.value;
if(!this.isUserTokenValid(token)){
return;
}
resolve(token);
});
window.on("closed", () => {
reject(new Error("Oculus login window closed by user"));
});
}).finally(() => {
if(!window.isDestroyed() && window.isClosable()){
window.close();
}
clearTimeout(timout);
});
return promise;
}
public downloadVersion(version: BSVersion){
return this.getUserToken();
}
}
+18 -11
View File
@@ -1,4 +1,4 @@
import { app, BrowserWindow, BrowserWindowConstructorOptions, shell } from "electron";
import { app, BrowserWindow, BrowserWindowConstructorOptions, shell, WebContents } from "electron";
import { resolveHtmlPath } from "../util";
import { UtilsService } from "./utils.service";
import { AppWindow } from "shared/models/window-manager/app-window.model";
@@ -10,6 +10,7 @@ export class WindowManagerService {
private static instance: WindowManagerService;
private readonly PRELOAD_PATH = app.isPackaged ? path.join(__dirname, "preload.js") : path.join(__dirname, "../../../.erb/dll/preload.js");
private readonly IS_DEBUG = process.env.NODE_ENV === "development" || process.env.DEBUG_PROD === "true"
private readonly utilsService: UtilsService = UtilsService.getInstance();
@@ -28,10 +29,10 @@ export class WindowManagerService {
show: false,
frame: false,
titleBarOverlay: false,
webPreferences: { preload: this.PRELOAD_PATH, webSecurity: false },
webPreferences: { preload: this.PRELOAD_PATH, webSecurity: !this.IS_DEBUG },
};
private readonly windows: Map<AppWindow, BrowserWindow> = new Map<AppWindow, BrowserWindow>();
private readonly windows = new Map<string, BrowserWindow>();
public static getInstance(): WindowManagerService {
if (!WindowManagerService.instance) {
@@ -42,8 +43,7 @@ export class WindowManagerService {
private constructor() {}
public openWindow(windowType: AppWindow, options?: BrowserWindowConstructorOptions): Promise<BrowserWindow> {
const window = new BrowserWindow({ ...this.appWindowsOptions[windowType], ...this.baseWindowOption, ...options });
private handleNewWindow(url: AppWindow, window: BrowserWindow){
window.webContents.setWindowOpenHandler(({ url }) => {
if(isValidUrl(url)){
@@ -51,12 +51,13 @@ export class WindowManagerService {
}
return { action: "deny"}
})
});
const promise = window.loadURL(resolveHtmlPath(windowType));
window.removeMenu();
window.setMenu(null);
const promise = window.loadURL(isValidUrl(url) ? url : resolveHtmlPath(url));
window.once("ready-to-show", () => {
if (!window) {
throw new Error('"window" is not defined');
@@ -65,18 +66,24 @@ export class WindowManagerService {
});
window.once("closed", () => {
this.windows.delete(windowType);
this.windows.delete(url);
if (!this.windows.size) {
app.quit();
}
});
this.windows.set(windowType, window);
this.utilsService.setMainWindows(this.windows);
this.windows.set(url, window);
this.utilsService.setMainWindows(this.windows as Map<AppWindow, BrowserWindow>); // TODO : remove
return promise.then(() => window);
}
public openWindow(windowType: AppWindow, options?: BrowserWindowConstructorOptions): Promise<BrowserWindow> {
const window = new BrowserWindow({ ...(this.appWindowsOptions[windowType] ?? {}), ...this.baseWindowOption, ...options });
return this.handleNewWindow(windowType, window);
}
public closeAllWindows(except?: AppWindow) {
this.windows.forEach((window, key) => {
if (key === except) {
@@ -96,7 +103,7 @@ export class WindowManagerService {
return this.windows.get(window);
}
public getAppWindowFromWebContents(sender: Electron.WebContents): AppWindow {
public getAppWindowFromWebContents(sender: WebContents): AppWindow {
return Array.from(this.windows.entries()).find(([, value]) => value.webContents.id === sender.id)[0];
}
@@ -4,7 +4,7 @@ import { MutableRefObject, useEffect, useRef, useState } from "react";
import { MAP_TYPES } from "renderer/partials/maps/map-tags/map-types";
import { MAP_STYLES } from "renderer/partials/maps/map-tags/map-styles";
import { BsmCheckbox } from "../shared/bsm-checkbox.component";
import { minToS } from "renderer/helpers/time-utils";
import { minToS } from "shared/helpers/time.helpers";
import dateFormat from "dateformat";
import { BsmRange } from "../shared/bsm-range.component";
import { useTranslation } from "renderer/hooks/use-translation.hook";
@@ -5,6 +5,10 @@ export function minToS(minutes: number): number {
return minutes * SECONDS_IN_MINUTE;
}
export function minToMs(minutes: number): number {
return minToS(minutes) * 1000;
}
export function hourToMin(hours: number): number {
return hours * MINUTES_IN_HOUR;
}
@@ -1 +1 @@
export type AppWindow = "index.html" | "launcher.html" | "oneclick-download-map.html" | "oneclick-download-playlist.html" | "oneclick-download-model.html" | "shortcut-launch.html";
export type AppWindow = "index.html" | "launcher.html" | "oneclick-download-map.html" | "oneclick-download-playlist.html" | "oneclick-download-model.html" | "shortcut-launch.html" | string;