misskey/packages/backend/src/queue/processors/ReportAbuseProcessorService.ts

115 lines
4.4 KiB
TypeScript

import { Injectable, Inject } from '@nestjs/common';
import { MoreThan, IsNull } from 'typeorm';
import RE2 from 're2';
import sanitizeHtml from 'sanitize-html';
import { bindThis } from '@/decorators.js';
import type Logger from '@/logger.js';
import { RoleService } from '@/core/RoleService.js';
import { MetaService } from '@/core/MetaService.js';
import { EmailService } from '@/core/EmailService.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { InstanceActorService } from '@/core/InstanceActorService.js';
import type { AbuseReportResolversRepository, AbuseUserReportsRepository, UsersRepository } from '@/models/index.js';
import { DI } from '@/di-symbols.js';
import { ApRendererService } from '@/core/activitypub/ApRendererService.js';
import { QueueService } from '@/core/QueueService.js';
import { QueueLoggerService } from '../QueueLoggerService.js';
import type { DbAbuseReportJobData } from '../types.js';
import type * as Bull from 'bullmq';
@Injectable()
export class ReportAbuseProcessorService {
private logger: Logger;
constructor(
@Inject(DI.abuseReportResolversRepository)
private abuseReportResolversRepository: AbuseReportResolversRepository,
@Inject(DI.abuseUserReportsRepository)
private abuseUserReportsRepository: AbuseUserReportsRepository,
@Inject(DI.usersRepository)
private usersRepository: UsersRepository,
private queueLoggerService: QueueLoggerService,
private globalEventService: GlobalEventService,
private instanceActorService: InstanceActorService,
private apRendererService: ApRendererService,
private roleService: RoleService,
private metaService: MetaService,
private emailService: EmailService,
private queueService: QueueService,
) {
this.logger = this.queueLoggerService.logger.createSubLogger('report-abuse');
}
@bindThis
public async process(job: Bull.Job<DbAbuseReportJobData>): Promise<void> {
this.logger.info('Running...');
const resolvers = await this.abuseReportResolversRepository.find({
where: [
{ expirationDate: MoreThan(new Date()) },
{ expirationDate: IsNull() },
],
});
const targetUser = await this.usersRepository.findOneByOrFail({
id: job.data.targetUserId,
});
const reporter = await this.usersRepository.findOneByOrFail({
id: job.data.reporterId,
});
const actor = await this.instanceActorService.getInstanceActor();
const targetUserAcct = targetUser.host ? `${targetUser.username.toLowerCase()}@${targetUser.host}` : targetUser.username.toLowerCase();
const reporterAcct = reporter.host ? `${reporter.username.toLowerCase()}@${reporter.host}` : reporter.username.toLowerCase();
for (const resolver of resolvers) {
if (!(resolver.targetUserPattern || resolver.reporterPattern || resolver.reportContentPattern)) {
continue;
}
const isTargetUserPatternMatched = resolver.targetUserPattern ? new RE2(resolver.targetUserPattern).test(targetUserAcct) : true;
const isReporterPatternMatched = resolver.reporterPattern ? new RE2(resolver.reporterPattern).test(reporterAcct) : true;
const isReportContentPatternMatched = resolver.reportContentPattern ? new RE2(resolver.reportContentPattern).test(job.data.comment) : true;
if (isTargetUserPatternMatched && isReporterPatternMatched && isReportContentPatternMatched) {
if (resolver.forward && job.data.targetUserHost !== null && job.data.reporterHost === null) {
this.queueService.deliver(actor, this.apRendererService.addContext(this.apRendererService.renderFlag(actor, targetUser.uri!, job.data.comment)), targetUser.inbox, false);
}
await this.abuseUserReportsRepository.update(job.data.id, {
resolved: true,
assigneeId: actor.id,
forwarded: resolver.forward && job.data.targetUserHost !== null && job.data.reporterHost === null,
});
return;
}
}
// Publish event to moderators
setImmediate(async () => {
const moderators = await this.roleService.getModerators();
for (const moderator of moderators) {
this.globalEventService.publishAdminStream(moderator.id, 'newAbuseUserReport', {
id: job.data.id,
targetUserId: job.data.targetUserId,
reporterId: job.data.reporterId,
comment: job.data.comment,
});
}
const meta = await this.metaService.fetch();
if (meta.email) {
this.emailService.sendEmail(meta.email, 'New abuse report',
sanitizeHtml(job.data.comment),
sanitizeHtml(job.data.comment));
}
});
}
}