1 import * as path from 'path'
2 import { diff } from 'deep-object-diff'
3 import { chain } from 'lodash'
4 import * as flatten from 'flat'
5 import * as winston from 'winston'
6 import { CONFIG } from '../initializers'
7 import { jsonLoggerFormat, labelFormatter } from './logger'
8 import { VideoDetails } from '../../shared'
16 const colors = winston.config.npm.colors
17 colors.audit = winston.config.npm.colors.info
19 winston.addColors(colors)
21 const auditLogger = winston.createLogger({
24 new winston.transports.File({
25 filename: path.join(CONFIG.STORAGE.LOG_DIR, 'peertube-audit.log'),
29 format: winston.format.combine(
30 winston.format.timestamp(),
32 winston.format.splat(),
40 function auditLoggerWrapper (domain: string, user: string, action: AUDIT_TYPE, entity: EntityAuditView, oldEntity: EntityAuditView = null) {
41 let entityInfos: object
42 if (action === AUDIT_TYPE.UPDATE && oldEntity) {
43 const oldEntityKeys = oldEntity.toLogKeys()
44 const diffObject = diff(oldEntityKeys, entity.toLogKeys())
45 const diffKeys = Object.entries(diffObject).reduce((newKeys, entry) => {
46 newKeys[`new-${entry[0]}`] = entry[1]
49 entityInfos = { ...oldEntityKeys, ...diffKeys }
51 entityInfos = { ...entity.toLogKeys() }
53 auditLogger.log('audit', JSON.stringify({
61 function auditLoggerFactory (domain: string) {
63 create (user: string, entity: EntityAuditView) {
64 auditLoggerWrapper(domain, user, AUDIT_TYPE.CREATE, entity)
66 update (user: string, entity: EntityAuditView, oldEntity: EntityAuditView) {
67 auditLoggerWrapper(domain, user, AUDIT_TYPE.UPDATE, entity, oldEntity)
69 delete (user: string, entity: EntityAuditView) {
70 auditLoggerWrapper(domain, user, AUDIT_TYPE.DELETE, entity)
75 abstract class EntityAuditView {
76 constructor (private keysToKeep: Array<string>, private prefix: string, private entityInfos: object) { }
77 toLogKeys (): object {
78 return chain(flatten(this.entityInfos, { delimiter: '-', safe: true }))
79 .pick(this.keysToKeep)
80 .mapKeys((value, key) => `${this.prefix}-${key}`)
85 const videoKeysToKeep = [
114 class VideoAuditView extends AuditEntity {
115 constructor (private video: VideoDetails) {
116 super(videoKeysToKeep, 'video', video)