Skip to content

Commit

Permalink
Merge pull request #716 from Zagrios/chore/reimplement-login-with-meta
Browse files Browse the repository at this point in the history
[chore] reimplement login with meta
  • Loading branch information
Zagrios authored Dec 26, 2024
2 parents 8eec1fe + cda8a8a commit b0b52f4
Show file tree
Hide file tree
Showing 18 changed files with 187 additions and 75 deletions.
4 changes: 2 additions & 2 deletions assets/jsons/translations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@
"UNABLE_TO_GET_MANIFEST": "Unmöglich, das für den Download erforderliche Manifest zu erhalten.",
"VERIFY_INTEGRITY_FAILED": "Beim Überprüfen der Dateien ist ein Fehler aufgetreten.",
"SOME_FILES_FAILED_TO_DOWNLOAD": "Einige Dateien konnten nicht heruntergeladen werden.",
"OCULUS_LOGIN_TIMED_OUT": "Es hat zu lange gedauert, das Anmelde-Token abzurufen.",
"OCULUS_LOGIN_WINDOW_CLOSED_BY_USER": "Das Meta-Anmeldefenster wurde geschlossen.",
"META_LOGIN_TIMED_OUT": "Es hat zu lange gedauert, das Anmelde-Token abzurufen.",
"META_LOGIN_WINDOW_CLOSED_BY_USER": "Das Meta-Anmeldefenster wurde geschlossen.",
"NO_META_AUTH_TOKEN": "Unmöglich, das für den Download erforderliche Meta-Anmelde-Token zu erhalten.",
"UNKNOWN_ERROR": "Ein unbekannter Fehler ist aufgetreten."
}
Expand Down
4 changes: 2 additions & 2 deletions assets/jsons/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@
"UNABLE_TO_GET_MANIFEST": "Unable to obtain the manifest required for download.",
"VERIFY_INTEGRITY_FAILED": "An error occurred during file verification.",
"SOME_FILES_FAILED_TO_DOWNLOAD": "Some files failed to download.",
"OCULUS_LOGIN_TIMED_OUT": "The login token took too long to retrieve.",
"OCULUS_LOGIN_WINDOW_CLOSED_BY_USER": "The Meta login window was closed.",
"META_LOGIN_TIMED_OUT": "The login token took too long to retrieve.",
"META_LOGIN_WINDOW_CLOSED_BY_USER": "The Meta login window was closed.",
"NO_META_AUTH_TOKEN": "Unable to retrieve the Meta login token required for download.",
"UNKNOWN_ERROR": "An unknown error occurred."
}
Expand Down
4 changes: 2 additions & 2 deletions assets/jsons/translations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@
"UNABLE_TO_GET_MANIFEST": "Imposible obtener el manifiesto necesario para la descarga.",
"VERIFY_INTEGRITY_FAILED": "Se produjo un error durante la verificación de archivos.",
"SOME_FILES_FAILED_TO_DOWNLOAD": "Algunos archivos no pudieron ser descargados.",
"OCULUS_LOGIN_TIMED_OUT": "El token de inicio de sesión tardó demasiado en recuperarse.",
"OCULUS_LOGIN_WINDOW_CLOSED_BY_USER": "La ventana de inicio de sesión de Meta fue cerrada.",
"META_LOGIN_TIMED_OUT": "El token de inicio de sesión tardó demasiado en recuperarse.",
"META_LOGIN_WINDOW_CLOSED_BY_USER": "La ventana de inicio de sesión de Meta fue cerrada.",
"NO_META_AUTH_TOKEN": "Imposible recuperar el token de inicio de sesión de Meta necesario para la descarga.",
"UNKNOWN_ERROR": "Se produjo un error desconocido."
}
Expand Down
4 changes: 2 additions & 2 deletions assets/jsons/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@
"UNABLE_TO_GET_MANIFEST": "Impossible d'obtenir le manifest nécessaire au téléchargement.",
"VERIFY_INTEGRITY_FAILED": "Une erreur c'est produite lors de la vérification des fichiers.",
"SOME_FILES_FAILED_TO_DOWNLOAD": "Certains fichiers n'ont pas pu être téléchargés.",
"OCULUS_LOGIN_TIMED_OUT": "Le Token de connexion à mis trop de temps à être récupéré.",
"OCULUS_LOGIN_WINDOW_CLOSED_BY_USER": "La fenêtre de connexion à Meta a été fermée.",
"META_LOGIN_TIMED_OUT": "Le Token de connexion à mis trop de temps à être récupéré.",
"META_LOGIN_WINDOW_CLOSED_BY_USER": "La fenêtre de connexion à Meta a été fermée.",
"NO_META_AUTH_TOKEN": "Impossible de récupérer le token de connexion à Meta nécessaire au téléchargement.",
"UNKNOWN_ERROR": "Une erreur inconnue s'est produite."
}
Expand Down
4 changes: 2 additions & 2 deletions assets/jsons/translations/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@
"UNABLE_TO_GET_MANIFEST": "ダウンロードに必要なマニフェストを取得できません。",
"VERIFY_INTEGRITY_FAILED": "ファイルの検証中にエラーが発生しました。",
"SOME_FILES_FAILED_TO_DOWNLOAD": "一部のファイルのダウンロードに失敗しました。",
"OCULUS_LOGIN_TIMED_OUT": "ログイントークンの取得に時間がかかりすぎました。",
"OCULUS_LOGIN_WINDOW_CLOSED_BY_USER": "メタ・ログイン・ウィンドウが閉じられた。",
"META_LOGIN_TIMED_OUT": "ログイントークンの取得に時間がかかりすぎました。",
"META_LOGIN_WINDOW_CLOSED_BY_USER": "メタ・ログイン・ウィンドウが閉じられた。",
"NO_META_AUTH_TOKEN": "ダウンロードに必要な Meta ログイン トークンを取得できません。",
"UNKNOWN_ERROR": "不明なエラーが発生しました。"
}
Expand Down
4 changes: 2 additions & 2 deletions assets/jsons/translations/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@
"UNABLE_TO_GET_MANIFEST": "다운로드에 필요한 매니페스트를 가져올 수 없습니다.",
"VERIFY_INTEGRITY_FAILED": "파일 검증 중 오류가 발생했습니다.",
"SOME_FILES_FAILED_TO_DOWNLOAD": "일부 파일을 다운로드하지 못했습니다.",
"OCULUS_LOGIN_TIMED_OUT": "로그인 토큰을 얻는 데 시간이 너무 오래 걸렸습니다.",
"OCULUS_LOGIN_WINDOW_CLOSED_BY_USER": "Meta 로그인 창이 닫혔습니다.",
"META_LOGIN_TIMED_OUT": "로그인 토큰을 얻는 데 시간이 너무 오래 걸렸습니다.",
"META_LOGIN_WINDOW_CLOSED_BY_USER": "Meta 로그인 창이 닫혔습니다.",
"NO_META_AUTH_TOKEN": "다운로드에 필요한 Meta 로그인 토큰을 얻을 수 없습니다.",
"UNKNOWN_ERROR": "알 수 없는 오류가 발생했습니다."
}
Expand Down
4 changes: 2 additions & 2 deletions assets/jsons/translations/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@
"UNABLE_TO_GET_MANIFEST": "Невозможно получить манифест, необходимый для загрузки.",
"VERIFY_INTEGRITY_FAILED": "При проверке файлов произошла ошибка.",
"SOME_FILES_FAILED_TO_DOWNLOAD": "Некоторые файлы не удалось загрузить.",
"OCULUS_LOGIN_TIMED_OUT": "Получение токена входа заняло слишком много времени.",
"OCULUS_LOGIN_WINDOW_CLOSED_BY_USER": "Окно входа в Meta было закрыто.",
"META_LOGIN_TIMED_OUT": "Получение токена входа заняло слишком много времени.",
"META_LOGIN_WINDOW_CLOSED_BY_USER": "Окно входа в Meta было закрыто.",
"NO_META_AUTH_TOKEN": "Невозможно получить токен входа в Meta, необходимый для загрузки.",
"UNKNOWN_ERROR": "Произошла неизвестная ошибка."
}
Expand Down
4 changes: 2 additions & 2 deletions assets/jsons/translations/zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@
"UNABLE_TO_GET_MANIFEST": "無法獲取下載所需的清單。",
"VERIFY_INTEGRITY_FAILED": "文件驗證過程中發生錯誤。",
"SOME_FILES_FAILED_TO_DOWNLOAD": "一些文件下載失敗。",
"OCULUS_LOGIN_TIMED_OUT": "獲取登錄令牌用時過長。",
"OCULUS_LOGIN_WINDOW_CLOSED_BY_USER": "Meta 登錄窗口被關閉。",
"META_LOGIN_TIMED_OUT": "獲取登錄令牌用時過長。",
"META_LOGIN_WINDOW_CLOSED_BY_USER": "Meta 登錄窗口被關閉。",
"NO_META_AUTH_TOKEN": "無法獲取下載所需的 Meta 登錄令牌。",
"UNKNOWN_ERROR": "發生未知錯誤。"
}
Expand Down
4 changes: 2 additions & 2 deletions assets/jsons/translations/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@
"UNABLE_TO_GET_MANIFEST": "无法获取下载所需的清单。",
"VERIFY_INTEGRITY_FAILED": "文件验证过程中发生错误。",
"SOME_FILES_FAILED_TO_DOWNLOAD": "一些文件下载失败。",
"OCULUS_LOGIN_TIMED_OUT": "获取登录令牌用时过长。",
"OCULUS_LOGIN_WINDOW_CLOSED_BY_USER": "Meta 登录窗口被关闭。",
"META_LOGIN_TIMED_OUT": "获取登录令牌用时过长。",
"META_LOGIN_WINDOW_CLOSED_BY_USER": "Meta 登录窗口被关闭。",
"NO_META_AUTH_TOKEN": "无法获取下载所需的 Meta 登录令牌。",
"UNKNOWN_ERROR": "发生未知错误。"
}
Expand Down
21 changes: 18 additions & 3 deletions src/main/ipcs/bs-version-download/bs-download-ipcs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BsOculusDownloaderService } from "../../services/bs-version-download/bs-oculus-downloader.service";
import { BsSteamDownloaderService } from "../../services/bs-version-download/bs-steam-downloader.service";
import { IpcService } from "../../services/ipc.service";
import { of } from "rxjs";
import { from, of } from "rxjs";
import { BSLocalVersionService } from "../../services/bs-local-version.service";

