From 97edaca3510572956abb98ac099cea3c1786d9fb Mon Sep 17 00:00:00 2001 From: Johann150 Date: Tue, 8 Mar 2022 21:16:51 +0100 Subject: [PATCH 1/9] getNote checks visibility Raise an error When a note is not visible to the requesting user. --- packages/backend/src/server/api/common/getters.ts | 14 +++++++++++--- .../src/server/api/endpoints/admin/promo/create.ts | 6 +++--- .../src/server/api/endpoints/clips/add-note.ts | 6 +++--- .../src/server/api/endpoints/notes/clips.ts | 6 +++--- .../src/server/api/endpoints/notes/conversation.ts | 6 +++--- .../src/server/api/endpoints/notes/delete.ts | 6 +++--- .../server/api/endpoints/notes/favorites/create.ts | 6 +++--- .../server/api/endpoints/notes/favorites/delete.ts | 6 +++--- .../src/server/api/endpoints/notes/polls/vote.ts | 6 +++--- .../src/server/api/endpoints/notes/reactions.ts | 8 ++++++++ .../server/api/endpoints/notes/reactions/create.ts | 6 +++--- .../server/api/endpoints/notes/reactions/delete.ts | 6 +++--- .../src/server/api/endpoints/notes/renotes.ts | 6 +++--- .../backend/src/server/api/endpoints/notes/show.ts | 6 +++--- .../api/endpoints/notes/thread-muting/create.ts | 6 +++--- .../api/endpoints/notes/thread-muting/delete.ts | 6 +++--- .../src/server/api/endpoints/notes/translate.ts | 10 +++------- .../src/server/api/endpoints/notes/unrenote.ts | 6 +++--- .../server/api/endpoints/notes/watching/create.ts | 6 +++--- .../server/api/endpoints/notes/watching/delete.ts | 6 +++--- .../backend/src/server/api/endpoints/promo/read.ts | 6 +++--- 21 files changed, 76 insertions(+), 64 deletions(-) diff --git a/packages/backend/src/server/api/common/getters.ts b/packages/backend/src/server/api/common/getters.ts index 783ea9ef7..c5a1e765e 100644 --- a/packages/backend/src/server/api/common/getters.ts +++ b/packages/backend/src/server/api/common/getters.ts @@ -2,12 +2,20 @@ import { IdentifiableError } from '@/misc/identifiable-error.js'; import { User } from '@/models/entities/user.js'; import { Note } from '@/models/entities/note.js'; import { Notes, Users } from '@/models/index.js'; +import { generateVisibilityQuery } from './generate-visibility-query.js'; /** - * Get note for API processing + * Get note for API processing, taking into account visibility. */ -export async function getNote(noteId: Note['id']) { - const note = await Notes.findOneBy({ id: noteId }); +export async function getNote(noteId: Note['id'], me: { id: User['id'] } | null) { + const query = Notes.createQueryBuilder('note') + .where("note.id = :id", { + id: noteId, + }); + + generateVisibilityQuery(query, me); + + const note = await query.getOne(); if (note == null) { throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.'); diff --git a/packages/backend/src/server/api/endpoints/admin/promo/create.ts b/packages/backend/src/server/api/endpoints/admin/promo/create.ts index 68a17867b..b5142fcf0 100644 --- a/packages/backend/src/server/api/endpoints/admin/promo/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/promo/create.ts @@ -35,9 +35,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); const exist = await PromoNotes.findOneBy({ noteId: note.id }); diff --git a/packages/backend/src/server/api/endpoints/clips/add-note.ts b/packages/backend/src/server/api/endpoints/clips/add-note.ts index 5d72f5c1b..91baa8eb7 100644 --- a/packages/backend/src/server/api/endpoints/clips/add-note.ts +++ b/packages/backend/src/server/api/endpoints/clips/add-note.ts @@ -52,9 +52,9 @@ export default define(meta, paramDef, async (ps, user) => { throw new ApiError(meta.errors.noSuchClip); } - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); const exist = await ClipNotes.findOneBy({ diff --git a/packages/backend/src/server/api/endpoints/notes/clips.ts b/packages/backend/src/server/api/endpoints/notes/clips.ts index e79f8563e..976c11260 100644 --- a/packages/backend/src/server/api/endpoints/notes/clips.ts +++ b/packages/backend/src/server/api/endpoints/notes/clips.ts @@ -38,9 +38,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, me) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, me).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); const clipNotes = await ClipNotes.findBy({ diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts index b731d1824..f939d7a6a 100644 --- a/packages/backend/src/server/api/endpoints/notes/conversation.ts +++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts @@ -40,9 +40,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); const conversation: Note[] = []; diff --git a/packages/backend/src/server/api/endpoints/notes/delete.ts b/packages/backend/src/server/api/endpoints/notes/delete.ts index 9c3ca136c..34d23448e 100644 --- a/packages/backend/src/server/api/endpoints/notes/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/delete.ts @@ -43,9 +43,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); if ((!user.isAdmin && !user.isModerator) && (note.userId !== user.id)) { diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts index 097371a42..b5dd88a4e 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/create.ts @@ -37,9 +37,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Get favoritee - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); // if already favorited diff --git a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts index 82ef4fa19..3f4d39254 100644 --- a/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/favorites/delete.ts @@ -36,9 +36,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { // Get favoritee - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); // if already favorited diff --git a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts index 45a832cbd..6dd5ddf9e 100644 --- a/packages/backend/src/server/api/endpoints/notes/polls/vote.ts +++ b/packages/backend/src/server/api/endpoints/notes/polls/vote.ts @@ -72,9 +72,9 @@ export default define(meta, paramDef, async (ps, user) => { const createdAt = new Date(); // Get votee - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); if (!note.hasPoll) { diff --git a/packages/backend/src/server/api/endpoints/notes/reactions.ts b/packages/backend/src/server/api/endpoints/notes/reactions.ts index d56bad965..02a288138 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions.ts @@ -2,6 +2,8 @@ import { FindOptionsWhere } from 'typeorm'; import { NoteReactions } from '@/models/index.js'; import { NoteReaction } from '@/models/entities/note-reaction.js'; import define from '../../define.js'; +import { ApiError } from '../../error.js'; +import { getNote } from '../../common/getters.js'; export const meta = { tags: ['notes', 'reactions'], @@ -45,6 +47,12 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { + // check note visibility + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; + }); + const query = { noteId: ps.noteId, } as FindOptionsWhere; diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts index 07e52a926..b5c0c9d17 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/create.ts @@ -42,9 +42,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); await createReaction(user, note, ps.reaction).catch(e => { if (e.id === '51c42bb4-931a-456b-bff7-e5a8a70dd298') throw new ApiError(meta.errors.alreadyReacted); diff --git a/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts b/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts index 83fdf6959..c25d88d1b 100644 --- a/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/reactions/delete.ts @@ -42,9 +42,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); await deleteReaction(user, note).catch(e => { if (e.id === '60527ec9-b4cb-4a88-a6bd-32d3ad26817d') throw new ApiError(meta.errors.notReacted); diff --git a/packages/backend/src/server/api/endpoints/notes/renotes.ts b/packages/backend/src/server/api/endpoints/notes/renotes.ts index 28be36076..1fa9c5230 100644 --- a/packages/backend/src/server/api/endpoints/notes/renotes.ts +++ b/packages/backend/src/server/api/endpoints/notes/renotes.ts @@ -44,9 +44,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); const query = makePaginationQuery(Notes.createQueryBuilder('note'), ps.sinceId, ps.untilId) diff --git a/packages/backend/src/server/api/endpoints/notes/show.ts b/packages/backend/src/server/api/endpoints/notes/show.ts index 5cd74bd2c..0f5d0c942 100644 --- a/packages/backend/src/server/api/endpoints/notes/show.ts +++ b/packages/backend/src/server/api/endpoints/notes/show.ts @@ -33,9 +33,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); return await Notes.pack(note, user, { diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts index cf360526d..4154b5dc5 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/create.ts @@ -31,9 +31,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); const mutedNotes = await Notes.find({ diff --git a/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts b/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts index ac310d0fe..cbc0e5ce5 100644 --- a/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/thread-muting/delete.ts @@ -29,9 +29,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); await NoteThreadMutings.delete({ diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index 5e40e7106..c42bf8c65 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -38,15 +38,11 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); - if (!(await Notes.isVisibleForMe(note, user ? user.id : null))) { - return 204; // TODO: 良い感じのエラー返す - } - if (note.text == null) { return 204; } diff --git a/packages/backend/src/server/api/endpoints/notes/unrenote.ts b/packages/backend/src/server/api/endpoints/notes/unrenote.ts index 1c7fa6812..1089a9e37 100644 --- a/packages/backend/src/server/api/endpoints/notes/unrenote.ts +++ b/packages/backend/src/server/api/endpoints/notes/unrenote.ts @@ -37,9 +37,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); const renotes = await Notes.findBy({ diff --git a/packages/backend/src/server/api/endpoints/notes/watching/create.ts b/packages/backend/src/server/api/endpoints/notes/watching/create.ts index 7d482b073..6025799fa 100644 --- a/packages/backend/src/server/api/endpoints/notes/watching/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/watching/create.ts @@ -29,9 +29,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); await watch(user.id, note); diff --git a/packages/backend/src/server/api/endpoints/notes/watching/delete.ts b/packages/backend/src/server/api/endpoints/notes/watching/delete.ts index 2c1a2e5fb..7021c7970 100644 --- a/packages/backend/src/server/api/endpoints/notes/watching/delete.ts +++ b/packages/backend/src/server/api/endpoints/notes/watching/delete.ts @@ -29,9 +29,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); await unwatch(user.id, note); diff --git a/packages/backend/src/server/api/endpoints/promo/read.ts b/packages/backend/src/server/api/endpoints/promo/read.ts index c6a940c65..7c37fcbf7 100644 --- a/packages/backend/src/server/api/endpoints/promo/read.ts +++ b/packages/backend/src/server/api/endpoints/promo/read.ts @@ -28,9 +28,9 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await getNote(ps.noteId).catch(e => { - if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); - throw e; + const note = await getNote(ps.noteId, user).catch(err => { + if (err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchNote); + throw err; }); const exist = await PromoReads.findOneBy({ From 3c6d9cc8ab61740fb2497a9ee88d8aa97e05b50b Mon Sep 17 00:00:00 2001 From: Johann150 Date: Tue, 8 Mar 2022 21:17:58 +0100 Subject: [PATCH 2/9] use getNote instead of Notes.find If a note is not visible to the requesting user, an error will be raised. --- .../api/endpoints/notes/conversation.ts | 6 +++++- .../src/server/api/endpoints/notes/create.ts | 19 +++++++++++-------- .../src/server/api/endpoints/notes/state.ts | 3 ++- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/notes/conversation.ts b/packages/backend/src/server/api/endpoints/notes/conversation.ts index f939d7a6a..7ee052001 100644 --- a/packages/backend/src/server/api/endpoints/notes/conversation.ts +++ b/packages/backend/src/server/api/endpoints/notes/conversation.ts @@ -50,7 +50,11 @@ export default define(meta, paramDef, async (ps, user) => { async function get(id: any) { i++; - const p = await Notes.findOneBy({ id }); + const p = await getNote(id, user).catch(e => { + if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') return null; + throw e; + }); + if (p == null) return; if (i > ps.offset!) { diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts index aeac02d39..82540f96b 100644 --- a/packages/backend/src/server/api/endpoints/notes/create.ts +++ b/packages/backend/src/server/api/endpoints/notes/create.ts @@ -10,6 +10,7 @@ import { noteVisibilities } from '../../../../types.js'; import { ApiError } from '../../error.js'; import define from '../../define.js'; import { HOUR } from '@/const.js'; +import { getNote } from '../../common/getters.js'; export const meta = { tags: ['notes'], @@ -185,11 +186,12 @@ export default define(meta, paramDef, async (ps, user) => { let renote: Note | null = null; if (ps.renoteId != null) { // Fetch renote to note - renote = await Notes.findOneBy({ id: ps.renoteId }); + renote = await getNote(ps.renoteId, user).catch(e => { + if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchRenoteTarget); + throw e; + }); - if (renote == null) { - throw new ApiError(meta.errors.noSuchRenoteTarget); - } else if (renote.renoteId && !renote.text && !renote.fileIds && !renote.hasPoll) { + if (renote.renoteId && !renote.text && !renote.fileIds && !renote.hasPoll) { throw new ApiError(meta.errors.cannotReRenote); } @@ -208,11 +210,12 @@ export default define(meta, paramDef, async (ps, user) => { let reply: Note | null = null; if (ps.replyId != null) { // Fetch reply - reply = await Notes.findOneBy({ id: ps.replyId }); + reply = await getNote(ps.replyId, user).catch(e => { + if (e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') throw new ApiError(meta.errors.noSuchReplyTarget); + throw e; + }); - if (reply == null) { - throw new ApiError(meta.errors.noSuchReplyTarget); - } else if (reply.renoteId && !reply.text && !reply.fileIds && !reply.hasPoll) { + if (reply.renoteId && !reply.text && !reply.fileIds && !reply.hasPoll) { throw new ApiError(meta.errors.cannotReplyToPureRenote); } diff --git a/packages/backend/src/server/api/endpoints/notes/state.ts b/packages/backend/src/server/api/endpoints/notes/state.ts index 01afa5add..67579b2a6 100644 --- a/packages/backend/src/server/api/endpoints/notes/state.ts +++ b/packages/backend/src/server/api/endpoints/notes/state.ts @@ -1,4 +1,5 @@ import { NoteFavorites, Notes, NoteThreadMutings, NoteWatchings } from '@/models/index.js'; +import { getNote } from '../../common/getters.js'; import define from '../../define.js'; export const meta = { @@ -36,7 +37,7 @@ export const paramDef = { // eslint-disable-next-line import/no-default-export export default define(meta, paramDef, async (ps, user) => { - const note = await Notes.findOneByOrFail({ id: ps.noteId }); + const note = await getNote(ps.noteId, user); const [favorite, watching, threadMuting] = await Promise.all([ NoteFavorites.count({ From 2486eff74710b2b7a52058cfee8cf0716eba9e30 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Fri, 22 Apr 2022 13:35:02 +0200 Subject: [PATCH 3/9] packing notes not visible to user raises an error Instead of just hiding specific fields, the entire note is hidden. This means that metadata of the note such as who is the author, when was it sent are completely hidden. --- .../backend/src/models/repositories/note.ts | 77 +++---------------- 1 file changed, 9 insertions(+), 68 deletions(-) diff --git a/packages/backend/src/models/repositories/note.ts b/packages/backend/src/models/repositories/note.ts index 3fefab031..e697b4cea 100644 --- a/packages/backend/src/models/repositories/note.ts +++ b/packages/backend/src/models/repositories/note.ts @@ -10,66 +10,7 @@ import { convertLegacyReaction, convertLegacyReactions, decodeReaction } from '@ import { NoteReaction } from '@/models/entities/note-reaction.js'; import { aggregateNoteEmojis, populateEmojis, prefetchEmojis } from '@/misc/populate-emojis.js'; import { db } from '@/db/postgre.js'; - -async function hideNote(packedNote: Packed<'Note'>, meId: User['id'] | null) { - // TODO: isVisibleForMe を使うようにしても良さそう(型違うけど) - let hide = false; - - // visibility が specified かつ自分が指定されていなかったら非表示 - if (packedNote.visibility === 'specified') { - if (meId == null) { - hide = true; - } else if (meId === packedNote.userId) { - hide = false; - } else { - // 指定されているかどうか - const specified = packedNote.visibleUserIds!.some((id: any) => meId === id); - - if (specified) { - hide = false; - } else { - hide = true; - } - } - } - - // visibility が followers かつ自分が投稿者のフォロワーでなかったら非表示 - if (packedNote.visibility === 'followers') { - if (meId == null) { - hide = true; - } else if (meId === packedNote.userId) { - hide = false; - } else if (packedNote.reply && (meId === packedNote.reply.userId)) { - // 自分の投稿に対するリプライ - hide = false; - } else if (packedNote.mentions && packedNote.mentions.some(id => meId === id)) { - // 自分へのメンション - hide = false; - } else { - // フォロワーかどうか - const following = await Followings.findOneBy({ - followeeId: packedNote.userId, - followerId: meId, - }); - - if (following == null) { - hide = true; - } else { - hide = false; - } - } - } - - if (hide) { - packedNote.visibleUserIds = undefined; - packedNote.fileIds = []; - packedNote.files = []; - packedNote.text = null; - packedNote.poll = undefined; - packedNote.cw = null; - packedNote.isHidden = true; - } -} +import { IdentifiableError } from '@/misc/identifiable-error.js'; async function populatePoll(note: Note, meId: User['id'] | null) { const poll = await Polls.findOneByOrFail({ noteId: note.id }); @@ -193,7 +134,6 @@ export const NoteRepository = db.getRepository(Note).extend({ me?: { id: User['id'] } | null | undefined, options?: { detail?: boolean; - skipHide?: boolean; _hint_?: { myReactions: Map; }; @@ -201,13 +141,16 @@ export const NoteRepository = db.getRepository(Note).extend({ ): Promise> { const opts = Object.assign({ detail: true, - skipHide: false, }, options); const meId = me ? me.id : null; const note = typeof src === 'object' ? src : await this.findOneByOrFail({ id: src }); const host = note.userHost; + if (!await this.isVisibleForMe(note, meId)) { + throw new IdentifiableError('9725d0ce-ba28-4dde-95a7-2cbb2c15de24', 'No such note.'); + } + let text = note.text; if (note.name && (note.url ?? note.uri)) { @@ -282,10 +225,6 @@ export const NoteRepository = db.getRepository(Note).extend({ packed.text = mfm.toString(tokens); } - if (!opts.skipHide) { - await hideNote(packed, meId); - } - return packed; }, @@ -294,7 +233,6 @@ export const NoteRepository = db.getRepository(Note).extend({ me?: { id: User['id'] } | null | undefined, options?: { detail?: boolean; - skipHide?: boolean; } ) { if (notes.length === 0) return []; @@ -316,11 +254,14 @@ export const NoteRepository = db.getRepository(Note).extend({ await prefetchEmojis(aggregateNoteEmojis(notes)); - return await Promise.all(notes.map(n => this.pack(n, me, { + const promises = await Promise.allSettled(notes.map(n => this.pack(n, me, { ...options, _hint_: { myReactions: myReactionsMap, }, }))); + + // filter out rejected promises, only keep fulfilled values + return promises.flatMap(result => result.status === 'fulfilled' ? [result.value] : []); }, }); From c6192ac95a21590276e53ba2bb4f26af0026e2f6 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Tue, 24 May 2022 09:48:33 +0200 Subject: [PATCH 4/9] fix: handle exception in note favorites --- packages/backend/src/models/repositories/note-favorite.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/models/repositories/note-favorite.ts b/packages/backend/src/models/repositories/note-favorite.ts index 9bd97f988..1d5702053 100644 --- a/packages/backend/src/models/repositories/note-favorite.ts +++ b/packages/backend/src/models/repositories/note-favorite.ts @@ -14,6 +14,7 @@ export const NoteFavoriteRepository = db.getRepository(NoteFavorite).extend({ id: favorite.id, createdAt: favorite.createdAt.toISOString(), noteId: favorite.noteId, + // may throw error note: await Notes.pack(favorite.note || favorite.noteId, me), }; }, @@ -22,6 +23,7 @@ export const NoteFavoriteRepository = db.getRepository(NoteFavorite).extend({ favorites: any[], me: { id: User['id'] } ) { - return Promise.all(favorites.map(x => this.pack(x, me))); + return Promise.allSettled(favorites.map(x => this.pack(x, me))) + .then(promises => promises.flatMap(result => result.status === 'fulfilled' ? [result.value] : [])); }, }); From cfa371b52b980991946ce0f3353479f0cc26dcc6 Mon Sep 17 00:00:00 2001 From: Johann150 Date: Tue, 24 May 2022 10:00:46 +0200 Subject: [PATCH 5/9] refactor: remove note re-packing in streaming API Instead of packing the note for public user before passing it to streams, the note is now either packed for the user the respective stream belongs to (`mainStream`) or not packed at all and then packed later (`notesStream`). Because this is a new common task between different channels, a shared implementation of packing a note from notesStream is created. This implementation will simply skip a note if it is not visible to the user that the channel belongs to. --- .../backend/src/server/api/stream/channel.ts | 30 +++++++++++++++++++ .../src/server/api/stream/channels/antenna.ts | 24 ++++++++++----- .../src/server/api/stream/channels/channel.ts | 17 ++--------- .../api/stream/channels/global-timeline.ts | 16 +--------- .../src/server/api/stream/channels/hashtag.ts | 10 +------ .../api/stream/channels/home-timeline.ts | 26 +--------------- .../api/stream/channels/hybrid-timeline.ts | 26 +--------------- .../api/stream/channels/local-timeline.ts | 16 +--------- .../src/server/api/stream/channels/main.ts | 15 ---------- .../server/api/stream/channels/user-list.ts | 27 ++--------------- .../backend/src/server/api/stream/types.ts | 2 +- packages/backend/src/services/note/create.ts | 29 +++++++++--------- packages/backend/src/services/stream.ts | 3 +- 13 files changed, 72 insertions(+), 169 deletions(-) diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts index d2cc5122d..c9cffd2d3 100644 --- a/packages/backend/src/server/api/stream/channel.ts +++ b/packages/backend/src/server/api/stream/channel.ts @@ -1,4 +1,8 @@ import Connection from '.'; +import { Note } from '@/models/entities/note.js'; +import { Notes } from '@/models/index.js'; +import { Packed } from '@/misc/schema.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; /** * Stream channel @@ -54,6 +58,32 @@ export default abstract class Channel { }); } + protected withPackedNote(callback: (note: Packed<'Note'>) => void): (Note) => void { + return async (note: Note) => { + try { + // because `note` was previously JSON.stringify'ed, the fields that + // were objects before are now strings and have to be restored or + // removed from the object + note.createdAt = new Date(note.createdAt); + delete note.reply; + delete note.renote; + delete note.user; + delete note.channel; + + const packed = await Notes.pack(note, this.user, { detail: true }); + + callback(packed); + } catch (err) { + if (err instanceof IdentifiableError && err.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') { + // skip: note not visible to user + return; + } else { + throw err; + } + } + }; + } + public abstract init(params: any): void; public dispose?(): void; public onMessage?(type: string, body: any): void; diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts index d28320d92..a9a98e904 100644 --- a/packages/backend/src/server/api/stream/channels/antenna.ts +++ b/packages/backend/src/server/api/stream/channels/antenna.ts @@ -2,6 +2,7 @@ import Channel from '../channel.js'; import { Notes } from '@/models/index.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { StreamMessages } from '../types.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; export default class extends Channel { public readonly chName = 'antenna'; @@ -23,16 +24,25 @@ export default class extends Channel { private async onEvent(data: StreamMessages['antenna']['payload']) { if (data.type === 'note') { - const note = await Notes.pack(data.body.id, this.user, { detail: true }); + try { + const note = await Notes.pack(data.body.id, this.user, { detail: true }); - // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する - if (isUserRelated(note, this.muting)) return; - // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する - if (isUserRelated(note, this.blocking)) return; + // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する + if (isUserRelated(note, this.muting)) return; + // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する + if (isUserRelated(note, this.blocking)) return; - this.connection.cacheNote(note); + this.connection.cacheNote(note); - this.send('note', note); + this.send('note', note); + } catch (e) { + if (e instanceof IdentifiableError && e.id === '9725d0ce-ba28-4dde-95a7-2cbb2c15de24') { + // skip: note not visible to user + return; + } else { + throw e; + } + } } else { this.send(data.type, data.body); } diff --git a/packages/backend/src/server/api/stream/channels/channel.ts b/packages/backend/src/server/api/stream/channels/channel.ts index 5148cfd05..5a26ea7bf 100644 --- a/packages/backend/src/server/api/stream/channels/channel.ts +++ b/packages/backend/src/server/api/stream/channels/channel.ts @@ -1,5 +1,5 @@ import Channel from '../channel.js'; -import { Notes, Users } from '@/models/index.js'; +import { Users } from '@/models/index.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { User } from '@/models/entities/user.js'; import { StreamMessages } from '../types.js'; @@ -15,7 +15,7 @@ export default class extends Channel { constructor(id: string, connection: Channel['connection']) { super(id, connection); - this.onNote = this.onNote.bind(this); + this.onNote = this.withPackedNote(this.onNote.bind(this)); } public async init(params: any) { @@ -30,19 +30,6 @@ export default class extends Channel { private async onNote(note: Packed<'Note'>) { if (note.channelId !== this.channelId) return; - // リプライなら再pack - if (note.replyId != null) { - note.reply = await Notes.pack(note.replyId, this.user, { - detail: true, - }); - } - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await Notes.pack(note.renoteId, this.user, { - detail: true, - }); - } - // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isUserRelated(note, this.muting)) return; // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する diff --git a/packages/backend/src/server/api/stream/channels/global-timeline.ts b/packages/backend/src/server/api/stream/channels/global-timeline.ts index 5b4ae850e..391851ecd 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -1,6 +1,5 @@ import Channel from '../channel.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Notes } from '@/models/index.js'; import { checkWordMute } from '@/misc/check-word-mute.js'; import { isInstanceMuted } from '@/misc/is-instance-muted.js'; import { isUserRelated } from '@/misc/is-user-related.js'; @@ -13,7 +12,7 @@ export default class extends Channel { constructor(id: string, connection: Channel['connection']) { super(id, connection); - this.onNote = this.onNote.bind(this); + this.onNote = this.withPackedNote(this.onNote.bind(this)); } public async init(params: any) { @@ -30,19 +29,6 @@ export default class extends Channel { if (note.visibility !== 'public') return; if (note.channelId != null) return; - // リプライなら再pack - if (note.replyId != null) { - note.reply = await Notes.pack(note.replyId, this.user, { - detail: true, - }); - } - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await Notes.pack(note.renoteId, this.user, { - detail: true, - }); - } - // 関係ない返信は除外 if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; diff --git a/packages/backend/src/server/api/stream/channels/hashtag.ts b/packages/backend/src/server/api/stream/channels/hashtag.ts index 741db447e..f9f7ae410 100644 --- a/packages/backend/src/server/api/stream/channels/hashtag.ts +++ b/packages/backend/src/server/api/stream/channels/hashtag.ts @@ -1,5 +1,4 @@ import Channel from '../channel.js'; -import { Notes } from '@/models/index.js'; import { normalizeForSearch } from '@/misc/normalize-for-search.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { Packed } from '@/misc/schema.js'; @@ -12,7 +11,7 @@ export default class extends Channel { constructor(id: string, connection: Channel['connection']) { super(id, connection); - this.onNote = this.onNote.bind(this); + this.onNote = this.withPackedNote(this.onNote.bind(this)); } public async init(params: any) { @@ -29,13 +28,6 @@ export default class extends Channel { const matched = this.q.some(tags => tags.every(tag => noteTags.includes(normalizeForSearch(tag)))); if (!matched) return; - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await Notes.pack(note.renoteId, this.user, { - detail: true, - }); - } - // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isUserRelated(note, this.muting)) return; // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する diff --git a/packages/backend/src/server/api/stream/channels/home-timeline.ts b/packages/backend/src/server/api/stream/channels/home-timeline.ts index 075a242ef..9f5188547 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -1,5 +1,4 @@ import Channel from '../channel.js'; -import { Notes } from '@/models/index.js'; import { checkWordMute } from '@/misc/check-word-mute.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { isInstanceMuted } from '@/misc/is-instance-muted.js'; @@ -12,7 +11,7 @@ export default class extends Channel { constructor(id: string, connection: Channel['connection']) { super(id, connection); - this.onNote = this.onNote.bind(this); + this.onNote = this.withPackedNote(this.onNote.bind(this)); } public async init(params: any) { @@ -31,29 +30,6 @@ export default class extends Channel { // Ignore notes from instances the user has muted if (isInstanceMuted(note, new Set(this.userProfile?.mutedInstances ?? []))) return; - if (['followers', 'specified'].includes(note.visibility)) { - note = await Notes.pack(note.id, this.user!, { - detail: true, - }); - - if (note.isHidden) { - return; - } - } else { - // リプライなら再pack - if (note.replyId != null) { - note.reply = await Notes.pack(note.replyId, this.user!, { - detail: true, - }); - } - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await Notes.pack(note.renoteId, this.user!, { - detail: true, - }); - } - } - // 関係ない返信は除外 if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; diff --git a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts index f5dedf77c..e73136b8e 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -1,6 +1,5 @@ import Channel from '../channel.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Notes } from '@/models/index.js'; import { checkWordMute } from '@/misc/check-word-mute.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { isInstanceMuted } from '@/misc/is-instance-muted.js'; @@ -13,7 +12,7 @@ export default class extends Channel { constructor(id: string, connection: Channel['connection']) { super(id, connection); - this.onNote = this.onNote.bind(this); + this.onNote = this.withPackedNote(this.onNote.bind(this)); } public async init(params: any) { @@ -36,29 +35,6 @@ export default class extends Channel { (note.channelId != null && this.followingChannels.has(note.channelId)) )) return; - if (['followers', 'specified'].includes(note.visibility)) { - note = await Notes.pack(note.id, this.user!, { - detail: true, - }); - - if (note.isHidden) { - return; - } - } else { - // リプライなら再pack - if (note.replyId != null) { - note.reply = await Notes.pack(note.replyId, this.user!, { - detail: true, - }); - } - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await Notes.pack(note.renoteId, this.user!, { - detail: true, - }); - } - } - // Ignore notes from instances the user has muted if (isInstanceMuted(note, new Set(this.userProfile?.mutedInstances ?? []))) return; diff --git a/packages/backend/src/server/api/stream/channels/local-timeline.ts b/packages/backend/src/server/api/stream/channels/local-timeline.ts index f01f47723..729de6d4a 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -1,6 +1,5 @@ import Channel from '../channel.js'; import { fetchMeta } from '@/misc/fetch-meta.js'; -import { Notes } from '@/models/index.js'; import { checkWordMute } from '@/misc/check-word-mute.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { Packed } from '@/misc/schema.js'; @@ -12,7 +11,7 @@ export default class extends Channel { constructor(id: string, connection: Channel['connection']) { super(id, connection); - this.onNote = this.onNote.bind(this); + this.onNote = this.withPackedNote(this.onNote.bind(this)); } public async init(params: any) { @@ -30,19 +29,6 @@ export default class extends Channel { if (note.visibility !== 'public') return; if (note.channelId != null && !this.followingChannels.has(note.channelId)) return; - // リプライなら再pack - if (note.replyId != null) { - note.reply = await Notes.pack(note.replyId, this.user, { - detail: true, - }); - } - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await Notes.pack(note.renoteId, this.user, { - detail: true, - }); - } - // 関係ない返信は除外 if (note.reply && !this.user!.showTimelineReplies) { const reply = note.reply; diff --git a/packages/backend/src/server/api/stream/channels/main.ts b/packages/backend/src/server/api/stream/channels/main.ts index 9cfea0bfc..7f42263db 100644 --- a/packages/backend/src/server/api/stream/channels/main.ts +++ b/packages/backend/src/server/api/stream/channels/main.ts @@ -1,5 +1,4 @@ import Channel from '../channel.js'; -import { Notes } from '@/models/index.js'; import { isInstanceMuted, isUserFromMutedInstance } from '@/misc/is-instance-muted.js'; export default class extends Channel { @@ -16,26 +15,12 @@ export default class extends Channel { if (isUserFromMutedInstance(data.body, new Set(this.userProfile?.mutedInstances ?? []))) return; if (data.body.userId && this.muting.has(data.body.userId)) return; - if (data.body.note && data.body.note.isHidden) { - const note = await Notes.pack(data.body.note.id, this.user, { - detail: true, - }); - this.connection.cacheNote(note); - data.body.note = note; - } break; } case 'mention': { if (isInstanceMuted(data.body, new Set(this.userProfile?.mutedInstances ?? []))) return; if (this.muting.has(data.body.userId)) return; - if (data.body.isHidden) { - const note = await Notes.pack(data.body.id, this.user, { - detail: true, - }); - this.connection.cacheNote(note); - data.body = note; - } break; } } diff --git a/packages/backend/src/server/api/stream/channels/user-list.ts b/packages/backend/src/server/api/stream/channels/user-list.ts index 97ad2983c..9b2476148 100644 --- a/packages/backend/src/server/api/stream/channels/user-list.ts +++ b/packages/backend/src/server/api/stream/channels/user-list.ts @@ -1,5 +1,5 @@ import Channel from '../channel.js'; -import { Notes, UserListJoinings, UserLists } from '@/models/index.js'; +import { UserListJoinings, UserLists } from '@/models/index.js'; import { User } from '@/models/entities/user.js'; import { isUserRelated } from '@/misc/is-user-related.js'; import { Packed } from '@/misc/schema.js'; @@ -15,7 +15,7 @@ export default class extends Channel { constructor(id: string, connection: Channel['connection']) { super(id, connection); this.updateListUsers = this.updateListUsers.bind(this); - this.onNote = this.onNote.bind(this); + this.onNote = this.withPackedNote(this.onNote.bind(this)); } public async init(params: any) { @@ -51,29 +51,6 @@ export default class extends Channel { private async onNote(note: Packed<'Note'>) { if (!this.listUsers.includes(note.userId)) return; - if (['followers', 'specified'].includes(note.visibility)) { - note = await Notes.pack(note.id, this.user, { - detail: true, - }); - - if (note.isHidden) { - return; - } - } else { - // リプライなら再pack - if (note.replyId != null) { - note.reply = await Notes.pack(note.replyId, this.user, { - detail: true, - }); - } - // Renoteなら再pack - if (note.renoteId != null) { - note.renote = await Notes.pack(note.renoteId, this.user, { - detail: true, - }); - } - } - // 流れてきたNoteがミュートしているユーザーが関わるものだったら無視する if (isUserRelated(note, this.muting)) return; // 流れてきたNoteがブロックされているユーザーが関わるものだったら無視する diff --git a/packages/backend/src/server/api/stream/types.ts b/packages/backend/src/server/api/stream/types.ts index 5fdc6dfcf..b969535ca 100644 --- a/packages/backend/src/server/api/stream/types.ts +++ b/packages/backend/src/server/api/stream/types.ts @@ -243,7 +243,7 @@ export type StreamMessages = { }; notes: { name: 'notesStream'; - payload: Packed<'Note'>; + payload: Note; }; }; diff --git a/packages/backend/src/services/note/create.ts b/packages/backend/src/services/note/create.ts index 865956746..61a811d70 100644 --- a/packages/backend/src/services/note/create.ts +++ b/packages/backend/src/services/note/create.ts @@ -345,19 +345,15 @@ export default async (user: { id: User['id']; username: User['username']; host: } } - // Pack the note - const noteObj = await Notes.pack(note); + publishNotesStream(note); - publishNotesStream(noteObj); + const webhooks = await getActiveWebhooks().then(webhooks => webhooks.filter(x => x.userId === user.id && x.on.includes('note'))); - getActiveWebhooks().then(webhooks => { - webhooks = webhooks.filter(x => x.userId === user.id && x.on.includes('note')); - for (const webhook of webhooks) { - webhookDeliver(webhook, 'note', { - note: noteObj, - }); - } - }); + for (const webhook of webhooks) { + webhookDeliver(webhook, 'note', { + note: await Notes.pack(note, user), + }); + } const nm = new NotificationManager(user, note); const nmRelatedPromises = []; @@ -378,12 +374,14 @@ export default async (user: { id: User['id']; username: User['username']; host: if (!threadMuted) { nm.push(data.reply.userId, 'reply'); - publishMainStream(data.reply.userId, 'reply', noteObj); + + const packedReply = await Notes.pack(note, { id: data.reply.userId }); + publishMainStream(data.reply.userId, 'reply', packedReply); const webhooks = (await getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('reply')); for (const webhook of webhooks) { webhookDeliver(webhook, 'reply', { - note: noteObj, + note: packedReply, }); } } @@ -404,12 +402,13 @@ export default async (user: { id: User['id']; username: User['username']; host: // Publish event if ((user.id !== data.renote.userId) && data.renote.userHost === null) { - publishMainStream(data.renote.userId, 'renote', noteObj); + const packedRenote = await Notes.pack(note, { id: data.renote.userId }); + publishMainStream(data.renote.userId, 'renote', packedRenote); const webhooks = (await getActiveWebhooks()).filter(x => x.userId === data.renote!.userId && x.on.includes('renote')); for (const webhook of webhooks) { webhookDeliver(webhook, 'renote', { - note: noteObj, + note: packedRenote, }); } } diff --git a/packages/backend/src/services/stream.ts b/packages/backend/src/services/stream.ts index 9fa2b9713..4895bbace 100644 --- a/packages/backend/src/services/stream.ts +++ b/packages/backend/src/services/stream.ts @@ -22,7 +22,6 @@ import { UserListStreamTypes, UserStreamTypes, } from '@/server/api/stream/types.js'; -import { Packed } from '@/misc/schema.js'; class Publisher { private publish = (channel: StreamChannels, type: string | null, value?: any): void => { @@ -87,7 +86,7 @@ class Publisher { this.publish(`messagingIndexStream:${userId}`, type, typeof value === 'undefined' ? null : value); }; - public publishNotesStream = (note: Packed<'Note'>): void => { + public publishNotesStream = (note: Note): void => { this.publish('notesStream', null, note); }; From 128d0f0d4e2b9d8b99108ef550c4f63f6329e03d Mon Sep 17 00:00:00 2001 From: Johann150 Date: Tue, 24 May 2022 10:08:57 +0200 Subject: [PATCH 6/9] remove isHidden and its uses The `isHidden` attribute is not being set any more and is thus removed. Handling in the client is no longer necessary. --- packages/backend/src/misc/get-note-summary.ts | 4 ---- packages/backend/src/models/schema/note.ts | 4 ---- packages/client/src/components/note-detailed.vue | 1 - packages/client/src/components/note.vue | 1 - packages/client/src/components/sub-note-content.vue | 1 - packages/client/src/scripts/get-note-summary.ts | 4 ---- 6 files changed, 15 deletions(-) diff --git a/packages/backend/src/misc/get-note-summary.ts b/packages/backend/src/misc/get-note-summary.ts index 3f35ccee8..45fb50964 100644 --- a/packages/backend/src/misc/get-note-summary.ts +++ b/packages/backend/src/misc/get-note-summary.ts @@ -9,10 +9,6 @@ export const getNoteSummary = (note: Packed<'Note'>): string => { return `(❌⛔)`; } - if (note.isHidden) { - return `(⛔)`; - } - let summary = ''; // 本文 diff --git a/packages/backend/src/models/schema/note.ts b/packages/backend/src/models/schema/note.ts index cdf4b9a54..292bbb82f 100644 --- a/packages/backend/src/models/schema/note.ts +++ b/packages/backend/src/models/schema/note.ts @@ -52,10 +52,6 @@ export const packedNoteSchema = { optional: true, nullable: true, ref: 'Note', }, - isHidden: { - type: 'boolean', - optional: true, nullable: false, - }, visibility: { type: 'string', optional: false, nullable: false, diff --git a/packages/client/src/components/note-detailed.vue b/packages/client/src/components/note-detailed.vue index e7bbd70a2..072db16e3 100644 --- a/packages/client/src/components/note-detailed.vue +++ b/packages/client/src/components/note-detailed.vue @@ -54,7 +54,6 @@

- ({{ i18n.ts.private }}) RN: diff --git a/packages/client/src/components/note.vue b/packages/client/src/components/note.vue index e6a35fe41..eaead8e78 100644 --- a/packages/client/src/components/note.vue +++ b/packages/client/src/components/note.vue @@ -43,7 +43,6 @@

- ({{ i18n.ts.private }}) RN: diff --git a/packages/client/src/components/sub-note-content.vue b/packages/client/src/components/sub-note-content.vue index 25ab883f4..9ee180345 100644 --- a/packages/client/src/components/sub-note-content.vue +++ b/packages/client/src/components/sub-note-content.vue @@ -1,7 +1,6 @@