Add audit logs in various modules
- Videos - Videos comments - Users - Videos channels - Videos abuses - Custom config
This commit is contained in:
parent
5939081838
commit
80e36cd9fa
|
@ -9,10 +9,13 @@ import { CONFIG, CONSTRAINTS_FIELDS, reloadConfig } from '../../initializers'
|
||||||
import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares'
|
import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../middlewares'
|
||||||
import { customConfigUpdateValidator } from '../../middlewares/validators/config'
|
import { customConfigUpdateValidator } from '../../middlewares/validators/config'
|
||||||
import { ClientHtml } from '../../lib/client-html'
|
import { ClientHtml } from '../../lib/client-html'
|
||||||
|
import { CustomConfigAuditView, auditLoggerFactory } from '../../helpers/audit-logger'
|
||||||
|
|
||||||
const packageJSON = require('../../../../package.json')
|
const packageJSON = require('../../../../package.json')
|
||||||
const configRouter = express.Router()
|
const configRouter = express.Router()
|
||||||
|
|
||||||
|
const auditLogger = auditLoggerFactory('config')
|
||||||
|
|
||||||
configRouter.get('/about', getAbout)
|
configRouter.get('/about', getAbout)
|
||||||
configRouter.get('/',
|
configRouter.get('/',
|
||||||
asyncMiddleware(getConfig)
|
asyncMiddleware(getConfig)
|
||||||
|
@ -119,6 +122,11 @@ async function getCustomConfig (req: express.Request, res: express.Response, nex
|
||||||
async function deleteCustomConfig (req: express.Request, res: express.Response, next: express.NextFunction) {
|
async function deleteCustomConfig (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
await unlinkPromise(CONFIG.CUSTOM_FILE)
|
await unlinkPromise(CONFIG.CUSTOM_FILE)
|
||||||
|
|
||||||
|
auditLogger.delete(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new CustomConfigAuditView(customConfig())
|
||||||
|
)
|
||||||
|
|
||||||
reloadConfig()
|
reloadConfig()
|
||||||
ClientHtml.invalidCache()
|
ClientHtml.invalidCache()
|
||||||
|
|
||||||
|
@ -129,6 +137,7 @@ async function deleteCustomConfig (req: express.Request, res: express.Response,
|
||||||
|
|
||||||
async function updateCustomConfig (req: express.Request, res: express.Response, next: express.NextFunction) {
|
async function updateCustomConfig (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
const toUpdate: CustomConfig = req.body
|
const toUpdate: CustomConfig = req.body
|
||||||
|
const oldCustomConfigAuditKeys = new CustomConfigAuditView(customConfig())
|
||||||
|
|
||||||
// Force number conversion
|
// Force number conversion
|
||||||
toUpdate.cache.previews.size = parseInt('' + toUpdate.cache.previews.size, 10)
|
toUpdate.cache.previews.size = parseInt('' + toUpdate.cache.previews.size, 10)
|
||||||
|
@ -150,6 +159,13 @@ async function updateCustomConfig (req: express.Request, res: express.Response,
|
||||||
ClientHtml.invalidCache()
|
ClientHtml.invalidCache()
|
||||||
|
|
||||||
const data = customConfig()
|
const data = customConfig()
|
||||||
|
|
||||||
|
auditLogger.update(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new CustomConfigAuditView(data),
|
||||||
|
oldCustomConfigAuditKeys
|
||||||
|
)
|
||||||
|
|
||||||
return res.json(data).end()
|
return res.json(data).end()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,9 @@ import { createReqFiles } from '../../helpers/express-utils'
|
||||||
import { UserVideoQuota } from '../../../shared/models/users/user-video-quota.model'
|
import { UserVideoQuota } from '../../../shared/models/users/user-video-quota.model'
|
||||||
import { updateAvatarValidator } from '../../middlewares/validators/avatar'
|
import { updateAvatarValidator } from '../../middlewares/validators/avatar'
|
||||||
import { updateActorAvatarFile } from '../../lib/avatar'
|
import { updateActorAvatarFile } from '../../lib/avatar'
|
||||||
|
import { auditLoggerFactory, UserAuditView } from '../../helpers/audit-logger'
|
||||||
|
|
||||||
|
const auditLogger = auditLoggerFactory('users')
|
||||||
|
|
||||||
const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR })
|
const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR })
|
||||||
const loginRateLimiter = new RateLimit({
|
const loginRateLimiter = new RateLimit({
|
||||||
|
@ -189,6 +192,7 @@ async function createUser (req: express.Request, res: express.Response) {
|
||||||
|
|
||||||
const { user, account } = await createUserAccountAndChannel(userToCreate)
|
const { user, account } = await createUserAccountAndChannel(userToCreate)
|
||||||
|
|
||||||
|
auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new UserAuditView(user.toFormattedJSON()))
|
||||||
logger.info('User %s with its channel and account created.', body.username)
|
logger.info('User %s with its channel and account created.', body.username)
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
|
@ -205,7 +209,7 @@ async function createUser (req: express.Request, res: express.Response) {
|
||||||
async function registerUser (req: express.Request, res: express.Response) {
|
async function registerUser (req: express.Request, res: express.Response) {
|
||||||
const body: UserCreate = req.body
|
const body: UserCreate = req.body
|
||||||
|
|
||||||
const user = new UserModel({
|
const userToCreate = new UserModel({
|
||||||
username: body.username,
|
username: body.username,
|
||||||
password: body.password,
|
password: body.password,
|
||||||
email: body.email,
|
email: body.email,
|
||||||
|
@ -215,8 +219,9 @@ async function registerUser (req: express.Request, res: express.Response) {
|
||||||
videoQuota: CONFIG.USER.VIDEO_QUOTA
|
videoQuota: CONFIG.USER.VIDEO_QUOTA
|
||||||
})
|
})
|
||||||
|
|
||||||
await createUserAccountAndChannel(user)
|
const { user } = await createUserAccountAndChannel(userToCreate)
|
||||||
|
|
||||||
|
auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
|
||||||
logger.info('User %s with its channel and account registered.', body.username)
|
logger.info('User %s with its channel and account registered.', body.username)
|
||||||
|
|
||||||
return res.type('json').status(204).end()
|
return res.type('json').status(204).end()
|
||||||
|
@ -269,6 +274,8 @@ async function removeUser (req: express.Request, res: express.Response, next: ex
|
||||||
|
|
||||||
await user.destroy()
|
await user.destroy()
|
||||||
|
|
||||||
|
auditLogger.delete(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new UserAuditView(user.toFormattedJSON()))
|
||||||
|
|
||||||
return res.sendStatus(204)
|
return res.sendStatus(204)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,6 +283,7 @@ async function updateMe (req: express.Request, res: express.Response, next: expr
|
||||||
const body: UserUpdateMe = req.body
|
const body: UserUpdateMe = req.body
|
||||||
|
|
||||||
const user: UserModel = res.locals.oauth.token.user
|
const user: UserModel = res.locals.oauth.token.user
|
||||||
|
const oldUserAuditView = new UserAuditView(user.toFormattedJSON())
|
||||||
|
|
||||||
if (body.password !== undefined) user.password = body.password
|
if (body.password !== undefined) user.password = body.password
|
||||||
if (body.email !== undefined) user.email = body.email
|
if (body.email !== undefined) user.email = body.email
|
||||||
|
@ -290,6 +298,12 @@ async function updateMe (req: express.Request, res: express.Response, next: expr
|
||||||
await user.Account.save({ transaction: t })
|
await user.Account.save({ transaction: t })
|
||||||
|
|
||||||
await sendUpdateActor(user.Account, t)
|
await sendUpdateActor(user.Account, t)
|
||||||
|
|
||||||
|
auditLogger.update(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new UserAuditView(user.toFormattedJSON()),
|
||||||
|
oldUserAuditView
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
return res.sendStatus(204)
|
return res.sendStatus(204)
|
||||||
|
@ -297,10 +311,18 @@ async function updateMe (req: express.Request, res: express.Response, next: expr
|
||||||
|
|
||||||
async function updateMyAvatar (req: express.Request, res: express.Response, next: express.NextFunction) {
|
async function updateMyAvatar (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ]
|
const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ]
|
||||||
const account = res.locals.oauth.token.user.Account
|
const user: UserModel = res.locals.oauth.token.user
|
||||||
|
const oldUserAuditView = new UserAuditView(user.toFormattedJSON())
|
||||||
|
const account = user.Account
|
||||||
|
|
||||||
const avatar = await updateActorAvatarFile(avatarPhysicalFile, account.Actor, account)
|
const avatar = await updateActorAvatarFile(avatarPhysicalFile, account.Actor, account)
|
||||||
|
|
||||||
|
auditLogger.update(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new UserAuditView(user.toFormattedJSON()),
|
||||||
|
oldUserAuditView
|
||||||
|
)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
.json({
|
.json({
|
||||||
avatar: avatar.toFormattedJSON()
|
avatar: avatar.toFormattedJSON()
|
||||||
|
@ -310,20 +332,27 @@ async function updateMyAvatar (req: express.Request, res: express.Response, next
|
||||||
|
|
||||||
async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
const body: UserUpdate = req.body
|
const body: UserUpdate = req.body
|
||||||
const user = res.locals.user as UserModel
|
const userToUpdate = res.locals.user as UserModel
|
||||||
const roleChanged = body.role !== undefined && body.role !== user.role
|
const oldUserAuditView = new UserAuditView(userToUpdate.toFormattedJSON())
|
||||||
|
const roleChanged = body.role !== undefined && body.role !== userToUpdate.role
|
||||||
|
|
||||||
if (body.email !== undefined) user.email = body.email
|
if (body.email !== undefined) userToUpdate.email = body.email
|
||||||
if (body.videoQuota !== undefined) user.videoQuota = body.videoQuota
|
if (body.videoQuota !== undefined) userToUpdate.videoQuota = body.videoQuota
|
||||||
if (body.role !== undefined) user.role = body.role
|
if (body.role !== undefined) userToUpdate.role = body.role
|
||||||
|
|
||||||
await user.save()
|
const user = await userToUpdate.save()
|
||||||
|
|
||||||
// Destroy user token to refresh rights
|
// Destroy user token to refresh rights
|
||||||
if (roleChanged) {
|
if (roleChanged) {
|
||||||
await OAuthTokenModel.deleteUserToken(user.id)
|
await OAuthTokenModel.deleteUserToken(userToUpdate.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auditLogger.update(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new UserAuditView(user.toFormattedJSON()),
|
||||||
|
oldUserAuditView
|
||||||
|
)
|
||||||
|
|
||||||
// Don't need to send this update to followers, these attributes are not propagated
|
// Don't need to send this update to followers, these attributes are not propagated
|
||||||
|
|
||||||
return res.sendStatus(204)
|
return res.sendStatus(204)
|
||||||
|
|
|
@ -27,7 +27,9 @@ import { logger } from '../../helpers/logger'
|
||||||
import { VideoModel } from '../../models/video/video'
|
import { VideoModel } from '../../models/video/video'
|
||||||
import { updateAvatarValidator } from '../../middlewares/validators/avatar'
|
import { updateAvatarValidator } from '../../middlewares/validators/avatar'
|
||||||
import { updateActorAvatarFile } from '../../lib/avatar'
|
import { updateActorAvatarFile } from '../../lib/avatar'
|
||||||
|
import { auditLoggerFactory, VideoChannelAuditView } from '../../helpers/audit-logger'
|
||||||
|
|
||||||
|
const auditLogger = auditLoggerFactory('channels')
|
||||||
const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR })
|
const reqAvatarFile = createReqFiles([ 'avatarfile' ], IMAGE_MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.AVATARS_DIR })
|
||||||
|
|
||||||
const videoChannelRouter = express.Router()
|
const videoChannelRouter = express.Router()
|
||||||
|
@ -99,10 +101,17 @@ async function listVideoChannels (req: express.Request, res: express.Response, n
|
||||||
|
|
||||||
async function updateVideoChannelAvatar (req: express.Request, res: express.Response, next: express.NextFunction) {
|
async function updateVideoChannelAvatar (req: express.Request, res: express.Response, next: express.NextFunction) {
|
||||||
const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ]
|
const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ]
|
||||||
const videoChannel = res.locals.videoChannel
|
const videoChannel = res.locals.videoChannel as VideoChannelModel
|
||||||
|
const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON())
|
||||||
|
|
||||||
const avatar = await updateActorAvatarFile(avatarPhysicalFile, videoChannel.Actor, videoChannel)
|
const avatar = await updateActorAvatarFile(avatarPhysicalFile, videoChannel.Actor, videoChannel)
|
||||||
|
|
||||||
|
auditLogger.update(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new VideoChannelAuditView(videoChannel.toFormattedJSON()),
|
||||||
|
oldVideoChannelAuditKeys
|
||||||
|
)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
.json({
|
.json({
|
||||||
avatar: avatar.toFormattedJSON()
|
avatar: avatar.toFormattedJSON()
|
||||||
|
@ -121,6 +130,10 @@ async function addVideoChannel (req: express.Request, res: express.Response) {
|
||||||
setAsyncActorKeys(videoChannelCreated.Actor)
|
setAsyncActorKeys(videoChannelCreated.Actor)
|
||||||
.catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.uuid, { err }))
|
.catch(err => logger.error('Cannot set async actor keys for account %s.', videoChannelCreated.Actor.uuid, { err }))
|
||||||
|
|
||||||
|
auditLogger.create(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new VideoChannelAuditView(videoChannelCreated.toFormattedJSON())
|
||||||
|
)
|
||||||
logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid)
|
logger.info('Video channel with uuid %s created.', videoChannelCreated.Actor.uuid)
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
|
@ -134,6 +147,7 @@ async function addVideoChannel (req: express.Request, res: express.Response) {
|
||||||
async function updateVideoChannel (req: express.Request, res: express.Response) {
|
async function updateVideoChannel (req: express.Request, res: express.Response) {
|
||||||
const videoChannelInstance = res.locals.videoChannel as VideoChannelModel
|
const videoChannelInstance = res.locals.videoChannel as VideoChannelModel
|
||||||
const videoChannelFieldsSave = videoChannelInstance.toJSON()
|
const videoChannelFieldsSave = videoChannelInstance.toJSON()
|
||||||
|
const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannelInstance.toFormattedJSON())
|
||||||
const videoChannelInfoToUpdate = req.body as VideoChannelUpdate
|
const videoChannelInfoToUpdate = req.body as VideoChannelUpdate
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -148,9 +162,14 @@ async function updateVideoChannel (req: express.Request, res: express.Response)
|
||||||
|
|
||||||
const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions)
|
const videoChannelInstanceUpdated = await videoChannelInstance.save(sequelizeOptions)
|
||||||
await sendUpdateActor(videoChannelInstanceUpdated, t)
|
await sendUpdateActor(videoChannelInstanceUpdated, t)
|
||||||
})
|
|
||||||
|
|
||||||
logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
|
auditLogger.update(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new VideoChannelAuditView(videoChannelInstanceUpdated.toFormattedJSON()),
|
||||||
|
oldVideoChannelAuditKeys
|
||||||
|
)
|
||||||
|
logger.info('Video channel with name %s and uuid %s updated.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
|
||||||
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.debug('Cannot update the video channel.', { err })
|
logger.debug('Cannot update the video channel.', { err })
|
||||||
|
|
||||||
|
@ -171,6 +190,10 @@ async function removeVideoChannel (req: express.Request, res: express.Response)
|
||||||
await sequelizeTypescript.transaction(async t => {
|
await sequelizeTypescript.transaction(async t => {
|
||||||
await videoChannelInstance.destroy({ transaction: t })
|
await videoChannelInstance.destroy({ transaction: t })
|
||||||
|
|
||||||
|
auditLogger.delete(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new VideoChannelAuditView(videoChannelInstance.toFormattedJSON())
|
||||||
|
)
|
||||||
logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
|
logger.info('Video channel with name %s and uuid %s deleted.', videoChannelInstance.name, videoChannelInstance.Actor.uuid)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,9 @@ import {
|
||||||
import { AccountModel } from '../../../models/account/account'
|
import { AccountModel } from '../../../models/account/account'
|
||||||
import { VideoModel } from '../../../models/video/video'
|
import { VideoModel } from '../../../models/video/video'
|
||||||
import { VideoAbuseModel } from '../../../models/video/video-abuse'
|
import { VideoAbuseModel } from '../../../models/video/video-abuse'
|
||||||
|
import { auditLoggerFactory, VideoAbuseAuditView } from '../../../helpers/audit-logger'
|
||||||
|
|
||||||
|
const auditLogger = auditLoggerFactory('abuse')
|
||||||
const abuseVideoRouter = express.Router()
|
const abuseVideoRouter = express.Router()
|
||||||
|
|
||||||
abuseVideoRouter.get('/abuse',
|
abuseVideoRouter.get('/abuse',
|
||||||
|
@ -64,14 +66,16 @@ async function reportVideoAbuse (req: express.Request, res: express.Response) {
|
||||||
await sequelizeTypescript.transaction(async t => {
|
await sequelizeTypescript.transaction(async t => {
|
||||||
const videoAbuseInstance = await VideoAbuseModel.create(abuseToCreate, { transaction: t })
|
const videoAbuseInstance = await VideoAbuseModel.create(abuseToCreate, { transaction: t })
|
||||||
videoAbuseInstance.Video = videoInstance
|
videoAbuseInstance.Video = videoInstance
|
||||||
|
videoAbuseInstance.Account = reporterAccount
|
||||||
|
|
||||||
// We send the video abuse to the origin server
|
// We send the video abuse to the origin server
|
||||||
if (videoInstance.isOwned() === false) {
|
if (videoInstance.isOwned() === false) {
|
||||||
await sendVideoAbuse(reporterAccount.Actor, videoAbuseInstance, videoInstance, t)
|
await sendVideoAbuse(reporterAccount.Actor, videoAbuseInstance, videoInstance, t)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
logger.info('Abuse report for video %s created.', videoInstance.name)
|
auditLogger.create(reporterAccount.Actor.getIdentifier(), new VideoAbuseAuditView(videoAbuseInstance.toFormattedJSON()))
|
||||||
|
logger.info('Abuse report for video %s created.', videoInstance.name)
|
||||||
|
})
|
||||||
|
|
||||||
return res.type('json').status(204).end()
|
return res.type('json').status(204).end()
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,9 @@ import {
|
||||||
} from '../../../middlewares/validators/video-comments'
|
} from '../../../middlewares/validators/video-comments'
|
||||||
import { VideoModel } from '../../../models/video/video'
|
import { VideoModel } from '../../../models/video/video'
|
||||||
import { VideoCommentModel } from '../../../models/video/video-comment'
|
import { VideoCommentModel } from '../../../models/video/video-comment'
|
||||||
|
import { auditLoggerFactory, CommentAuditView } from '../../../helpers/audit-logger'
|
||||||
|
|
||||||
|
const auditLogger = auditLoggerFactory('comments')
|
||||||
const videoCommentRouter = express.Router()
|
const videoCommentRouter = express.Router()
|
||||||
|
|
||||||
videoCommentRouter.get('/:videoId/comment-threads',
|
videoCommentRouter.get('/:videoId/comment-threads',
|
||||||
|
@ -107,6 +109,8 @@ async function addVideoCommentThread (req: express.Request, res: express.Respons
|
||||||
}, t)
|
}, t)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new CommentAuditView(comment.toFormattedJSON()))
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
comment: comment.toFormattedJSON()
|
comment: comment.toFormattedJSON()
|
||||||
}).end()
|
}).end()
|
||||||
|
@ -124,6 +128,8 @@ async function addVideoCommentReply (req: express.Request, res: express.Response
|
||||||
}, t)
|
}, t)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new CommentAuditView(comment.toFormattedJSON()))
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
comment: comment.toFormattedJSON()
|
comment: comment.toFormattedJSON()
|
||||||
}).end()
|
}).end()
|
||||||
|
@ -136,6 +142,10 @@ async function removeVideoComment (req: express.Request, res: express.Response)
|
||||||
await videoCommentInstance.destroy({ transaction: t })
|
await videoCommentInstance.destroy({ transaction: t })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
auditLogger.delete(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new CommentAuditView(videoCommentInstance.toFormattedJSON())
|
||||||
|
)
|
||||||
logger.info('Video comment %d deleted.', videoCommentInstance.id)
|
logger.info('Video comment %d deleted.', videoCommentInstance.id)
|
||||||
|
|
||||||
return res.type('json').status(204).end()
|
return res.type('json').status(204).end()
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { renamePromise } from '../../../helpers/core-utils'
|
||||||
import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
|
import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils'
|
||||||
import { processImage } from '../../../helpers/image-utils'
|
import { processImage } from '../../../helpers/image-utils'
|
||||||
import { logger } from '../../../helpers/logger'
|
import { logger } from '../../../helpers/logger'
|
||||||
|
import { auditLoggerFactory, VideoAuditView } from '../../../helpers/audit-logger'
|
||||||
import { getFormattedObjects, getServerActor, resetSequelizeInstance } from '../../../helpers/utils'
|
import { getFormattedObjects, getServerActor, resetSequelizeInstance } from '../../../helpers/utils'
|
||||||
import {
|
import {
|
||||||
CONFIG,
|
CONFIG,
|
||||||
|
@ -54,6 +55,7 @@ import { createReqFiles, buildNSFWFilter } from '../../../helpers/express-utils'
|
||||||
import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update'
|
import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update'
|
||||||
import { videoCaptionsRouter } from './captions'
|
import { videoCaptionsRouter } from './captions'
|
||||||
|
|
||||||
|
const auditLogger = auditLoggerFactory('videos')
|
||||||
const videosRouter = express.Router()
|
const videosRouter = express.Router()
|
||||||
|
|
||||||
const reqVideoFileAdd = createReqFiles(
|
const reqVideoFileAdd = createReqFiles(
|
||||||
|
@ -247,6 +249,7 @@ async function addVideo (req: express.Request, res: express.Response) {
|
||||||
|
|
||||||
await federateVideoIfNeeded(video, true, t)
|
await federateVideoIfNeeded(video, true, t)
|
||||||
|
|
||||||
|
auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoAuditView(videoCreated.toFormattedDetailsJSON()))
|
||||||
logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid)
|
logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid)
|
||||||
|
|
||||||
return videoCreated
|
return videoCreated
|
||||||
|
@ -273,6 +276,7 @@ async function addVideo (req: express.Request, res: express.Response) {
|
||||||
async function updateVideo (req: express.Request, res: express.Response) {
|
async function updateVideo (req: express.Request, res: express.Response) {
|
||||||
const videoInstance: VideoModel = res.locals.video
|
const videoInstance: VideoModel = res.locals.video
|
||||||
const videoFieldsSave = videoInstance.toJSON()
|
const videoFieldsSave = videoInstance.toJSON()
|
||||||
|
const oldVideoAuditView = new VideoAuditView(videoInstance.toFormattedDetailsJSON())
|
||||||
const videoInfoToUpdate: VideoUpdate = req.body
|
const videoInfoToUpdate: VideoUpdate = req.body
|
||||||
const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE
|
const wasPrivateVideo = videoInstance.privacy === VideoPrivacy.PRIVATE
|
||||||
|
|
||||||
|
@ -344,9 +348,14 @@ async function updateVideo (req: express.Request, res: express.Response) {
|
||||||
|
|
||||||
const isNewVideo = wasPrivateVideo && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE
|
const isNewVideo = wasPrivateVideo && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE
|
||||||
await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t)
|
await federateVideoIfNeeded(videoInstanceUpdated, isNewVideo, t)
|
||||||
})
|
|
||||||
|
|
||||||
logger.info('Video with name %s and uuid %s updated.', videoInstance.name, videoInstance.uuid)
|
auditLogger.update(
|
||||||
|
res.locals.oauth.token.User.Account.Actor.getIdentifier(),
|
||||||
|
new VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()),
|
||||||
|
oldVideoAuditView
|
||||||
|
)
|
||||||
|
logger.info('Video with name %s and uuid %s updated.', videoInstance.name, videoInstance.uuid)
|
||||||
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Force fields we want to update
|
// Force fields we want to update
|
||||||
// If the transaction is retried, sequelize will think the object has not changed
|
// If the transaction is retried, sequelize will think the object has not changed
|
||||||
|
@ -423,6 +432,7 @@ async function removeVideo (req: express.Request, res: express.Response) {
|
||||||
await videoInstance.destroy({ transaction: t })
|
await videoInstance.destroy({ transaction: t })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
auditLogger.delete(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new VideoAuditView(videoInstance.toFormattedDetailsJSON()))
|
||||||
logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid)
|
logger.info('Video with name %s and uuid %s deleted.', videoInstance.name, videoInstance.uuid)
|
||||||
|
|
||||||
return res.type('json').status(204).end()
|
return res.type('json').status(204).end()
|
||||||
|
|
|
@ -5,7 +5,9 @@ import * as flatten from 'flat'
|
||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
import { CONFIG } from '../initializers'
|
import { CONFIG } from '../initializers'
|
||||||
import { jsonLoggerFormat, labelFormatter } from './logger'
|
import { jsonLoggerFormat, labelFormatter } from './logger'
|
||||||
import { VideoDetails } from '../../shared'
|
import { VideoDetails, User, VideoChannel, VideoAbuse } from '../../shared'
|
||||||
|
import { VideoComment } from '../../shared/models/videos/video-comment.model'
|
||||||
|
import { CustomConfig } from '../../shared/models/server/custom-config.model'
|
||||||
|
|
||||||
enum AUDIT_TYPE {
|
enum AUDIT_TYPE {
|
||||||
CREATE = 'create',
|
CREATE = 'create',
|
||||||
|
@ -111,13 +113,143 @@ const videoKeysToKeep = [
|
||||||
'support',
|
'support',
|
||||||
'commentsEnabled'
|
'commentsEnabled'
|
||||||
]
|
]
|
||||||
class VideoAuditView extends AuditEntity {
|
class VideoAuditView extends EntityAuditView {
|
||||||
constructor (private video: VideoDetails) {
|
constructor (private video: VideoDetails) {
|
||||||
super(videoKeysToKeep, 'video', video)
|
super(videoKeysToKeep, 'video', video)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const commentKeysToKeep = [
|
||||||
|
'id',
|
||||||
|
'text',
|
||||||
|
'threadId',
|
||||||
|
'inReplyToCommentId',
|
||||||
|
'videoId',
|
||||||
|
'createdAt',
|
||||||
|
'updatedAt',
|
||||||
|
'totalReplies',
|
||||||
|
'account-id',
|
||||||
|
'account-uuid',
|
||||||
|
'account-name'
|
||||||
|
]
|
||||||
|
class CommentAuditView extends EntityAuditView {
|
||||||
|
constructor (private comment: VideoComment) {
|
||||||
|
super(commentKeysToKeep, 'comment', comment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const userKeysToKeep = [
|
||||||
|
'id',
|
||||||
|
'username',
|
||||||
|
'email',
|
||||||
|
'nsfwPolicy',
|
||||||
|
'autoPlayVideo',
|
||||||
|
'role',
|
||||||
|
'videoQuota',
|
||||||
|
'createdAt',
|
||||||
|
'account-id',
|
||||||
|
'account-uuid',
|
||||||
|
'account-name',
|
||||||
|
'account-followingCount',
|
||||||
|
'account-followersCount',
|
||||||
|
'account-createdAt',
|
||||||
|
'account-updatedAt',
|
||||||
|
'account-avatar-path',
|
||||||
|
'account-avatar-createdAt',
|
||||||
|
'account-avatar-updatedAt',
|
||||||
|
'account-displayName',
|
||||||
|
'account-description',
|
||||||
|
'videoChannels'
|
||||||
|
]
|
||||||
|
class UserAuditView extends EntityAuditView {
|
||||||
|
constructor (private user: User) {
|
||||||
|
super(userKeysToKeep, 'user', user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const channelKeysToKeep = [
|
||||||
|
'id',
|
||||||
|
'uuid',
|
||||||
|
'name',
|
||||||
|
'followingCount',
|
||||||
|
'followersCount',
|
||||||
|
'createdAt',
|
||||||
|
'updatedAt',
|
||||||
|
'avatar-path',
|
||||||
|
'avatar-createdAt',
|
||||||
|
'avatar-updatedAt',
|
||||||
|
'displayName',
|
||||||
|
'description',
|
||||||
|
'support',
|
||||||
|
'isLocal',
|
||||||
|
'ownerAccount-id',
|
||||||
|
'ownerAccount-uuid',
|
||||||
|
'ownerAccount-name',
|
||||||
|
'ownerAccount-displayedName'
|
||||||
|
]
|
||||||
|
class VideoChannelAuditView extends EntityAuditView {
|
||||||
|
constructor (private channel: VideoChannel) {
|
||||||
|
super(channelKeysToKeep, 'channel', channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoAbuseKeysToKeep = [
|
||||||
|
'id',
|
||||||
|
'reason',
|
||||||
|
'reporterAccount',
|
||||||
|
'video-id',
|
||||||
|
'video-name',
|
||||||
|
'video-uuid',
|
||||||
|
'createdAt'
|
||||||
|
]
|
||||||
|
class VideoAbuseAuditView extends EntityAuditView {
|
||||||
|
constructor (private videoAbuse: VideoAbuse) {
|
||||||
|
super(videoAbuseKeysToKeep, 'abuse', videoAbuse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const customConfigKeysToKeep = [
|
||||||
|
'instance-name',
|
||||||
|
'instance-shortDescription',
|
||||||
|
'instance-description',
|
||||||
|
'instance-terms',
|
||||||
|
'instance-defaultClientRoute',
|
||||||
|
'instance-defaultNSFWPolicy',
|
||||||
|
'instance-customizations-javascript',
|
||||||
|
'instance-customizations-css',
|
||||||
|
'services-twitter-username',
|
||||||
|
'services-twitter-whitelisted',
|
||||||
|
'cache-previews-size',
|
||||||
|
'cache-captions-size',
|
||||||
|
'signup-enabled',
|
||||||
|
'signup-limit',
|
||||||
|
'admin-email',
|
||||||
|
'user-videoQuota',
|
||||||
|
'transcoding-enabled',
|
||||||
|
'transcoding-threads',
|
||||||
|
'transcoding-resolutions'
|
||||||
|
]
|
||||||
|
class CustomConfigAuditView extends EntityAuditView {
|
||||||
|
constructor (customConfig: CustomConfig) {
|
||||||
|
const infos: any = customConfig
|
||||||
|
const resolutionsDict = infos.transcoding.resolutions
|
||||||
|
const resolutionsArray = []
|
||||||
|
Object.entries(resolutionsDict).forEach(([resolution, isEnabled]) => {
|
||||||
|
if (isEnabled) {
|
||||||
|
resolutionsArray.push(resolution)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
infos.transcoding.resolutions = resolutionsArray
|
||||||
|
super(customConfigKeysToKeep, 'config', infos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
auditLoggerFactory,
|
auditLoggerFactory,
|
||||||
VideoAuditView
|
VideoChannelAuditView,
|
||||||
|
CommentAuditView,
|
||||||
|
UserAuditView,
|
||||||
|
VideoAuditView,
|
||||||
|
VideoAbuseAuditView,
|
||||||
|
CustomConfigAuditView
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ async function createUserAccountAndChannel (userToCreate: UserModel, validateUse
|
||||||
|
|
||||||
const userCreated = await userToCreate.save(userOptions)
|
const userCreated = await userToCreate.save(userOptions)
|
||||||
const accountCreated = await createLocalAccountWithoutKeys(userToCreate.username, userToCreate.id, null, t)
|
const accountCreated = await createLocalAccountWithoutKeys(userToCreate.username, userToCreate.id, null, t)
|
||||||
|
userCreated.Account = accountCreated
|
||||||
|
|
||||||
const videoChannelDisplayName = `Default ${userCreated.username} channel`
|
const videoChannelDisplayName = `Default ${userCreated.username} channel`
|
||||||
const videoChannelInfo = {
|
const videoChannelInfo = {
|
||||||
|
|
|
@ -454,6 +454,10 @@ export class ActorModel extends Model<ActorModel> {
|
||||||
return 'acct:' + this.preferredUsername + '@' + this.getHost()
|
return 'acct:' + this.preferredUsername + '@' + this.getHost()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getIdentifier () {
|
||||||
|
return this.Server ? `${this.preferredUsername}@${this.Server.host}` : this.preferredUsername
|
||||||
|
}
|
||||||
|
|
||||||
getHost () {
|
getHost () {
|
||||||
return this.Server ? this.Server.host : CONFIG.WEBSERVER.HOST
|
return this.Server ? this.Server.host : CONFIG.WEBSERVER.HOST
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user