diff --git a/packages/backend/src/server/web/UrlPreviewService.ts b/packages/backend/src/server/web/UrlPreviewService.ts
index 9b5f0acd2c..531d085315 100644
--- a/packages/backend/src/server/web/UrlPreviewService.ts
+++ b/packages/backend/src/server/web/UrlPreviewService.ts
@@ -37,12 +37,10 @@ export class UrlPreviewService {
@bindThis
private wrap(url?: string | null): string | null {
return url != null
- ? url.match(/^https?:\/\//)
- ? `${this.config.mediaProxy}/preview.webp?${query({
- url,
- preview: '1',
- })}`
- : url
+ ? `${this.config.mediaProxy}/preview.webp?${query({
+ url,
+ preview: '1',
+ })}`
: null;
}
diff --git a/packages/frontend-shared/js/url.ts b/packages/frontend-shared/js/url.ts
index eb830b1eea..e4f9ca513d 100644
--- a/packages/frontend-shared/js/url.ts
+++ b/packages/frontend-shared/js/url.ts
@@ -26,3 +26,20 @@ export function extractDomain(url: string) {
const match = url.match(/^(?:https?:)?(?:\/\/)?(?:[^@\n]+@)?([^:\/\n]+)/im);
return match ? match[1] : null;
}
+
+export function maybeMakeRelative(urlStr: string, baseStr: string): string {
+ try {
+ const baseObj = new URL(baseStr);
+ const urlObj = new URL(urlStr);
+ /* in all places where maybeMakeRelative is used, baseStr is the
+ * instance's public URL, which can't have path components, so the
+ * relative URL will always have the whole path from the urlStr
+ */
+ if (urlObj.origin === baseObj.origin) {
+ return urlObj.pathname + urlObj.search + urlObj.hash;
+ }
+ return urlStr;
+ } catch (e) {
+ return '';
+ }
+}
diff --git a/packages/frontend/src/components/MkLink.vue b/packages/frontend/src/components/MkLink.vue
index 4bac2bcea4..4cbf289448 100644
--- a/packages/frontend/src/components/MkLink.vue
+++ b/packages/frontend/src/components/MkLink.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
@@ -21,6 +21,7 @@ import { useTooltip } from '@/use/use-tooltip.js';
import * as os from '@/os.js';
import { isEnabledUrlPreview } from '@/instance.js';
import type { MkABehavior } from '@/components/global/MkA.vue';
+import { maybeMakeRelative } from '@@/js/url.js';
const props = withDefaults(defineProps<{
url: string;
@@ -29,7 +30,8 @@ const props = withDefaults(defineProps<{
}>(), {
});
-const self = props.url.startsWith(local);
+const maybeRelativeUrl = maybeMakeRelative(props.url, local);
+const self = maybeRelativeUrl !== props.url;
const attr = self ? 'to' : 'href';
const target = self ? null : '_blank';
diff --git a/packages/frontend/src/components/MkUrlPreview.vue b/packages/frontend/src/components/MkUrlPreview.vue
index 20dab6f028..71c8a6a6e8 100644
--- a/packages/frontend/src/components/MkUrlPreview.vue
+++ b/packages/frontend/src/components/MkUrlPreview.vue
@@ -44,8 +44,8 @@ SPDX-License-Identifier: AGPL-3.0-only
-
-
+
+
@@ -94,6 +94,7 @@ import MkButton from '@/components/MkButton.vue';
import { transformPlayerUrl } from '@/utility/player-url-transform.js';
import { store } from '@/store.js';
import { prefer } from '@/preferences.js';
+import { maybeMakeRelative } from '@@/js/url.js';
type SummalyResult = Awaited>;
@@ -111,7 +112,8 @@ const props = withDefaults(defineProps<{
const MOBILE_THRESHOLD = 500;
const isMobile = ref(deviceKind === 'smartphone' || window.innerWidth <= MOBILE_THRESHOLD);
-const self = props.url.startsWith(local);
+const maybeRelativeUrl = maybeMakeRelative(props.url, local);
+const self = maybeRelativeUrl !== props.url;
const attr = self ? 'to' : 'href';
const target = self ? null : '_blank';
const fetching = ref(true);
diff --git a/packages/frontend/src/components/MkUserInfo.vue b/packages/frontend/src/components/MkUserInfo.vue
index cff531b2ca..69144d3824 100644
--- a/packages/frontend/src/components/MkUserInfo.vue
+++ b/packages/frontend/src/components/MkUserInfo.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
diff --git a/packages/frontend/src/components/MkUserPopup.vue b/packages/frontend/src/components/MkUserPopup.vue
index 17a882a3a6..3bd2a2ffae 100644
--- a/packages/frontend/src/components/MkUserPopup.vue
+++ b/packages/frontend/src/components/MkUserPopup.vue
@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
>
{ emit('mouseover'); }" @mouseleave="() => { emit('mouseleave'); }">
-
+
{{ i18n.ts.followsYou }}
@@ -67,7 +67,7 @@ SPDX-License-Identifier: AGPL-3.0-only
MEM {{ memP }}%