mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-21 10:03:56 +00:00
feat: handle login from deeplink
This commit is contained in:
17
src/main/events/auth/signout.ts
Normal file
17
src/main/events/auth/signout.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { userAuthRepository } from "@main/repository";
|
||||
import { registerEvent } from "../register-event";
|
||||
import { HydraApi } from "@main/services/hydra-api";
|
||||
import { WindowManager } from "@main/services";
|
||||
|
||||
const signout = async (_event: Electron.IpcMainInvokeEvent): Promise<void> => {
|
||||
await Promise.all([
|
||||
userAuthRepository.delete({ id: 1 }),
|
||||
HydraApi.post("/auth/logout"),
|
||||
]).finally(() => {
|
||||
if (WindowManager.mainWindow) {
|
||||
WindowManager.mainWindow.webContents.send("on-signout");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
registerEvent("signout", signout);
|
||||
@@ -40,7 +40,8 @@ import "./download-sources/validate-download-source";
|
||||
import "./download-sources/add-download-source";
|
||||
import "./download-sources/remove-download-source";
|
||||
import "./download-sources/sync-download-sources";
|
||||
import "./profile/get-user-profile";
|
||||
import "./auth/signout";
|
||||
import "./user/get-user";
|
||||
import "./profile/get-me";
|
||||
|
||||
ipcMain.handle("ping", () => "pong");
|
||||
|
||||
@@ -5,7 +5,7 @@ import { UserProfile } from "@types";
|
||||
import { convertSteamGameToCatalogueEntry } from "../helpers/search-games";
|
||||
import { getSteamAppAsset } from "@main/helpers";
|
||||
|
||||
const getUserProfile = async (
|
||||
const getUser = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
username: string
|
||||
): Promise<UserProfile | null> => {
|
||||
@@ -53,4 +53,4 @@ const getUserProfile = async (
|
||||
}
|
||||
};
|
||||
|
||||
registerEvent("getUserProfile", getUserProfile);
|
||||
registerEvent("getUser", getUser);
|
||||
@@ -7,6 +7,7 @@ import { DownloadManager, logger, WindowManager } from "@main/services";
|
||||
import { dataSource } from "@main/data-source";
|
||||
import * as resources from "@locales";
|
||||
import { userPreferencesRepository } from "@main/repository";
|
||||
import { HydraApi } from "./services/hydra-api";
|
||||
|
||||
const { autoUpdater } = updater;
|
||||
|
||||
@@ -71,7 +72,7 @@ app.on("browser-window-created", (_, window) => {
|
||||
optimizer.watchWindowShortcuts(window);
|
||||
});
|
||||
|
||||
app.on("second-instance", (_event, commandLine) => {
|
||||
app.on("second-instance", async (_event, commandLine) => {
|
||||
// Someone tried to run a second instance, we should focus our window.
|
||||
if (WindowManager.mainWindow) {
|
||||
if (WindowManager.mainWindow.isMinimized())
|
||||
@@ -83,7 +84,14 @@ app.on("second-instance", (_event, commandLine) => {
|
||||
}
|
||||
|
||||
const [, path] = commandLine.pop()?.split("://") ?? [];
|
||||
if (path) WindowManager.redirect(path);
|
||||
if (path) {
|
||||
if (path.startsWith("auth")) {
|
||||
//hydralauncher://auth?payload=responsedaapiembase64
|
||||
await HydraApi.handleExternalAuth(path.split("=")[1]);
|
||||
} else {
|
||||
WindowManager.redirect(path);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.on("open-url", (_event, url) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { userAuthRepository } from "@main/repository";
|
||||
import axios, { AxiosError, AxiosInstance } from "axios";
|
||||
import { WindowManager } from "./window-manager";
|
||||
|
||||
export class HydraApi {
|
||||
private static instance: AxiosInstance;
|
||||
@@ -16,6 +17,38 @@ export class HydraApi {
|
||||
return this.userAuth.authToken !== "";
|
||||
}
|
||||
|
||||
static async handleExternalAuth(auth: string) {
|
||||
const decodedBase64 = atob(auth);
|
||||
const jsonData = JSON.parse(decodedBase64);
|
||||
|
||||
const { accessToken, expiresIn, refreshToken } = jsonData;
|
||||
|
||||
const now = new Date();
|
||||
|
||||
const tokenExpirationTimestamp =
|
||||
now.getTime() + expiresIn - this.EXPIRATION_OFFSET_IN_MS;
|
||||
|
||||
this.userAuth = {
|
||||
authToken: accessToken,
|
||||
refreshToken: refreshToken,
|
||||
expirationTimestamp: tokenExpirationTimestamp,
|
||||
};
|
||||
|
||||
await userAuthRepository.upsert(
|
||||
{
|
||||
id: 1,
|
||||
accessToken,
|
||||
tokenExpirationTimestamp,
|
||||
refreshToken,
|
||||
},
|
||||
["id"]
|
||||
);
|
||||
|
||||
if (WindowManager.mainWindow) {
|
||||
WindowManager.mainWindow.webContents.send("on-signin");
|
||||
}
|
||||
}
|
||||
|
||||
static async setupApi() {
|
||||
this.instance = axios.create({
|
||||
baseURL: import.meta.env.MAIN_VITE_API_URL,
|
||||
@@ -33,6 +66,8 @@ export class HydraApi {
|
||||
}
|
||||
|
||||
private static async revalidateAccessTokenIfExpired() {
|
||||
if (!this.userAuth.authToken) throw new Error("user is not logged in");
|
||||
|
||||
const now = new Date();
|
||||
if (this.userAuth.expirationTimestamp < now.getTime()) {
|
||||
try {
|
||||
@@ -64,15 +99,11 @@ export class HydraApi {
|
||||
this.userAuth.authToken = "";
|
||||
this.userAuth.expirationTimestamp = 0;
|
||||
|
||||
userAuthRepository.upsert(
|
||||
{
|
||||
id: 1,
|
||||
accessToken: "",
|
||||
refreshToken: "",
|
||||
tokenExpirationTimestamp: 0,
|
||||
},
|
||||
["id"]
|
||||
);
|
||||
if (WindowManager.mainWindow) {
|
||||
WindowManager.mainWindow.webContents.send("on-signout");
|
||||
}
|
||||
|
||||
userAuthRepository.delete({ id: 1 });
|
||||
}
|
||||
|
||||
throw err;
|
||||
|
||||
Reference in New Issue
Block a user