From 2f67ec2f843bc05f37b960399f7f6e37ac37d54b Mon Sep 17 00:00:00 2001
From: tamaina <tamaina@hotmail.co.jp>
Date: Thu, 27 Jan 2022 00:08:48 +0900
Subject: [PATCH] =?UTF-8?q?enhance:=20MediaList=E3=81=A7=E3=81=AF=E3=80=81?=
 =?UTF-8?q?=E3=82=B5=E3=83=BC=E3=83=90=E3=83=BC=E3=81=A7=E8=A8=B1=E5=8F=AF?=
 =?UTF-8?q?=E3=81=95=E3=82=8C=E3=81=9F=E5=BD=A2=E5=BC=8F=E3=81=97=E3=81=8B?=
 =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E3=81=97=E3=81=AA=E3=81=84=E3=82=88=E3=81=86?=
 =?UTF-8?q?=E3=81=AB=20(#8113)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* wip

* fix
---
 packages/client/src/components/media-list.vue | 36 +++++++++------
 packages/client/src/const.ts                  | 44 +++++++++++++++++++
 2 files changed, 66 insertions(+), 14 deletions(-)
 create mode 100644 packages/client/src/const.ts

diff --git a/packages/client/src/components/media-list.vue b/packages/client/src/components/media-list.vue
index 2970d06c9..efcbb1292 100644
--- a/packages/client/src/components/media-list.vue
+++ b/packages/client/src/components/media-list.vue
@@ -3,7 +3,7 @@
 	<XBanner v-for="media in mediaList.filter(media => !previewable(media))" :key="media.id" :media="media"/>
 	<div v-if="mediaList.filter(media => previewable(media)).length > 0" class="gird-container">
 		<div ref="gallery" :data-count="mediaList.filter(media => previewable(media)).length">
-			<template v-for="media in mediaList">
+			<template v-for="media in mediaList.filter(media => previewable(media))">
 				<XVideo v-if="media.type.startsWith('video')" :key="media.id" :video="media"/>
 				<XImage v-else-if="media.type.startsWith('image')" :key="media.id" class="image" :data-id="media.id" :image="media" :raw="raw"/>
 			</template>
@@ -22,6 +22,7 @@ import XBanner from './media-banner.vue';
 import XImage from './media-image.vue';
 import XVideo from './media-video.vue';
 import * as os from '@/os';
+import { FILE_TYPE_BROWSERSAFE } from '@/const';
 import { defaultStore } from '@/store';
 
 export default defineComponent({
@@ -44,18 +45,23 @@ export default defineComponent({
 
 		onMounted(() => {
 			const lightbox = new PhotoSwipeLightbox({
-				dataSource: props.mediaList.filter(media => media.type.startsWith('image')).map(media => {
-					const item = {
-						src: media.url,
-						w: media.properties.width,
-						h: media.properties.height,
-						alt: media.name,
-					};
-					if (media.properties.orientation != null && media.properties.orientation >= 5) {
-						[item.w, item.h] = [item.h, item.w];
-					}
-					return item;
-				}),
+				dataSource: props.mediaList
+					.filter(media => {
+						if (media.type === 'image/svg+xml') return true; // svgのwebpublicはpngなのでtrue
+						return media.type.startsWith('image') && FILE_TYPE_BROWSERSAFE.includes(media.type);
+					})
+					.map(media => {
+						const item = {
+							src: media.url,
+							w: media.properties.width,
+							h: media.properties.height,
+							alt: media.name,
+						};
+						if (media.properties.orientation != null && media.properties.orientation >= 5) {
+							[item.w, item.h] = [item.h, item.w];
+						}
+						return item;
+					}),
 				gallery: gallery.value,
 				children: '.image',
 				thumbSelector: '.image',
@@ -99,7 +105,9 @@ export default defineComponent({
 		});
 
 		const previewable = (file: misskey.entities.DriveFile): boolean => {
-			return file.type.startsWith('video') || file.type.startsWith('image');
+			if (file.type === 'image/svg+xml') return true; // svgのwebpublic/thumbnailはpngなのでtrue
+			// FILE_TYPE_BROWSERSAFEに適合しないものはブラウザで表示するのに不適切
+			return (file.type.startsWith('video') || file.type.startsWith('image')) && FILE_TYPE_BROWSERSAFE.includes(file.type);
 		};
 
 		return {
diff --git a/packages/client/src/const.ts b/packages/client/src/const.ts
new file mode 100644
index 000000000..505cf2748
--- /dev/null
+++ b/packages/client/src/const.ts
@@ -0,0 +1,44 @@
+// ブラウザで直接表示することを許可するファイルの種類のリスト
+// ここに含まれないものは application/octet-stream としてレスポンスされる
+// SVGはXSSを生むので許可しない
+export const FILE_TYPE_BROWSERSAFE = [
+	// Images
+	'image/png',
+	'image/gif',
+	'image/jpeg',
+	'image/webp',
+	'image/apng',
+	'image/bmp',
+	'image/tiff',
+	'image/x-icon',
+
+	// OggS
+	'audio/opus',
+	'video/ogg',
+	'audio/ogg',
+	'application/ogg',
+
+	// ISO/IEC base media file format
+	'video/quicktime',
+	'video/mp4',
+	'audio/mp4',
+	'video/x-m4v',
+	'audio/x-m4a',
+	'video/3gpp',
+	'video/3gpp2',
+
+	'video/mpeg',
+	'audio/mpeg',
+
+	'video/webm',
+	'audio/webm',
+
+	'audio/aac',
+	'audio/x-flac',
+	'audio/vnd.wave',
+];
+/*
+https://github.com/sindresorhus/file-type/blob/main/supported.js
+https://github.com/sindresorhus/file-type/blob/main/core.js
+https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers
+*/