Emoji only mode WIP:
* refactoring + optimization * migration
This commit is contained in:
@ -120,9 +120,10 @@ async function initChannelConfiguration (options: RegisterServerOptions): Promis
|
||||
// but will be more efficient to add here, as we already tested hasChat).
|
||||
// Note: no need to await here, would only degrade performances.
|
||||
// FIXME: should also update livechat_muc_terms if channel has changed.
|
||||
// FIXME: should also update livechat_emoji_only_regexp if channel has changed.
|
||||
updateProsodyRoom(options, video.uuid, {
|
||||
name: video.name
|
||||
name: video.name,
|
||||
// In case the channel changed:
|
||||
livechat_custom_emoji_regexp: await Emojis.singletonSafe()?.getChannelCustomEmojisRegexp(video.channelId)
|
||||
}).then(
|
||||
() => {},
|
||||
(err) => logger.error(err)
|
||||
|
@ -144,7 +144,7 @@ export class Emojis {
|
||||
* @param sn short name
|
||||
*/
|
||||
public validShortName (sn: any): boolean {
|
||||
// Important note: do not change this without checking if it can breaks getChannelEmojisOnlyRegexp.
|
||||
// Important note: do not change this without checking if it can breaks getChannelCustomEmojisRegexp.
|
||||
if ((typeof sn !== 'string') || !/^:?[\w-]+:?$/.test(sn)) {
|
||||
this.logger.debug('Short name invalid: ' + (typeof sn === 'string' ? sn : '???'))
|
||||
return false
|
||||
@ -395,14 +395,13 @@ export class Emojis {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representing a regular expression (Perl Compatible RE) that can validate that a message
|
||||
* contains only emojis (for this channel).
|
||||
* Returns a string representing a regular expression validating channel custom emojis.
|
||||
* This is used for the emoji only mode (test are made on the Prosody server).
|
||||
*
|
||||
* @param channelId channel id
|
||||
*/
|
||||
public async getChannelEmojisOnlyRegexp (channelId: number): Promise<string | undefined> {
|
||||
const parts = [...this.commonEmojisCodes]
|
||||
public async getChannelCustomEmojisRegexp (channelId: number): Promise<string | undefined> {
|
||||
const parts = []
|
||||
|
||||
if (await this.channelHasCustomEmojis(channelId)) {
|
||||
const def = await this.channelCustomEmojisDefinition(channelId)
|
||||
@ -411,11 +410,17 @@ export class Emojis {
|
||||
}
|
||||
}
|
||||
|
||||
// Note: validShortName should ensure we won't put special chars.
|
||||
// And for the common emojis, we assume that there is no special regexp chars
|
||||
const regexp = '^\\s*(?:(?:' + parts.join('|') + ')\\s*)+\\s*$'
|
||||
if (parts.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return regexp
|
||||
// Note: validShortName should ensure we won't put special chars.
|
||||
return parts.join('|')
|
||||
}
|
||||
|
||||
public getCommonEmojisRegexp (): string {
|
||||
// We assume that there is no special regexp chars (should only contains unicode emojis)
|
||||
return this.commonEmojisCodes.join('|')
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,7 +66,7 @@ async function updateProsodyRoom (
|
||||
slow_mode_duration?: number
|
||||
moderation_delay?: number
|
||||
livechat_emoji_only?: boolean
|
||||
livechat_emoji_only_regexp?: string
|
||||
livechat_custom_emoji_regexp?: string
|
||||
livechat_muc_terms?: string
|
||||
addAffiliations?: Affiliations
|
||||
removeAffiliationsFor?: string[]
|
||||
@ -105,8 +105,8 @@ async function updateProsodyRoom (
|
||||
if ('livechat_emoji_only' in data) {
|
||||
apiData.livechat_emoji_only = data.livechat_emoji_only ?? false
|
||||
}
|
||||
if ('livechat_emoji_only_regexp' in data) {
|
||||
apiData.livechat_emoji_only_regexp = data.livechat_emoji_only_regexp ?? ''
|
||||
if ('livechat_custom_emoji_regexp' in data) {
|
||||
apiData.livechat_custom_emoji_regexp = data.livechat_custom_emoji_regexp ?? ''
|
||||
}
|
||||
if (('addAffiliations' in data) && data.addAffiliations !== undefined) {
|
||||
apiData.addAffiliations = data.addAffiliations
|
||||
|
@ -19,6 +19,7 @@ import { BotConfiguration } from '../configuration/bot'
|
||||
import { debugMucAdmins } from '../debug'
|
||||
import { ExternalAuthOIDC } from '../external-auth/oidc'
|
||||
import { listModFirewallFiles } from '../firewall/config'
|
||||
import { Emojis } from '../emojis'
|
||||
|
||||
async function getWorkingDir (options: RegisterServerOptions): Promise<string> {
|
||||
const peertubeHelpers = options.peertubeHelpers
|
||||
@ -389,6 +390,13 @@ async function getProsodyConfig (options: RegisterServerOptionsV5): Promise<Pros
|
||||
config.useModFirewall(modFirewallFiles)
|
||||
}
|
||||
|
||||
const commonEmojisRegexp = Emojis.singletonSafe()?.getCommonEmojisRegexp()
|
||||
if (commonEmojisRegexp) {
|
||||
config.useRestrictMessage(commonEmojisRegexp)
|
||||
} else {
|
||||
logger.error('Fail to load common emojis regexp, disabling restrict message module.')
|
||||
}
|
||||
|
||||
config.useTestModule(apikey, testApiUrl)
|
||||
|
||||
const debugMucAdminJids = debugMucAdmins(options)
|
||||
@ -500,6 +508,11 @@ function getProsodyConfigContentForDiagnostic (config: ProsodyConfig, content?:
|
||||
// replaceAll not available, using trick:
|
||||
r = r.split(value).join(`***${key}***`)
|
||||
}
|
||||
// We also replace `peertubelivechat_restrict_message_common_emoji_regexp` because it could be a very long line
|
||||
r = r.replace(
|
||||
/^(?:(\s*peertubelivechat_restrict_message_common_emoji_regexp\s*=\s*.{0,10}).*)$/gm,
|
||||
'$1 ***long line truncated***'
|
||||
)
|
||||
return r
|
||||
}
|
||||
|
||||
|
@ -260,8 +260,6 @@ class ProsodyConfigContent {
|
||||
this.muc.set('anonymize_moderation_actions_form_position', 117)
|
||||
|
||||
this.muc.add('modules_enabled', 'muc_mam_search')
|
||||
|
||||
this.muc.add('modules_enabled', 'muc_peertubelivechat_restrict_message')
|
||||
}
|
||||
|
||||
useAnonymous (autoBanIP: boolean): void {
|
||||
@ -564,6 +562,18 @@ class ProsodyConfigContent {
|
||||
this.global.set('firewall_scripts', files)
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable and configure the restrict message module.
|
||||
* @param commonEmojiRegexp A regexp to match common emojis.
|
||||
*/
|
||||
useRestrictMessage (commonEmojiRegexp: string): void {
|
||||
this.muc.add('modules_enabled', 'muc_peertubelivechat_restrict_message')
|
||||
this.muc.set(
|
||||
'peertubelivechat_restrict_message_common_emoji_regexp',
|
||||
new ConfigEntryValueMultiLineString(commonEmojiRegexp)
|
||||
)
|
||||
}
|
||||
|
||||
addMucAdmins (jids: string[]): void {
|
||||
for (const jid of jids) {
|
||||
this.muc.add('admins', jid)
|
||||
|
76
server/lib/prosody/migration/migrageV11-1.ts
Normal file
76
server/lib/prosody/migration/migrageV11-1.ts
Normal file
@ -0,0 +1,76 @@
|
||||
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type { RegisterServerOptions } from '@peertube/peertube-types'
|
||||
import { listProsodyRooms, updateProsodyRoom } from '../api/manage-rooms'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import { Emojis } from '../../emojis'
|
||||
|
||||
/**
|
||||
* Livechat v11.1.0: we must send channel custom emojis regexp to Prosody.
|
||||
*
|
||||
* This script will only be launched one time.
|
||||
*/
|
||||
async function updateProsodyChannelEmojisRegex (options: RegisterServerOptions): Promise<void> {
|
||||
const logger = options.peertubeHelpers.logger
|
||||
|
||||
// First, detect if we already run this script.
|
||||
const doneFilePath = path.resolve(options.peertubeHelpers.plugin.getDataDirectoryPath(), 'fix-v11.1-emojis')
|
||||
if (fs.existsSync(doneFilePath)) {
|
||||
logger.debug('[migratev11_1_ChannelEmojis] Channel Emojis Regex already updated on Prosody.')
|
||||
return
|
||||
}
|
||||
|
||||
logger.info('[migratev11_1_ChannelEmojis] Updating Channel custom emojis regexp on Prosody')
|
||||
|
||||
const emojis = Emojis.singleton()
|
||||
const rooms = await listProsodyRooms(options)
|
||||
logger.debug('[migratev11_1_ChannelEmojis] Found ' + rooms.length.toString() + ' rooms.')
|
||||
|
||||
for (const room of rooms) {
|
||||
try {
|
||||
let channelId: number
|
||||
logger.info('[migratev11_1_ChannelEmojis] Must update custom emojis regexp for room ' + room.localpart)
|
||||
const matches = room.localpart.match(/^channel\.(\d+)$/)
|
||||
if (matches?.[1]) {
|
||||
// room associated to a channel
|
||||
channelId = parseInt(matches[1])
|
||||
} else {
|
||||
// room associated to a video
|
||||
const video = await options.peertubeHelpers.videos.loadByIdOrUUID(room.localpart)
|
||||
if (!video || video.remote) {
|
||||
logger.info('[migratev11_1_ChannelEmojis] Video ' + room.localpart + ' not found or remote, skipping')
|
||||
continue
|
||||
}
|
||||
channelId = video.channelId
|
||||
}
|
||||
|
||||
if (!channelId) {
|
||||
throw new Error('Cant find channelId')
|
||||
}
|
||||
|
||||
const regexp = await emojis.getChannelCustomEmojisRegexp(channelId)
|
||||
if (regexp === undefined) {
|
||||
logger.info('[migratev11_1_ChannelEmojis] Room ' + room.localpart + ' channel has no custom emojis, skipping.')
|
||||
continue
|
||||
}
|
||||
|
||||
await updateProsodyRoom(options, room.jid, {
|
||||
livechat_custom_emoji_regexp: regexp
|
||||
})
|
||||
} catch (err) {
|
||||
logger.error(
|
||||
'[migratev11_1_ChannelEmojis] Failed to handle room ' + room.localpart + ', skipping. Error: ' + (err as string)
|
||||
)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
await fs.promises.writeFile(doneFilePath, '')
|
||||
}
|
||||
|
||||
export {
|
||||
updateProsodyChannelEmojisRegex
|
||||
}
|
@ -171,13 +171,13 @@ async function initConfigurationApiRouter (options: RegisterServerOptions, route
|
||||
await emojis.saveChannelDefinition(channelInfos.id, emojisDefinitionSanitized, bufferInfos)
|
||||
|
||||
// We must update the emoji only regexp on the Prosody server.
|
||||
const emojisOnlyRegexp = await emojis.getChannelEmojisOnlyRegexp(channelInfos.id)
|
||||
const customEmojisRegexp = await emojis.getChannelCustomEmojisRegexp(channelInfos.id)
|
||||
const roomJIDs = RoomChannel.singleton().getChannelRoomJIDs(channelInfos.id)
|
||||
for (const roomJID of roomJIDs) {
|
||||
// No need to await here
|
||||
logger.info(`Updating room ${roomJID} emoji only regexp...`)
|
||||
updateProsodyRoom(options, roomJID, {
|
||||
livechat_emoji_only_regexp: emojisOnlyRegexp
|
||||
livechat_custom_emoji_regexp: customEmojisRegexp
|
||||
}).then(
|
||||
() => {},
|
||||
(err) => logger.error(err)
|
||||
|
@ -39,7 +39,7 @@ interface RoomDefaults {
|
||||
slow_mode_duration?: number
|
||||
mute_anonymous?: boolean
|
||||
livechat_emoji_only?: boolean
|
||||
livechat_emoji_only_regexp?: string
|
||||
livechat_custom_emoji_regexp?: string
|
||||
livechat_muc_terms?: string
|
||||
moderation_delay?: number
|
||||
anonymize_moderation_actions?: boolean
|
||||
@ -54,12 +54,12 @@ async function _getChannelSpecificOptions (
|
||||
const channelOptions = await getChannelConfigurationOptions(options, channelId) ??
|
||||
getDefaultChannelConfigurationOptions(options)
|
||||
|
||||
const emojiOnlyRegexp = await Emojis.singletonSafe()?.getChannelEmojisOnlyRegexp(channelId)
|
||||
const customEmojisRegexp = await Emojis.singletonSafe()?.getChannelCustomEmojisRegexp(channelId)
|
||||
|
||||
return {
|
||||
slow_mode_duration: channelOptions.slowMode.duration,
|
||||
mute_anonymous: channelOptions.mute.anonymous,
|
||||
livechat_emoji_only_regexp: emojiOnlyRegexp,
|
||||
livechat_custom_emoji_regexp: customEmojisRegexp,
|
||||
livechat_muc_terms: channelOptions.terms,
|
||||
moderation_delay: channelOptions.moderation.delay,
|
||||
anonymize_moderation_actions: channelOptions.moderation.anonymize
|
||||
|
Reference in New Issue
Block a user