feat(backend): 通報および通報解決時に送出されるSystemWebhookにユーザ情報を含めるようにする (#14698)

* feat(backend): 通報および通報解決時に送出されるSystemWebhookにユーザ情報を含めるようにする

* テスト送信もペイロード形式を合わせる

* add spaces

* fix test
This commit is contained in:
おさむのひと 2024-10-05 12:51:46 +09:00 committed by GitHub
parent ae3c155490
commit 88698462a9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 46 additions and 6 deletions

View file

@ -21,7 +21,7 @@
### Server ### Server
- Enhance: セキュリティ向上のため、ログイン時にメール通知を行うように - Enhance: セキュリティ向上のため、ログイン時にメール通知を行うように
- Enhance: 自分とモデレーター以外のユーザーから二要素認証関連のデータが取得できないように - Enhance: 自分とモデレーター以外のユーザーから二要素認証関連のデータが取得できないように
- Enhance: 通報および通報解決時に送出されるSystemWebhookにユーザ情報を含めるように ( #14697 )
## 2024.9.0 ## 2024.9.0

View file

@ -22,6 +22,7 @@ import { RoleService } from '@/core/RoleService.js';
import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js'; import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
import { ModerationLogService } from '@/core/ModerationLogService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js';
import { SystemWebhookService } from '@/core/SystemWebhookService.js'; import { SystemWebhookService } from '@/core/SystemWebhookService.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { IdService } from './IdService.js'; import { IdService } from './IdService.js';
@Injectable() @Injectable()
@ -42,6 +43,7 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
private emailService: EmailService, private emailService: EmailService,
private moderationLogService: ModerationLogService, private moderationLogService: ModerationLogService,
private globalEventService: GlobalEventService, private globalEventService: GlobalEventService,
private userEntityService: UserEntityService,
) { ) {
this.redisForSub.on('message', this.onMessage); this.redisForSub.on('message', this.onMessage);
} }
@ -135,6 +137,26 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
return; return;
} }
const usersMap = await this.userEntityService.packMany(
[
...new Set([
...abuseReports.map(it => it.reporter ?? it.reporterId),
...abuseReports.map(it => it.targetUser ?? it.targetUserId),
...abuseReports.map(it => it.assignee ?? it.assigneeId),
].filter(x => x != null)),
],
null,
{ schema: 'UserLite' },
).then(it => new Map(it.map(it => [it.id, it])));
const convertedReports = abuseReports.map(it => {
return {
...it,
reporter: usersMap.get(it.reporterId),
targetUser: usersMap.get(it.targetUserId),
assignee: it.assigneeId ? usersMap.get(it.assigneeId) : null,
};
});
const recipientWebhookIds = await this.fetchWebhookRecipients() const recipientWebhookIds = await this.fetchWebhookRecipients()
.then(it => it .then(it => it
.filter(it => it.isActive && it.systemWebhookId && it.method === 'webhook') .filter(it => it.isActive && it.systemWebhookId && it.method === 'webhook')
@ -142,7 +164,7 @@ export class AbuseReportNotificationService implements OnApplicationShutdown {
.filter(x => x != null)); .filter(x => x != null));
for (const webhookId of recipientWebhookIds) { for (const webhookId of recipientWebhookIds) {
await Promise.all( await Promise.all(
abuseReports.map(it => { convertedReports.map(it => {
return this.systemWebhookService.enqueueSystemWebhook( return this.systemWebhookService.enqueueSystemWebhook(
webhookId, webhookId,
type, type,

View file

@ -15,8 +15,14 @@ import { QueueService } from '@/core/QueueService.js';
const oneDayMillis = 24 * 60 * 60 * 1000; const oneDayMillis = 24 * 60 * 60 * 1000;
function generateAbuseReport(override?: Partial<MiAbuseUserReport>): MiAbuseUserReport { type AbuseUserReportDto = Omit<MiAbuseUserReport, 'targetUser' | 'reporter' | 'assignee'> & {
return { targetUser: Packed<'UserLite'> | null,
reporter: Packed<'UserLite'> | null,
assignee: Packed<'UserLite'> | null,
};
function generateAbuseReport(override?: Partial<MiAbuseUserReport>): AbuseUserReportDto {
const result: MiAbuseUserReport = {
id: 'dummy-abuse-report1', id: 'dummy-abuse-report1',
targetUserId: 'dummy-target-user', targetUserId: 'dummy-target-user',
targetUser: null, targetUser: null,
@ -31,6 +37,13 @@ function generateAbuseReport(override?: Partial<MiAbuseUserReport>): MiAbuseUser
reporterHost: null, reporterHost: null,
...override, ...override,
}; };
return {
...result,
targetUser: result.targetUser ? toPackedUserLite(result.targetUser) : null,
reporter: result.reporter ? toPackedUserLite(result.reporter) : null,
assignee: result.assignee ? toPackedUserLite(result.assignee) : null,
};
} }
function generateDummyUser(override?: Partial<MiUser>): MiUser { function generateDummyUser(override?: Partial<MiUser>): MiUser {
@ -268,7 +281,8 @@ const dummyUser3 = generateDummyUser({
@Injectable() @Injectable()
export class WebhookTestService { export class WebhookTestService {
public static NoSuchWebhookError = class extends Error {}; public static NoSuchWebhookError = class extends Error {
};
constructor( constructor(
private userWebhookService: UserWebhookService, private userWebhookService: UserWebhookService,

View file

@ -5,6 +5,7 @@
import { jest } from '@jest/globals'; import { jest } from '@jest/globals';
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { randomString } from '../utils.js';
import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js';
import { import {
AbuseReportNotificationRecipientRepository, AbuseReportNotificationRecipientRepository,
@ -25,7 +26,7 @@ import { ModerationLogService } from '@/core/ModerationLogService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js';
import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js'; import { RecipientMethod } from '@/models/AbuseReportNotificationRecipient.js';
import { SystemWebhookService } from '@/core/SystemWebhookService.js'; import { SystemWebhookService } from '@/core/SystemWebhookService.js';
import { randomString } from '../utils.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js';
process.env.NODE_ENV = 'test'; process.env.NODE_ENV = 'test';
@ -110,6 +111,9 @@ describe('AbuseReportNotificationService', () => {
{ {
provide: SystemWebhookService, useFactory: () => ({ enqueueSystemWebhook: jest.fn() }), provide: SystemWebhookService, useFactory: () => ({ enqueueSystemWebhook: jest.fn() }),
}, },
{
provide: UserEntityService, useFactory: () => ({ pack: (v: any) => v }),
},
{ {
provide: EmailService, useFactory: () => ({ sendEmail: jest.fn() }), provide: EmailService, useFactory: () => ({ sendEmail: jest.fn() }),
}, },