X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Fmoderation.ts;h=dc5d8c83c3592bc94235805255a4900cb4805581;hb=f50bff17f5b69c576960360857e25224cea13c0a;hp=55f7a985dee6b0ccf941dcdadab47cea01873467;hpb=818c449b3c34e9f324ac744120c8774e724ab25e;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/moderation.ts b/server/lib/moderation.ts index 55f7a985d..dc5d8c83c 100644 --- a/server/lib/moderation.ts +++ b/server/lib/moderation.ts @@ -1,28 +1,64 @@ +import express, { VideoUploadFile } from 'express' +import { PathLike } from 'fs-extra' +import { Transaction } from 'sequelize/types' +import { AbuseAuditView, auditLoggerFactory } from '@server/helpers/audit-logger' +import { afterCommitIfTransaction } from '@server/helpers/database-utils' +import { logger } from '@server/helpers/logger' +import { AbuseModel } from '@server/models/abuse/abuse' +import { VideoAbuseModel } from '@server/models/abuse/video-abuse' +import { VideoCommentAbuseModel } from '@server/models/abuse/video-comment-abuse' +import { VideoFileModel } from '@server/models/video/video-file' +import { FilteredModelAttributes } from '@server/types' +import { + MAbuseFull, + MAccountDefault, + MAccountLight, + MComment, + MCommentAbuseAccountVideo, + MCommentOwnerVideo, + MUser, + MVideoAbuseVideoFull, + MVideoAccountLightBlacklistAllFiles +} from '@server/types/models' +import { LiveVideoCreate, VideoCreate, VideoImportCreate } from '../../shared/models/videos' +import { VideoCommentCreate } from '../../shared/models/videos/comment' +import { UserModel } from '../models/user/user' import { VideoModel } from '../models/video/video' import { VideoCommentModel } from '../models/video/video-comment' -import { VideoCommentCreate } from '../../shared/models/videos/video-comment.model' -import { VideoCreate } from '../../shared/models/videos' -import { UserModel } from '../models/account/user' -import { VideoTorrentObject } from '../../shared/models/activitypub/objects' -import { ActivityCreate } from '../../shared/models/activitypub' -import { ActorModel } from '../models/activitypub/actor' -import { VideoCommentObject } from '../../shared/models/activitypub/objects/video-comment-object' +import { sendAbuse } from './activitypub/send/send-flag' +import { Notifier } from './notifier' export type AcceptResult = { accepted: boolean errorMessage?: string } -// Can be filtered by plugins +// --------------------------------------------------------------------------- + +// Stub function that can be filtered by plugins function isLocalVideoAccepted (object: { videoBody: VideoCreate - videoFile: Express.Multer.File & { duration?: number } + videoFile: VideoUploadFile + user: UserModel +}): AcceptResult { + return { accepted: true } +} + +// --------------------------------------------------------------------------- + +// Stub function that can be filtered by plugins +function isLocalLiveVideoAccepted (object: { + liveVideoBody: LiveVideoCreate user: UserModel }): AcceptResult { return { accepted: true } } +// --------------------------------------------------------------------------- + +// Stub function that can be filtered by plugins function isLocalVideoThreadAccepted (_object: { + req: express.Request commentBody: VideoCommentCreate video: VideoModel user: UserModel @@ -30,7 +66,9 @@ function isLocalVideoThreadAccepted (_object: { return { accepted: true } } +// Stub function that can be filtered by plugins function isLocalVideoCommentReplyAccepted (_object: { + req: express.Request commentBody: VideoCommentCreate parentComment: VideoCommentModel video: VideoModel @@ -39,26 +77,182 @@ function isLocalVideoCommentReplyAccepted (_object: { return { accepted: true } } -function isRemoteVideoAccepted (_object: { - activity: ActivityCreate - videoAP: VideoTorrentObject - byActor: ActorModel +// --------------------------------------------------------------------------- + +// Stub function that can be filtered by plugins +function isRemoteVideoCommentAccepted (_object: { + comment: MComment }): AcceptResult { return { accepted: true } } -function isRemoteVideoCommentAccepted (_object: { - activity: ActivityCreate - commentAP: VideoCommentObject - byActor: ActorModel +// --------------------------------------------------------------------------- + +// Stub function that can be filtered by plugins +function isPreImportVideoAccepted (object: { + videoImportBody: VideoImportCreate + user: MUser }): AcceptResult { return { accepted: true } } +// Stub function that can be filtered by plugins +function isPostImportVideoAccepted (object: { + videoFilePath: PathLike + videoFile: VideoFileModel + user: MUser +}): AcceptResult { + return { accepted: true } +} + +// --------------------------------------------------------------------------- + +async function createVideoAbuse (options: { + baseAbuse: FilteredModelAttributes + videoInstance: MVideoAccountLightBlacklistAllFiles + startAt: number + endAt: number + transaction: Transaction + reporterAccount: MAccountDefault + skipNotification: boolean +}) { + const { baseAbuse, videoInstance, startAt, endAt, transaction, reporterAccount, skipNotification } = options + + const associateFun = async (abuseInstance: MAbuseFull) => { + const videoAbuseInstance: MVideoAbuseVideoFull = await VideoAbuseModel.create({ + abuseId: abuseInstance.id, + videoId: videoInstance.id, + startAt, + endAt + }, { transaction }) + + videoAbuseInstance.Video = videoInstance + abuseInstance.VideoAbuse = videoAbuseInstance + + return { isOwned: videoInstance.isOwned() } + } + + return createAbuse({ + base: baseAbuse, + reporterAccount, + flaggedAccount: videoInstance.VideoChannel.Account, + transaction, + skipNotification, + associateFun + }) +} + +function createVideoCommentAbuse (options: { + baseAbuse: FilteredModelAttributes + commentInstance: MCommentOwnerVideo + transaction: Transaction + reporterAccount: MAccountDefault + skipNotification: boolean +}) { + const { baseAbuse, commentInstance, transaction, reporterAccount, skipNotification } = options + + const associateFun = async (abuseInstance: MAbuseFull) => { + const commentAbuseInstance: MCommentAbuseAccountVideo = await VideoCommentAbuseModel.create({ + abuseId: abuseInstance.id, + videoCommentId: commentInstance.id + }, { transaction }) + + commentAbuseInstance.VideoComment = commentInstance + abuseInstance.VideoCommentAbuse = commentAbuseInstance + + return { isOwned: commentInstance.isOwned() } + } + + return createAbuse({ + base: baseAbuse, + reporterAccount, + flaggedAccount: commentInstance.Account, + transaction, + skipNotification, + associateFun + }) +} + +function createAccountAbuse (options: { + baseAbuse: FilteredModelAttributes + accountInstance: MAccountDefault + transaction: Transaction + reporterAccount: MAccountDefault + skipNotification: boolean +}) { + const { baseAbuse, accountInstance, transaction, reporterAccount, skipNotification } = options + + const associateFun = () => { + return Promise.resolve({ isOwned: accountInstance.isOwned() }) + } + + return createAbuse({ + base: baseAbuse, + reporterAccount, + flaggedAccount: accountInstance, + transaction, + skipNotification, + associateFun + }) +} + +// --------------------------------------------------------------------------- + export { + isLocalLiveVideoAccepted, + isLocalVideoAccepted, isLocalVideoThreadAccepted, - isRemoteVideoAccepted, isRemoteVideoCommentAccepted, - isLocalVideoCommentReplyAccepted + isLocalVideoCommentReplyAccepted, + isPreImportVideoAccepted, + isPostImportVideoAccepted, + + createAbuse, + createVideoAbuse, + createVideoCommentAbuse, + createAccountAbuse +} + +// --------------------------------------------------------------------------- + +async function createAbuse (options: { + base: FilteredModelAttributes + reporterAccount: MAccountDefault + flaggedAccount: MAccountLight + associateFun: (abuseInstance: MAbuseFull) => Promise<{ isOwned: boolean }> + skipNotification: boolean + transaction: Transaction +}) { + const { base, reporterAccount, flaggedAccount, associateFun, transaction, skipNotification } = options + const auditLogger = auditLoggerFactory('abuse') + + const abuseAttributes = Object.assign({}, base, { flaggedAccountId: flaggedAccount.id }) + const abuseInstance: MAbuseFull = await AbuseModel.create(abuseAttributes, { transaction }) + + abuseInstance.ReporterAccount = reporterAccount + abuseInstance.FlaggedAccount = flaggedAccount + + const { isOwned } = await associateFun(abuseInstance) + + if (isOwned === false) { + sendAbuse(reporterAccount.Actor, abuseInstance, abuseInstance.FlaggedAccount, transaction) + } + + const abuseJSON = abuseInstance.toFormattedAdminJSON() + auditLogger.create(reporterAccount.Actor.getIdentifier(), new AbuseAuditView(abuseJSON)) + + if (!skipNotification) { + afterCommitIfTransaction(transaction, () => { + Notifier.Instance.notifyOnNewAbuse({ + abuse: abuseJSON, + abuseInstance, + reporter: reporterAccount.Actor.getIdentifier() + }) + }) + } + + logger.info('Abuse report %d created.', abuseInstance.id) + + return abuseJSON }