1 import { PathLike } from 'fs-extra'
2 import { Transaction } from 'sequelize/types'
3 import { AbuseAuditView, auditLoggerFactory } from '@server/helpers/audit-logger'
4 import { logger } from '@server/helpers/logger'
5 import { AbuseModel } from '@server/models/abuse/abuse'
6 import { VideoAbuseModel } from '@server/models/abuse/video-abuse'
7 import { VideoCommentAbuseModel } from '@server/models/abuse/video-comment-abuse'
8 import { VideoFileModel } from '@server/models/video/video-file'
9 import { FilteredModelAttributes } from '@server/types'
14 MCommentAbuseAccountVideo,
18 MVideoAccountLightBlacklistAllFiles
19 } from '@server/types/models'
20 import { ActivityCreate } from '../../shared/models/activitypub'
21 import { VideoObject } from '../../shared/models/activitypub/objects'
22 import { VideoCommentObject } from '../../shared/models/activitypub/objects/video-comment-object'
23 import { LiveVideoCreate, VideoCreate, VideoImportCreate } from '../../shared/models/videos'
24 import { VideoCommentCreate } from '../../shared/models/videos/video-comment.model'
25 import { UserModel } from '../models/account/user'
26 import { ActorModel } from '../models/activitypub/actor'
27 import { VideoModel } from '../models/video/video'
28 import { VideoCommentModel } from '../models/video/video-comment'
29 import { sendAbuse } from './activitypub/send/send-flag'
30 import { Notifier } from './notifier'
31 import { afterCommitIfTransaction } from '@server/helpers/database-utils'
33 export type AcceptResult = {
38 // Can be filtered by plugins
39 function isLocalVideoAccepted (object: {
40 videoBody: VideoCreate
41 videoFile: Express.Multer.File & { duration?: number }
44 return { accepted: true }
47 function isLocalLiveVideoAccepted (object: {
48 liveVideoBody: LiveVideoCreate
51 return { accepted: true }
54 function isLocalVideoThreadAccepted (_object: {
55 commentBody: VideoCommentCreate
59 return { accepted: true }
62 function isLocalVideoCommentReplyAccepted (_object: {
63 commentBody: VideoCommentCreate
64 parentComment: VideoCommentModel
68 return { accepted: true }
71 function isRemoteVideoAccepted (_object: {
72 activity: ActivityCreate
76 return { accepted: true }
79 function isRemoteVideoCommentAccepted (_object: {
80 activity: ActivityCreate
81 commentAP: VideoCommentObject
84 return { accepted: true }
87 function isPreImportVideoAccepted (object: {
88 videoImportBody: VideoImportCreate
91 return { accepted: true }
94 function isPostImportVideoAccepted (object: {
95 videoFilePath: PathLike
96 videoFile: VideoFileModel
99 return { accepted: true }
102 async function createVideoAbuse (options: {
103 baseAbuse: FilteredModelAttributes<AbuseModel>
104 videoInstance: MVideoAccountLightBlacklistAllFiles
107 transaction: Transaction
108 reporterAccount: MAccountDefault
110 const { baseAbuse, videoInstance, startAt, endAt, transaction, reporterAccount } = options
112 const associateFun = async (abuseInstance: MAbuseFull) => {
113 const videoAbuseInstance: MVideoAbuseVideoFull = await VideoAbuseModel.create({
114 abuseId: abuseInstance.id,
115 videoId: videoInstance.id,
120 videoAbuseInstance.Video = videoInstance
121 abuseInstance.VideoAbuse = videoAbuseInstance
123 return { isOwned: videoInstance.isOwned() }
129 flaggedAccount: videoInstance.VideoChannel.Account,
135 function createVideoCommentAbuse (options: {
136 baseAbuse: FilteredModelAttributes<AbuseModel>
137 commentInstance: MCommentOwnerVideo
138 transaction: Transaction
139 reporterAccount: MAccountDefault
141 const { baseAbuse, commentInstance, transaction, reporterAccount } = options
143 const associateFun = async (abuseInstance: MAbuseFull) => {
144 const commentAbuseInstance: MCommentAbuseAccountVideo = await VideoCommentAbuseModel.create({
145 abuseId: abuseInstance.id,
146 videoCommentId: commentInstance.id
149 commentAbuseInstance.VideoComment = commentInstance
150 abuseInstance.VideoCommentAbuse = commentAbuseInstance
152 return { isOwned: commentInstance.isOwned() }
158 flaggedAccount: commentInstance.Account,
164 function createAccountAbuse (options: {
165 baseAbuse: FilteredModelAttributes<AbuseModel>
166 accountInstance: MAccountDefault
167 transaction: Transaction
168 reporterAccount: MAccountDefault
170 const { baseAbuse, accountInstance, transaction, reporterAccount } = options
172 const associateFun = async () => {
173 return { isOwned: accountInstance.isOwned() }
179 flaggedAccount: accountInstance,
186 isLocalLiveVideoAccepted,
188 isLocalVideoAccepted,
189 isLocalVideoThreadAccepted,
190 isRemoteVideoAccepted,
191 isRemoteVideoCommentAccepted,
192 isLocalVideoCommentReplyAccepted,
193 isPreImportVideoAccepted,
194 isPostImportVideoAccepted,
198 createVideoCommentAbuse,
202 // ---------------------------------------------------------------------------
204 async function createAbuse (options: {
205 base: FilteredModelAttributes<AbuseModel>
206 reporterAccount: MAccountDefault
207 flaggedAccount: MAccountLight
208 associateFun: (abuseInstance: MAbuseFull) => Promise<{ isOwned: boolean} >
209 transaction: Transaction
211 const { base, reporterAccount, flaggedAccount, associateFun, transaction } = options
212 const auditLogger = auditLoggerFactory('abuse')
214 const abuseAttributes = Object.assign({}, base, { flaggedAccountId: flaggedAccount.id })
215 const abuseInstance: MAbuseFull = await AbuseModel.create(abuseAttributes, { transaction })
217 abuseInstance.ReporterAccount = reporterAccount
218 abuseInstance.FlaggedAccount = flaggedAccount
220 const { isOwned } = await associateFun(abuseInstance)
222 if (isOwned === false) {
223 await sendAbuse(reporterAccount.Actor, abuseInstance, abuseInstance.FlaggedAccount, transaction)
226 const abuseJSON = abuseInstance.toFormattedAdminJSON()
227 auditLogger.create(reporterAccount.Actor.getIdentifier(), new AbuseAuditView(abuseJSON))
229 afterCommitIfTransaction(transaction, () => {
230 Notifier.Instance.notifyOnNewAbuse({
233 reporter: reporterAccount.Actor.getIdentifier()
237 logger.info('Abuse report %d created.', abuseInstance.id)