8e99199f29
* new setting * new configuration screen for Peertube admins * include the mod_firewall module * load mod_firewall if enabled * sys admin can disable the firewall config editing by creating a special file on the disk * user documentation
109 lines
3.6 KiB
TypeScript
109 lines
3.6 KiB
TypeScript
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
|
|
//
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
import type { RegisterClientOptions } from '@peertube/peertube-types/client'
|
|
import type { AdminFirewallConfiguration } from 'shared/lib/types'
|
|
import {
|
|
maxFirewallFileSize, maxFirewallNameLength, maxFirewallFiles, firewallNameRegexp
|
|
} from 'shared/lib/admin-firewall'
|
|
import { ValidationError, ValidationErrorType } from '../../../lib/models/validation'
|
|
import { getBaseRoute } from '../../../../utils/uri'
|
|
|
|
export class AdminFirewallService {
|
|
public _registerClientOptions: RegisterClientOptions
|
|
|
|
private readonly _headers: any = {}
|
|
|
|
constructor (registerClientOptions: RegisterClientOptions) {
|
|
this._registerClientOptions = registerClientOptions
|
|
|
|
this._headers = this._registerClientOptions.peertubeHelpers.getAuthHeader() ?? {}
|
|
this._headers['content-type'] = 'application/json;charset=UTF-8'
|
|
}
|
|
|
|
async validateConfiguration (adminFirewallConfiguration: AdminFirewallConfiguration): Promise<boolean> {
|
|
const propertiesError: ValidationError['properties'] = {}
|
|
|
|
if (adminFirewallConfiguration.files.length > maxFirewallFiles) {
|
|
const validationError = new ValidationError(
|
|
'AdminFirewallConfigurationValidationError',
|
|
await this._registerClientOptions.peertubeHelpers.translate(LOC_TOO_MANY_ENTRIES),
|
|
propertiesError
|
|
)
|
|
throw validationError
|
|
}
|
|
|
|
const seen = new Map<string, true>()
|
|
for (const [i, e] of adminFirewallConfiguration.files.entries()) {
|
|
propertiesError[`files.${i}.name`] = []
|
|
if (e.name === '') {
|
|
propertiesError[`files.${i}.name`].push(ValidationErrorType.Missing)
|
|
} else if (e.name.length > maxFirewallNameLength) {
|
|
propertiesError[`files.${i}.name`].push(ValidationErrorType.TooLong)
|
|
} else if (!firewallNameRegexp.test(e.name)) {
|
|
propertiesError[`files.${i}.name`].push(ValidationErrorType.WrongFormat)
|
|
} else if (seen.has(e.name)) {
|
|
propertiesError[`files.${i}.name`].push(ValidationErrorType.Duplicate)
|
|
} else {
|
|
seen.set(e.name, true)
|
|
}
|
|
|
|
propertiesError[`files.${i}.content`] = []
|
|
if (e.content.length > maxFirewallFileSize) {
|
|
propertiesError[`files.${i}.content`].push(ValidationErrorType.TooLong)
|
|
}
|
|
}
|
|
|
|
if (Object.values(propertiesError).find(e => e.length > 0)) {
|
|
const validationError = new ValidationError(
|
|
'AdminFirewallConfigurationValidationError',
|
|
await this._registerClientOptions.peertubeHelpers.translate(LOC_VALIDATION_ERROR),
|
|
propertiesError
|
|
)
|
|
throw validationError
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
async saveConfiguration (
|
|
adminFirewallConfiguration: AdminFirewallConfiguration
|
|
): Promise<AdminFirewallConfiguration> {
|
|
if (!await this.validateConfiguration(adminFirewallConfiguration)) {
|
|
throw new Error('Invalid form data')
|
|
}
|
|
|
|
const response = await fetch(
|
|
getBaseRoute(this._registerClientOptions) + '/api/admin/firewall/',
|
|
{
|
|
method: 'POST',
|
|
headers: this._headers,
|
|
body: JSON.stringify(adminFirewallConfiguration)
|
|
}
|
|
)
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to save configuration.')
|
|
}
|
|
|
|
return response.json()
|
|
}
|
|
|
|
async fetchConfiguration (): Promise<AdminFirewallConfiguration> {
|
|
const response = await fetch(
|
|
getBaseRoute(this._registerClientOptions) + '/api/admin/firewall/',
|
|
{
|
|
method: 'GET',
|
|
headers: this._headers
|
|
}
|
|
)
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Can\'t get firewall configuration.')
|
|
}
|
|
|
|
return response.json()
|
|
}
|
|
}
|