summaryrefslogtreecommitdiff
path: root/packages/backend/src/server
diff options
context:
space:
mode:
authordakkar <dakkar@thenautilus.net>2024-08-30 12:08:31 +0100
committerdakkar <dakkar@thenautilus.net>2024-08-30 12:08:31 +0100
commit6151099f5ba07d14a651aea8f816dd280d74209d (patch)
tree4b014a2f4b198facc8bdd92c70b49fec2801d51a /packages/backend/src/server
parentmerge: thunk the min/max promises (!603) (diff)
parentMerge pull request #14391 from misskey-dev/develop (diff)
downloadsharkey-6151099f5ba07d14a651aea8f816dd280d74209d.tar.gz
sharkey-6151099f5ba07d14a651aea8f816dd280d74209d.tar.bz2
sharkey-6151099f5ba07d14a651aea8f816dd280d74209d.zip
Merge remote-tracking branch 'misskey/master' into feature/misskey-2024.8
Diffstat (limited to 'packages/backend/src/server')
-rw-r--r--packages/backend/src/server/api/endpoints/admin/accounts/delete.ts23
-rw-r--r--packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts15
-rw-r--r--packages/backend/src/server/api/endpoints/admin/suspend-user.ts50
-rw-r--r--packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts14
-rw-r--r--packages/backend/src/server/api/endpoints/flash/delete.ts24
-rw-r--r--packages/backend/src/server/api/endpoints/gallery/posts/delete.ts35
-rw-r--r--packages/backend/src/server/api/endpoints/pages/delete.ts24
-rw-r--r--packages/backend/src/server/api/endpoints/users/followers.ts34
-rw-r--r--packages/backend/src/server/api/endpoints/users/following.ts34
-rw-r--r--packages/backend/src/server/api/stream/Connection.ts29
-rw-r--r--packages/backend/src/server/api/stream/channels/queue-stats.ts3
-rw-r--r--packages/backend/src/server/api/stream/channels/reversi-game.ts13
-rw-r--r--packages/backend/src/server/api/stream/channels/server-stats.ts3
-rw-r--r--packages/backend/src/server/web/views/base.pug1
14 files changed, 162 insertions, 140 deletions
diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts
index 4074e416b8..01dea703a3 100644
--- a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts
+++ b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts
@@ -7,9 +7,9 @@ import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UsersRepository } from '@/models/_.js';
import { QueueService } from '@/core/QueueService.js';
-import { UserSuspendService } from '@/core/UserSuspendService.js';
import { DI } from '@/di-symbols.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
+import { DeleteAccountService } from '@/core/DeleteAccountService.js';
export const meta = {
tags: ['admin'],
@@ -33,9 +33,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
- private userEntityService: UserEntityService,
- private queueService: QueueService,
- private userSuspendService: UserSuspendService,
+ private deleteAccoountService: DeleteAccountService,
) {
super(meta, paramDef, async (ps, me) => {
const user = await this.usersRepository.findOneBy({ id: ps.userId });
@@ -48,22 +46,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new Error('cannot delete a root account');
}
- if (this.userEntityService.isLocalUser(user)) {
- // 物理削除する前にDelete activityを送信する
- await this.userSuspendService.doPostSuspend(user).catch(err => {});
-
- this.queueService.createDeleteAccountJob(user, {
- soft: false,
- });
- } else {
- this.queueService.createDeleteAccountJob(user, {
- soft: true, // リモートユーザーの削除は、完全にDBから物理削除してしまうと再度連合してきてアカウントが復活する可能性があるため、soft指定する
- });
- }
-
- await this.usersRepository.update(user.id, {
- isDeleted: true,
- });
+ await this.deleteAccoountService.deleteAccount(user);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts b/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts
index d7209965db..5cf49670be 100644
--- a/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts
+++ b/packages/backend/src/server/api/endpoints/admin/roles/update-default-policies.ts
@@ -7,6 +7,7 @@ import { Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { MetaService } from '@/core/MetaService.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
export const meta = {
tags: ['admin', 'role'],
@@ -33,12 +34,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
constructor(
private metaService: MetaService,
private globalEventService: GlobalEventService,
+ private moderationLogService: ModerationLogService,
) {
- super(meta, paramDef, async (ps) => {
+ super(meta, paramDef, async (ps, me) => {
+ const before = await this.metaService.fetch(true);
+
await this.metaService.update({
policies: ps.policies,
});
- this.globalEventService.publishInternalEvent('policiesUpdated', ps.policies);
+
+ const after = await this.metaService.fetch(true);
+
+ this.globalEventService.publishInternalEvent('policiesUpdated', after.policies);
+ this.moderationLogService.log(me, 'updateServerSettings', {
+ before: before.policies,
+ after: after.policies,
+ });
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts
index 8a946405cc..bea1bdc4ed 100644
--- a/packages/backend/src/server/api/endpoints/admin/suspend-user.ts
+++ b/packages/backend/src/server/api/endpoints/admin/suspend-user.ts
@@ -3,18 +3,12 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { IsNull, Not } from 'typeorm';
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import type { UsersRepository, FollowingsRepository } from '@/models/_.js';
-import type { MiUser } from '@/models/User.js';
-import type { RelationshipJobData } from '@/queue/types.js';
-import { ModerationLogService } from '@/core/ModerationLogService.js';
+import type { UsersRepository } from '@/models/_.js';
import { UserSuspendService } from '@/core/UserSuspendService.js';
import { DI } from '@/di-symbols.js';
-import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
-import { QueueService } from '@/core/QueueService.js';
export const meta = {
tags: ['admin'],
@@ -38,13 +32,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
- @Inject(DI.followingsRepository)
- private followingsRepository: FollowingsRepository,
-
private userSuspendService: UserSuspendService,
private roleService: RoleService,
- private moderationLogService: ModerationLogService,
- private queueService: QueueService,
) {
super(meta, paramDef, async (ps, me) => {
const user = await this.usersRepository.findOneBy({ id: ps.userId });
@@ -57,42 +46,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new Error('cannot suspend moderator account');
}
- await this.usersRepository.update(user.id, {
- isSuspended: true,
- });
-
- this.moderationLogService.log(me, 'suspend', {
- userId: user.id,
- userUsername: user.username,
- userHost: user.host,
- });
-
- (async () => {
- await this.userSuspendService.doPostSuspend(user).catch(e => {});
- await this.unFollowAll(user).catch(e => {});
- })();
- });
- }
-
- @bindThis
- private async unFollowAll(follower: MiUser) {
- const followings = await this.followingsRepository.find({
- where: {
- followerId: follower.id,
- followeeId: Not(IsNull()),
- },
+ await this.userSuspendService.suspend(user, me);
});
-
- const jobs: RelationshipJobData[] = [];
- for (const following of followings) {
- if (following.followeeId && following.followerId) {
- jobs.push({
- from: { id: following.followerId },
- to: { id: following.followeeId },
- silent: true,
- });
- }
- }
- this.queueService.createUnfollowJob(jobs);
}
}
diff --git a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts
index 2c2b1bf6f5..b52c638cdb 100644
--- a/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts
+++ b/packages/backend/src/server/api/endpoints/admin/unsuspend-user.ts
@@ -6,7 +6,6 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UsersRepository } from '@/models/_.js';
-import { ModerationLogService } from '@/core/ModerationLogService.js';
import { UserSuspendService } from '@/core/UserSuspendService.js';
import { DI } from '@/di-symbols.js';
@@ -33,7 +32,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private usersRepository: UsersRepository,
private userSuspendService: UserSuspendService,
- private moderationLogService: ModerationLogService,
) {
super(meta, paramDef, async (ps, me) => {
const user = await this.usersRepository.findOneBy({ id: ps.userId });
@@ -42,17 +40,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
throw new Error('user not found');
}
- await this.usersRepository.update(user.id, {
- isSuspended: false,
- });
-
- this.moderationLogService.log(me, 'unsuspend', {
- userId: user.id,
- userUsername: user.username,
- userHost: user.host,
- });
-
- this.userSuspendService.doPostUnsuspend(user);
+ await this.userSuspendService.unsuspend(user, me);
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/flash/delete.ts b/packages/backend/src/server/api/endpoints/flash/delete.ts
index d3d47e5deb..6912450abf 100644
--- a/packages/backend/src/server/api/endpoints/flash/delete.ts
+++ b/packages/backend/src/server/api/endpoints/flash/delete.ts
@@ -4,9 +4,11 @@
*/
import { Inject, Injectable } from '@nestjs/common';
-import type { FlashsRepository } from '@/models/_.js';
+import type { FlashsRepository, UsersRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -44,17 +46,35 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
constructor(
@Inject(DI.flashsRepository)
private flashsRepository: FlashsRepository,
+
+ @Inject(DI.usersRepository)
+ private usersRepository: UsersRepository,
+
+ private moderationLogService: ModerationLogService,
+ private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
const flash = await this.flashsRepository.findOneBy({ id: ps.flashId });
+
if (flash == null) {
throw new ApiError(meta.errors.noSuchFlash);
}
- if (flash.userId !== me.id) {
+
+ if (!await this.roleService.isModerator(me) && flash.userId !== me.id) {
throw new ApiError(meta.errors.accessDenied);
}
await this.flashsRepository.delete(flash.id);
+
+ if (flash.userId !== me.id) {
+ const user = await this.usersRepository.findOneByOrFail({ id: flash.userId });
+ this.moderationLogService.log(me, 'deleteFlash', {
+ flashId: flash.id,
+ flashUserId: flash.userId,
+ flashUserUsername: user.username,
+ flash,
+ });
+ }
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts b/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts
index 527e3fb52d..b6b94db161 100644
--- a/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts
+++ b/packages/backend/src/server/api/endpoints/gallery/posts/delete.ts
@@ -5,8 +5,10 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
-import type { GalleryPostsRepository } from '@/models/_.js';
+import type { GalleryPostsRepository, UsersRepository } from '@/models/_.js';
import { DI } from '@/di-symbols.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../../error.js';
export const meta = {
@@ -22,6 +24,12 @@ export const meta = {
code: 'NO_SUCH_POST',
id: 'ae52f367-4bd7-4ecd-afc6-5672fff427f5',
},
+
+ accessDenied: {
+ message: 'Access denied.',
+ code: 'ACCESS_DENIED',
+ id: 'c86e09de-1c48-43ac-a435-1c7e42ed4496',
+ },
},
} as const;
@@ -38,18 +46,35 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
constructor(
@Inject(DI.galleryPostsRepository)
private galleryPostsRepository: GalleryPostsRepository,
+
+ @Inject(DI.usersRepository)
+ private usersRepository: UsersRepository,
+
+ private moderationLogService: ModerationLogService,
+ private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
- const post = await this.galleryPostsRepository.findOneBy({
- id: ps.postId,
- userId: me.id,
- });
+ const post = await this.galleryPostsRepository.findOneBy({ id: ps.postId });
if (post == null) {
throw new ApiError(meta.errors.noSuchPost);
}
+ if (!await this.roleService.isModerator(me) && post.userId !== me.id) {
+ throw new ApiError(meta.errors.accessDenied);
+ }
+
await this.galleryPostsRepository.delete(post.id);
+
+ if (post.userId !== me.id) {
+ const user = await this.usersRepository.findOneByOrFail({ id: post.userId });
+ this.moderationLogService.log(me, 'deleteGalleryPost', {
+ postId: post.id,
+ postUserId: post.userId,
+ postUserUsername: user.username,
+ post,
+ });
+ }
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/pages/delete.ts b/packages/backend/src/server/api/endpoints/pages/delete.ts
index aa2ba75a41..f2bc946788 100644
--- a/packages/backend/src/server/api/endpoints/pages/delete.ts
+++ b/packages/backend/src/server/api/endpoints/pages/delete.ts
@@ -4,9 +4,11 @@
*/
import { Inject, Injectable } from '@nestjs/common';
-import type { PagesRepository } from '@/models/_.js';
+import type { PagesRepository, UsersRepository } from '@/models/_.js';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { DI } from '@/di-symbols.js';
+import { ModerationLogService } from '@/core/ModerationLogService.js';
+import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -44,17 +46,35 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
constructor(
@Inject(DI.pagesRepository)
private pagesRepository: PagesRepository,
+
+ @Inject(DI.usersRepository)
+ private usersRepository: UsersRepository,
+
+ private moderationLogService: ModerationLogService,
+ private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
const page = await this.pagesRepository.findOneBy({ id: ps.pageId });
+
if (page == null) {
throw new ApiError(meta.errors.noSuchPage);
}
- if (page.userId !== me.id) {
+
+ if (!await this.roleService.isModerator(me) && page.userId !== me.id) {
throw new ApiError(meta.errors.accessDenied);
}
await this.pagesRepository.delete(page.id);
+
+ if (page.userId !== me.id) {
+ const user = await this.usersRepository.findOneByOrFail({ id: page.userId });
+ this.moderationLogService.log(me, 'deletePage', {
+ pageId: page.id,
+ pageUserId: page.userId,
+ pageUserUsername: user.username,
+ page,
+ });
+ }
});
}
}
diff --git a/packages/backend/src/server/api/endpoints/users/followers.ts b/packages/backend/src/server/api/endpoints/users/followers.ts
index 7ce7734f53..a8b4319a61 100644
--- a/packages/backend/src/server/api/endpoints/users/followers.ts
+++ b/packages/backend/src/server/api/endpoints/users/followers.ts
@@ -11,6 +11,7 @@ import { QueryService } from '@/core/QueryService.js';
import { FollowingEntityService } from '@/core/entities/FollowingEntityService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { DI } from '@/di-symbols.js';
+import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -81,6 +82,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private utilityService: UtilityService,
private followingEntityService: FollowingEntityService,
private queryService: QueryService,
+ private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
const user = await this.usersRepository.findOneBy(ps.userId != null
@@ -93,22 +95,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
- if (profile.followersVisibility === 'private') {
- if (me == null || (me.id !== user.id)) {
- throw new ApiError(meta.errors.forbidden);
- }
- } else if (profile.followersVisibility === 'followers') {
- if (me == null) {
- throw new ApiError(meta.errors.forbidden);
- } else if (me.id !== user.id) {
- const isFollowing = await this.followingsRepository.exists({
- where: {
- followeeId: user.id,
- followerId: me.id,
- },
- });
- if (!isFollowing) {
+ if (profile.followersVisibility !== 'public' && !await this.roleService.isModerator(me)) {
+ if (profile.followersVisibility === 'private') {
+ if (me == null || (me.id !== user.id)) {
+ throw new ApiError(meta.errors.forbidden);
+ }
+ } else if (profile.followersVisibility === 'followers') {
+ if (me == null) {
throw new ApiError(meta.errors.forbidden);
+ } else if (me.id !== user.id) {
+ const isFollowing = await this.followingsRepository.exists({
+ where: {
+ followeeId: user.id,
+ followerId: me.id,
+ },
+ });
+ if (!isFollowing) {
+ throw new ApiError(meta.errors.forbidden);
+ }
}
}
}
diff --git a/packages/backend/src/server/api/endpoints/users/following.ts b/packages/backend/src/server/api/endpoints/users/following.ts
index 6b3389f0b2..feda5bb353 100644
--- a/packages/backend/src/server/api/endpoints/users/following.ts
+++ b/packages/backend/src/server/api/endpoints/users/following.ts
@@ -12,6 +12,7 @@ import { QueryService } from '@/core/QueryService.js';
import { FollowingEntityService } from '@/core/entities/FollowingEntityService.js';
import { UtilityService } from '@/core/UtilityService.js';
import { DI } from '@/di-symbols.js';
+import { RoleService } from '@/core/RoleService.js';
import { ApiError } from '../../error.js';
export const meta = {
@@ -90,6 +91,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
private utilityService: UtilityService,
private followingEntityService: FollowingEntityService,
private queryService: QueryService,
+ private roleService: RoleService,
) {
super(meta, paramDef, async (ps, me) => {
const user = await this.usersRepository.findOneBy(ps.userId != null
@@ -102,22 +104,24 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: user.id });
- if (profile.followingVisibility === 'private') {
- if (me == null || (me.id !== user.id)) {
- throw new ApiError(meta.errors.forbidden);
- }
- } else if (profile.followingVisibility === 'followers') {
- if (me == null) {
- throw new ApiError(meta.errors.forbidden);
- } else if (me.id !== user.id) {
- const isFollowing = await this.followingsRepository.exists({
- where: {
- followeeId: user.id,
- followerId: me.id,
- },
- });
- if (!isFollowing) {
+ if (profile.followingVisibility !== 'public' && !await this.roleService.isModerator(me)) {
+ if (profile.followingVisibility === 'private') {
+ if (me == null || (me.id !== user.id)) {
+ throw new ApiError(meta.errors.forbidden);
+ }
+ } else if (profile.followingVisibility === 'followers') {
+ if (me == null) {
throw new ApiError(meta.errors.forbidden);
+ } else if (me.id !== user.id) {
+ const isFollowing = await this.followingsRepository.exists({
+ where: {
+ followeeId: user.id,
+ followerId: me.id,
+ },
+ });
+ if (!isFollowing) {
+ throw new ApiError(meta.errors.forbidden);
+ }
}
}
}
diff --git a/packages/backend/src/server/api/stream/Connection.ts b/packages/backend/src/server/api/stream/Connection.ts
index 9378b6c62b..3cacb77620 100644
--- a/packages/backend/src/server/api/stream/Connection.ts
+++ b/packages/backend/src/server/api/stream/Connection.ts
@@ -14,7 +14,8 @@ 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 type { JsonObject } from '@/misc/json-value.js';
+import { isJsonObject } 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';
@@ -23,6 +24,8 @@ import type Logger from '@/logger.js';
const MAX_CHANNELS_PER_CONNECTION = 32;
+const MAX_CHANNELS_PER_CONNECTION = 32;
+
/**
* Main stream connection
*/
@@ -149,8 +152,6 @@ export default class Connection {
const { type, body } = obj;
- if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
-
switch (type) {
case 'readNotification': this.onReadNotification(body); break;
case 'subNote': this.onSubscribeNote(body); break;
@@ -191,7 +192,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);
@@ -203,7 +205,7 @@ export default class Connection {
}
@bindThis
- private onReadNotification(payload: JsonObject) {
+ private onReadNotification(payload: JsonValue | undefined) {
this.notificationService.readAllNotification(this.user!.id);
}
@@ -211,7 +213,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;
@@ -227,7 +230,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];
@@ -265,12 +269,13 @@ 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;
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);
}
@@ -278,7 +283,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);
@@ -350,7 +356,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;
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 ff7e740226..91b62255b4 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 17823a164a..7597a1cfa3 100644
--- a/packages/backend/src/server/api/stream/channels/reversi-game.ts
+++ b/packages/backend/src/server/api/stream/channels/reversi-game.ts
@@ -9,8 +9,10 @@ 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';
+import { reversiUpdateKeys } from 'misskey-js';
class ReversiGameChannel extends Channel {
public readonly chName = 'reversiGame';
@@ -44,16 +46,17 @@ class ReversiGameChannel extends Channel {
this.ready(body);
break;
case 'updateSettings':
- if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
- if (typeof body.key !== 'string') return;
- if (typeof body.value !== 'object' || body.value === null || Array.isArray(body.value)) return;
+ if (!isJsonObject(body)) return;
+ if (!this.reversiService.isValidReversiUpdateKey(body.key)) return;
+ if (!this.reversiService.isValidReversiUpdateValue(body.key, 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);
@@ -63,7 +66,7 @@ class ReversiGameChannel extends Channel {
}
@bindThis
- private async updateSettings(key: string, value: JsonObject) {
+ private async updateSettings<K extends typeof reversiUpdateKeys[number]>(key: K, value: MiReversiGame[K]) {
if (this.user == null) return;
this.reversiService.updateSettings(this.gameId!, this.user, key, value);
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 6258afba35..ec5352d12d 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);
});
diff --git a/packages/backend/src/server/web/views/base.pug b/packages/backend/src/server/web/views/base.pug
index 4007632291..36cec20c85 100644
--- a/packages/backend/src/server/web/views/base.pug
+++ b/packages/backend/src/server/web/views/base.pug
@@ -32,6 +32,7 @@ html
meta(property='og:site_name' content= instanceName || 'Sharkey')
meta(property='instance_url' content= instanceUrl)
meta(name='viewport' content='width=device-width, initial-scale=1')
+ meta(name='format-detection' content='telephone=no,date=no,address=no,email=no,url=no')
link(rel='icon' href= icon || '/favicon.ico')
link(rel='apple-touch-icon' href= appleTouchIcon || '/apple-touch-icon.png')
link(rel='manifest' href='/manifest.json')