]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/lib/moderation.ts
Bumped to version v5.2.1
[github/Chocobozzz/PeerTube.git] / server / lib / moderation.ts
1 import express, { VideoUploadFile } from 'express'
2 import { PathLike } from 'fs-extra'
3 import { Transaction } from 'sequelize/types'
4 import { AbuseAuditView, auditLoggerFactory } from '@server/helpers/audit-logger'
5 import { afterCommitIfTransaction } from '@server/helpers/database-utils'
6 import { logger } from '@server/helpers/logger'
7 import { AbuseModel } from '@server/models/abuse/abuse'
8 import { VideoAbuseModel } from '@server/models/abuse/video-abuse'
9 import { VideoCommentAbuseModel } from '@server/models/abuse/video-comment-abuse'
10 import { VideoFileModel } from '@server/models/video/video-file'
11 import { FilteredModelAttributes } from '@server/types'
12 import {
13 MAbuseFull,
14 MAccountDefault,
15 MAccountLight,
16 MComment,
17 MCommentAbuseAccountVideo,
18 MCommentOwnerVideo,
19 MUser,
20 MVideoAbuseVideoFull,
21 MVideoAccountLightBlacklistAllFiles
22 } from '@server/types/models'
23 import { LiveVideoCreate, VideoCreate, VideoImportCreate } from '../../shared/models/videos'
24 import { VideoCommentCreate } from '../../shared/models/videos/comment'
25 import { UserModel } from '../models/user/user'
26 import { VideoModel } from '../models/video/video'
27 import { VideoCommentModel } from '../models/video/video-comment'
28 import { sendAbuse } from './activitypub/send/send-flag'
29 import { Notifier } from './notifier'
30
31 export type AcceptResult = {
32 accepted: boolean
33 errorMessage?: string
34 }
35
36 // ---------------------------------------------------------------------------
37
38 // Stub function that can be filtered by plugins
39 function isLocalVideoAccepted (object: {
40 videoBody: VideoCreate
41 videoFile: VideoUploadFile
42 user: UserModel
43 }): AcceptResult {
44 return { accepted: true }
45 }
46
47 // ---------------------------------------------------------------------------
48
49 // Stub function that can be filtered by plugins
50 function isLocalLiveVideoAccepted (object: {
51 liveVideoBody: LiveVideoCreate
52 user: UserModel
53 }): AcceptResult {
54 return { accepted: true }
55 }
56
57 // ---------------------------------------------------------------------------
58
59 // Stub function that can be filtered by plugins
60 function isLocalVideoThreadAccepted (_object: {
61 req: express.Request
62 commentBody: VideoCommentCreate
63 video: VideoModel
64 user: UserModel
65 }): AcceptResult {
66 return { accepted: true }
67 }
68
69 // Stub function that can be filtered by plugins
70 function isLocalVideoCommentReplyAccepted (_object: {
71 req: express.Request
72 commentBody: VideoCommentCreate
73 parentComment: VideoCommentModel
74 video: VideoModel
75 user: UserModel
76 }): AcceptResult {
77 return { accepted: true }
78 }
79
80 // ---------------------------------------------------------------------------
81
82 // Stub function that can be filtered by plugins
83 function isRemoteVideoCommentAccepted (_object: {
84 comment: MComment
85 }): AcceptResult {
86 return { accepted: true }
87 }
88
89 // ---------------------------------------------------------------------------
90
91 // Stub function that can be filtered by plugins
92 function isPreImportVideoAccepted (object: {
93 videoImportBody: VideoImportCreate
94 user: MUser
95 }): AcceptResult {
96 return { accepted: true }
97 }
98
99 // Stub function that can be filtered by plugins
100 function isPostImportVideoAccepted (object: {
101 videoFilePath: PathLike
102 videoFile: VideoFileModel
103 user: MUser
104 }): AcceptResult {
105 return { accepted: true }
106 }
107
108 // ---------------------------------------------------------------------------
109
110 async function createVideoAbuse (options: {
111 baseAbuse: FilteredModelAttributes<AbuseModel>
112 videoInstance: MVideoAccountLightBlacklistAllFiles
113 startAt: number
114 endAt: number
115 transaction: Transaction
116 reporterAccount: MAccountDefault
117 skipNotification: boolean
118 }) {
119 const { baseAbuse, videoInstance, startAt, endAt, transaction, reporterAccount, skipNotification } = options
120
121 const associateFun = async (abuseInstance: MAbuseFull) => {
122 const videoAbuseInstance: MVideoAbuseVideoFull = await VideoAbuseModel.create({
123 abuseId: abuseInstance.id,
124 videoId: videoInstance.id,
125 startAt,
126 endAt
127 }, { transaction })
128
129 videoAbuseInstance.Video = videoInstance
130 abuseInstance.VideoAbuse = videoAbuseInstance
131
132 return { isOwned: videoInstance.isOwned() }
133 }
134
135 return createAbuse({
136 base: baseAbuse,
137 reporterAccount,
138 flaggedAccount: videoInstance.VideoChannel.Account,
139 transaction,
140 skipNotification,
141 associateFun
142 })
143 }
144
145 function createVideoCommentAbuse (options: {
146 baseAbuse: FilteredModelAttributes<AbuseModel>
147 commentInstance: MCommentOwnerVideo
148 transaction: Transaction
149 reporterAccount: MAccountDefault
150 skipNotification: boolean
151 }) {
152 const { baseAbuse, commentInstance, transaction, reporterAccount, skipNotification } = options
153
154 const associateFun = async (abuseInstance: MAbuseFull) => {
155 const commentAbuseInstance: MCommentAbuseAccountVideo = await VideoCommentAbuseModel.create({
156 abuseId: abuseInstance.id,
157 videoCommentId: commentInstance.id
158 }, { transaction })
159
160 commentAbuseInstance.VideoComment = commentInstance
161 abuseInstance.VideoCommentAbuse = commentAbuseInstance
162
163 return { isOwned: commentInstance.isOwned() }
164 }
165
166 return createAbuse({
167 base: baseAbuse,
168 reporterAccount,
169 flaggedAccount: commentInstance.Account,
170 transaction,
171 skipNotification,
172 associateFun
173 })
174 }
175
176 function createAccountAbuse (options: {
177 baseAbuse: FilteredModelAttributes<AbuseModel>
178 accountInstance: MAccountDefault
179 transaction: Transaction
180 reporterAccount: MAccountDefault
181 skipNotification: boolean
182 }) {
183 const { baseAbuse, accountInstance, transaction, reporterAccount, skipNotification } = options
184
185 const associateFun = () => {
186 return Promise.resolve({ isOwned: accountInstance.isOwned() })
187 }
188
189 return createAbuse({
190 base: baseAbuse,
191 reporterAccount,
192 flaggedAccount: accountInstance,
193 transaction,
194 skipNotification,
195 associateFun
196 })
197 }
198
199 // ---------------------------------------------------------------------------
200
201 export {
202 isLocalLiveVideoAccepted,
203
204 isLocalVideoAccepted,
205 isLocalVideoThreadAccepted,
206 isRemoteVideoCommentAccepted,
207 isLocalVideoCommentReplyAccepted,
208 isPreImportVideoAccepted,
209 isPostImportVideoAccepted,
210
211 createAbuse,
212 createVideoAbuse,
213 createVideoCommentAbuse,
214 createAccountAbuse
215 }
216
217 // ---------------------------------------------------------------------------
218
219 async function createAbuse (options: {
220 base: FilteredModelAttributes<AbuseModel>
221 reporterAccount: MAccountDefault
222 flaggedAccount: MAccountLight
223 associateFun: (abuseInstance: MAbuseFull) => Promise<{ isOwned: boolean }>
224 skipNotification: boolean
225 transaction: Transaction
226 }) {
227 const { base, reporterAccount, flaggedAccount, associateFun, transaction, skipNotification } = options
228 const auditLogger = auditLoggerFactory('abuse')
229
230 const abuseAttributes = Object.assign({}, base, { flaggedAccountId: flaggedAccount.id })
231 const abuseInstance: MAbuseFull = await AbuseModel.create(abuseAttributes, { transaction })
232
233 abuseInstance.ReporterAccount = reporterAccount
234 abuseInstance.FlaggedAccount = flaggedAccount
235
236 const { isOwned } = await associateFun(abuseInstance)
237
238 if (isOwned === false) {
239 sendAbuse(reporterAccount.Actor, abuseInstance, abuseInstance.FlaggedAccount, transaction)
240 }
241
242 const abuseJSON = abuseInstance.toFormattedAdminJSON()
243 auditLogger.create(reporterAccount.Actor.getIdentifier(), new AbuseAuditView(abuseJSON))
244
245 if (!skipNotification) {
246 afterCommitIfTransaction(transaction, () => {
247 Notifier.Instance.notifyOnNewAbuse({
248 abuse: abuseJSON,
249 abuseInstance,
250 reporter: reporterAccount.Actor.getIdentifier()
251 })
252 })
253 }
254
255 logger.info('Abuse report %d created.', abuseInstance.id)
256
257 return abuseJSON
258 }