From 8b7791a7572b6a1a1b53f93267f8b3616f2815a7 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 7 Aug 2024 17:45:46 +0900 Subject: [PATCH 1/4] refactor: add and use isJsonObject --- packages/backend/src/misc/json-value.ts | 4 ++++ packages/backend/src/server/api/stream/Connection.ts | 5 +++-- .../backend/src/server/api/stream/channels/queue-stats.ts | 3 ++- .../backend/src/server/api/stream/channels/reversi-game.ts | 7 ++++--- .../backend/src/server/api/stream/channels/server-stats.ts | 3 ++- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/backend/src/misc/json-value.ts b/packages/backend/src/misc/json-value.ts index 79944417915e..bd7fe12058a0 100644 --- a/packages/backend/src/misc/json-value.ts +++ b/packages/backend/src/misc/json-value.ts @@ -6,3 +6,7 @@ export type JsonValue = JsonArray | JsonObject | string | number | boolean | null; export type JsonObject = {[K in string]?: JsonValue}; export type JsonArray = JsonValue[]; + +export function isJsonObject(value: JsonValue | undefined): value is JsonObject { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts index 96082827f81f..f892968ab5b4 100644 --- a/packages/backend/src/server/api/stream/Connection.ts +++ b/packages/backend/src/server/api/stream/Connection.ts @@ -14,6 +14,7 @@ import { CacheService } from '@/core/CacheService.js'; import { MiFollowing, MiUserProfile } from '@/models/_.js'; import type { StreamEventEmitter, GlobalEvents } from '@/core/GlobalEventService.js'; import { ChannelFollowingService } from '@/core/ChannelFollowingService.js'; +import { isJsonObject } from '@/misc/json-value.js'; import type { JsonObject } from '@/misc/json-value.js'; import type { ChannelsService } from './ChannelsService.js'; import type { EventEmitter } from 'events'; @@ -112,7 +113,7 @@ export default class Connection { const { type, body } = obj; - if (typeof body !== 'object' || body === null || Array.isArray(body)) return; + if (!isJsonObject(body)) return; switch (type) { case 'readNotification': this.onReadNotification(body); break; @@ -221,7 +222,7 @@ export default class Connection { if (typeof id !== 'string') return; if (typeof channel !== 'string') return; if (typeof pong !== 'boolean' && typeof pong !== 'undefined' && pong !== null) return; - if (typeof params !== 'undefined' && (typeof params !== 'object' || params === null || Array.isArray(params))) return; + if (typeof params !== 'undefined' && !isJsonObject(params)) return; this.connectChannel(id, params, channel, pong ?? undefined); } diff --git a/packages/backend/src/server/api/stream/channels/queue-stats.ts b/packages/backend/src/server/api/stream/channels/queue-stats.ts index ff7e7402261b..91b62255b4f6 100644 --- a/packages/backend/src/server/api/stream/channels/queue-stats.ts +++ b/packages/backend/src/server/api/stream/channels/queue-stats.ts @@ -6,6 +6,7 @@ import Xev from 'xev'; import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; +import { isJsonObject } from '@/misc/json-value.js'; import type { JsonObject, JsonValue } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -36,7 +37,7 @@ class QueueStatsChannel extends Channel { public onMessage(type: string, body: JsonValue) { switch (type) { case 'requestLog': - if (typeof body !== 'object' || body === null || Array.isArray(body)) return; + if (!isJsonObject(body)) return; if (typeof body.id !== 'string') return; if (typeof body.length !== 'number') return; ev.once(`queueStatsLog:${body.id}`, statsLog => { diff --git a/packages/backend/src/server/api/stream/channels/reversi-game.ts b/packages/backend/src/server/api/stream/channels/reversi-game.ts index 17823a164a2d..c6f4a4ae3b9a 100644 --- a/packages/backend/src/server/api/stream/channels/reversi-game.ts +++ b/packages/backend/src/server/api/stream/channels/reversi-game.ts @@ -9,6 +9,7 @@ import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; import { ReversiService } from '@/core/ReversiService.js'; import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js'; +import { isJsonObject } from '@/misc/json-value.js'; import type { JsonObject, JsonValue } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -44,16 +45,16 @@ class ReversiGameChannel extends Channel { this.ready(body); break; case 'updateSettings': - if (typeof body !== 'object' || body === null || Array.isArray(body)) return; + if (!isJsonObject(body)) return; if (typeof body.key !== 'string') return; - if (typeof body.value !== 'object' || body.value === null || Array.isArray(body.value)) return; + if (!isJsonObject(body.value)) return; this.updateSettings(body.key, body.value); break; case 'cancel': this.cancelGame(); break; case 'putStone': - if (typeof body !== 'object' || body === null || Array.isArray(body)) return; + if (!isJsonObject(body)) return; if (typeof body.pos !== 'number') return; if (typeof body.id !== 'string') return; this.putStone(body.pos, body.id); diff --git a/packages/backend/src/server/api/stream/channels/server-stats.ts b/packages/backend/src/server/api/stream/channels/server-stats.ts index 6258afba35c3..ec5352d12dba 100644 --- a/packages/backend/src/server/api/stream/channels/server-stats.ts +++ b/packages/backend/src/server/api/stream/channels/server-stats.ts @@ -6,6 +6,7 @@ import Xev from 'xev'; import { Injectable } from '@nestjs/common'; import { bindThis } from '@/decorators.js'; +import { isJsonObject } from '@/misc/json-value.js'; import type { JsonObject, JsonValue } from '@/misc/json-value.js'; import Channel, { type MiChannelService } from '../channel.js'; @@ -36,7 +37,7 @@ class ServerStatsChannel extends Channel { public onMessage(type: string, body: JsonValue) { switch (type) { case 'requestLog': - if (typeof body !== 'object' || body === null || Array.isArray(body)) return; + if (!isJsonObject(body)) return; ev.once(`serverStatsLog:${body.id}`, statsLog => { this.send('statsLog', statsLog); }); From 8567e36c34fc646ee19398ecfc689e33b2503fe3 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 7 Aug 2024 17:49:13 +0900 Subject: [PATCH 2/4] fix: readNotification message without body is not working --- .../src/server/api/stream/Connection.ts | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts index f892968ab5b4..7773150b74d5 100644 --- a/packages/backend/src/server/api/stream/Connection.ts +++ b/packages/backend/src/server/api/stream/Connection.ts @@ -15,7 +15,7 @@ import { MiFollowing, MiUserProfile } from '@/models/_.js'; import type { StreamEventEmitter, GlobalEvents } from '@/core/GlobalEventService.js'; import { ChannelFollowingService } from '@/core/ChannelFollowingService.js'; import { isJsonObject } from '@/misc/json-value.js'; -import type { JsonObject } from '@/misc/json-value.js'; +import type { JsonObject, JsonValue } from '@/misc/json-value.js'; import type { ChannelsService } from './ChannelsService.js'; import type { EventEmitter } from 'events'; import type Channel from './channel.js'; @@ -113,8 +113,6 @@ export default class Connection { const { type, body } = obj; - if (!isJsonObject(body)) return; - switch (type) { case 'readNotification': this.onReadNotification(body); break; case 'subNote': this.onSubscribeNote(body); break; @@ -155,7 +153,8 @@ export default class Connection { } @bindThis - private readNote(body: JsonObject) { + private readNote(body: JsonValue | undefined) { + if (!isJsonObject(body)) return; const id = body.id; const note = this.cachedNotes.find(n => n.id === id); @@ -167,7 +166,7 @@ export default class Connection { } @bindThis - private onReadNotification(payload: JsonObject) { + private onReadNotification(payload: JsonValue | undefined) { this.notificationService.readAllNotification(this.user!.id); } @@ -175,7 +174,8 @@ export default class Connection { * 投稿購読要求時 */ @bindThis - private onSubscribeNote(payload: JsonObject) { + private onSubscribeNote(payload: JsonValue | undefined) { + if (!isJsonObject(payload)) return; if (!payload.id || typeof payload.id !== 'string') return; const current = this.subscribingNotes[payload.id] ?? 0; @@ -191,7 +191,8 @@ export default class Connection { * 投稿購読解除要求時 */ @bindThis - private onUnsubscribeNote(payload: JsonObject) { + private onUnsubscribeNote(payload: JsonValue | undefined) { + if (!isJsonObject(payload)) return; if (!payload.id || typeof payload.id !== 'string') return; const current = this.subscribingNotes[payload.id]; @@ -217,7 +218,8 @@ export default class Connection { * チャンネル接続要求時 */ @bindThis - private onChannelConnectRequested(payload: JsonObject) { + private onChannelConnectRequested(payload: JsonValue | undefined) { + if (!isJsonObject(payload)) return; const { channel, id, params, pong } = payload; if (typeof id !== 'string') return; if (typeof channel !== 'string') return; @@ -230,7 +232,8 @@ export default class Connection { * チャンネル切断要求時 */ @bindThis - private onChannelDisconnectRequested(payload: JsonObject) { + private onChannelDisconnectRequested(payload: JsonValue | undefined) { + if (!isJsonObject(payload)) return; const { id } = payload; if (typeof id !== 'string') return; this.disconnectChannel(id); @@ -298,7 +301,8 @@ export default class Connection { * @param data メッセージ */ @bindThis - private onChannelMessageRequested(data: JsonObject) { + private onChannelMessageRequested(data: JsonValue | undefined) { + if (!isJsonObject(data)) return; if (typeof data.id !== 'string') return; if (typeof data.type !== 'string') return; if (typeof data.body === 'undefined') return; From 9b679dd67389fb099c7ce4ec9526beb2c4b9162d Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Wed, 7 Aug 2024 17:52:35 +0900 Subject: [PATCH 3/4] =?UTF-8?q?docs(changelog):=20WS=E3=81=AE`readAllNotif?= =?UTF-8?q?ications`=20=E3=83=A1=E3=83=83=E3=82=BB=E3=83=BC=E3=82=B8?= =?UTF-8?q?=E3=81=8C=20`body`=20=E3=82=92=E6=8C=81=E3=81=9F=E3=81=AA?= =?UTF-8?q?=E3=81=84=E5=A0=B4=E5=90=88=E3=81=AB=E5=8B=95=E4=BD=9C=E3=81=97?= =?UTF-8?q?=E3=81=AA=E3=81=84=E5=95=8F=E9=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86e33a827261..f2cf5ee4ceab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - ### Server -- +- Fix: WSの`readAllNotifications` メッセージが `body` を持たない場合に動作しない問題 #14374 ## 2024.7.0 From d2544a0ac59ec84a6630eba8b4daaa5bdfba411a Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Thu, 8 Aug 2024 01:28:36 +0900 Subject: [PATCH 4/4] Update CHANGELOG.md Co-authored-by: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2cf5ee4ceab..1335db786ff1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ### Server - Fix: WSの`readAllNotifications` メッセージが `body` を持たない場合に動作しない問題 #14374 + - 通知ページや通知カラム(デッキ)を開いている状態において、新たに発生した通知が既読されない問題が修正されます。 + - これにより、プッシュ通知が有効な同条件下の環境において、プッシュ通知が常に発生してしまう問題も修正されます。 ## 2024.7.0