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