From deb0a7e9195118285402edc4371abc65bd7ea9ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Wed, 18 Mar 2026 18:28:59 +0100 Subject: [PATCH] nicolium: use URL.canParse instead of a try/catch block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- .../nicolium/src/actions/consumer-auth.ts | 3 +-- packages/nicolium/src/stores/auth.ts | 14 +++++++------ packages/nicolium/src/utils/auth.ts | 20 +++---------------- packages/nicolium/src/utils/state.ts | 5 ++--- 4 files changed, 14 insertions(+), 28 deletions(-) diff --git a/packages/nicolium/src/actions/consumer-auth.ts b/packages/nicolium/src/actions/consumer-auth.ts index dc9044e61..b814d5876 100644 --- a/packages/nicolium/src/actions/consumer-auth.ts +++ b/packages/nicolium/src/actions/consumer-auth.ts @@ -1,5 +1,4 @@ import * as BuildConfig from '@/build-config'; -import { isURL } from '@/utils/auth'; import sourceCode from '@/utils/code'; import { getScopes } from '@/utils/scopes'; @@ -19,7 +18,7 @@ const createProviderApp = () => { }; const prepareRequest = async (provider: string) => { - const baseURL = isURL(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : ''; + const baseURL = URL.canParse(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : ''; const scopes = getScopes(undefined, true); const app = await createProviderApp(); diff --git a/packages/nicolium/src/stores/auth.ts b/packages/nicolium/src/stores/auth.ts index 3c173eadb..7869752c6 100644 --- a/packages/nicolium/src/stores/auth.ts +++ b/packages/nicolium/src/stores/auth.ts @@ -26,7 +26,7 @@ import { coerceObject } from '@/schemas/utils'; import { setSentryAccount, unsetSentryAccount } from '@/sentry'; import KVStore from '@/storage/kv-store'; import toast from '@/toast'; -import { validId, isURL, parseBaseURL } from '@/utils/auth'; +import { validId, parseBaseURL } from '@/utils/auth'; import sourceCode from '@/utils/code'; import { normalizeUsername } from '@/utils/input'; import { getScopes } from '@/utils/scopes'; @@ -68,7 +68,7 @@ const instance = (() => { } })(); -const backendUrl = isURL(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : ''; +const backendUrl = URL.canParse(BuildConfig.BACKEND_URL) ? BuildConfig.BACKEND_URL : ''; const mastodonPreloadSchema = coerceObject({ meta: coerceObject({ @@ -189,7 +189,7 @@ const setSessionUser = (state: AuthData) => { const isUpgradingUrlId = (state: AuthData) => { const me = state.me; const user = state.users[me!]; - return validId(me) && user && !isURL(me); + return validId(me) && user && !URL.canParse(me as string); }; const sanitizeState = (state: AuthData) => { @@ -263,7 +263,7 @@ const importTokenData = (state: AuthData, token: Token, app?: CredentialApplicat }; const upgradeNonUrlId = (state: AuthData, account: CredentialAccount) => { - if (isURL(state.me)) return; + if (state.me && URL.canParse(state.me)) return; state.me = state.me === account.id ? account.url : state.me; delete state.users[account.id]; }; @@ -312,7 +312,7 @@ const importMastodonPreloadData = (state: AuthData, data: Record) = const accountUrl = parsedData.accounts[accountId]?.url; const accessToken = parsedData.meta.access_token; - if (validId(accessToken) && validId(accountId) && isURL(accountUrl)) { + if (validId(accessToken) && validId(accountId) && URL.canParse(accountUrl)) { state.tokens[accessToken] = v.parse(tokenSchema, { access_token: accessToken, account: accountId, @@ -830,7 +830,9 @@ const isLoggedIn = () => validId(getCurrentAccountId()); const getAuthUserUrl = () => { const { me, users } = useAuthStore.getState(); - return [users[me!]?.url, me].filter((url) => url).find(isURL); + return [users[me!]?.url, me] + .filter((url): url is string => !!url) + .find((url) => URL.canParse(url)); }; const getMeUrl = () => getOwnAccount()?.url; diff --git a/packages/nicolium/src/utils/auth.ts b/packages/nicolium/src/utils/auth.ts index 9a0008915..246311fe2 100644 --- a/packages/nicolium/src/utils/auth.ts +++ b/packages/nicolium/src/utils/auth.ts @@ -1,23 +1,9 @@ const validId = (id?: string | null | false) => typeof id === 'string' && id !== 'null' && id !== 'undefined'; -const isURL = (url?: string | null) => { - if (typeof url !== 'string') return false; - try { - new URL(url); - return true; - } catch { - return false; - } -}; - const parseBaseURL = (url?: string) => { - if (typeof url !== 'string') return ''; - try { - return new URL(url).origin; - } catch { - return ''; - } + if (!url || !URL.canParse(url)) return ''; + return new URL(url).origin; }; -export { validId, isURL, parseBaseURL }; +export { validId, parseBaseURL }; diff --git a/packages/nicolium/src/utils/state.ts b/packages/nicolium/src/utils/state.ts index 89399bf52..d31b16b3e 100644 --- a/packages/nicolium/src/utils/state.ts +++ b/packages/nicolium/src/utils/state.ts @@ -6,7 +6,6 @@ import * as BuildConfig from '@/build-config'; import { isPrerendered } from '@/precheck'; import { useInstanceStore } from '@/stores/instance'; -import { isURL } from '@/utils/auth'; /** * Determine whether Nicolium is running in standalone mode. @@ -14,12 +13,12 @@ import { isURL } from '@/utils/auth'; */ const isStandalone = (): boolean => { const instanceFetchFailed = useInstanceStore.getState().instanceFetchFailed; - return isURL(BuildConfig.BACKEND_URL) ? false : !isPrerendered && instanceFetchFailed; + return URL.canParse(BuildConfig.BACKEND_URL) ? false : !isPrerendered && instanceFetchFailed; }; const useIsStandalone = () => { const instanceFetchFailed = useInstanceStore((state) => state.instanceFetchFailed); - return isURL(BuildConfig.BACKEND_URL) ? false : !isPrerendered && instanceFetchFailed; + return URL.canParse(BuildConfig.BACKEND_URL) ? false : !isPrerendered && instanceFetchFailed; }; const useFederationRestrictionsDisclosed = () =>