Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: センシティブな画像をアイコン・バナーに指定できないように #13676

Open
wants to merge 35 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
fafe980
fix: センシティブな画像をアイコン・バナーに指定できないように
kakkokari-gtyih Apr 8, 2024
16e92e6
センシティブなファイルを選択できないように
kakkokari-gtyih Apr 8, 2024
b13446f
tweak design
kakkokari-gtyih Apr 8, 2024
aa2ab69
fix
kakkokari-gtyih Apr 8, 2024
3c3decc
Update Changelog
kakkokari-gtyih Apr 8, 2024
7c45dc1
enhance(frontend): アイコン画像・バナー画像を外せるように
kakkokari-gtyih Apr 8, 2024
ec79544
use option
kakkokari-gtyih Apr 8, 2024
466835a
use options
kakkokari-gtyih Apr 8, 2024
991cbf5
Merge branch 'develop' into fix-7311
syuilo Apr 8, 2024
db27623
いろいろ変えた
kakkokari-gtyih Apr 9, 2024
5b0db2b
Merge branch 'fix-7311' of https://github.com/kakkokari-gtyih/misskey…
kakkokari-gtyih Apr 9, 2024
599f7ad
Merge branch 'develop' into fix-7311
kakkokari-gtyih Apr 9, 2024
08e8b31
Merge branch 'develop' into fix-7311
kakkokari-gtyih Apr 11, 2024
168eaec
Merge branch 'develop' into fix-7311
kakkokari-gtyih Apr 13, 2024
0db9ec2
Merge branch 'develop' into fix-7311
kakkokari-gtyih Apr 14, 2024
54a41d3
refactor
kakkokari-gtyih Apr 14, 2024
5f29c23
Merge branch 'develop' into fix-7311
kakkokari-gtyih Apr 14, 2024
7dfd93f
Merge branch 'develop' into fix-7311
kakkokari-gtyih Apr 16, 2024
c6c18db
Merge branch 'develop' into fix-7311
kakkokari-gtyih Apr 20, 2024
4ca1598
Merge branch 'develop' into fix-7311
kakkokari-gtyih Apr 27, 2024
66bbe0e
Merge branch 'develop' into fix-7311
kakkokari-gtyih Apr 27, 2024
21e5fe6
Merge branch 'develop' into fix-7311
kakkokari-gtyih Jun 1, 2024
b6704a8
Update packages/frontend/src/os.ts
kakkokari-gtyih Jun 3, 2024
9a27e42
Update os.ts
kakkokari-gtyih Jun 3, 2024
a5424f4
Merge branch 'develop' into fix-7311
kakkokari-gtyih Jun 9, 2024
1650d49
Merge branch 'develop' into fix-7311
kakkokari-gtyih Jun 22, 2024
ac3d65a
Merge branch 'develop' into fix-7311
kakkokari-gtyih Jun 22, 2024
f3d2956
Merge branch 'develop' into fix-7311
kakkokari-gtyih Jun 23, 2024
30441b2
Merge branch 'develop' into fix-7311
kakkokari-gtyih Aug 23, 2024
0f7ee33
Merge branch 'develop' into fix-7311
kakkokari-gtyih Nov 5, 2024
e2c9043
Update os.ts
kakkokari-gtyih Nov 5, 2024
784931c
Update profile.vue
kakkokari-gtyih Nov 5, 2024
2016c8a
Update CHANGELOG.md
kakkokari-gtyih Nov 5, 2024
a631446
Update CHANGELOG.md
kakkokari-gtyih Nov 5, 2024
aee1c34
Update CHANGELOG.md
kakkokari-gtyih Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Enhance: URLプレビューの有効化・無効化を設定できるように #13569
- Enhance: アンテナでBotによるノートを除外できるように
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
- Fix: センシティブな画像をアイコン・バナーに指定できないように
- Fix: Play作成時に設定した公開範囲が機能していない問題を修正

