Skip to content

Commit

Permalink
Enhance(frontend): フロント側でもリアクション権限のチェックをするように (misskey-dev#13134)
Browse files Browse the repository at this point in the history
* フロント側でもリアクション権限のチェックをするように

* update CHANGELOG.md

* lint fixes

* remove unrelated diffs

* deny -> reject
denyは「(信用しないことを理由に)拒否する」という意味らしい

* allow -> accept

* EmojiSimpleにlocalOnlyを含めるように

* リアクション権限のない絵文字は打てないように(ダイアログを出すのではなく)

* regenerate type definitions

* lint fix

* remove unused locales

* remove unnecessary async
  • Loading branch information
1STEP621 authored and AyumuNekozuki committed Feb 16, 2024
1 parent 8ead1f8 commit e3f6d57
Show file tree
Hide file tree
Showing 17 changed files with 53 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
- Enhance: 絵文字編集ダイアログをモーダルではなくウィンドウで表示するように
- Enhance: リモートのユーザーはメニューから直接リモートで表示できるように
- Enhance: コードのシンタックスハイライトにテーマを適用できるように
- Enhance: リアクション権限がない場合、ハートにフォールバックするのではなく、権限がないことをダイアログで表示するように
- リモートのユーザーにローカルのみのカスタム絵文字をリアクションしようとした場合
- センシティブなリアクションを認めていないユーザーにセンシティブなカスタム絵文字をリアクションしようとした場合
- ロールが必要な絵文字をリアクションしようとした場合
- Fix: ネイティブモードの絵文字がモノクロにならないように
- Fix: v2023.12.0で追加された「モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能」が管理画面上で正しく表示されていない問題を修正
- Fix: AiScriptの`readline`関数が不正な値を返すことがある問題のv2023.12.0時点での修正がPlay以外に適用されていないのを修正
Expand Down
1 change: 1 addition & 0 deletions packages/backend/src/core/entities/EmojiEntityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export class EmojiEntityService {
category: emoji.category,
// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
url: emoji.publicUrl || emoji.originalUrl,
localOnly: emoji.localOnly ? true : undefined,
isSensitive: emoji.isSensitive ? true : undefined,
roleIdsThatCanBeUsedThisEmojiAsReaction: emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length > 0 ? emoji.roleIdsThatCanBeUsedThisEmojiAsReaction : undefined,
};
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/models/json-schema/emoji.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ export const packedEmojiSimpleSchema = {
type: 'string',
optional: false, nullable: false,
},
localOnly: {
type: 'boolean',
optional: true, nullable: false,
},
isSensitive: {
type: 'boolean',
optional: true, nullable: false,
Expand Down
4 changes: 3 additions & 1 deletion packages/frontend/src/components/MkEmojiPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ import { i18n } from '@/i18n.js';
import { defaultStore } from '@/store.js';
import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis.js';
import { $i } from '@/account.js';
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';

const props = withDefaults(defineProps<{
showPinned?: boolean;
Expand All @@ -126,6 +127,7 @@ const props = withDefaults(defineProps<{
asDrawer?: boolean;
asWindow?: boolean;
asReactionPicker?: boolean; // 今は使われてないが将来的に使いそう
targetNote?: Misskey.entities.Note;
}>(), {
showPinned: true,
});
Expand Down Expand Up @@ -340,7 +342,7 @@ watch(q, () => {
});

function filterAvailable(emoji: Misskey.entities.EmojiSimple): boolean {
return ((emoji.roleIdsThatCanBeUsedThisEmojiAsReaction == null || emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0) || ($i && $i.roles.some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction?.includes(r.id)))) ?? false;
return !props.targetNote || checkReactionPermissions($i!, props.targetNote, emoji);
}

function focus() {
Expand Down
3 changes: 3 additions & 0 deletions packages/frontend/src/components/MkEmojiPickerDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:showPinned="showPinned"
:pinnedEmojis="pinnedEmojis"
:asReactionPicker="asReactionPicker"
:targetNote="targetNote"
:asDrawer="type === 'drawer'"
:max-height="maxHeight"
@chosen="chosen"
Expand All @@ -32,6 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>

<script lang="ts" setup>
import * as Misskey from 'misskey-js';
import { shallowRef } from 'vue';
import MkModal from '@/components/MkModal.vue';
import MkEmojiPicker from '@/components/MkEmojiPicker.vue';
Expand All @@ -43,6 +45,7 @@ const props = withDefaults(defineProps<{
showPinned?: boolean;
pinnedEmojis?: string[],
asReactionPicker?: boolean;
targetNote?: Misskey.entities.Note;
choseAndClose?: boolean;
}>(), {
manualShowing: null,
Expand Down
4 changes: 3 additions & 1 deletion packages/frontend/src/components/MkEmojiPickerWindow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@ SPDX-License-Identifier: AGPL-3.0-only
:front="true"
@closed="emit('closed')"
>
<MkEmojiPicker :showPinned="showPinned" :asReactionPicker="asReactionPicker" asWindow :class="$style.picker" @chosen="chosen"/>
<MkEmojiPicker :showPinned="showPinned" :asReactionPicker="asReactionPicker" :targetNote="targetNote" asWindow :class="$style.picker" @chosen="chosen"/>
</MkWindow>
</template>

<script lang="ts" setup>
import { } from 'vue';
import * as Misskey from 'misskey-js';
import MkWindow from '@/components/MkWindow.vue';
import MkEmojiPicker from '@/components/MkEmojiPicker.vue';

withDefaults(defineProps<{
src?: HTMLElement;
showPinned?: boolean;
asReactionPicker?: boolean;
targetNote?: Misskey.entities.Note
}>(), {
showPinned: true,
});
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkNote.vue
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ function react(viaKeyboard = false): void {
}
} else {
blur();
reactionPicker.show(reactButton.value ?? null, reaction => {
reactionPicker.show(reactButton.value ?? null, note.value, reaction => {
sound.playMisskeySfx('reaction');

if (props.mock) {
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/components/MkNoteDetailed.vue
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ function react(viaKeyboard = false): void {
}
} else {
blur();
reactionPicker.show(reactButton.value ?? null, reaction => {
reactionPicker.show(reactButton.value ?? null, note.value, reaction => {
sound.playMisskeySfx('reaction');

misskeyApi('notes/reactions/create', {
Expand Down
18 changes: 13 additions & 5 deletions packages/frontend/src/components/MkReactionsViewer.reaction.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import { claimAchievement } from '@/scripts/achievements.js';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import * as sound from '@/scripts/sound.js';
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js';
import { customEmojis } from '@/custom-emojis.js';

const props = defineProps<{
reaction: string;
Expand All @@ -48,13 +50,19 @@ const emit = defineEmits<{

const buttonEl = shallowRef<HTMLElement>();

const canToggle = computed(() => !props.reaction.match(/@\w/) && $i);
const isCustomEmoji = computed(() => props.reaction.includes(':'));
const emoji = computed(() => isCustomEmoji.value ? customEmojis.value.find(emoji => emoji.name === props.reaction.replace(/:/g, '').replace(/@\./, '')) : null);

const canToggle = computed(() => {
return !props.reaction.match(/@\w/) && $i
&& (emoji.value && checkReactionPermissions($i, props.note, emoji.value))
|| !isCustomEmoji.value;
});
const canGetInfo = computed(() => !props.reaction.match(/@\w/) && props.reaction.includes(':'));

async function toggleReaction() {
if (!canToggle.value) return;

// TODO: その絵文字を使う権限があるかどうか確認

const oldReaction = props.note.myReaction;
if (oldReaction) {
const confirm = await os.confirm({
Expand Down Expand Up @@ -101,8 +109,8 @@ async function toggleReaction() {
}

async function menu(ev) {
if (!canToggle.value) return;
if (!props.reaction.includes(':')) return;
if (!canGetInfo.value) return;

os.popupMenu([{
text: i18n.ts.info,
icon: 'ti ti-info-circle',
Expand Down
2 changes: 1 addition & 1 deletion packages/frontend/src/pages/settings/emoji-picker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ const chooseEmoji = (ev: MouseEvent) => pickEmoji(pinnedEmojis, ev);
const setDefaultEmoji = () => setDefault(pinnedEmojis);

function previewReaction(ev: MouseEvent) {
reactionPicker.show(getHTMLElement(ev));
reactionPicker.show(getHTMLElement(ev), null);
}

function previewEmoji(ev: MouseEvent) {
Expand Down
8 changes: 8 additions & 0 deletions packages/frontend/src/scripts/check-reaction-permissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as Misskey from 'misskey-js';

export function checkReactionPermissions(me: Misskey.entities.MeDetailed, note: Misskey.entities.Note, emoji: Misskey.entities.EmojiSimple): boolean {
const roleIdsThatCanBeUsedThisEmojiAsReaction = emoji.roleIdsThatCanBeUsedThisEmojiAsReaction ?? [];
return !(emoji.localOnly && note.user.host !== me.host)
&& !(emoji.isSensitive && (note.reactionAcceptance === 'nonSensitiveOnly' || note.reactionAcceptance === 'nonSensitiveOnlyForLocalLikeOnlyForRemote'))
&& (roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0 || me.roles.some(role => roleIdsThatCanBeUsedThisEmojiAsReaction.includes(role.id)));
}
6 changes: 5 additions & 1 deletion packages/frontend/src/scripts/reaction-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/

import * as Misskey from 'misskey-js';
import { defineAsyncComponent, Ref, ref } from 'vue';
import { popup } from '@/os.js';
import { defaultStore } from '@/store.js';

class ReactionPicker {
private src: Ref<HTMLElement | null> = ref(null);
private manualShowing = ref(false);
private targetNote: Ref<Misskey.entities.Note | null> = ref(null);
private onChosen?: (reaction: string) => void;
private onClosed?: () => void;

Expand All @@ -23,6 +25,7 @@ class ReactionPicker {
src: this.src,
pinnedEmojis: reactionsRef,
asReactionPicker: true,
targetNote: this.targetNote,
manualShowing: this.manualShowing,
}, {
done: reaction => {
Expand All @@ -38,8 +41,9 @@ class ReactionPicker {
});
}

public show(src: HTMLElement | null, onChosen?: ReactionPicker['onChosen'], onClosed?: ReactionPicker['onClosed']) {
public show(src: HTMLElement | null, targetNote: Misskey.entities.Note | null, onChosen?: ReactionPicker['onChosen'], onClosed?: ReactionPicker['onClosed']) {
this.src.value = src;
this.targetNote.value = targetNote;
this.manualShowing.value = true;
this.onChosen = onChosen;
this.onClosed = onClosed;
Expand Down
2 changes: 1 addition & 1 deletion packages/misskey-js/src/autogen/apiClientJSDoc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* version: 2024.2.0-beta.8
* generatedAt: 2024-02-04T11:51:13.598Z
* generatedAt: 2024-02-04T16:51:09.469Z
*/

import type { SwitchCaseResponseType } from '../api.js';
Expand Down
2 changes: 1 addition & 1 deletion packages/misskey-js/src/autogen/endpoint.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* version: 2024.2.0-beta.8
* generatedAt: 2024-02-04T11:51:13.595Z
* generatedAt: 2024-02-04T16:51:09.467Z
*/

import type {
Expand Down
2 changes: 1 addition & 1 deletion packages/misskey-js/src/autogen/entities.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* version: 2024.2.0-beta.8
* generatedAt: 2024-02-04T11:51:13.593Z
* generatedAt: 2024-02-04T16:51:09.466Z
*/

import { operations } from './types.js';
Expand Down
2 changes: 1 addition & 1 deletion packages/misskey-js/src/autogen/models.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* version: 2024.2.0-beta.8
* generatedAt: 2024-02-04T11:51:13.592Z
* generatedAt: 2024-02-04T16:51:09.465Z
*/

import { components } from './types.js';
Expand Down
3 changes: 2 additions & 1 deletion packages/misskey-js/src/autogen/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

/*
* version: 2024.2.0-beta.8
* generatedAt: 2024-02-04T11:51:13.473Z
* generatedAt: 2024-02-04T16:51:09.378Z
*/

/**
Expand Down Expand Up @@ -4423,6 +4423,7 @@ export type components = {
name: string;
category: string | null;
url: string;
localOnly?: boolean;
isSensitive?: boolean;
roleIdsThatCanBeUsedThisEmojiAsReaction?: string[];
};
Expand Down

0 comments on commit e3f6d57

Please sign in to comment.