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'
32 export type AcceptResult = {
37 // Can be filtered by plugins
38 function isLocalVideoAccepted (object: {
39 videoBody: VideoCreate
40 videoFile: Express.Multer.File & { duration?: number }
43 return { accepted: true }
46 function isLocalLiveVideoAccepted (object: {
47 liveVideoBody: LiveVideoCreate
50 return { accepted: true }
53 function isLocalVideoThreadAccepted (_object: {
54 commentBody: VideoCommentCreate
58 return { accepted: true }
61 function isLocalVideoCommentReplyAccepted (_object: {
62 commentBody: VideoCommentCreate
63 parentComment: VideoCommentModel
67 return { accepted: true }
70 function isRemoteVideoAccepted (_object: {
71 activity: ActivityCreate
75 return { accepted: true }
78 function isRemoteVideoCommentAccepted (_object: {
79 activity: ActivityCreate
80 commentAP: VideoCommentObject
83 return { accepted: true }
86 function isPreImportVideoAccepted (object: {
87 videoImportBody: VideoImportCreate
90 return { accepted: true }
93 function isPostImportVideoAccepted (object: {
94 videoFilePath: PathLike
95 videoFile: VideoFileModel
98 return { accepted: true }
101 async function createVideoAbuse (options: {
102 baseAbuse: FilteredModelAttributes<AbuseModel>
103 videoInstance: MVideoAccountLightBlacklistAllFiles
106 transaction: Transaction
107 reporterAccount: MAccountDefault
109 const { baseAbuse, videoInstance, startAt, endAt, transaction, reporterAccount } = options
111 const associateFun = async (abuseInstance: MAbuseFull) => {
112 const videoAbuseInstance: MVideoAbuseVideoFull = await VideoAbuseModel.create({
113 abuseId: abuseInstance.id,
114 videoId: videoInstance.id,
119 videoAbuseInstance.Video = videoInstance
120 abuseInstance.VideoAbuse = videoAbuseInstance
122 return { isOwned: videoInstance.isOwned() }
128 flaggedAccount: videoInstance.VideoChannel.Account,
134 function createVideoCommentAbuse (options: {
135 baseAbuse: FilteredModelAttributes<AbuseModel>
136 commentInstance: MCommentOwnerVideo
137 transaction: Transaction
138 reporterAccount: MAccountDefault
140 const { baseAbuse, commentInstance, transaction, reporterAccount } = options
142 const associateFun = async (abuseInstance: MAbuseFull) => {
143 const commentAbuseInstance: MCommentAbuseAccountVideo = await VideoCommentAbuseModel.create({
144 abuseId: abuseInstance.id,
145 videoCommentId: commentInstance.id
148 commentAbuseInstance.VideoComment = commentInstance
149 abuseInstance.VideoCommentAbuse = commentAbuseInstance
151 return { isOwned: commentInstance.isOwned() }
157 flaggedAccount: commentInstance.Account,
163 function createAccountAbuse (options: {
164 baseAbuse: FilteredModelAttributes<AbuseModel>
165 accountInstance: MAccountDefault
166 transaction: Transaction
167 reporterAccount: MAccountDefault
169 const { baseAbuse, accountInstance, transaction, reporterAccount } = options
171 const associateFun = async () => {
172 return { isOwned: accountInstance.isOwned() }
178 flaggedAccount: accountInstance,
185 isLocalLiveVideoAccepted,
187 isLocalVideoAccepted,
188 isLocalVideoThreadAccepted,
189 isRemoteVideoAccepted,
190 isRemoteVideoCommentAccepted,
191 isLocalVideoCommentReplyAccepted,
192 isPreImportVideoAccepted,
193 isPostImportVideoAccepted,
197 createVideoCommentAbuse,
201 // ---------------------------------------------------------------------------
203 async function createAbuse (options: {
204 base: FilteredModelAttributes<AbuseModel>
205 reporterAccount: MAccountDefault
206 flaggedAccount: MAccountLight
207 associateFun: (abuseInstance: MAbuseFull) => Promise<{ isOwned: boolean} >
208 transaction: Transaction
210 const { base, reporterAccount, flaggedAccount, associateFun, transaction } = options
211 const auditLogger = auditLoggerFactory('abuse')
213 const abuseAttributes = Object.assign({}, base, { flaggedAccountId: flaggedAccount.id })
214 const abuseInstance: MAbuseFull = await AbuseModel.create(abuseAttributes, { transaction })
216 abuseInstance.ReporterAccount = reporterAccount
217 abuseInstance.FlaggedAccount = flaggedAccount
219 const { isOwned } = await associateFun(abuseInstance)
221 if (isOwned === false) {
222 await sendAbuse(reporterAccount.Actor, abuseInstance, abuseInstance.FlaggedAccount, transaction)
225 const abuseJSON = abuseInstance.toFormattedAdminJSON()
226 auditLogger.create(reporterAccount.Actor.getIdentifier(), new AbuseAuditView(abuseJSON))
228 Notifier.Instance.notifyOnNewAbuse({
231 reporter: reporterAccount.Actor.getIdentifier()
234 logger.info('Abuse report %d created.', abuseInstance.id)