### Client
Expand All @@ -25,6 +26,7 @@
- Enhance: ノートについているリアクションの「もっと!」から、リアクションの一覧を表示できるように
- Enhance: リプライにて引用がある場合テキストが空でもノートできるように
- 引用したいノートのURLをコピーしリプライ投稿画面にペーストして添付することで達成できます
- Enhance: アイコン画像・バナー画像を外せるように
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
- Fix: 周年の実績が閏年を考慮しない問題を修正
- Fix: ローカルURLのプレビューポップアップが左上に表示される
Expand Down
9 changes: 9 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4936,6 +4936,15 @@ export interface Locale extends ILocale {
* 動画・音声の再生にブラウザのUIを使用する
*/
"useNativeUIForVideoAudioPlayer": string;
/**
* センシティブなメディアは選択できません
*/
"cannotSelectSensitiveMedia": string;
/**
* 自分でセンシティブ設定を行っていないのにこのエラーが出ている場合、自動判定によりセンシティブなメディアとされている可能性があります。
* サーバーの規則に照らして不要な場合は、ファイルのセンシティブ設定を解除してもう一度お試しください。
*/
"cannotSelectSensitiveMediaDescription": string;
"_bubbleGame": {
/**
* 遊び方
Expand Down
2 changes: 2 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1230,6 +1230,8 @@ useTotp: "ワンタイムパスワードを使う"
useBackupCode: "バックアップコードを使う"
launchApp: "アプリを起動"
useNativeUIForVideoAudioPlayer: "動画・音声の再生にブラウザのUIを使用する"
cannotSelectSensitiveMedia: "センシティブなメディアは選択できません"
cannotSelectSensitiveMediaDescription: "自分でセンシティブ設定を行っていないのにこのエラーが出ている場合、自動判定によりセンシティブなメディアとされている可能性があります。\nサーバーの規則に照らして不要な場合は、ファイルのセンシティブ設定を解除してもう一度お試しください。"

_bubbleGame:
howToPlay: "遊び方"
Expand Down
14 changes: 14 additions & 0 deletions packages/backend/src/server/api/endpoints/i/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ export const meta = {
id: '75aedb19-2afd-4e6d-87fc-67941256fa60',
},

avatarIsSensitive: {
message: 'The file specified as an avatar is marked as sensitive.',
code: 'AVATAR_IS_SENSITIVE',
id: '71bb5e53-4742-4609-b465-36081e131208',
},

bannerIsSensitive: {
message: 'The file specified as a banner is marked as sensitive.',
code: 'BANNER_IS_SENSITIVE',
id: 'e148b34c-9f33-4300-93e0-7817008fb366',
},

noSuchPage: {
message: 'No such page.',
code: 'NO_SUCH_PAGE',
Expand Down Expand Up @@ -326,6 +338,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-

if (avatar == null || avatar.userId !== user.id) throw new ApiError(meta.errors.noSuchAvatar);
if (!avatar.type.startsWith('image/')) throw new ApiError(meta.errors.avatarNotAnImage);
if (avatar.isSensitive) throw new ApiError(meta.errors.avatarIsSensitive);

updates.avatarId = avatar.id;
updates.avatarUrl = this.driveFileEntityService.getPublicUrl(avatar, 'avatar');
Expand All @@ -341,6 +354,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-

if (banner == null || banner.userId !== user.id) throw new ApiError(meta.errors.noSuchBanner);
if (!banner.type.startsWith('image/')) throw new ApiError(meta.errors.bannerNotAnImage);
if (banner.isSensitive) throw new ApiError(meta.errors.bannerIsSensitive);

updates.bannerId = banner.id;
updates.bannerUrl = this.driveFileEntityService.getPublicUrl(banner);
Expand Down
25 changes: 24 additions & 1 deletion packages/frontend/src/components/MkDrive.file.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only

<template>
<div
:class="[$style.root, { [$style.isSelected]: isSelected }]"
:class="[$style.root, { [$style.isSelected]: isSelected, [$style.isDisabled]: isDisabled }]"
draggable="true"
:title="title"
@click="onClick"
Expand Down Expand Up @@ -55,9 +55,11 @@ const props = withDefaults(defineProps<{
file: Misskey.entities.DriveFile;
folder: Misskey.entities.DriveFolder | null;
isSelected?: boolean;
isDisabled?: boolean;
selectMode?: boolean;
}>(), {
isSelected: false,
isDisabled: false,
selectMode: false,
});

Expand All @@ -72,6 +74,8 @@ const isDragging = ref(false);
const title = computed(() => `${props.file.name}\n${props.file.type} ${bytes(props.file.size)}`);

function onClick(ev: MouseEvent) {
if (props.isDisabled) return;

if (props.selectMode) {
emit('chosen', props.file);
} else {
Expand All @@ -88,6 +92,8 @@ function onContextmenu(ev: MouseEvent) {
}

function onDragstart(ev: DragEvent) {
if (props.isDisabled) return;

if (ev.dataTransfer) {
ev.dataTransfer.effectAllowed = 'move';
ev.dataTransfer.setData(_DATA_TRANSFER_DRIVE_FILE_, JSON.stringify(props.file));
Expand Down Expand Up @@ -173,6 +179,23 @@ function onDragend() {
color: #fff;
}
}

&.isDisabled {
cursor: not-allowed;

.thumbnail {
opacity: 0.5;
}

.name {
opacity: 0.5;
}

&:hover,
&:active {
background: none;
}
}
}

.label {
Expand Down
3 changes: 3 additions & 0 deletions packages/frontend/src/components/MkDrive.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:folder="folder"
:selectMode="select === 'file'"
:isSelected="selectedFiles.some(x => x.id === file.id)"
:isDisabled="excludeSensitive && file.isSensitive"
@chosen="chooseFile"
@dragstart="isDragSource = true"
@dragend="isDragSource = false"
Expand Down Expand Up @@ -114,9 +115,11 @@ const props = withDefaults(defineProps<{
initialFolder?: Misskey.entities.DriveFolder;
type?: string;
multiple?: boolean;
excludeSensitive?: boolean;
select?: 'file' | 'folder' | null;
}>(), {
multiple: false,
excludeSensitive: false,
select: null,
});

Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/src/components/MkDriveSelectDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
{{ multiple ? ((type === 'file') ? i18n.ts.selectFiles : i18n.ts.selectFolders) : ((type === 'file') ? i18n.ts.selectFile : i18n.ts.selectFolder) }}
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span>
</template>
<XDrive :multiple="multiple" :select="type" @changeSelection="onChangeSelection" @selected="ok()"/>
<XDrive :multiple="multiple" :excludeSensitive="excludeSensitive" :select="type" @changeSelection="onChangeSelection" @selected="ok()"/>
</MkModalWindow>
</template>

Expand All @@ -34,6 +34,7 @@ import { i18n } from '@/i18n.js';
withDefaults(defineProps<{
type?: 'file' | 'folder';
multiple: boolean;
excludeSensitive: boolean;
}>(), {
type: 'file',
});
Expand Down
6 changes: 4 additions & 2 deletions packages/frontend/src/os.ts
Original file line number Diff line number Diff line change
Expand Up @@ -541,11 +541,12 @@ export async function selectUser(opts: { includeSelf?: boolean; localOnly?: bool
});
}

export async function selectDriveFile(multiple: boolean): Promise<Misskey.entities.DriveFile[]> {
export async function selectDriveFile(multiple: boolean, excludeSensitive: boolean): Promise<Misskey.entities.DriveFile[]> {
return new Promise(resolve => {
popup(defineAsyncComponent(() => import('@/components/MkDriveSelectDialog.vue')), {
type: 'file',
multiple,
excludeSensitive,
}, {
done: files => {
if (files) {
Expand All @@ -556,11 +557,12 @@ export async function selectDriveFile(multiple: boolean): Promise<Misskey.entiti
});
}

export async function selectDriveFolder(multiple: boolean): Promise<Misskey.entities.DriveFolder[]> {
export async function selectDriveFolder(multiple: boolean, excludeSensitive: boolean): Promise<Misskey.entities.DriveFolder[]> {
return new Promise(resolve => {
popup(defineAsyncComponent(() => import('@/components/MkDriveSelectDialog.vue')), {
type: 'folder',
multiple,
excludeSensitive,
}, {
done: folders => {
if (folders) {
Expand Down
36 changes: 34 additions & 2 deletions packages/frontend/src/pages/settings/profile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,23 @@ function save() {
}

function changeAvatar(ev) {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.avatar).then(async (file) => {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.avatar, true, $i.avatarId ? [
{ type: 'divider' },
{
type: 'button',
text: i18n.ts.detach,
icon: 'ti ti-circle-x',
action: () => {
os.apiWithDialog('i/update', {
avatarId: null,
}).then(() => {
$i.avatarId = null;
$i.avatarUrl = null;
globalEvents.emit('requestClearPageCache');
});
},
},
] : undefined).then(async (file) => {
let originalOrCropped = file;

const { canceled } = await os.confirm({
Expand All @@ -231,7 +247,23 @@ function changeAvatar(ev) {
}

function changeBanner(ev) {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.banner).then(async (file) => {
selectFile(ev.currentTarget ?? ev.target, i18n.ts.banner, true, $i.bannerId ? [
{ type: 'divider' },
{
type: 'button',
text: i18n.ts.detach,
icon: 'ti ti-circle-x',
action: () => {
os.apiWithDialog('i/update', {
bannerId: null,
}).then(() => {
$i.bannerId = null;
$i.bannerUrl = null;
globalEvents.emit('requestClearPageCache');
});
},
},
] : undefined).then(async (file) => {
let originalOrCropped = file;

const { canceled } = await os.confirm({
Expand Down
36 changes: 25 additions & 11 deletions packages/frontend/src/scripts/select-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import { ref } from 'vue';
import * as Misskey from 'misskey-js';
import type { MenuItem } from '@/types/menu.js';
import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { useStream } from '@/stream.js';
Expand Down Expand Up @@ -39,9 +40,9 @@ export function chooseFileFromPc(multiple: boolean, keepOriginal = false): Promi
});
}

export function chooseFileFromDrive(multiple: boolean): Promise<Misskey.entities.DriveFile[]> {
export function chooseFileFromDrive(multiple: boolean, excludeSensitive: boolean): Promise<Misskey.entities.DriveFile[]> {
return new Promise((res, rej) => {
os.selectDriveFile(multiple).then(files => {
os.selectDriveFile(multiple, excludeSensitive).then(files => {
res(files);
});
});
Expand Down Expand Up @@ -80,10 +81,23 @@ export function chooseFileFromUrl(): Promise<Misskey.entities.DriveFile> {
});
}

function select(src: any, label: string | null, multiple: boolean): Promise<Misskey.entities.DriveFile[]> {
function select(src: any, label: string | null, multiple: boolean, excludeSensitive: boolean, additionalMenu: MenuItem[] = []): Promise<Misskey.entities.DriveFile[]> {
syuilo marked this conversation as resolved.
Show resolved Hide resolved
return new Promise((res, rej) => {
const keepOriginal = ref(defaultStore.state.keepOriginalUploading);

function _resolve(files: Misskey.entities.DriveFile[]) {
if (excludeSensitive && files.some(file => file.isSensitive)) {
os.alert({
title: i18n.ts.cannotSelectSensitiveMedia,
text: i18n.ts.cannotSelectSensitiveMediaDescription,
});
rej(new Error('Sensitive media is selected'));
return;
}

res(files);
}

os.popupMenu([label ? {
text: label,
type: 'label',
Expand All @@ -94,23 +108,23 @@ function select(src: any, label: string | null, multiple: boolean): Promise<Miss
}, {
text: i18n.ts.upload,
icon: 'ti ti-upload',
action: () => chooseFileFromPc(multiple, keepOriginal.value).then(files => res(files)),
action: () => chooseFileFromPc(multiple, keepOriginal.value).then(files => _resolve(files)),
}, {
text: i18n.ts.fromDrive,
icon: 'ti ti-cloud',
action: () => chooseFileFromDrive(multiple).then(files => res(files)),
action: () => chooseFileFromDrive(multiple, excludeSensitive).then(files => _resolve(files)),
}, {
text: i18n.ts.fromUrl,
icon: 'ti ti-link',
action: () => chooseFileFromUrl().then(file => res([file])),
}], src);
action: () => chooseFileFromUrl().then(file => _resolve([file])),
}, ...additionalMenu], src);
});
}

export function selectFile(src: any, label: string | null = null): Promise<Misskey.entities.DriveFile> {
return select(src, label, false).then(files => files[0]);
export function selectFile(src: any, label: string | null = null, excludeSensitive = false, additionalMenu?: MenuItem[]): Promise<Misskey.entities.DriveFile> {
return select(src, label, false, excludeSensitive, additionalMenu).then(files => files[0]);
}

export function selectFiles(src: any, label: string | null = null): Promise<Misskey.entities.DriveFile[]> {
return select(src, label, true);
export function selectFiles(src: any, label: string | null = null, excludeSensitive = false, additionalMenu?: MenuItem[]): Promise<Misskey.entities.DriveFile[]> {
return select(src, label, true, excludeSensitive, additionalMenu);
}
Loading