diff options
| author | Julia <julia@insertdomain.name> | 2025-05-29 00:07:38 +0000 |
|---|---|---|
| committer | Julia <julia@insertdomain.name> | 2025-05-29 00:07:38 +0000 |
| commit | 6b554c178b81f13f83a69b19d44b72b282a0c119 (patch) | |
| tree | f5537f1a56323a4dd57ba150b3cb84a2d8b5dc63 /packages/backend/src/server/api/stream | |
| parent | merge: Security fixes (!970) (diff) | |
| parent | bump version for release (diff) | |
| download | sharkey-6b554c178b81f13f83a69b19d44b72b282a0c119.tar.gz sharkey-6b554c178b81f13f83a69b19d44b72b282a0c119.tar.bz2 sharkey-6b554c178b81f13f83a69b19d44b72b282a0c119.zip | |
merge: release 2025.4.2 (!1051)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1051
Approved-by: Hazelnoot <acomputerdog@gmail.com>
Approved-by: Marie <github@yuugi.dev>
Approved-by: Julia <julia@insertdomain.name>
Diffstat (limited to 'packages/backend/src/server/api/stream')
16 files changed, 238 insertions, 106 deletions
diff --git a/packages/backend/src/server/api/stream/ChannelsService.ts b/packages/backend/src/server/api/stream/ChannelsService.ts index 83c5fcdf52..13934628a8 100644 --- a/packages/backend/src/server/api/stream/ChannelsService.ts +++ b/packages/backend/src/server/api/stream/ChannelsService.ts @@ -20,6 +20,8 @@ import { AntennaChannelService } from './channels/antenna.js'; import { DriveChannelService } from './channels/drive.js'; import { HashtagChannelService } from './channels/hashtag.js'; import { RoleTimelineChannelService } from './channels/role-timeline.js'; +import { ChatUserChannelService } from './channels/chat-user.js'; +import { ChatRoomChannelService } from './channels/chat-room.js'; import { ReversiChannelService } from './channels/reversi.js'; import { ReversiGameChannelService } from './channels/reversi-game.js'; import { type MiChannelService } from './channel.js'; @@ -42,6 +44,8 @@ export class ChannelsService { private serverStatsChannelService: ServerStatsChannelService, private queueStatsChannelService: QueueStatsChannelService, private adminChannelService: AdminChannelService, + private chatUserChannelService: ChatUserChannelService, + private chatRoomChannelService: ChatRoomChannelService, private reversiChannelService: ReversiChannelService, private reversiGameChannelService: ReversiGameChannelService, ) { @@ -65,6 +69,8 @@ export class ChannelsService { case 'serverStats': return this.serverStatsChannelService; case 'queueStats': return this.queueStatsChannelService; case 'admin': return this.adminChannelService; + case 'chatUser': return this.chatUserChannelService; + case 'chatRoom': return this.chatRoomChannelService; case 'reversi': return this.reversiChannelService; case 'reversiGame': return this.reversiGameChannelService; diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts index e98e2a2f3f..e0535a2f14 100644 --- a/packages/backend/src/server/api/stream/Connection.ts +++ b/packages/backend/src/server/api/stream/Connection.ts @@ -7,7 +7,6 @@ import * as WebSocket from 'ws'; import type { MiUser } from '@/models/User.js'; import type { MiAccessToken } from '@/models/AccessToken.js'; import type { Packed } from '@/misc/json-schema.js'; -import type { NoteReadService } from '@/core/NoteReadService.js'; import type { NotificationService } from '@/core/NotificationService.js'; import { bindThis } from '@/decorators.js'; import { CacheService } from '@/core/CacheService.js'; @@ -23,6 +22,7 @@ import type { EventEmitter } from 'events'; import type Channel from './channel.js'; const MAX_CHANNELS_PER_CONNECTION = 32; +const MAX_SUBSCRIPTIONS_PER_CONNECTION = 512; /** * Main stream connection @@ -31,12 +31,10 @@ const MAX_CHANNELS_PER_CONNECTION = 32; export default class Connection { public user?: MiUser; public token?: MiAccessToken; - private rateLimiter?: () => Promise<boolean>; private wsConnection: WebSocket.WebSocket; public subscriber: StreamEventEmitter; - private channels: Channel[] = []; - private subscribingNotes: Partial<Record<string, number>> = {}; - private cachedNotes: Packed<'Note'>[] = []; + private channels = new Map<string, Channel>(); + private subscribingNotes = new Map<string, number>(); public userProfile: MiUserProfile | null = null; public following: Record<string, Pick<MiFollowing, 'withReplies'> | undefined> = {}; public followingChannels: Set<string> = new Set(); @@ -45,13 +43,11 @@ export default class Connection { public userIdsWhoMeMutingRenotes: Set<string> = new Set(); public userMutedInstances: Set<string> = new Set(); private fetchIntervalId: NodeJS.Timeout | null = null; - private activeRateLimitRequests = 0; private closingConnection = false; private logger: Logger; constructor( private channelsService: ChannelsService, - private noteReadService: NoteReadService, private notificationService: NotificationService, private cacheService: CacheService, private channelFollowingService: ChannelFollowingService, @@ -60,11 +56,10 @@ export default class Connection { user: MiUser | null | undefined, token: MiAccessToken | null | undefined, private ip: string, - rateLimiter: () => Promise<boolean>, + private readonly rateLimiter: () => Promise<boolean>, ) { if (user) this.user = user; if (token) this.token = token; - if (rateLimiter) this.rateLimiter = rateLimiter; this.logger = loggerService.getLogger('streaming', 'coral'); } @@ -121,25 +116,13 @@ export default class Connection { if (this.closingConnection) return; - if (this.rateLimiter) { - // this 4096 should match the `max` of the `rateLimiter`, see - // StreamingApiServerService - if (this.activeRateLimitRequests <= 4096) { - this.activeRateLimitRequests++; - const shouldRateLimit = await this.rateLimiter(); - this.activeRateLimitRequests--; + // The rate limit is very high, so we can safely disconnect any client that hits it. + if (await this.rateLimiter()) { + this.logger.warn(`Closing a connection from ${this.ip} (user=${this.user?.id}}) due to an excessive influx of messages.`); - if (shouldRateLimit) return; - if (this.closingConnection) return; - } else { - let connectionInfo = `IP ${this.ip}`; - if (this.user) connectionInfo += `, user ID ${this.user.id}`; - - this.logger.warn(`Closing a connection (${connectionInfo}) due to an excessive influx of messages.`); - this.closingConnection = true; - this.wsConnection.close(1008, 'Please stop spamming the streaming API.'); - return; - } + this.closingConnection = true; + this.wsConnection.close(1008, 'Disconnected - too many requests'); + return; } try { @@ -154,7 +137,7 @@ export default class Connection { case 'readNotification': this.onReadNotification(body); break; case 'subNote': this.onSubscribeNote(body); break; case 's': this.onSubscribeNote(body); break; // alias - case 'sr': this.onSubscribeNote(body); this.readNote(body); break; + case 'sr': this.onSubscribeNote(body); break; case 'unsubNote': this.onUnsubscribeNote(body); break; case 'un': this.onUnsubscribeNote(body); break; // alias case 'connect': this.onChannelConnectRequested(body); break; @@ -170,39 +153,6 @@ export default class Connection { } @bindThis - public cacheNote(note: Packed<'Note'>) { - const add = (note: Packed<'Note'>) => { - const existIndex = this.cachedNotes.findIndex(n => n.id === note.id); - if (existIndex > -1) { - this.cachedNotes[existIndex] = note; - return; - } - - this.cachedNotes.unshift(note); - if (this.cachedNotes.length > 32) { - this.cachedNotes.splice(32); - } - }; - - add(note); - if (note.reply) add(note.reply); - if (note.renote) add(note.renote); - } - - @bindThis - private readNote(body: JsonValue | undefined) { - if (!isJsonObject(body)) return; - const id = body.id; - - const note = this.cachedNotes.find(n => n.id === id); - if (note == null) return; - - if (this.user && (note.userId !== this.user.id)) { - this.noteReadService.read(this.user.id, [note]); - } - } - - @bindThis private onReadNotification(payload: JsonValue | undefined) { this.notificationService.readAllNotification(this.user!.id); } @@ -215,9 +165,19 @@ export default class Connection { if (!isJsonObject(payload)) return; if (!payload.id || typeof payload.id !== 'string') return; - const current = this.subscribingNotes[payload.id] ?? 0; + const current = this.subscribingNotes.get(payload.id) ?? 0; const updated = current + 1; - this.subscribingNotes[payload.id] = updated; + this.subscribingNotes.set(payload.id, updated); + + // Limit the number of distinct notes that can be subscribed to. + while (this.subscribingNotes.size > MAX_SUBSCRIPTIONS_PER_CONNECTION) { + // Map maintains insertion order, so first key is always the oldest + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const oldestKey = this.subscribingNotes.keys().next().value!; + + this.subscribingNotes.delete(oldestKey); + this.subscriber.off(`noteStream:${oldestKey}`, this.onNoteStreamMessage); + } if (updated === 1) { this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage); @@ -232,12 +192,12 @@ export default class Connection { if (!isJsonObject(payload)) return; if (!payload.id || typeof payload.id !== 'string') return; - const current = this.subscribingNotes[payload.id]; + const current = this.subscribingNotes.get(payload.id); if (current == null) return; const updated = current - 1; - this.subscribingNotes[payload.id] = updated; + this.subscribingNotes.set(payload.id, updated); if (updated <= 0) { - delete this.subscribingNotes[payload.id]; + this.subscribingNotes.delete(payload.id); this.subscriber.off(`noteStream:${payload.id}`, this.onNoteStreamMessage); } } @@ -304,7 +264,11 @@ export default class Connection { */ @bindThis public connectChannel(id: string, params: JsonObject | undefined, channel: string, pong = false) { - if (this.channels.length >= MAX_CHANNELS_PER_CONNECTION) { + if (this.channels.has(id)) { + this.disconnectChannel(id); + } + + if (this.channels.size >= MAX_CHANNELS_PER_CONNECTION) { return; } @@ -320,12 +284,16 @@ export default class Connection { } // 共有可能チャンネルに接続しようとしていて、かつそのチャンネルに既に接続していたら無意味なので無視 - if (channelService.shouldShare && this.channels.some(c => c.chName === channel)) { - return; + if (channelService.shouldShare) { + for (const c of this.channels.values()) { + if (c.chName === channel) { + return; + } + } } const ch: Channel = channelService.create(id, this); - this.channels.push(ch); + this.channels.set(ch.id, ch); ch.init(params ?? {}); if (pong) { @@ -341,11 +309,11 @@ export default class Connection { */ @bindThis public disconnectChannel(id: string) { - const channel = this.channels.find(c => c.id === id); + const channel = this.channels.get(id); if (channel) { if (channel.dispose) channel.dispose(); - this.channels = this.channels.filter(c => c.id !== id); + this.channels.delete(id); } } @@ -360,7 +328,7 @@ export default class Connection { if (typeof data.type !== 'string') return; if (typeof data.body === 'undefined') return; - const channel = this.channels.find(c => c.id === data.id); + const channel = this.channels.get(data.id); if (channel != null && channel.onMessage != null) { channel.onMessage(data.type, data.body); } @@ -372,8 +340,15 @@ export default class Connection { @bindThis public dispose() { if (this.fetchIntervalId) clearInterval(this.fetchIntervalId); - for (const c of this.channels.filter(c => c.dispose)) { + for (const c of this.channels.values()) { if (c.dispose) c.dispose(); } + for (const k of this.subscribingNotes.keys()) { + this.subscriber.off(`noteStream:${k}`, this.onNoteStreamMessage); + } + + this.fetchIntervalId = null; + this.channels.clear(); + this.subscribingNotes.clear(); } } diff --git a/packages/backend/src/server/api/stream/channel.ts b/packages/backend/src/server/api/stream/channel.ts index 7a6193ccfc..9af816dfbb 100644 --- a/packages/backend/src/server/api/stream/channel.ts +++ b/packages/backend/src/server/api/stream/channel.ts @@ -82,6 +82,11 @@ export default abstract class Channel { return false; } + /** + * This function modifies {@link note}, please make sure it has been shallow cloned. + * See Dakkar's comment of {@link assignMyReaction} for more + * @param note The note to change + */ protected async hideNote(note: Packed<'Note'>): Promise<void> { if (note.renote) { await this.hideNote(note.renote); @@ -101,8 +106,8 @@ export default abstract class Channel { this.noteEntityService = noteEntityService; } - public send(payload: { type: string, body: JsonValue }): void - public send(type: string, payload: JsonValue): void + public send(payload: { type: string, body: JsonValue }): void; + public send(type: string, payload: JsonValue): void; @bindThis public send(typeOrPayload: { type: string, body: JsonValue } | string, payload?: JsonValue) { const type = payload === undefined ? (typeOrPayload as { type: string, body: JsonValue }).type : (typeOrPayload as string); @@ -122,7 +127,6 @@ export default abstract class Channel { public onMessage?(type: string, body: JsonValue): void; public async assignMyReaction(note: Packed<'Note'>): Promise<Packed<'Note'>> { - let changed = false; // StreamingApiServerService creates a single EventEmitter per server process, // so a new note arriving from redis gets de-serialised once per server process, // and then that single object is passed to all active channels on each connection. @@ -133,7 +137,6 @@ export default abstract class Channel { if (note.renote && Object.keys(note.renote.reactions).length > 0) { const myReaction = await this.noteEntityService.populateMyReaction(note.renote, this.user.id); if (myReaction) { - changed = true; clonedNote.renote = { ...note.renote }; clonedNote.renote.myReaction = myReaction; } @@ -141,7 +144,6 @@ export default abstract class Channel { if (note.renote?.reply && Object.keys(note.renote.reply.reactions).length > 0) { const myReaction = await this.noteEntityService.populateMyReaction(note.renote.reply, this.user.id); if (myReaction) { - changed = true; clonedNote.renote = { ...note.renote }; clonedNote.renote.reply = { ...note.renote.reply }; clonedNote.renote.reply.myReaction = myReaction; @@ -151,12 +153,11 @@ export default abstract class Channel { if (this.user && note.reply && Object.keys(note.reply.reactions).length > 0) { const myReaction = await this.noteEntityService.populateMyReaction(note.reply, this.user.id); if (myReaction) { - changed = true; clonedNote.reply = { ...note.reply }; clonedNote.reply.myReaction = myReaction; } } - return changed ? clonedNote : note; + return clonedNote; } } @@ -165,4 +166,4 @@ export type MiChannelService<T extends boolean> = { requireCredential: T; kind: T extends true ? string : string | null | undefined; create: (id: string, connection: Connection) => Channel; -} +}; diff --git a/packages/backend/src/server/api/stream/channels/antenna.ts b/packages/backend/src/server/api/stream/channels/antenna.ts index a73d158b7f..0974dbdb25 100644 --- a/packages/backend/src/server/api/stream/channels/antenna.ts +++ b/packages/backend/src/server/api/stream/channels/antenna.ts @@ -43,8 +43,6 @@ class AntennaChannel extends Channel { if (this.isNoteMutedOrBlocked(note)) return; - this.connection.cacheNote(note); - this.send('note', note); } else { this.send(data.type, data.body); diff --git a/packages/backend/src/server/api/stream/channels/bubble-timeline.ts b/packages/backend/src/server/api/stream/channels/bubble-timeline.ts index 5ebbdcbb86..d29101cbc5 100644 --- a/packages/backend/src/server/api/stream/channels/bubble-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/bubble-timeline.ts @@ -53,9 +53,11 @@ class BubbleTimelineChannel extends Channel { if (this.withFiles && (note.fileIds == null || note.fileIds.length === 0)) return; if (!this.withBots && note.user.isBot) return; - if (!(note.user.host != null && this.instance.bubbleInstances.includes(note.user.host) && note.visibility === 'public' )) return; - + if (note.visibility !== 'public') return; if (note.channelId != null) return; + if (note.user.host == null) return; + if (!this.instance.bubbleInstances.includes(note.user.host)) return; + if (note.user.requireSigninToViewContents && this.user == null) return; if (isRenotePacked(note) && !isQuotePacked(note) && !this.withRenotes) return; @@ -66,8 +68,6 @@ class BubbleTimelineChannel extends Channel { const clonedNote = await this.assignMyReaction(note); await this.hideNote(clonedNote); - this.connection.cacheNote(clonedNote); - this.send('note', clonedNote); } diff --git a/packages/backend/src/server/api/stream/channels/channel.ts b/packages/backend/src/server/api/stream/channels/channel.ts index ec0bc7e13a..65fb8d67cb 100644 --- a/packages/backend/src/server/api/stream/channels/channel.ts +++ b/packages/backend/src/server/api/stream/channels/channel.ts @@ -52,8 +52,6 @@ class ChannelChannel extends Channel { const clonedNote = await this.assignMyReaction(note); await this.hideNote(clonedNote); - this.connection.cacheNote(clonedNote); - this.send('note', clonedNote); } diff --git a/packages/backend/src/server/api/stream/channels/chat-room.ts b/packages/backend/src/server/api/stream/channels/chat-room.ts new file mode 100644 index 0000000000..648e407569 --- /dev/null +++ b/packages/backend/src/server/api/stream/channels/chat-room.ts @@ -0,0 +1,82 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { bindThis } from '@/decorators.js'; +import type { GlobalEvents } from '@/core/GlobalEventService.js'; +import type { JsonObject } from '@/misc/json-value.js'; +import { ChatService } from '@/core/ChatService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; +import Channel, { type MiChannelService } from '../channel.js'; + +class ChatRoomChannel extends Channel { + public readonly chName = 'chatRoom'; + public static shouldShare = false; + public static requireCredential = true as const; + public static kind = 'read:chat'; + private roomId: string; + + constructor( + private chatService: ChatService, + + id: string, + connection: Channel['connection'], + noteEntityService: NoteEntityService, + ) { + super(id, connection, noteEntityService); + } + + @bindThis + public async init(params: JsonObject) { + if (typeof params.roomId !== 'string') return; + this.roomId = params.roomId; + + this.subscriber.on(`chatRoomStream:${this.roomId}`, this.onEvent); + } + + @bindThis + private async onEvent(data: GlobalEvents['chatRoom']['payload']) { + this.send(data.type, data.body); + } + + @bindThis + public onMessage(type: string, body: any) { + switch (type) { + case 'read': + if (this.roomId) { + this.chatService.readRoomChatMessage(this.user!.id, this.roomId); + } + break; + } + } + + @bindThis + public dispose() { + this.subscriber.off(`chatRoomStream:${this.roomId}`, this.onEvent); + } +} + +@Injectable() +export class ChatRoomChannelService implements MiChannelService<true> { + public readonly shouldShare = ChatRoomChannel.shouldShare; + public readonly requireCredential = ChatRoomChannel.requireCredential; + public readonly kind = ChatRoomChannel.kind; + + constructor( + private chatService: ChatService, + private readonly noteEntityService: NoteEntityService, + ) { + } + + @bindThis + public create(id: string, connection: Channel['connection']): ChatRoomChannel { + return new ChatRoomChannel( + this.chatService, + id, + connection, + this.noteEntityService, + ); + } +} diff --git a/packages/backend/src/server/api/stream/channels/chat-user.ts b/packages/backend/src/server/api/stream/channels/chat-user.ts new file mode 100644 index 0000000000..b37aef29d1 --- /dev/null +++ b/packages/backend/src/server/api/stream/channels/chat-user.ts @@ -0,0 +1,82 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { bindThis } from '@/decorators.js'; +import type { GlobalEvents } from '@/core/GlobalEventService.js'; +import type { JsonObject } from '@/misc/json-value.js'; +import { ChatService } from '@/core/ChatService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; +import Channel, { type MiChannelService } from '../channel.js'; + +class ChatUserChannel extends Channel { + public readonly chName = 'chatUser'; + public static shouldShare = false; + public static requireCredential = true as const; + public static kind = 'read:chat'; + private otherId: string; + + constructor( + private chatService: ChatService, + + id: string, + connection: Channel['connection'], + noteEntityService: NoteEntityService, + ) { + super(id, connection, noteEntityService); + } + + @bindThis + public async init(params: JsonObject) { + if (typeof params.otherId !== 'string') return; + this.otherId = params.otherId; + + this.subscriber.on(`chatUserStream:${this.user!.id}-${this.otherId}`, this.onEvent); + } + + @bindThis + private async onEvent(data: GlobalEvents['chatUser']['payload']) { + this.send(data.type, data.body); + } + + @bindThis + public onMessage(type: string, body: any) { + switch (type) { + case 'read': + if (this.otherId) { + this.chatService.readUserChatMessage(this.user!.id, this.otherId); + } + break; + } + } + + @bindThis + public dispose() { + this.subscriber.off(`chatUserStream:${this.user!.id}-${this.otherId}`, this.onEvent); + } +} + +@Injectable() +export class ChatUserChannelService implements MiChannelService<true> { + public readonly shouldShare = ChatUserChannel.shouldShare; + public readonly requireCredential = ChatUserChannel.requireCredential; + public readonly kind = ChatUserChannel.kind; + + constructor( + private chatService: ChatService, + private readonly noteEntityService: NoteEntityService, + ) { + } + + @bindThis + public create(id: string, connection: Channel['connection']): ChatUserChannel { + return new ChatUserChannel( + this.chatService, + id, + connection, + this.noteEntityService, + ); + } +} 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 72a8a8b156..c899ad9490 100644 --- a/packages/backend/src/server/api/stream/channels/global-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/global-timeline.ts @@ -53,6 +53,9 @@ class GlobalTimelineChannel extends Channel { if (note.visibility !== 'public') return; if (note.channelId != null) return; + if (note.user.requireSigninToViewContents && this.user == null) return; + if (note.renote && note.renote.user.requireSigninToViewContents && this.user == null) return; + if (note.reply && note.reply.user.requireSigninToViewContents && this.user == null) return; if (isRenotePacked(note) && !isQuotePacked(note) && !this.withRenotes) return; @@ -63,8 +66,6 @@ class GlobalTimelineChannel extends Channel { const clonedNote = await this.assignMyReaction(note); await this.hideNote(clonedNote); - this.connection.cacheNote(clonedNote); - this.send('note', clonedNote); } diff --git a/packages/backend/src/server/api/stream/channels/hashtag.ts b/packages/backend/src/server/api/stream/channels/hashtag.ts index 7c8df87721..f47a10f293 100644 --- a/packages/backend/src/server/api/stream/channels/hashtag.ts +++ b/packages/backend/src/server/api/stream/channels/hashtag.ts @@ -48,8 +48,6 @@ class HashtagChannel extends Channel { const clonedNote = await this.assignMyReaction(note); await this.hideNote(clonedNote); - this.connection.cacheNote(clonedNote); - this.send('note', clonedNote); } 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 c87a21be82..dfdb491113 100644 --- a/packages/backend/src/server/api/stream/channels/home-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/home-timeline.ts @@ -84,8 +84,6 @@ class HomeTimelineChannel extends Channel { const clonedNote = await this.assignMyReaction(note); await this.hideNote(clonedNote); - this.connection.cacheNote(clonedNote); - this.send('note', clonedNote); } 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 95b762e2b7..6cb425ff81 100644 --- a/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/hybrid-timeline.ts @@ -101,8 +101,6 @@ class HybridTimelineChannel extends Channel { const clonedNote = await this.assignMyReaction(note); await this.hideNote(clonedNote); - this.connection.cacheNote(clonedNote); - this.send('note', clonedNote); } 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 b9e0a4c234..82b128eae0 100644 --- a/packages/backend/src/server/api/stream/channels/local-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/local-timeline.ts @@ -56,6 +56,9 @@ class LocalTimelineChannel extends Channel { if (note.user.host !== null) return; if (note.visibility !== 'public') return; if (note.channelId != null) return; + if (note.user.requireSigninToViewContents && this.user == null) return; + if (note.renote && note.renote.user.requireSigninToViewContents && this.user == null) return; + if (note.reply && note.reply.user.requireSigninToViewContents && this.user == null) return; // 関係ない返信は除外 if (note.reply && this.user && !this.following[note.userId]?.withReplies && !this.withReplies) { @@ -73,8 +76,6 @@ class LocalTimelineChannel extends Channel { const clonedNote = await this.assignMyReaction(note); await this.hideNote(clonedNote); - this.connection.cacheNote(clonedNote); - this.send('note', clonedNote); } diff --git a/packages/backend/src/server/api/stream/channels/main.ts b/packages/backend/src/server/api/stream/channels/main.ts index 6b144e43e4..6194bb78dd 100644 --- a/packages/backend/src/server/api/stream/channels/main.ts +++ b/packages/backend/src/server/api/stream/channels/main.ts @@ -39,7 +39,6 @@ class MainChannel extends Channel { const note = await this.noteEntityService.pack(data.body.note.id, this.user, { detail: true, }); - this.connection.cacheNote(note); data.body.note = note; } break; @@ -52,7 +51,6 @@ class MainChannel extends Channel { const note = await this.noteEntityService.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/role-timeline.ts b/packages/backend/src/server/api/stream/channels/role-timeline.ts index 14c4d96479..78cd9bf868 100644 --- a/packages/backend/src/server/api/stream/channels/role-timeline.ts +++ b/packages/backend/src/server/api/stream/channels/role-timeline.ts @@ -51,8 +51,6 @@ class RoleTimelineChannel extends Channel { const clonedNote = await this.assignMyReaction(note); await this.hideNote(clonedNote); - this.connection.cacheNote(clonedNote); - this.send('note', clonedNote); } else { this.send(data.type, data.body); 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 d09a9b8d9f..8a7c2b2633 100644 --- a/packages/backend/src/server/api/stream/channels/user-list.ts +++ b/packages/backend/src/server/api/stream/channels/user-list.ts @@ -114,8 +114,6 @@ class UserListChannel extends Channel { const clonedNote = await this.assignMyReaction(note); await this.hideNote(clonedNote); - this.connection.cacheNote(clonedNote); - this.send('note', clonedNote); } |