From 70fe23a3ce8a37b9a848c2da80c0a84cf8f559bf Mon Sep 17 00:00:00 2001
From: syuilo <Syuilotan@yahoo.co.jp>
Date: Thu, 9 Feb 2023 18:01:12 +0900
Subject: [PATCH] fix(client): validate url to improve security

---
 packages/frontend/src/pages/auth.vue   | 2 ++
 packages/frontend/src/pages/miauth.vue | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/packages/frontend/src/pages/auth.vue b/packages/frontend/src/pages/auth.vue
index bb55881a2..b7727ca30 100644
--- a/packages/frontend/src/pages/auth.vue
+++ b/packages/frontend/src/pages/auth.vue
@@ -77,6 +77,8 @@ export default defineComponent({
 		accepted() {
 			this.state = 'accepted';
 			if (this.session.app.callbackUrl) {
+				const url = new URL(this.session.app.callbackUrl);
+				if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(url.protocol)) throw new Error('invalid url');
 				location.href = `${this.session.app.callbackUrl}?token=${this.session.token}`;
 			}
 		}, onLogin(res) {
diff --git a/packages/frontend/src/pages/miauth.vue b/packages/frontend/src/pages/miauth.vue
index 3debaeeb6..9a4019e5b 100644
--- a/packages/frontend/src/pages/miauth.vue
+++ b/packages/frontend/src/pages/miauth.vue
@@ -70,7 +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');
+		if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(cbUrl.protocol)) throw new Error('invalid url');
 		cbUrl.searchParams.set('session', props.session);
 		location.href = cbUrl.href;
 	}