const ipc = IpcService.getInstance();
Expand Down Expand Up @@ -42,14 +42,29 @@ ipc.on("send-input-bs-download", (args, reply) => {

// #region Oculus

ipc.on("bs-oculus-download", async (args, reply) => {
ipc.on("bs-oculus-download", (args, reply) => {
const oculusDownloader = BsOculusDownloaderService.getInstance();
reply(oculusDownloader.downloadVersion(args));
});

ipc.on("bs-oculus-stop-download", async (_, reply) => {
ipc.on("bs-oculus-stop-download", (_, reply) => {
const oculusDownloader = BsOculusDownloaderService.getInstance();
reply(of(oculusDownloader.stopDownload()));
});

ipc.on("login-with-meta", (stay, reply) => {
const oculusDownloader = BsOculusDownloaderService.getInstance();
reply(from(oculusDownloader.getUserTokenFromMetaAuth(stay)));
});

ipc.on("delete-meta-session", (_, reply) => {
const oculusDownloader = BsOculusDownloaderService.getInstance();
reply(from(oculusDownloader.clearAuthToken()));
});

ipc.on("meta-session-exists", (_, reply) => {
const oculusDownloader = BsOculusDownloaderService.getInstance();
reply(from(oculusDownloader.metaSessionExists()));
});

// #endregion
8 changes: 8 additions & 0 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,11 @@ function deleteOlestLogs(): void{
}
});
}

export function addFilterStringLog(filter: string): void {
filterStrings.add(filter);
}

export function addFilterPatternLog(filter: RegExp): void {
filterPatterns.add(filter);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ 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";
import { CustomError } from "shared/models/exceptions/custom-error.class";
import { minToMs } from "shared/helpers/time.helpers";
import { session } from "electron";
import { WindowManagerService } from "../window-manager.service";
import { addFilterStringLog } from "../../main";
import { MetaAuthErrorCodes } from "shared/models/bs-version-download/oculus-download.model";

export class BsOculusDownloaderService {

Expand All @@ -23,13 +29,63 @@ export class BsOculusDownloaderService {

private readonly oculusDownloader: OculusDownloader;
private readonly versions: BSLocalVersionService;
private readonly windows: WindowManagerService;

private constructor() {
this.versions = BSLocalVersionService.getInstance();

this.windows = WindowManagerService.getInstance();
this.oculusDownloader = new OculusDownloader();
}

public async getUserTokenFromMetaAuth(keepToken: boolean): Promise<string>{

const loginUrl = "https://secure.oculus.com";
const redirectUrl = `${loginUrl}/my/profile`;
const window = await this.windows.openWindow(loginUrl, { frame: true, width: 650, height: 800 });

let timout: NodeJS.Timeout;

return new Promise<string>((resolve, reject) => {
timout = setTimeout(() => {
reject(new CustomError("Trying to get Oculus user token timed out", MetaAuthErrorCodes.META_LOGIN_TIMED_OUT));
window.close();
}, minToMs(10));

const tryExtractToken = async () => {
log.info("Meta auth window navigated to", new URL(window.webContents.getURL()).origin + new URL(window.webContents.getURL()).pathname); // Dot not log full url for privacy reasons
if(!window.webContents.getURL()?.startsWith(redirectUrl)){ return; }

const token = (await window.webContents.session.cookies.get({ name: "oc_ac_at" })).at(0)?.value;

if(!isOculusTokenValid(token, log.info)){
return;
}

addFilterStringLog(token);
resolve(token);
}

window.webContents.on("did-stop-loading", tryExtractToken);
window.webContents.on("did-navigate", tryExtractToken);
window.webContents.on("did-navigate-in-page", tryExtractToken);

window.on("closed", () => {
reject(new CustomError("Oculus login window closed by user", MetaAuthErrorCodes.META_LOGIN_WINDOW_CLOSED_BY_USER));
});
}).finally(() => {

clearTimeout(timout);

if(!keepToken){
this.clearAuthToken();
}

if(!window.isDestroyed() && window.isClosable()){
window.close();
}
});
}

private async createDownloadVersion(version: BSVersion): Promise<{version: BSVersion, dest: string}>{
const dest = await ensurePathNotAlreadyExist(await this.versions.getVersionPath(version));
return {
Expand All @@ -46,7 +102,7 @@ export class BsOculusDownloaderService {
this.oculusDownloader.stopDownload();
}

public downloadVersion(downloadInfo: DownloadInfo): Observable<Progression<BSVersion>>{
public downloadVersion(downloadInfo: OculusDownloadInfo): Observable<Progression<BSVersion>>{

let downloadVersion: BSVersion

Expand All @@ -69,9 +125,16 @@ export class BsOculusDownloaderService {
);
}

public clearAuthToken(): Promise<void>{
return session.defaultSession.clearStorageData({ storages: ["cookies"], origin: ".oculus.com" })
}

public metaSessionExists(): Promise<boolean>{
return session.defaultSession.cookies.get({ domain: ".oculus.com" }).then(cookies => cookies.length > 0);
}

}

export interface OculusDownloadInfo {
version: BSVersion;
stay?: boolean;
export interface OculusDownloadInfo extends DownloadInfo {
token: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,6 @@ export interface DownloadInfo {
bsVersion: BSVersion;
isVerification?: boolean;
stay?: boolean;
token?: string;
}

export interface DownloadSteamInfo extends DownloadInfo {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,52 @@
import { ModalComponent, ModalExitCode } from "../../../../services/modale.service";
import { useState } from "react";
import { ModalComponent, ModalExitCode, ModalService } from "../../../../services/modale.service";
import { MouseEventHandler, useState } from "react";
import { BsmButton } from "renderer/components/shared/bsm-button.component";
import { useTranslation } from "renderer/hooks/use-translation.hook";
import { useTranslationV2 } 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";
import { useService } from "renderer/hooks/use-service.hook";
import { IpcService } from "renderer/services/ipc.service";
import { lastValueFrom } from "rxjs";
import { EnterMetaTokenModal } from "./enter-meta-token-modal.component";
import { CustomError } from "shared/models/exceptions/custom-error.class";
import { MetaAuthErrorCodes } from "shared/models/bs-version-download/oculus-download.model";
import { NotificationService } from "renderer/services/notification.service";

type ReturnType = { method: MetaAuthMethod.META, stay: boolean } | { method: MetaAuthMethod.MANUAL };
export const LoginToMetaModal: ModalComponent<string> = ({ resolver }) => {

export const LoginToMetaModal: ModalComponent<ReturnType> = ({ resolver }) => {
const { text: t } = useTranslationV2();

const t = useTranslation();
const ipc = useService(IpcService);
const modal = useService(ModalService);
const notifications = useService(NotificationService);

const [stay, setStay] = useState(false);
const [stay, setStay] = useState(true);
const [authWindowOpen, setAuthWindowOpen] = useState(false);

const submit = () => {
resolver({ exitCode: ModalExitCode.COMPLETED, data: { method: MetaAuthMethod.META, stay } });
};
const handleLoginWithMeta = () => {
setAuthWindowOpen(() => true);
lastValueFrom(ipc.sendV2("login-with-meta", stay)).then(token => {
resolver({ exitCode: ModalExitCode.COMPLETED, data: token });
}).catch((e: CustomError) => {
if(e.code === MetaAuthErrorCodes.META_LOGIN_WINDOW_CLOSED_BY_USER){
return;
}

const enterTokenManually = () => {
resolver({ exitCode: ModalExitCode.COMPLETED, data: { method: MetaAuthMethod.MANUAL } });
if(e.code){
notifications.notifyError({title: "notifications.types.error", desc: `notifications.bs-download.oculus-download.errors.msg.${e.code}`});
}

resolver({ exitCode: ModalExitCode.CANCELED });
}).finally(() => {
setAuthWindowOpen(() => false);
})
}

const handleEnterTokenManually: MouseEventHandler<HTMLButtonElement> = async (e) => {
e.preventDefault();
const res = await modal.openModal(EnterMetaTokenModal);
resolver(res);
}

return (
Expand All @@ -38,17 +65,12 @@ export const LoginToMetaModal: ModalComponent<ReturnType> = ({ resolver }) => {
<span>{t("modals.connect-to-meta.stay")}</span>
</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}/>
<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={handleLoginWithMeta} disabled={authWindowOpen}/>

<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>
<button className="text-sm italic underline text-center -translate-y-1 leading-3 cursor-pointer" onClick={handleEnterTokenManually}>{t("modals.connect-to-meta.body.enter-token-manually")}</button>
</Tippy>

</form>
);
};

export enum MetaAuthMethod {
MANUAL = "manual",
META = "meta"
}
Loading

0 comments on commit b0b52f4

Please sign in to comment.