From 8dd59a8c06da49b8f302d902d73d04397ee29366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Fri, 31 Jul 2026 16:11:39 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20RSS=E7=B3=BB=E3=82=A6=E3=82=A3=E3=82=B8?= =?UTF-8?q?=E3=82=A7=E3=83=83=E3=83=88=E3=81=AB=E3=83=95=E3=82=A3=E3=83=BC?= =?UTF-8?q?=E3=83=89URL=E6=A4=9C=E6=9F=BB=E6=A9=9F=E6=A7=8B=E3=82=92?= =?UTF-8?q?=E8=BF=BD=E5=8A=A0=20(#17831)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend-shared/js/url.ts | 8 +++++++ .../src/ui/_common_/statusbar-rss.vue | 5 +++-- packages/frontend/src/widgets/WidgetRss.vue | 7 ++++--- .../frontend/src/widgets/WidgetRssTicker.vue | 11 +++++----- packages/frontend/test/unit/url.test.ts | 21 +++++++++++++++++++ 5 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 packages/frontend/test/unit/url.test.ts diff --git a/packages/frontend-shared/js/url.ts b/packages/frontend-shared/js/url.ts index 1f3550d951..b70c7cfee4 100644 --- a/packages/frontend-shared/js/url.ts +++ b/packages/frontend-shared/js/url.ts @@ -27,6 +27,14 @@ export function extractDomain(url: string) { return match ? match[1] : null; } +export function tryParseUrl(url: string | URL, base?: string | URL): URL | null { + try { + return new URL(url, base); + } catch { + return null; + } +} + export function maybeMakeRelative(urlStr: string, baseStr: string): string { try { const baseObj = new URL(baseStr); diff --git a/packages/frontend/src/ui/_common_/statusbar-rss.vue b/packages/frontend/src/ui/_common_/statusbar-rss.vue index 1c4c29769a..13f69e74fa 100644 --- a/packages/frontend/src/ui/_common_/statusbar-rss.vue +++ b/packages/frontend/src/ui/_common_/statusbar-rss.vue @@ -31,6 +31,7 @@ import { ref } from 'vue'; import * as Misskey from 'misskey-js'; import { useInterval } from '@@/js/use-interval.js'; import { url as baseUrl } from '@@/js/config.js'; +import { tryParseUrl } from '@@/js/url.js'; import MkMarqueeText from '@/components/MkMarqueeText.vue'; import { shuffle } from '@/utility/shuffle.js'; @@ -56,8 +57,8 @@ const tick = () => { } items.value = feed.items.filter((item) => { if (!item.link) return false; - const itemUrl = new URL(item.link, baseUrl); - return ['http:', 'https:'].includes(itemUrl.protocol); + const itemUrl = tryParseUrl(item.link, baseUrl); + return itemUrl != null && ['http:', 'https:'].includes(itemUrl.protocol); }); fetching.value = false; key.value++; diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue index 9cc5d8ad39..510de0234a 100644 --- a/packages/frontend/src/widgets/WidgetRss.vue +++ b/packages/frontend/src/widgets/WidgetRss.vue @@ -24,10 +24,11 @@ import { ref, watch, computed } from 'vue'; import * as Misskey from 'misskey-js'; import { url as base } from '@@/js/config.js'; import { useInterval } from '@@/js/use-interval.js'; +import { tryParseUrl } from '@@/js/url.js'; import { useWidgetPropsManager } from './widget.js'; -import { i18n } from '@/i18n.js'; import type { WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget.js'; import type { FormWithDefault, GetFormResultType } from '@/utility/form.js'; +import { i18n } from '@/i18n.js'; import MkContainer from '@/components/MkContainer.vue'; const name = 'rss'; @@ -83,8 +84,8 @@ const tick = () => { .then((feed: Misskey.entities.FetchRssResponse) => { rawItems.value = feed.items.filter((item) => { if (!item.link) return false; - const itemUrl = new URL(item.link, base); - return ['http:', 'https:'].includes(itemUrl.protocol); + const itemUrl = tryParseUrl(item.link, base); + return itemUrl != null && ['http:', 'https:'].includes(itemUrl.protocol); }); fetching.value = false; }); diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue index 7b0ee60e63..7e339d1dd7 100644 --- a/packages/frontend/src/widgets/WidgetRssTicker.vue +++ b/packages/frontend/src/widgets/WidgetRssTicker.vue @@ -29,15 +29,16 @@ SPDX-License-Identifier: AGPL-3.0-only