From 868423a138e1ba042f5ec740f71db2456fd72307 Mon Sep 17 00:00:00 2001 From: yyh Date: Tue, 10 Feb 2026 14:23:47 +0800 Subject: [PATCH] refactor(web): migrate OAuth redirect storage to utility and preserve query params - Use storage utility instead of raw localStorage for OAuth pending redirect with legacy fallback for backward compatibility - Forward search params from root page to /apps so query strings (e.g. redirect_url) are not lost during server-side redirect --- web/app/account/oauth/authorize/page.tsx | 3 +- web/app/page.tsx | 24 +++++++++++- web/app/signin/utils/post-login-redirect.ts | 43 +++++++++++++++------ 3 files changed, 56 insertions(+), 14 deletions(-) diff --git a/web/app/account/oauth/authorize/page.tsx b/web/app/account/oauth/authorize/page.tsx index 7948a8896d..ea375e1a32 100644 --- a/web/app/account/oauth/authorize/page.tsx +++ b/web/app/account/oauth/authorize/page.tsx @@ -19,6 +19,7 @@ import { useLanguage } from '@/app/components/header/account-setting/model-provi import { useAppContext } from '@/context/app-context' import { useIsLogin } from '@/service/use-common' import { useAuthorizeOAuthApp, useOAuthAppInfo } from '@/service/use-oauth' +import { storage } from '@/utils/storage' import { OAUTH_AUTHORIZE_PENDING_KEY, OAUTH_AUTHORIZE_PENDING_TTL, @@ -30,7 +31,7 @@ function setItemWithExpiry(key: string, value: string, ttl: number) { value, expiry: Math.floor((Date.now() + ttl * 1000) / 1000), } - localStorage.setItem(key, JSON.stringify(item)) + storage.set(key, item) } function buildReturnUrl(pathname: string, search: string) { diff --git a/web/app/page.tsx b/web/app/page.tsx index 7f47a1455f..33f67bfd07 100644 --- a/web/app/page.tsx +++ b/web/app/page.tsx @@ -1,5 +1,27 @@ import { redirect } from 'next/navigation' -const Home = () => redirect('/apps') +type HomePageProps = { + searchParams: Promise> +} + +const Home = async ({ searchParams }: HomePageProps) => { + const resolvedSearchParams = await searchParams + const urlSearchParams = new URLSearchParams() + + Object.entries(resolvedSearchParams).forEach(([key, value]) => { + if (value === undefined) + return + + if (Array.isArray(value)) { + value.forEach(item => urlSearchParams.append(key, item)) + return + } + + urlSearchParams.set(key, value) + }) + + const queryString = urlSearchParams.toString() + redirect(queryString ? `/apps?${queryString}` : '/apps') +} export default Home diff --git a/web/app/signin/utils/post-login-redirect.ts b/web/app/signin/utils/post-login-redirect.ts index c5b976c643..c106a629a7 100644 --- a/web/app/signin/utils/post-login-redirect.ts +++ b/web/app/signin/utils/post-login-redirect.ts @@ -1,31 +1,50 @@ import type { ReadonlyURLSearchParams } from 'next/navigation' import { OAUTH_AUTHORIZE_PENDING_KEY, REDIRECT_URL_KEY } from '@/app/account/oauth/authorize/constants' +import { storage } from '@/utils/storage' const getCurrentUnixTimestamp = () => Math.floor(Date.now() / 1000) +type OAuthPendingRedirect = { + value?: string + expiry?: number +} -function getOAuthPendingRedirect(): string | null { - const itemStr = localStorage.getItem(OAUTH_AUTHORIZE_PENDING_KEY) - if (!itemStr) - return null - +function getLegacyOAuthPendingRedirect(): OAuthPendingRedirect | null { try { - const item = JSON.parse(itemStr) - localStorage.removeItem(OAUTH_AUTHORIZE_PENDING_KEY) - if (!item?.value) - return null - - return getCurrentUnixTimestamp() > item.expiry ? null : item.value + const itemStr = localStorage.getItem(OAUTH_AUTHORIZE_PENDING_KEY) + return itemStr ? JSON.parse(itemStr) : null } catch { return null } } +function removeOAuthPendingRedirect() { + storage.remove(OAUTH_AUTHORIZE_PENDING_KEY) + try { + localStorage.removeItem(OAUTH_AUTHORIZE_PENDING_KEY) + } + catch { + // ignore legacy key cleanup failures + } +} + +function getOAuthPendingRedirect(): string | null { + const item = storage.get(OAUTH_AUTHORIZE_PENDING_KEY) ?? getLegacyOAuthPendingRedirect() + if (!item) + return null + + removeOAuthPendingRedirect() + if (!item.value || typeof item.expiry !== 'number') + return null + + return getCurrentUnixTimestamp() > item.expiry ? null : item.value +} + export const resolvePostLoginRedirect = (searchParams: ReadonlyURLSearchParams) => { const redirectUrl = searchParams.get(REDIRECT_URL_KEY) if (redirectUrl) { try { - localStorage.removeItem(OAUTH_AUTHORIZE_PENDING_KEY) + removeOAuthPendingRedirect() return decodeURIComponent(redirectUrl) } catch (e) {