From ab5d2eca1fbdbd17a4913229cd5812337d9ed7be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E3=81=BE=E3=81=A3=E3=81=A1=E3=82=83=E3=81=A8=E3=83=BC?=
 =?UTF-8?q?=E3=81=AB=E3=82=85?=
 <17376330+u1-liquid@users.noreply.github.com>
Date: Fri, 8 Dec 2023 17:48:18 +0900
Subject: [PATCH] =?UTF-8?q?enhance(frontend):=20window.open=E3=82=84a?=
 =?UTF-8?q?=E3=82=BF=E3=82=B0=E3=81=ABnoopener=E3=82=AA=E3=83=97=E3=82=B7?=
 =?UTF-8?q?=E3=83=A7=E3=83=B3=E3=82=92=E3=81=A4=E3=81=91=E3=82=8B=20(Missk?=
 =?UTF-8?q?eyIO#283)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 packages/frontend/src/components/MkGoogle.vue          |  2 +-
 packages/frontend/src/components/MkLink.vue            |  2 +-
 packages/frontend/src/components/MkPageWindow.vue      |  2 +-
 .../frontend/src/components/MkVisitorDashboard.vue     | 10 +++++-----
 packages/frontend/src/components/global/MkA.vue        |  2 +-
 packages/frontend/src/components/global/MkUrl.vue      |  2 +-
 packages/frontend/src/pages/admin-file.vue             |  2 +-
 packages/frontend/src/pages/admin/queue.vue            |  2 +-
 packages/frontend/src/pages/instance-info.vue          |  2 +-
 packages/frontend/src/plugin.ts                        |  2 +-
 packages/frontend/src/scripts/get-note-menu.ts         |  4 ++--
 packages/frontend/src/ui/_common_/common.ts            |  8 ++++----
 12 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/packages/frontend/src/components/MkGoogle.vue b/packages/frontend/src/components/MkGoogle.vue
index efbd775f5c..fb142b31b5 100644
--- a/packages/frontend/src/components/MkGoogle.vue
+++ b/packages/frontend/src/components/MkGoogle.vue
@@ -23,7 +23,7 @@ const query = ref(props.q);
 const search = () => {
 	const sp = new URLSearchParams();
 	sp.append('q', query.value);
-	window.open(`https://www.google.com/search?${sp.toString()}`, '_blank');
+	window.open(`https://www.google.com/search?${sp.toString()}`, '_blank', 'noopener');
 };
 </script>
 
diff --git a/packages/frontend/src/components/MkLink.vue b/packages/frontend/src/components/MkLink.vue
index 808a071d10..8517eff40b 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
 
 <template>
 <component
-	:is="self ? 'MkA' : 'a'" ref="el" style="word-break: break-all;" class="_link" :[attr]="self ? url.substring(local.length) : url" :rel="rel" :target="target"
+	:is="self ? 'MkA' : 'a'" ref="el" style="word-break: break-all;" class="_link" :[attr]="self ? url.substring(local.length) : url" :rel="rel ?? 'nofollow noopener'" :target="target"
 	:title="url"
 >
 	<slot></slot>
diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue
index 441296e05d..23eb70ecd2 100644
--- a/packages/frontend/src/components/MkPageWindow.vue
+++ b/packages/frontend/src/components/MkPageWindow.vue
@@ -112,7 +112,7 @@ const contextmenu = computed(() => ([{
 	icon: 'ti ti-external-link',
 	text: i18n.ts.openInNewTab,
 	action: () => {
-		window.open(url + router.getCurrentPath(), '_blank');
+		window.open(url + router.getCurrentPath(), '_blank', 'noopener');
 		windowEl.value.close();
 	},
 }, {
diff --git a/packages/frontend/src/components/MkVisitorDashboard.vue b/packages/frontend/src/components/MkVisitorDashboard.vue
index 7a41720e3f..102cb8d139 100644
--- a/packages/frontend/src/components/MkVisitorDashboard.vue
+++ b/packages/frontend/src/components/MkVisitorDashboard.vue
@@ -107,31 +107,31 @@ function showMenu(ev) {
 		text: i18n.ts.impressum,
 		icon: 'ti ti-file-invoice',
 		action: () => {
-			window.open(instance.impressumUrl, '_blank');
+			window.open(instance.impressumUrl, '_blank', 'noopener');
 		},
 	} : undefined, (instance.tosUrl) ? {
 		text: i18n.ts.termsOfService,
 		icon: 'ti ti-notebook',
 		action: () => {
-			window.open(instance.tosUrl, '_blank');
+			window.open(instance.tosUrl, '_blank', 'noopener');
 		},
 	} : undefined, (instance.privacyPolicyUrl) ? {
 		text: i18n.ts.privacyPolicy,
 		icon: 'ti ti-shield-lock',
 		action: () => {
-			window.open(instance.privacyPolicyUrl, '_blank');
+			window.open(instance.privacyPolicyUrl, '_blank', 'noopener');
 		},
 	} : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl) ? undefined : null, {
 		text: i18n.ts.help,
 		icon: 'ti ti-help-circle',
 		action: () => {
-			window.open('https://misskey-hub.net/help.md', '_blank');
+			window.open('https://misskey-hub.net/help.md', '_blank', 'noopener');
 		},
 	}], ev.currentTarget ?? ev.target);
 }
 
 function exploreOtherServers() {
-	window.open('https://join.misskey.page/instances', '_blank');
+	window.open('https://join.misskey.page/instances', '_blank', 'noopener');
 }
 </script>
 
diff --git a/packages/frontend/src/components/global/MkA.vue b/packages/frontend/src/components/global/MkA.vue
index 008d10f8eb..809dae421a 100644
--- a/packages/frontend/src/components/global/MkA.vue
+++ b/packages/frontend/src/components/global/MkA.vue
@@ -61,7 +61,7 @@ function onContextmenu(ev) {
 		icon: 'ti ti-external-link',
 		text: i18n.ts.openInNewTab,
 		action: () => {
-			window.open(props.to, '_blank');
+			window.open(props.to, '_blank', 'noopener');
 		},
 	}, {
 		icon: 'ti ti-link',
diff --git a/packages/frontend/src/components/global/MkUrl.vue b/packages/frontend/src/components/global/MkUrl.vue
index db8a8399b5..9a59b5a68e 100644
--- a/packages/frontend/src/components/global/MkUrl.vue
+++ b/packages/frontend/src/components/global/MkUrl.vue
@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 
 <template>
 <component
-	:is="self ? 'MkA' : 'a'" ref="el" :class="$style.root" class="_link" :[attr]="self ? props.url.substring(local.length) : props.url" :rel="rel" :target="target"
+	:is="self ? 'MkA' : 'a'" ref="el" :class="$style.root" class="_link" :[attr]="self ? props.url.substring(local.length) : props.url" :rel="rel ?? 'nofollow noopener'" :target="target"
 	@contextmenu.stop="() => {}"
 >
 	<template v-if="!self">
diff --git a/packages/frontend/src/pages/admin-file.vue b/packages/frontend/src/pages/admin-file.vue
index aefff69c60..dd61aea4c7 100644
--- a/packages/frontend/src/pages/admin-file.vue
+++ b/packages/frontend/src/pages/admin-file.vue
@@ -120,7 +120,7 @@ const headerActions = computed(() => [{
 	text: i18n.ts.openInNewTab,
 	icon: 'ti ti-external-link',
 	handler: () => {
-		window.open(file.value.url, '_blank');
+		window.open(file.value.url, '_blank', 'noopener');
 	},
 }]);
 
diff --git a/packages/frontend/src/pages/admin/queue.vue b/packages/frontend/src/pages/admin/queue.vue
index f07fba8d15..5a8f960cf6 100644
--- a/packages/frontend/src/pages/admin/queue.vue
+++ b/packages/frontend/src/pages/admin/queue.vue
@@ -56,7 +56,7 @@ const headerActions = computed(() => [{
 	icon: 'ti ti-external-link',
 	text: i18n.ts.dashboard,
 	handler: () => {
-		window.open(config.url + '/queue', '_blank');
+		window.open(config.url + '/queue', '_blank', 'noopener');
 	},
 }]);
 
diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue
index 93d74fb42e..97dc0a8633 100644
--- a/packages/frontend/src/pages/instance-info.vue
+++ b/packages/frontend/src/pages/instance-info.vue
@@ -218,7 +218,7 @@ const headerActions = computed(() => [{
 	text: `https://${props.host}`,
 	icon: 'ti ti-external-link',
 	handler: () => {
-		window.open(`https://${props.host}`, '_blank');
+		window.open(`https://${props.host}`, '_blank', 'noopener');
 	},
 }]);
 
diff --git a/packages/frontend/src/plugin.ts b/packages/frontend/src/plugin.ts
index e24f646a35..5e49af4858 100644
--- a/packages/frontend/src/plugin.ts
+++ b/packages/frontend/src/plugin.ts
@@ -96,7 +96,7 @@ function createPluginEnv(opts: { plugin: Plugin; storageKey: string }): Record<s
 		}),
 		'Plugin:open_url': values.FN_NATIVE(([url]) => {
 			utils.assertString(url);
-			window.open(url.value, '_blank');
+			window.open(url.value, '_blank', 'noopener');
 		}),
 		'Plugin:config': values.OBJ(config),
 	};
diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts
index 763f6ff513..14ada9b7f0 100644
--- a/packages/frontend/src/scripts/get-note-menu.ts
+++ b/packages/frontend/src/scripts/get-note-menu.ts
@@ -278,7 +278,7 @@ export function getNoteMenu(props: {
 				icon: 'ti ti-external-link',
 				text: i18n.ts.showOnRemote,
 				action: () => {
-					window.open(appearNote.url ?? appearNote.uri, '_blank');
+					window.open(appearNote.url ?? appearNote.uri, '_blank', 'noopener');
 				},
 			} : undefined,
 			...(isSupportShare() ? [{
@@ -382,7 +382,7 @@ export function getNoteMenu(props: {
 			icon: 'ti ti-external-link',
 			text: i18n.ts.showOnRemote,
 			action: () => {
-				window.open(appearNote.url ?? appearNote.uri, '_blank');
+				window.open(appearNote.url ?? appearNote.uri, '_blank', 'noopener');
 			},
 		} : undefined]
 			.filter(x => x !== undefined);
diff --git a/packages/frontend/src/ui/_common_/common.ts b/packages/frontend/src/ui/_common_/common.ts
index 64008c5748..48a1144df7 100644
--- a/packages/frontend/src/ui/_common_/common.ts
+++ b/packages/frontend/src/ui/_common_/common.ts
@@ -83,25 +83,25 @@ export function openInstanceMenu(ev: MouseEvent) {
 		text: i18n.ts.impressum,
 		icon: 'ti ti-file-invoice',
 		action: () => {
-			window.open(instance.impressumUrl, '_blank');
+			window.open(instance.impressumUrl, '_blank', 'noopener');
 		},
 	} : undefined, (instance.tosUrl) ? {
 		text: i18n.ts.termsOfService,
 		icon: 'ti ti-notebook',
 		action: () => {
-			window.open(instance.tosUrl, '_blank');
+			window.open(instance.tosUrl, '_blank', 'noopener');
 		},
 	} : undefined, (instance.privacyPolicyUrl) ? {
 		text: i18n.ts.privacyPolicy,
 		icon: 'ti ti-shield-lock',
 		action: () => {
-			window.open(instance.privacyPolicyUrl, '_blank');
+			window.open(instance.privacyPolicyUrl, '_blank', 'noopener');
 		},
 	} : undefined, (!instance.impressumUrl && !instance.tosUrl && !instance.privacyPolicyUrl) ? undefined : null, {
 		text: i18n.ts.help,
 		icon: 'ti ti-help-circle',
 		action: () => {
-			window.open('https://misskey-hub.net/help.html', '_blank');
+			window.open('https://misskey-hub.net/help.html', '_blank', 'noopener');
 		},
 	}, ($i) ? {
 		text: i18n.ts._initialTutorial.launchTutorial,