Merge remote-tracking branch 'misskey/master' into feature/misskey-2024.8
This commit is contained in:
commit
6151099f5b
81 changed files with 1428 additions and 567 deletions
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 => {});
|
||||
})();
|
||||
await this.userSuspendService.suspend(user, me);
|
||||
});
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private async unFollowAll(follower: MiUser) {
|
||||
const followings = await this.followingsRepository.find({
|
||||
where: {
|
||||
followerId: follower.id,
|
||||
followeeId: Not(IsNull()),
|
||||
},
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,23 +95,25 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,23 +104,25 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue