Add ability to disable audit logs

This commit is contained in:
Wicklow 2023-10-12 14:56:57 +02:00
parent 5bd42bbca7
commit a90b8fddbc
19 changed files with 148 additions and 7 deletions

View File

@ -136,4 +136,27 @@
</div> </div>
</div> </div>
<div class="row mt-4"> <!-- cache grid -->
<div class="col-12 col-lg-4 col-xl-3">
<div class="anchor" id="customizations"></div> <!-- customizations anchor -->
<h2 i18n class="inner-form-title">LOGS</h2>
<div i18n class="inner-form-description">
Slight modifications to your PeerTube instance for when creating a plugin or theme is overkill.
</div>
</div>
<div class="col-12 col-lg-8 col-xl-9">
<ng-container formGroupName="instance">
<ng-container formGroupName="logs">
<ng-container formGroupName="auditLogs">
<div class="form-group">
<my-peertube-checkbox inputName="auditLogsEnabled" formControlName="enabled" i18n-labelText
labelText="Enable audit logs"></my-peertube-checkbox>
</div>
</ng-container>
</ng-container>
</ng-container>
</div>
</div>
</ng-container> </ng-container>

View File

@ -93,6 +93,11 @@ export class EditCustomConfigComponent extends FormReactive implements OnInit {
customizations: { customizations: {
javascript: null, javascript: null,
css: null css: null
},
logs: {
auditLogs: {
enabled: null
}
} }
}, },
theme: { theme: {

View File

@ -37,7 +37,9 @@
<div *ngIf="loading" i18n>Loading...</div> <div *ngIf="loading" i18n>Loading...</div>
<div #logsElement> <div #logsElement>
<div *ngIf="!loading && logs.length === 0" i18n>No log.</div> <div *ngIf="isAuditLog && !isAuditLogsEnabled" i18n>Audit logs disabled.</div>
<div *ngIf="!loading && logs.length === 0 && isAuditLogsEnabled" i18n>No log.</div>
<div *ngFor="let log of logs" class="log-row" [ngClass]="{ error: log.level === 'error', warn: log.level === 'warn' }"> <div *ngFor="let log of logs" class="log-row" [ngClass]="{ error: log.level === 'error', warn: log.level === 'warn' }">
<span class="log-level">{{ log.level }}</span> <span class="log-level">{{ log.level }}</span>

View File

@ -1,6 +1,6 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core' import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
import { LocalStorageService, Notifier } from '@app/core' import { LocalStorageService, Notifier, ServerService } from '@app/core'
import { ServerLogLevel } from '@peertube/peertube-models' import { HTMLServerConfig, ServerLogLevel } from '@peertube/peertube-models'
import { LogRow } from './log-row.model' import { LogRow } from './log-row.model'
import { LogsService } from './logs.service' import { LogsService } from './logs.service'
@ -25,13 +25,20 @@ export class LogsComponent implements OnInit {
logType: 'audit' | 'standard' logType: 'audit' | 'standard'
tagsOneOf: string[] = [] tagsOneOf: string[] = []
serverConfig: HTMLServerConfig
isAuditLogsEnabled: boolean
constructor ( constructor (
private logsService: LogsService, private logsService: LogsService,
private notifier: Notifier, private notifier: Notifier,
private localStorage: LocalStorageService private localStorage: LocalStorageService,
private serverService: ServerService
) { } ) { }
ngOnInit (): void { ngOnInit (): void {
this.serverConfig = this.serverService.getHTMLConfig()
console.log(JSON.stringify(this.serverConfig))
this.buildTimeChoices() this.buildTimeChoices()
this.buildLevelChoices() this.buildLevelChoices()
this.buildLogTypeChoices() this.buildLogTypeChoices()
@ -55,7 +62,10 @@ export class LogsComponent implements OnInit {
const tagsOneOf = this.tagsOneOf.length !== 0 const tagsOneOf = this.tagsOneOf.length !== 0
? this.tagsOneOf ? this.tagsOneOf
: undefined : undefined
if (!this.isAuditLogsEnabled) {
this.loading = false
return
}
this.logsService.getLogs({ this.logsService.getLogs({
isAuditLog: this.isAuditLog(), isAuditLog: this.isAuditLog(),
level: this.level, level: this.level,

View File

@ -763,6 +763,9 @@ instance:
securitytxt: | securitytxt: |
Contact: https://github.com/Chocobozzz/PeerTube/blob/develop/SECURITY.md Contact: https://github.com/Chocobozzz/PeerTube/blob/develop/SECURITY.md
Expires: 2025-12-31T11:00:00.000Z' Expires: 2025-12-31T11:00:00.000Z'
logs:
audit_logs:
enabled: true
services: services:
# Cards configuration to format video in Twitter # Cards configuration to format video in Twitter

View File

@ -39,6 +39,12 @@ export interface CustomConfig {
javascript?: string javascript?: string
css?: string css?: string
} }
logs: {
auditLogs: {
enabled: boolean
}
}
} }
theme: { theme: {

View File

@ -90,6 +90,11 @@ export interface ServerConfig {
javascript: string javascript: string
css: string css: string
} }
logs: {
auditLogs: {
enabled: boolean
}
}
} }
search: { search: {

View File

@ -371,6 +371,12 @@ export class ConfigCommand extends AbstractCommand {
customizations: { customizations: {
javascript: 'alert("coucou")', javascript: 'alert("coucou")',
css: 'body { background-color: red; }' css: 'body { background-color: red; }'
},
logs: {
auditLogs: {
enabled: true
}
} }
}, },
theme: { theme: {

View File

@ -42,6 +42,11 @@ describe('Test config API validators', function () {
customizations: { customizations: {
javascript: 'alert("coucou")', javascript: 'alert("coucou")',
css: 'body { background-color: red; }' css: 'body { background-color: red; }'
},
logs: {
auditLogs: {
enabled: true
}
} }
}, },
theme: { theme: {

View File

@ -264,6 +264,11 @@ const newCustomConfig: CustomConfig = {
customizations: { customizations: {
javascript: 'alert("coucou")', javascript: 'alert("coucou")',
css: 'body { background-color: red; }' css: 'body { background-color: red; }'
},
logs: {
auditLogs: {
enabled: true
}
} }
}, },
theme: { theme: {

View File

@ -193,6 +193,41 @@ describe('Test logs', function () {
expect(logsString.includes('video 10')).to.be.true expect(logsString.includes('video 10')).to.be.true
expect(logsString.includes('video 11')).to.be.false expect(logsString.includes('video 11')).to.be.false
}) })
it('Should refuse to create logs if disabled', async function () {
this.timeout(60000)
await server.config.updateCustomSubConfig({
newConfig: {
instance: {
logs: {
auditLogs:{
enabled: false
}
}
}
}
})
await server.videos.upload({ attributes: { name: 'video 12' } })
await waitJobs([ server ])
const now1 = new Date()
await server.videos.upload({ attributes: { name: 'video 13' } })
await waitJobs([ server ])
const now2 = new Date()
await server.videos.upload({ attributes: { name: 'video 14' } })
await waitJobs([ server ])
await logsCommand.getAuditLogs({
startDate: now1,
endDate: now2,
expectedStatus: HttpStatusCode.FORBIDDEN_403
})
})
}) })
describe('When creating log from the client', function () { describe('When creating log from the client', function () {

View File

@ -158,6 +158,12 @@ function customConfig (): CustomConfig {
customizations: { customizations: {
css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS, css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS,
javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT
},
logs: {
auditLogs: {
enabled: CONFIG.INSTANCE.LOGS.AUDIT_LOGS.ENABLED
}
} }
}, },
theme: { theme: {

View File

@ -242,6 +242,7 @@ const customConfigKeysToKeep = new Set([
'instance-defaultNSFWPolicy', 'instance-defaultNSFWPolicy',
'instance-customizations-javascript', 'instance-customizations-javascript',
'instance-customizations-css', 'instance-customizations-css',
'instance-logs-auditLogs-enabled',
'services-twitter-username', 'services-twitter-username',
'services-twitter-whitelisted', 'services-twitter-whitelisted',
'cache-previews-size', 'cache-previews-size',

View File

@ -48,7 +48,7 @@ function checkMissedConfig () {
'client.videos.miniature.prefer_author_display_name', 'client.menu.login.redirect_on_single_external_auth', 'client.videos.miniature.prefer_author_display_name', 'client.menu.login.redirect_on_single_external_auth',
'defaults.publish.download_enabled', 'defaults.publish.comments_enabled', 'defaults.publish.privacy', 'defaults.publish.licence', 'defaults.publish.download_enabled', 'defaults.publish.comments_enabled', 'defaults.publish.privacy', 'defaults.publish.licence',
'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route',
'instance.is_nsfw', 'instance.default_nsfw_policy', 'instance.robots', 'instance.securitytxt', 'instance.is_nsfw', 'instance.default_nsfw_policy', 'instance.robots', 'instance.securitytxt', 'instance.logs.audit_logs.enabled',
'services.twitter.username', 'services.twitter.whitelisted', 'services.twitter.username', 'services.twitter.whitelisted',
'followers.instance.enabled', 'followers.instance.manual_approval', 'followers.instance.enabled', 'followers.instance.manual_approval',
'tracker.enabled', 'tracker.private', 'tracker.reject_too_many_announces', 'tracker.enabled', 'tracker.private', 'tracker.reject_too_many_announces',

View File

@ -546,7 +546,12 @@ const CONFIG = {
get CSS () { return config.get<string>('instance.customizations.css') } get CSS () { return config.get<string>('instance.customizations.css') }
}, },
get ROBOTS () { return config.get<string>('instance.robots') }, get ROBOTS () { return config.get<string>('instance.robots') },
get SECURITYTXT () { return config.get<string>('instance.securitytxt') } get SECURITYTXT () { return config.get<string>('instance.securitytxt') },
LOGS: {
AUDIT_LOGS:{
get ENABLED () { return config.get<boolean>('instance.logs.audit_logs.enabled') }
}
}
}, },
SERVICES: { SERVICES: {
TWITTER: { TWITTER: {

View File

@ -100,6 +100,11 @@ class ServerConfigManager {
customizations: { customizations: {
javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT, javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT,
css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS
},
logs: {
auditLogs: {
enabled: CONFIG.INSTANCE.LOGS.AUDIT_LOGS.ENABLED
}
} }
}, },
search: { search: {

View File

@ -17,6 +17,7 @@ const customConfigUpdateValidator = [
body('instance.defaultClientRoute').exists(), body('instance.defaultClientRoute').exists(),
body('instance.customizations.css').exists(), body('instance.customizations.css').exists(),
body('instance.customizations.javascript').exists(), body('instance.customizations.javascript').exists(),
body('instance.logs.auditLogs.enabled').exists(),
body('services.twitter.username').exists(), body('services.twitter.username').exists(),
body('services.twitter.whitelisted').isBoolean(), body('services.twitter.whitelisted').isBoolean(),

View File

@ -80,6 +80,8 @@ const getAuditLogsValidator = [
(req: express.Request, res: express.Response, next: express.NextFunction) => { (req: express.Request, res: express.Response, next: express.NextFunction) => {
if (areValidationErrors(req, res)) return if (areValidationErrors(req, res)) return
if (!CONFIG.INSTANCE.LOGS.AUDIT_LOGS.ENABLED) return res.sendStatus(HttpStatusCode.FORBIDDEN_403)
return next() return next()
} }
] ]

View File

@ -7935,6 +7935,14 @@ components:
type: string type: string
css: css:
type: string type: string
logs:
type: object
properties:
auditLogs:
type: object
properties:
enabled:
type: boolean
search: search:
type: object type: object
properties: properties:
@ -8252,6 +8260,14 @@ components:
type: string type: string
css: css:
type: string type: string
logs:
type: object
properties:
auditLogs:
type: object
properties:
enabled:
type: boolean
theme: theme:
type: object type: object
properties: properties: