Chat Federation: fetch remote server information when missing.

This commit is contained in:
John Livingston
2023-05-24 16:09:55 +02:00
parent 6ed69d2c2f
commit e719dc3079
6 changed files with 118 additions and 53 deletions

View File

@ -1,6 +1,8 @@
import type { RegisterServerOptions } from '@peertube/peertube-types'
import { hasRemoteServerInfos, storeRemoteServerInfos } from './storage'
import { getBaseRouterRoute } from '../helpers'
import { canonicalizePluginUri } from '../uri/canonicalize'
import { sanitizePeertubeLiveChatServerInfos } from './sanitize'
import { URL } from 'url'
const got = require('got')
@ -33,13 +35,18 @@ const got = require('got')
* @param remoteInstanceUrl remote instance url to check (as readed in the request header)
* @returns true if the remote instance is ok
*/
async function remoteServerInfos (
async function fetchMissingRemoteServerInfos (
options: RegisterServerOptions,
remoteInstanceUrl: string
): Promise<boolean> {
): Promise<void> {
const logger = options.peertubeHelpers.logger
logger.debug(`remoteServerInfos: checking if we have remote server infos for host ${remoteInstanceUrl}.`)
// FIXME: add a max age.
if (await hasRemoteServerInfos(options, remoteInstanceUrl)) {
return
}
let url: string
try {
const u = new URL(remoteInstanceUrl)
@ -53,7 +60,7 @@ async function remoteServerInfos (
})
} catch (_err) {
logger.info('remoteServerInfos: Invalid remote instance url provided: ' + remoteInstanceUrl)
return false
return
}
try {
@ -66,18 +73,18 @@ async function remoteServerInfos (
if (!response) {
logger.info('remoteServerInfos: Invalid remote server options')
return false
return
}
// FIXME/TODO
return true
const serverInfos = sanitizePeertubeLiveChatServerInfos(options, response)
if (serverInfos) {
await storeRemoteServerInfos(options, serverInfos)
}
} catch (_err) {
logger.info('remoteServerInfos: Can\'t get remote instance informations using url ' + url)
return false
}
}
export {
remoteServerInfos
fetchMissingRemoteServerInfos
}

View File

@ -20,7 +20,9 @@ async function readIncomingAPVideo (
await storeVideoLiveChatInfos(options, video, peertubeLiveChat)
if (video.remote) {
await storeRemoteServerInfos(options, peertubeLiveChat)
if (peertubeLiveChat !== false && peertubeLiveChat.xmppserver) {
await storeRemoteServerInfos(options, peertubeLiveChat.xmppserver)
}
}
}

View File

@ -1,5 +1,5 @@
import type { RegisterServerOptions } from '@peertube/peertube-types'
import type { LiveChatJSONLDAttributeV1 } from './types'
import type { LiveChatJSONLDAttributeV1, PeertubeXMPPServerInfos } from './types'
import { URL } from 'url'
/**
@ -28,7 +28,24 @@ function sanitizePeertubeLiveChatInfos (options: RegisterServerOptions, chatInfo
if (!chatInfos.xmppserver || (typeof chatInfos.xmppserver !== 'object')) {
return false
}
const xmppserver = chatInfos.xmppserver
const xmppserver = sanitizePeertubeLiveChatServerInfos(options, chatInfos.xmppserver)
if (!xmppserver) { return false }
const r: LiveChatJSONLDAttributeV1 = {
type: chatInfos.type,
jid: chatInfos.jid,
xmppserver
}
return r
}
function sanitizePeertubeLiveChatServerInfos (
options: RegisterServerOptions, xmppserver: any
): PeertubeXMPPServerInfos | false {
if (!xmppserver || (typeof xmppserver !== 'object')) {
return false
}
if ((typeof xmppserver.host) !== 'string') { return false }
const host = _validateHost(xmppserver.host)
@ -37,20 +54,16 @@ function sanitizePeertubeLiveChatInfos (options: RegisterServerOptions, chatInfo
const muc = _validateHost(xmppserver.muc)
if (!muc) { return false }
const r: LiveChatJSONLDAttributeV1 = {
type: chatInfos.type,
jid: chatInfos.jid,
xmppserver: {
host,
muc
}
const r: PeertubeXMPPServerInfos = {
host,
muc
}
if (xmppserver.directs2s) {
if ((typeof xmppserver.directs2s) === 'object') {
const port = xmppserver.directs2s.port
if ((typeof port === 'string') && /^\d+$/.test(port)) {
r.xmppserver.directs2s = {
r.directs2s = {
port
}
}
@ -63,7 +76,7 @@ function sanitizePeertubeLiveChatInfos (options: RegisterServerOptions, chatInfo
noSearchParams: true,
protocol: 'ws.'
})) {
r.xmppserver.websockets2s = {
r.websockets2s = {
url
}
}
@ -72,7 +85,7 @@ function sanitizePeertubeLiveChatInfos (options: RegisterServerOptions, chatInfo
if (xmppserver.anonymous) {
const virtualhost = _validateHost(xmppserver.anonymous.virtualhost)
if (virtualhost) {
r.xmppserver.anonymous = {
r.anonymous = {
virtualhost
}
@ -81,7 +94,7 @@ function sanitizePeertubeLiveChatInfos (options: RegisterServerOptions, chatInfo
noSearchParams: true,
protocol: 'http.'
})) {
r.xmppserver.anonymous.bosh = bosh
r.anonymous.bosh = bosh
}
const websocket = xmppserver.anonymous.websocket
@ -89,7 +102,7 @@ function sanitizePeertubeLiveChatInfos (options: RegisterServerOptions, chatInfo
noSearchParams: true,
protocol: 'ws.'
})) {
r.xmppserver.anonymous.websocket = websocket
r.anonymous.websocket = websocket
}
}
}
@ -206,6 +219,23 @@ function _sanitizePeertubeLiveChatInfosV0 (options: RegisterServerOptions, chatI
return r
}
export {
sanitizePeertubeLiveChatInfos
function sanitizeXMPPHost (options: RegisterServerOptions, host: any): false | string {
return _validateHost(host)
}
function sanitizeXMPPHostFromInstanceUrl (_options: RegisterServerOptions, s: any): false | string {
try {
if (typeof s !== 'string') { return false }
const url = new URL(s)
return url.hostname
} catch (_err) {
return false
}
}
export {
sanitizePeertubeLiveChatInfos,
sanitizePeertubeLiveChatServerInfos,
sanitizeXMPPHost,
sanitizeXMPPHostFromInstanceUrl
}

View File

@ -1,6 +1,6 @@
import type { RegisterServerOptions, MVideoFullLight, MVideoAP, Video, MVideoThumbnail } from '@peertube/peertube-types'
import type { LiveChatJSONLDAttribute, LiveChatJSONLDAttributeV1 } from './types'
import { sanitizePeertubeLiveChatInfos } from './sanitize'
import type { LiveChatJSONLDAttribute, LiveChatJSONLDAttributeV1, PeertubeXMPPServerInfos } from './types'
import { sanitizePeertubeLiveChatInfos, sanitizeXMPPHostFromInstanceUrl } from './sanitize'
import { URL } from 'url'
import * as fs from 'fs'
import * as path from 'path'
@ -111,21 +111,18 @@ async function getVideoLiveChatInfos (
* kind of urls.
*
* @param options server optiosn
* @param liveChatInfos livechat stored data
* @param xmppserver remote server informations
*/
async function storeRemoteServerInfos (
options: RegisterServerOptions,
liveChatInfos: LiveChatJSONLDAttributeV1
xmppserver: PeertubeXMPPServerInfos
): Promise<void> {
if (!liveChatInfos) { return }
if (!liveChatInfos.xmppserver) { return }
const logger = options.peertubeHelpers.logger
const mainHost = liveChatInfos.xmppserver.host
const mainHost = xmppserver.host
const hosts = [
liveChatInfos.xmppserver.host,
liveChatInfos.xmppserver.muc
xmppserver.host,
xmppserver.muc
]
for (const host of hosts) {
@ -144,27 +141,55 @@ async function storeRemoteServerInfos (
)
const s2sFilePath = path.resolve(dir, 's2s')
const wsS2SFilePath = path.resolve(dir, 'ws-s2s')
const timestampFilePath = path.resolve(dir, 'last-update')
if (liveChatInfos.xmppserver.directs2s?.port) {
if (xmppserver.directs2s?.port) {
await _store(options, s2sFilePath, {
host: mainHost,
port: liveChatInfos.xmppserver.directs2s.port
port: xmppserver.directs2s.port
})
} else {
await _del(options, s2sFilePath)
}
if (liveChatInfos.xmppserver.websockets2s?.url) {
if (xmppserver.websockets2s?.url) {
await _store(options, wsS2SFilePath, {
host: mainHost,
url: liveChatInfos.xmppserver.websockets2s.url
url: xmppserver.websockets2s.url
})
} else {
await _del(options, wsS2SFilePath)
}
await _store(options, timestampFilePath, {
timestamp: (new Date()).getTime()
})
}
}
/**
* Indicate if we have the remote hosts informations.
* @param options server options
* @param host host domain
*/
async function hasRemoteServerInfos (options: RegisterServerOptions, hostParam: any): Promise<boolean> {
const host = sanitizeXMPPHostFromInstanceUrl(options, hostParam)
if (!host) {
return false
}
if (host.includes('..')) {
options.peertubeHelpers.logger.error(`Host seems not correct, contains ..: ${host}`)
return false
}
const filePath = path.resolve(
options.peertubeHelpers.plugin.getDataDirectoryPath(),
'serverInfos',
host,
'last-update'
)
return fs.existsSync(filePath)
}
async function _getFilePath (
options: RegisterServerOptions,
remote: boolean,
@ -269,6 +294,7 @@ function getRemoteServerInfosDir (options: RegisterServerOptions): string {
export {
storeVideoLiveChatInfos,
storeRemoteServerInfos,
hasRemoteServerInfos,
getVideoLiveChatInfos,
getRemoteServerInfosDir
}