Refresh token to check if user was verifed after a 403

This commit is contained in:
Zoe Roux 2024-03-10 17:54:43 +01:00
parent 5f936d36b1
commit 8ee4446b30
2 changed files with 27 additions and 11 deletions

View File

@ -20,7 +20,7 @@
import { queryFn } from "./query";
import { KyooErrors } from "./kyoo-errors";
import { Account, TokenP, getCurrentApiUrl } from "./accounts";
import { Account, Token, TokenP, getCurrentApiUrl } from "./accounts";
import { UserP } from "./resources";
import { addAccount, getCurrentAccount, removeAccounts, updateAccount } from "./account-internal";
import { Platform } from "react-native";
@ -88,16 +88,21 @@ export const oidcLogin = async (provider: string, code: string, apiUrl?: string)
}
};
let running_id: string | null = null;
let running: ReturnType<typeof getTokenWJ> | null = null;
export const getTokenWJ = async (account?: Account | null): ReturnType<typeof run> => {
async function run() {
if (account === undefined) account = getCurrentAccount();
if (!account) return [null, null, null] as const;
export const getTokenWJ = async (
acc?: Account | null,
forceRefresh: boolean = false,
): Promise<readonly [string, Token, null] | readonly [null, null, KyooErrors | null]> => {
if (acc === undefined) acc = getCurrentAccount();
if (!acc) return [null, null, null] as const;
const account = acc;
async function run() {
let token = account.token;
if (account.token.expire_at <= new Date(new Date().getTime() + 10 * 1000)) {
if (forceRefresh || account.token.expire_at <= new Date(new Date().getTime() + 10 * 1000)) {
console.log("refreshing token for account", account.slug);
try {
token = await queryFn(
@ -121,9 +126,11 @@ export const getTokenWJ = async (account?: Account | null): ReturnType<typeof ru
// Do not cache promise durring ssr.
if (Platform.OS === "web" && typeof window === "undefined") return await run();
if (running) return await running;
if (running && running_id === account.id) return await running;
running_id = account.id;
running = run();
const ret = await running;
running_id = null;
running = null;
return ret;
};

View File

@ -28,7 +28,7 @@ import {
import { z } from "zod";
import { KyooErrors } from "./kyoo-errors";
import { Page, Paged } from "./page";
import { getToken } from "./login";
import { getToken, getTokenWJ } from "./login";
import { getCurrentApiUrl } from ".";
export let lastUsedUrl: string = null!;
@ -48,12 +48,13 @@ export const queryFn = async <Parser extends z.ZodTypeAny>(
} & Partial<QueryFunctionContext>)
),
type?: Parser,
token?: string | null,
iToken?: string | null,
): Promise<z.infer<Parser>> => {
const url = context.apiUrl && context.apiUrl.length > 0 ? context.apiUrl : getCurrentApiUrl();
lastUsedUrl = url!;
if (token === undefined && context.authenticated !== false) token = await getToken();
const token =
iToken === undefined && context.authenticated !== false ? await getToken() : undefined;
const path = [url]
.concat(
"path" in context
@ -90,6 +91,14 @@ export const queryFn = async <Parser extends z.ZodTypeAny>(
if (resp.status === 404) {
throw { errors: ["Resource not found."], status: 404 } as KyooErrors;
}
// If we got a forbidden, try to refresh the token
// if we got a token as an argument, it either means we already retried or we go one provided that's fresh
// so we can't retry either ways.
if (resp.status === 403 && iToken === undefined && token) {
const [newToken, _, error] = await getTokenWJ(undefined, true);
if (newToken) return await queryFn(context, type, newToken);
else console.error("refresh error while retrying a forbidden", error);
}
if (!resp.ok) {
const error = await resp.text();
let data;
@ -128,7 +137,7 @@ export const queryFn = async <Parser extends z.ZodTypeAny>(
errors: [
"Invalid response from kyoo. Possible version mismatch between the server and the application.",
],
status: "parse"
status: "parse",
} as KyooErrors;
}
return parsed.data;