160 lines
4.7 KiB
TypeScript
160 lines
4.7 KiB
TypeScript
import type { RegisterServerOptions } from '@peertube/peertube-types'
|
|
import type { ChannelConfigurationOptions } from '../../../../shared/lib/types'
|
|
import type { ChannelCommonRoomConf } from '../../configuration/bot'
|
|
import { RoomChannel } from '../../room-channel'
|
|
import { sanitizeChannelConfigurationOptions } from '../../configuration/channel/sanitize'
|
|
import * as fs from 'fs'
|
|
import * as path from 'path'
|
|
|
|
// FIXME: should be exported by xmppjs-chat-bot
|
|
type ConfigHandlers = ChannelCommonRoomConf['handlers']
|
|
type ConfigHandler = ConfigHandlers[0]
|
|
|
|
/**
|
|
* Get saved configuration options for the given channel.
|
|
* Can throw an exception.
|
|
* @param options Peertube server options
|
|
* @param channelInfos Info from channel from which we want to get infos
|
|
* @returns Channel configuration data, or null if nothing is stored
|
|
*/
|
|
async function getChannelConfigurationOptions (
|
|
options: RegisterServerOptions,
|
|
channelId: number | string
|
|
): Promise<ChannelConfigurationOptions | null> {
|
|
const logger = options.peertubeHelpers.logger
|
|
const filePath = _getFilePath(options, channelId)
|
|
if (!fs.existsSync(filePath)) {
|
|
logger.debug('No stored data for channel, returning default values')
|
|
return null
|
|
}
|
|
const content = await fs.promises.readFile(filePath, {
|
|
encoding: 'utf-8'
|
|
})
|
|
const sanitized = await sanitizeChannelConfigurationOptions(options, channelId, JSON.parse(content))
|
|
return sanitized
|
|
}
|
|
|
|
function getDefaultChannelConfigurationOptions (_options: RegisterServerOptions): ChannelConfigurationOptions {
|
|
return {
|
|
bot: false,
|
|
botNickname: 'Sepia',
|
|
// bannedJIDs: [],
|
|
forbiddenWords: []
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save channel configuration options.
|
|
* Can throw an exception.
|
|
* @param options Peertube server options
|
|
* @param ChannelConfigurationOptions data to save
|
|
*/
|
|
async function storeChannelConfigurationOptions (
|
|
options: RegisterServerOptions,
|
|
channelId: number | string,
|
|
channelConfigurationOptions: ChannelConfigurationOptions
|
|
): Promise<void> {
|
|
const filePath = _getFilePath(options, channelId)
|
|
|
|
if (!fs.existsSync(filePath)) {
|
|
const dir = path.dirname(filePath)
|
|
if (!fs.existsSync(dir)) {
|
|
fs.mkdirSync(dir, { recursive: true })
|
|
}
|
|
}
|
|
|
|
const jsonContent = JSON.stringify(channelConfigurationOptions)
|
|
|
|
await fs.promises.writeFile(filePath, jsonContent, {
|
|
encoding: 'utf-8'
|
|
})
|
|
|
|
RoomChannel.singleton().refreshChannelConfigurationOptions(channelId)
|
|
}
|
|
|
|
/**
|
|
* Converts the channel configuration to the bot room configuration object (minus the room JID and domain)
|
|
* @param options server options
|
|
* @param channelConfigurationOptions The channel configuration
|
|
* @returns Partial bot room configuration
|
|
*/
|
|
function channelConfigurationOptionsToBotRoomConf (
|
|
options: RegisterServerOptions,
|
|
channelConfigurationOptions: ChannelConfigurationOptions
|
|
): ChannelCommonRoomConf {
|
|
// Note concerning handlers:
|
|
// If we want the bot to correctly enable/disable the handlers,
|
|
// we must always define all handlers, even if not used.
|
|
const handlers: ConfigHandlers = []
|
|
handlers.push(_getForbiddenWordsHandler(
|
|
'forbidden_words_0',
|
|
channelConfigurationOptions.forbiddenWords
|
|
))
|
|
|
|
const roomConf: ChannelCommonRoomConf = {
|
|
enabled: channelConfigurationOptions.bot,
|
|
handlers
|
|
}
|
|
if (channelConfigurationOptions.botNickname && channelConfigurationOptions.botNickname !== '') {
|
|
roomConf.nick = channelConfigurationOptions.botNickname
|
|
}
|
|
return roomConf
|
|
}
|
|
|
|
function _getForbiddenWordsHandler (
|
|
id: string,
|
|
forbiddenWords: string[],
|
|
reason?: string
|
|
): ConfigHandler {
|
|
const handler: ConfigHandler = {
|
|
type: 'moderate',
|
|
id,
|
|
enabled: false,
|
|
options: {
|
|
rules: []
|
|
}
|
|
}
|
|
if (forbiddenWords.length === 0) {
|
|
return handler
|
|
}
|
|
|
|
handler.enabled = true
|
|
// Note: on the Peertube frontend, channelConfigurationOptions.forbiddenWords
|
|
// is an array of RegExp definition (strings).
|
|
// They are validated one by bone.
|
|
// To increase the bot performance, we will join them all (hopping the bot will optimize them).
|
|
const rule: any = {
|
|
name: id,
|
|
regexp: '(?:' + forbiddenWords.join(')|(?:') + ')'
|
|
}
|
|
if (reason) {
|
|
rule.reason = reason
|
|
}
|
|
handler.options.rules.push(rule)
|
|
return handler
|
|
}
|
|
|
|
function _getFilePath (
|
|
options: RegisterServerOptions,
|
|
channelId: number | string
|
|
): string {
|
|
// some sanitization, just in case...
|
|
channelId = parseInt(channelId.toString())
|
|
if (isNaN(channelId)) {
|
|
throw new Error(`Invalid channelId: ${channelId}`)
|
|
}
|
|
|
|
return path.resolve(
|
|
options.peertubeHelpers.plugin.getDataDirectoryPath(),
|
|
'channelConfigurationOptions',
|
|
channelId.toString() + '.json'
|
|
)
|
|
}
|
|
|
|
export {
|
|
getChannelConfigurationOptions,
|
|
getDefaultChannelConfigurationOptions,
|
|
channelConfigurationOptionsToBotRoomConf,
|
|
storeChannelConfigurationOptions
|
|
}
|