From 0f39ac8960e4e5ebbb9d09d904fdaceda89d520c Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Fri, 22 May 2026 18:23:56 +0800 Subject: [PATCH] fix web lint --- pnpm-workspace.yaml | 7 ---- web/app/signin/utils/post-login-redirect.ts | 38 ++++++++++++------ web/service/device-flow.ts | 43 ++++++++++++++------- 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 865cea7925..5d62a0c1e0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -93,12 +93,6 @@ catalog: '@napi-rs/keyring': 1.1.6 '@next/eslint-plugin-next': 16.2.6 '@next/mdx': 16.2.6 - '@oclif/core': 4.11.1 - '@oclif/plugin-autocomplete': 3.2.6 - '@oclif/plugin-help': 6.2.10 - '@oclif/plugin-not-found': 3.2.18 - '@oclif/plugin-version': 2.2.16 - '@oclif/plugin-warn-if-update-available': 3.1.13 '@orpc/client': 1.14.3 '@orpc/contract': 1.14.3 '@orpc/openapi-client': 1.14.3 @@ -212,7 +206,6 @@ catalog: next: 16.2.6 next-themes: 0.4.6 nuqs: 2.8.9 - oclif: 4.15.5 open: 10.1.0 ora: 8.1.0 picocolors: 1.1.0 diff --git a/web/app/signin/utils/post-login-redirect.ts b/web/app/signin/utils/post-login-redirect.ts index 326ba9e08a..2c8d82d9bb 100644 --- a/web/app/signin/utils/post-login-redirect.ts +++ b/web/app/signin/utils/post-login-redirect.ts @@ -18,14 +18,18 @@ type OAuthPendingRedirect = { const getCurrentUnixTimestamp = () => Math.floor(Date.now() / 1000) function validate(target: string): string | null { - if (typeof window === 'undefined') return null + if (typeof window === 'undefined') + return null try { const url = new URL(target, window.location.origin) - if (url.origin !== window.location.origin) return null + if (url.origin !== window.location.origin) + return null const allowedKeys = ALLOWED[url.pathname] - if (!allowedKeys) return null + if (!allowedKeys) + return null for (const key of url.searchParams.keys()) { - if (!allowedKeys.has(key)) return null + if (!allowedKeys.has(key)) + return null } return url.pathname + (url.search || '') } @@ -39,13 +43,18 @@ function validate(target: string): string | null { // /device tabs don't clobber each other. 15-min TTL drops stale values. // Same-origin + exact-path whitelist prevents open-redirect. export const setPostLoginRedirect = (value: string | null) => { - if (typeof window === 'undefined') return + if (typeof window === 'undefined') + return if (value === null) { - try { sessionStorage.removeItem(DEVICE_REDIRECT_KEY) } catch {} + try { + sessionStorage.removeItem(DEVICE_REDIRECT_KEY) + } + catch {} return } const safe = validate(value) - if (!safe) return + if (!safe) + return try { sessionStorage.setItem(DEVICE_REDIRECT_KEY, JSON.stringify({ target: safe, ts: Date.now() })) } @@ -53,7 +62,8 @@ export const setPostLoginRedirect = (value: string | null) => { } function getDeviceRedirect(): string | null { - if (typeof window === 'undefined') return null + if (typeof window === 'undefined') + return null let raw: string | null = null try { raw = sessionStorage.getItem(DEVICE_REDIRECT_KEY) @@ -62,11 +72,14 @@ function getDeviceRedirect(): string | null { catch { return null } - if (!raw) return null + if (!raw) + return null try { const parsed = JSON.parse(raw) - if (typeof parsed?.target !== 'string' || typeof parsed?.ts !== 'number') return null - if (Date.now() - parsed.ts > DEVICE_TTL_MS) return null + if (typeof parsed?.target !== 'string' || typeof parsed?.ts !== 'number') + return null + if (Date.now() - parsed.ts > DEVICE_TTL_MS) + return null return validate(parsed.target) } catch { @@ -124,6 +137,7 @@ export const resolvePostLoginRedirect = (searchParams?: ReadonlyURLSearchParams) } } const device = getDeviceRedirect() - if (device) return device + if (device) + return device return getOAuthPendingRedirect() } diff --git a/web/service/device-flow.ts b/web/service/device-flow.ts index d936a48fb2..2ae4c4ab92 100644 --- a/web/service/device-flow.ts +++ b/web/service/device-flow.ts @@ -22,9 +22,14 @@ const DEVICE_BASE = '/openapi/v1/oauth/device' // switches on `code` to choose user-facing copy / view; never render // `status` or raw body to the user. export class DeviceFlowError extends Error { - constructor(public code: string, public status: number) { + code: string + status: number + + constructor(code: string, status: number) { super(code) this.name = 'DeviceFlowError' + this.code = code + this.status = status } } @@ -35,7 +40,8 @@ async function failFromResponse(res: Response): Promise { let serverCode = '' try { const body = await res.clone().json() - if (body && typeof body.error === 'string') serverCode = body.error + if (body && typeof body.error === 'string') + serverCode = body.error } catch { /* non-JSON body — fall through to status mapping */ } @@ -44,12 +50,18 @@ async function failFromResponse(res: Response): Promise { } function statusFallbackCode(status: number): string { - if (status === 429) return 'rate_limited' - if (status === 401) return 'no_session' - if (status === 403) return 'forbidden' - if (status === 404) return 'not_found' - if (status === 409) return 'conflict' - if (status >= 500) return 'server_error' + if (status === 429) + return 'rate_limited' + if (status === 401) + return 'no_session' + if (status === 403) + return 'forbidden' + if (status === 404) + return 'not_found' + if (status === 409) + return 'conflict' + if (status >= 500) + return 'server_error' return 'unknown' } @@ -69,7 +81,8 @@ export async function deviceLookup(user_code: string): Promise { method: 'GET', credentials: 'include', }) - if (!res.ok) await failFromResponse(res) + if (!res.ok) + await failFromResponse(res) return res.json() } @@ -130,5 +146,6 @@ export async function approveExternal(ctx: ApprovalContext, user_code: string): }, body: JSON.stringify({ user_code }), }) - if (!res.ok) await failFromResponse(res) + if (!res.ok) + await failFromResponse(res) }