From 788ae2f6ca37d297e912bfba02821543e8566522 Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Sat, 4 Feb 2023 09:10:01 +0900
Subject: [PATCH] fix(client): validate urls to improve security

---
 packages/frontend/src/components/MkUrlPreview.vue    | 1 +
 packages/frontend/src/components/MkYoutubePlayer.vue | 1 +
 packages/frontend/src/components/global/MkUrl.vue    | 1 +
 packages/frontend/src/pages/miauth.vue               | 1 +
 4 files changed, 4 insertions(+)

diff --git a/packages/frontend/src/components/MkUrlPreview.vue b/packages/frontend/src/components/MkUrlPreview.vue
index 4689f5e772..f7677faf74 100644
--- a/packages/frontend/src/components/MkUrlPreview.vue
+++ b/packages/frontend/src/components/MkUrlPreview.vue
@@ -86,6 +86,7 @@ let tweetHeight = $ref(150);
 let unknownUrl = $ref(false);
 
 const requestUrl = new URL(props.url);
+if (!['http:', 'https:'].includes(requestUrl.protocol)) throw new Error('invalid url');
 
 if (requestUrl.hostname === 'twitter.com' || requestUrl.hostname === 'mobile.twitter.com') {
 	const m = requestUrl.pathname.match(/^\/.+\/status(?:es)?\/(\d+)/);
diff --git a/packages/frontend/src/components/MkYoutubePlayer.vue b/packages/frontend/src/components/MkYoutubePlayer.vue
index d1f1f9e9c5..50d38a71bd 100644
--- a/packages/frontend/src/components/MkYoutubePlayer.vue
+++ b/packages/frontend/src/components/MkYoutubePlayer.vue
@@ -26,6 +26,7 @@ const props = defineProps<{
 }>();
 
 const requestUrl = new URL(props.url);
+if (!['http:', 'https:'].includes(requestUrl.protocol)) throw new Error('invalid url');
 
 let fetching = $ref(true);
 let title = $ref<string | null>(null);
diff --git a/packages/frontend/src/components/global/MkUrl.vue b/packages/frontend/src/components/global/MkUrl.vue
index 27c8329dcc..2a92780306 100644
--- a/packages/frontend/src/components/global/MkUrl.vue
+++ b/packages/frontend/src/components/global/MkUrl.vue
@@ -33,6 +33,7 @@ const props = defineProps<{
 
 const self = props.url.startsWith(local);
 const url = new URL(props.url);
+if (!['http:', 'https:'].includes(url.protocol)) throw new Error('invalid url');
 const el = ref();
 
 useTooltip(el, (showing) => {
diff --git a/packages/frontend/src/pages/miauth.vue b/packages/frontend/src/pages/miauth.vue
index a01c7c5c4b..3debaeeb61 100644
--- a/packages/frontend/src/pages/miauth.vue
+++ b/packages/frontend/src/pages/miauth.vue
@@ -70,6 +70,7 @@ async function accept(): Promise<void> {
 	state = 'accepted';
 	if (props.callback) {
 		const cbUrl = new URL(props.callback);
+		if (!['http:', 'https:'].includes(cbUrl.protocol)) throw new Error('invalid url');
 		cbUrl.searchParams.set('session', props.session);
 		location.href = cbUrl.href;
 	}