diff --git a/client/admin-plugin-client-plugin.ts b/client/admin-plugin-client-plugin.ts
index 9c5c2810..67646642 100644
--- a/client/admin-plugin-client-plugin.ts
+++ b/client/admin-plugin-client-plugin.ts
@@ -205,6 +205,7 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re
return options.formValues['prosody-c2s'] !== true
case 'prosody-s2s-port':
case 'prosody-s2s-interfaces':
+ case 'prosody-certificates-dir':
return options.formValues['prosody-room-allow-s2s'] !== true
case 'prosody-components-port':
case 'prosody-components-list':
diff --git a/languages/settings/en.yml b/languages/settings/en.yml
index a6250d50..33ca19f3 100644
--- a/languages/settings/en.yml
+++ b/languages/settings/en.yml
@@ -170,6 +170,12 @@ prosody_s2s_interfaces_description: |
172.18.0.42
+prosody_certificates_dir_label: "Certificates directory"
+prosody_certificates_dir_description: |
+ If this field is empty, the plugin will generate and use self-signed certificates.
+ If you want to use other certificates, just specify here the folder where
+ Prosody can find them. Note: the `peertube` user must have read access to this directory.
+
prosody_c2s_label: "Enable client to server connections"
prosody_c2s_description: |
Enable XMPP clients to connect to the built-in Prosody server.
diff --git a/languages/settings/fr.yml b/languages/settings/fr.yml
index 672b3d6a..c8f4537b 100644
--- a/languages/settings/fr.yml
+++ b/languages/settings/fr.yml
@@ -180,6 +180,12 @@ prosody_s2s_interfaces_description: |
172.18.0.42
+prosody_certificates_dir_label: "Dossiers des certificats"
+prosody_certificates_dir_description: |
+ Si ce champ est vide, le plugin va générer et utiliser des certificats auto-signés.
+ Si vous voulez utiliser d'autres certificats, vous avez juste à spécifier ici le dossier où
+ Prosody peut les trouver. Note: l'utilisateur `peertube` doit avoir un accès en lecture à ce dossier.
+
prosody_c2s_label: "Activer les connexions client vers serveur"
prosody_c2s_description: |
Autoriser les clients XMPP à se connecter au serveur Prosody.
diff --git a/server/lib/diagnostic/prosody.ts b/server/lib/diagnostic/prosody.ts
index 28039e68..f8c3961b 100644
--- a/server/lib/diagnostic/prosody.ts
+++ b/server/lib/diagnostic/prosody.ts
@@ -80,6 +80,14 @@ export async function diagProsody (test: string, options: RegisterServerOptions)
}
result.messages.push(`Room content will be saved for '${wantedConfig.logExpiration.value}'`)
+ if (wantedConfig.paths.certs === undefined) {
+ result.messages.push({
+ level: 'error',
+ message: 'Error: The certificates path is misconfigured.'
+ })
+ return result
+ }
+
await fs.promises.access(filePath, fs.constants.R_OK) // throw an error if file does not exist.
result.messages.push(`The prosody configuration file (${filePath}) exists`)
const actualContent = await fs.promises.readFile(filePath, {
diff --git a/server/lib/prosody/certificates.ts b/server/lib/prosody/certificates.ts
index 1855afcc..45e37d5a 100644
--- a/server/lib/prosody/certificates.ts
+++ b/server/lib/prosody/certificates.ts
@@ -7,71 +7,10 @@ import * as fs from 'fs'
interface Renew {
timer: NodeJS.Timer
+ lastFromDirMtime?: number
}
let renew: Renew | undefined
-function _filePathToTest (options: RegisterServerOptions, config: ProsodyConfig): string {
- return path.resolve(config.paths.certs, config.host + '.crt')
-}
-
-async function ensureProsodyCertificates (options: RegisterServerOptions, config: ProsodyConfig): Promise {
- if (config.certificates !== 'generate-self-signed') { return }
- const logger = options.peertubeHelpers.logger
- logger.info('Prosody needs certicicates, checking if certificates are okay...')
-
- const prosodyDomain = config.host
- const filepath = _filePathToTest(options, config)
- if (fs.existsSync(filepath)) {
- logger.info(`The certificate ${filepath} exists, no need to generate it`)
- return
- }
-
- // Using: prososyctl --config /.../prosody.cfg.lua cert generate prosodyDomain.tld
- await prosodyCtl(options, 'cert', {
- additionalArgs: ['generate', prosodyDomain],
- yesMode: true,
- stdErrFilter: (data) => {
- // For an unknow reason, `prosodyctl cert generate` outputs openssl data on stderr...
- // So we filter these logs.
- if (data.match(/Generating \w+ private key/)) { return false }
- if (data.match(/^[.+o*\n]*$/m)) { return false }
- if (data.match(/e is \d+/)) { return false }
- return true
- }
- })
-}
-
-async function renewCheckSelfSigned (options: RegisterServerOptions, config: ProsodyConfig): Promise {
- const logger = options.peertubeHelpers.logger
- // We have to check if the self signed certificate is still valid.
- // Prosodyctl generated certificates are valid 365 days.
- // We will renew it every 10 months (and every X minutes in debug mode)
-
- const renewEvery = isDebugMode(options) ? 5 * 60000 : 3600000 * 24 * 30 * 10
- // getting the file date...
- const filepath = _filePathToTest(options, config)
- if (!fs.existsSync(filepath)) {
- logger.error('Missing certificate file: ' + filepath)
- return
- }
- const stat = fs.statSync(filepath)
- const age = (new Date()).getTime() - stat.mtimeMs
- if (age <= renewEvery) {
- logger.debug(`The age of the certificate ${filepath} is ${age}ms, which is less than the period ${renewEvery}ms`)
- return
- }
- logger.info(`The age of the certificate ${filepath} is ${age}ms, which is more than the period ${renewEvery}ms`)
- await ensureProsodyCertificates(options, config)
- await reloadProsody(options)
-}
-
-async function renewCheck (options: RegisterServerOptions, config: ProsodyConfig): Promise {
- if (config.certificates === 'generate-self-signed') {
- return renewCheckSelfSigned(options, config)
- }
- throw new Error('Unknown value for config.certificates')
-}
-
function startProsodyCertificatesRenewCheck (options: RegisterServerOptions, config: ProsodyConfig): void {
const logger = options.peertubeHelpers.logger
@@ -109,6 +48,105 @@ function stopProsodyCertificatesRenewCheck (options: RegisterServerOptions): voi
clearInterval(renew.timer)
}
+async function ensureProsodyCertificates (options: RegisterServerOptions, config: ProsodyConfig): Promise {
+ if (config.certificates !== 'generate-self-signed') { return }
+ const logger = options.peertubeHelpers.logger
+ logger.info('Prosody needs certificates, checking if certificates are okay...')
+
+ const prosodyDomain = config.host
+ const filepath = _filePathToTest(options, config)
+ if (!filepath) { return }
+ if (fs.existsSync(filepath)) {
+ logger.info(`The certificate ${filepath} exists, no need to generate it`)
+ return
+ }
+
+ // Using: prososyctl --config /.../prosody.cfg.lua cert generate prosodyDomain.tld
+ await prosodyCtl(options, 'cert', {
+ additionalArgs: ['generate', prosodyDomain],
+ yesMode: true,
+ stdErrFilter: (data) => {
+ // For an unknow reason, `prosodyctl cert generate` outputs openssl data on stderr...
+ // So we filter these logs.
+ if (data.match(/Generating \w+ private key/)) { return false }
+ if (data.match(/^[.+o*\n]*$/m)) { return false }
+ if (data.match(/e is \d+/)) { return false }
+ return true
+ }
+ })
+}
+
+async function renewCheck (options: RegisterServerOptions, config: ProsodyConfig): Promise {
+ if (config.certificates === 'generate-self-signed') {
+ return renewCheckSelfSigned(options, config)
+ }
+ if (config.certificates === 'use-from-dir') {
+ return renewCheckFromDir(options, config)
+ }
+ throw new Error('Unknown value for config.certificates')
+}
+
+async function renewCheckSelfSigned (options: RegisterServerOptions, config: ProsodyConfig): Promise {
+ const logger = options.peertubeHelpers.logger
+ // We have to check if the self signed certificate is still valid.
+ // Prosodyctl generated certificates are valid 365 days.
+ // We will renew it every 10 months (and every X minutes in debug mode)
+
+ const renewEvery = isDebugMode(options) ? 5 * 60000 : 3600000 * 24 * 30 * 10
+ // getting the file date...
+ const filepath = _filePathToTest(options, config)
+ if (!filepath) { return }
+ if (!fs.existsSync(filepath)) {
+ logger.error('Missing certificate file: ' + filepath)
+ return
+ }
+ const stat = fs.statSync(filepath)
+ const age = (new Date()).getTime() - stat.mtimeMs
+ if (age <= renewEvery) {
+ logger.debug(`The age of the certificate ${filepath} is ${age}ms, which is less than the period ${renewEvery}ms`)
+ return
+ }
+ logger.info(`The age of the certificate ${filepath} is ${age}ms, which is more than the period ${renewEvery}ms`)
+ await ensureProsodyCertificates(options, config)
+ await reloadProsody(options)
+}
+
+async function renewCheckFromDir (options: RegisterServerOptions, config: ProsodyConfig): Promise {
+ // We will browse all dir files, get the more recent file update time, and compare it to the previous call.
+ const logger = options.peertubeHelpers.logger
+ if (!renew) { return }
+ let mtimeMs: number | undefined
+ const dir = config.paths.certs
+ if (!dir) { return }
+ const files = fs.readdirSync(dir, { withFileTypes: true })
+ files.forEach(file => {
+ if (!file.isFile()) { return }
+ const stat = fs.statSync(path.resolve(dir, file.name))
+ if (stat.mtimeMs > (mtimeMs ?? 0)) {
+ mtimeMs = stat.mtimeMs
+ }
+ })
+ logger.debug('renewCheckFromDir: the most recent file in the certs dir has mtimeMs=' + (mtimeMs ?? '').toString())
+ if (!mtimeMs) {
+ return
+ }
+ if (!renew.lastFromDirMtime) {
+ renew.lastFromDirMtime = mtimeMs
+ return
+ }
+ if (renew.lastFromDirMtime === mtimeMs) {
+ logger.debug('No change in certs modification dates.')
+ return
+ }
+ logger.info('There is a file that was modified in the certs dir, reloading prosody...')
+ await reloadProsody(options)
+}
+
+function _filePathToTest (options: RegisterServerOptions, config: ProsodyConfig): string | null {
+ if (!config.paths.certs) { return null }
+ return path.resolve(config.paths.certs, config.host + '.crt')
+}
+
export {
ensureProsodyCertificates,
startProsodyCertificatesRenewCheck,
diff --git a/server/lib/prosody/config.ts b/server/lib/prosody/config.ts
index b9efa12e..01f9d46e 100644
--- a/server/lib/prosody/config.ts
+++ b/server/lib/prosody/config.ts
@@ -27,7 +27,9 @@ async function getProsodyFilePaths (options: RegisterServerOptions): Promise {
const logger = options.peertubeHelpers.logger
@@ -33,7 +34,7 @@ async function _ensureWorkingDir (
logger.debug(`data dir ${dataDir} was created`)
}
- if (!fs.existsSync(certsDir)) {
+ if (certsDir && !certsDirIsCustom && !fs.existsSync(certsDir)) {
// Certificates dir for Prosody.
// Note: not used yet, but we create the directory to avoid errors in prosody logs.
logger.info(`The certs dir ${certsDir} does not exists, trying to create it`)
@@ -61,7 +62,14 @@ async function prepareProsody (options: RegisterServerOptions): Promise {
const filePaths = await getProsodyFilePaths(options)
logger.debug('Ensuring that the working dir exists')
- await _ensureWorkingDir(options, filePaths.dir, filePaths.data, filePaths.certs, filePaths.appImageExtractPath)
+ await _ensureWorkingDir(
+ options,
+ filePaths.dir,
+ filePaths.data,
+ filePaths.certs,
+ filePaths.certsDirIsCustom,
+ filePaths.appImageExtractPath
+ )
const appImageToExtract = filePaths.appImageToExtract
if (!appImageToExtract) {
diff --git a/server/lib/settings.ts b/server/lib/settings.ts
index 3fa65473..735e2eff 100644
--- a/server/lib/settings.ts
+++ b/server/lib/settings.ts
@@ -329,6 +329,15 @@ Please read
descriptionHTML: loc('prosody_s2s_interfaces_description')
})
+ registerSetting({
+ name: 'prosody-certificates-dir',
+ label: loc('prosody_certificates_dir_label'),
+ type: 'input',
+ default: '',
+ private: true,
+ descriptionHTML: loc('prosody_certificates_dir_description')
+ })
+
registerSetting({
name: 'prosody-c2s',
label: loc('prosody_c2s_label'),
diff --git a/support/documentation/content/documentation/admin/settings.de.md b/support/documentation/content/documentation/admin/settings.de.md
index 07539e27..a4d997b0 100644
--- a/support/documentation/content/documentation/admin/settings.de.md
+++ b/support/documentation/content/documentation/admin/settings.de.md
@@ -139,6 +139,36 @@ indem Sie seine Eigenschaften bearbeiten.
Hier können Sie die Ablaufzeit für Raumprotokolle einstellen.
Siehe die Online-Hilfe für akzeptierte Werte.
+### Enable connection to room using external XMPP accounts
+
+By enabling this option, it will be possible to connect to rooms using external XMPP accounts and XMPP clients.
+Warning, enabling this option can request extra server and DNS configuration.
+Please refer to the documentation: [Enable external XMPP account connections](/peertube-plugin-livechat/documentation/admin/advanced/xmpp_clients/).
+
+### Prosody server to server port
+
+The port that will be used for XMPP s2s (server to server) connections.
+You should use the standard 5269 port.
+Otherwise you should [setup a specific DNS record](https://prosody.im/doc/s2s).
+
+### Server to server network interfaces
+
+The network interfaces to listen on for server to server connections.
+List of IP to listen on, coma separated (spaces will be stripped).
+You can use «*» to listen on all IPv4 interfaces, and «::» for all IPv6.
+Examples:
+
+- `*, ::`
+- `*`
+- `127.0.0.1, ::1`
+- `172.18.0.42`
+
+### Certificates directory
+
+If this field is empty, the plugin will generate and use self-signed certificates.
+If you want to use other certificates, just specify here the folder where
+Prosody can find them. Note: the `peertube` user must have read access to this directory.
+
### Enable client to server connections (Aktivieren von Client-Server-Verbindungen)
Diese Einstellung ermöglicht es XMPP-Clients, sich mit dem eingebauten Prosody-Server zu verbinden.
diff --git a/support/documentation/content/documentation/admin/settings.en.md b/support/documentation/content/documentation/admin/settings.en.md
index 749dfe90..860cd82b 100644
--- a/support/documentation/content/documentation/admin/settings.en.md
+++ b/support/documentation/content/documentation/admin/settings.en.md
@@ -159,6 +159,12 @@ Examples:
- `127.0.0.1, ::1`
- `172.18.0.42`
+### Certificates directory
+
+If this field is empty, the plugin will generate and use self-signed certificates.
+If you want to use other certificates, just specify here the folder where
+Prosody can find them. Note: the `peertube` user must have read access to this directory.
+
### Enable client to server connections
This setting enable XMPP clients to connect to the built-in Prosody server.