mirror of
https://github.com/HangarMC/Hangar.git
synced 2025-01-06 13:56:14 +08:00
further improve cookie handling
this is a bit messy but it works soooooo
This commit is contained in:
parent
ed404fc6bf
commit
80d0fde4cb
@ -8,6 +8,7 @@ import { Ref } from "vue";
|
||||
import { authLog, fetchLog } from "~/composables/useLog";
|
||||
import { isEmpty } from "lodash-es";
|
||||
import { useAuth } from "~/composables/useAuth";
|
||||
import { useResponse } from "~/composables/useResReq";
|
||||
|
||||
interface StatCookie {
|
||||
// eslint-disable-next-line camelcase
|
||||
@ -53,7 +54,8 @@ function request<T>(url: string, method: AxiosRequestConfig["method"], data: obj
|
||||
resolve(data);
|
||||
})
|
||||
.catch(async (error: AxiosError) => {
|
||||
authLog("failed", error);
|
||||
const { trace, ...err } = error.response?.data as object;
|
||||
authLog("failed", err);
|
||||
// do we have an expired token?
|
||||
if (error.response?.status === 403) {
|
||||
if (retry) {
|
||||
@ -67,6 +69,10 @@ function request<T>(url: string, method: AxiosRequestConfig["method"], data: obj
|
||||
if (result) {
|
||||
// retry
|
||||
authLog("Retrying request...");
|
||||
if (typeof result === "string") {
|
||||
headers = { ...headers, Authorization: `HangarAuth ${result}` };
|
||||
authLog("using new token");
|
||||
}
|
||||
try {
|
||||
const response = await request<T>(url, method, data, headers, true);
|
||||
return resolve(response);
|
||||
@ -106,10 +112,17 @@ export async function useInternalApi<T>(
|
||||
return processAuthStuff(headers, authed, (headers) => request(`internal/${url}`, method, data, headers));
|
||||
}
|
||||
|
||||
function processAuthStuff<T>(headers: Record<string, string>, authRequired: boolean, handler: (headers: Record<string, string>) => Promise<T>) {
|
||||
export function processAuthStuff<T>(headers: Record<string, string>, authRequired: boolean, handler: (headers: Record<string, string>) => Promise<T>) {
|
||||
if (import.meta.env.SSR) {
|
||||
// forward cookies I guess?
|
||||
const token = useCookies().get("HangarAuth");
|
||||
let token = useCookies().get("HangarAuth");
|
||||
if (!token) {
|
||||
const header = useResponse()?.getHeader("set-cookie") as string[];
|
||||
if (header) {
|
||||
token = new Cookies(header.join("; ")).get("HangarAuth");
|
||||
authLog("found token in set-cookie header");
|
||||
}
|
||||
}
|
||||
if (token) {
|
||||
authLog("forward token from cookie");
|
||||
headers = { ...headers, Authorization: `HangarAuth ${token}` };
|
||||
|
@ -1,11 +1,14 @@
|
||||
import { useAuthStore } from "~/store/auth";
|
||||
import { useCookies } from "~/composables/useCookies";
|
||||
import { useContext } from "vite-ssr";
|
||||
import { useInternalApi } from "~/composables/useApi";
|
||||
import { processAuthStuff, useInternalApi } from "~/composables/useApi";
|
||||
import { useAxios } from "~/composables/useAxios";
|
||||
import { authLog } from "~/composables/useLog";
|
||||
import { HangarUser } from "hangar-internal";
|
||||
import { useRequest } from "~/composables/useResReq";
|
||||
import * as domain from "~/composables/useDomain";
|
||||
import { Pinia } from "pinia";
|
||||
import { AxiosError, AxiosRequestHeaders } from "axios";
|
||||
import { useResponse } from "~/composables/useResReq";
|
||||
import Cookies from "universal-cookie";
|
||||
|
||||
class Auth {
|
||||
loginUrl(redirectUrl: string): string {
|
||||
@ -20,7 +23,7 @@ class Auth {
|
||||
}
|
||||
|
||||
// TODO do we need to scope this to the user?
|
||||
refreshPromise: Promise<boolean> | null = null;
|
||||
refreshPromise: Promise<boolean | string> | null = null;
|
||||
|
||||
async refreshToken() {
|
||||
authLog("refresh token");
|
||||
@ -32,16 +35,40 @@ class Auth {
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
this.refreshPromise = new Promise<boolean>(async (resolve) => {
|
||||
this.refreshPromise = new Promise<boolean | string>(async (resolve) => {
|
||||
try {
|
||||
authLog("do request");
|
||||
await useAxios.get("/refresh");
|
||||
authLog("done");
|
||||
resolve(true);
|
||||
const headers: AxiosRequestHeaders = {};
|
||||
if (import.meta.env.SSR) {
|
||||
headers.cookie = "HangarAuth_REFRESH=" + useCookies().get("HangarAuth_REFRESH");
|
||||
authLog("pass refresh cookie");
|
||||
}
|
||||
const response = await useAxios.get("/refresh", { headers });
|
||||
if (import.meta.env.SSR) {
|
||||
if (response.headers["set-cookie"]) {
|
||||
useResponse()?.setHeader("set-cookie", response.headers["set-cookie"]!);
|
||||
const token = new Cookies(response.headers["set-cookie"]?.join("; ")).get("HangarAuth");
|
||||
if (token) {
|
||||
authLog("got token");
|
||||
resolve(token);
|
||||
} else {
|
||||
authLog("got no token in cookie header", response.headers["set-cookie"]);
|
||||
resolve(false);
|
||||
}
|
||||
} else {
|
||||
authLog("got no cookie header back");
|
||||
resolve(false);
|
||||
}
|
||||
} else {
|
||||
authLog("done");
|
||||
resolve(true);
|
||||
}
|
||||
this.refreshPromise = null;
|
||||
} catch (e) {
|
||||
authLog("Refresh failed", e);
|
||||
const { trace, ...err } = (e as AxiosError).response?.data as object;
|
||||
authLog("Refresh failed", err);
|
||||
resolve(false);
|
||||
this.refreshPromise = null;
|
||||
}
|
||||
});
|
||||
return this.refreshPromise;
|
||||
@ -62,7 +89,7 @@ class Auth {
|
||||
}
|
||||
|
||||
async updateUser(): Promise<void> {
|
||||
const user = await useInternalApi<HangarUser>("users/@me").catch(async (err) => {
|
||||
const user = await useInternalApi<HangarUser>("users/@me", false).catch(async (err) => {
|
||||
authLog("no user");
|
||||
return this.invalidate();
|
||||
});
|
||||
@ -76,7 +103,7 @@ class Auth {
|
||||
}
|
||||
|
||||
usePiniaIfPresent() {
|
||||
return import.meta.env.SSR ? useRequest()?.pinia : null;
|
||||
return import.meta.env.SSR ? domain.get<Pinia>("pinia") : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@ export default viteSSR(App, options, async (ctx) => {
|
||||
const head = createHead();
|
||||
const pinia = createPinia();
|
||||
app.use(pinia).use(head);
|
||||
domain.set("pinia", pinia);
|
||||
|
||||
// install all modules under `modules/`
|
||||
for (const module of Object.values(import.meta.globEager("./modules/*.ts"))) {
|
||||
|
Loading…
Reference in New Issue
Block a user