Disallow renote of direct note (#11970)

* chore: renoteに関するチェックをまとめる

* fix: ダイレクト投稿をrenoteできる

* fix(frontend): 自分のダイレクト投稿をrenoteできる

* docs(changelog): ダイレクト投稿をリノートできてしまう

* fix lint

* chore(backend): visibilityに関するエラーをApi Errorとして返す
This commit is contained in:
anatawa12 2023-10-05 17:03:50 +09:00 committed by GitHub
parent 2a7bc847b0
commit ee483f2dee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 39 additions and 13 deletions

View file

@ -27,6 +27,7 @@
- Enhance: ソフトワードミュートとハードワードミュートは統合されました - Enhance: ソフトワードミュートとハードワードミュートは統合されました
- Enhance: モデレーションログ機能の強化 - Enhance: モデレーションログ機能の強化
- Enhance: ローカリゼーションの更新 - Enhance: ローカリゼーションの更新
- Fix: ダイレクト投稿をリノートできてしまう
### Client ### Client
- Enhance: 二要素認証のバックアップコード一覧をテキストファイルでダウンロード可能に - Enhance: 二要素認証のバックアップコード一覧をテキストファイルでダウンロード可能に

View file

@ -252,19 +252,30 @@ export class NoteCreateService implements OnApplicationShutdown {
} }
} }
// Renote対象が「ホームまたは全体」以外の公開範囲ならreject if (data.renote) {
if (data.renote && data.renote.visibility !== 'public' && data.renote.visibility !== 'home' && data.renote.userId !== user.id) { switch (data.renote.visibility) {
throw new Error('Renote target is not public or home'); case 'public':
} // public noteは無条件にrenote可能
break;
case 'home':
// home noteはhome以下にrenote可能
if (data.visibility === 'public') {
data.visibility = 'home';
}
break;
case 'followers':
// 他人のfollowers noteはreject
if (data.renote.userId !== user.id) {
throw new Error('Renote target is not public or home');
}
// Renote対象がpublicではないならhomeにする // Renote対象がfollowersならfollowersにする
if (data.renote && data.renote.visibility !== 'public' && data.visibility === 'public') { data.visibility = 'followers';
data.visibility = 'home'; break;
} case 'specified':
// specified / direct noteはreject
// Renote対象がfollowersならfollowersにする throw new Error('Renote target is not public or home');
if (data.renote && data.renote.visibility === 'followers') { }
data.visibility = 'followers';
} }
// 返信対象がpublicではないならhomeにする // 返信対象がpublicではないならhomeにする

View file

@ -57,6 +57,12 @@ export const meta = {
id: 'fd4cc33e-2a37-48dd-99cc-9b806eb2031a', id: 'fd4cc33e-2a37-48dd-99cc-9b806eb2031a',
}, },
cannotRenoteDueToVisibility: {
message: 'You can not Renote due to target visibility.',
code: 'CANNOT_RENOTE_DUE_TO_VISIBILITY',
id: 'be9529e9-fe72-4de0-ae43-0b363c4938af',
},
noSuchReplyTarget: { noSuchReplyTarget: {
message: 'No such reply target.', message: 'No such reply target.',
code: 'NO_SUCH_REPLY_TARGET', code: 'NO_SUCH_REPLY_TARGET',
@ -231,6 +237,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new ApiError(meta.errors.youHaveBeenBlocked); throw new ApiError(meta.errors.youHaveBeenBlocked);
} }
} }
if (renote.visibility === 'followers' && renote.userId !== me.id) {
// 他人のfollowers noteはreject
throw new ApiError(meta.errors.cannotRenoteDueToVisibility);
} else if (renote.visibility === 'specified') {
// specified / direct noteはreject
throw new ApiError(meta.errors.cannotRenoteDueToVisibility);
}
} }
let reply: MiNote | null = null; let reply: MiNote | null = null;

View file

@ -215,7 +215,7 @@ const muted = ref($i ? checkWordMute(appearNote, $i, $i.mutedWords) : false);
const translation = ref<any>(null); const translation = ref<any>(null);
const translating = ref(false); const translating = ref(false);
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance); const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance);
const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || appearNote.userId === $i.id); const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || (appearNote.visibility === 'followers' && appearNote.userId === $i.id));
let renoteCollapsed = $ref(defaultStore.state.collapseRenotes && isRenote && (($i && ($i.id === note.userId || $i.id === appearNote.userId)) || (appearNote.myReaction != null))); let renoteCollapsed = $ref(defaultStore.state.collapseRenotes && isRenote && (($i && ($i.id === note.userId || $i.id === appearNote.userId)) || (appearNote.myReaction != null)));
const keymap = { const keymap = {