Chat Federation: using S2S if available.
* if both local and remote instance have external XMPP connections enabled, the user joins the remote room with his local account * some code refactoring (builtin.ts) Note: documentation and settings descriptions are to do. Related to #112
This commit is contained in:
parent
1003378b24
commit
3bc05d88df
@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## ??? (Not Release Yet)
|
||||||
|
|
||||||
|
### New Features
|
||||||
|
|
||||||
|
* Chat Federation: if both local and remote instance have external XMPP connections enabled, you can use your local xmpp account to join remote rooms.
|
||||||
|
|
||||||
## 6.3.0
|
## 6.3.0
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
@ -1,246 +1,77 @@
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
import type { InitConverseParams } from './lib/types'
|
||||||
interface Window {
|
import { inIframe } from './lib/utils'
|
||||||
converse: {
|
import { initDom } from './lib/dom'
|
||||||
initialize: (args: any) => void
|
import {
|
||||||
plugins: {
|
defaultConverseParams,
|
||||||
add: (name: string, plugin: any) => void
|
localRoomAnonymousParams,
|
||||||
}
|
localRoomAuthenticatedParams,
|
||||||
}
|
remoteRoomAnonymousParams,
|
||||||
initConverse: (args: any) => void
|
remoteRoomAuthenticatedParams
|
||||||
}
|
} from './lib/converse-params'
|
||||||
|
import { getLocalAuthentInfos } from './lib/auth'
|
||||||
|
import { randomNick } from './lib/nick'
|
||||||
|
|
||||||
function inIframe (): boolean {
|
declare global {
|
||||||
try {
|
interface Window {
|
||||||
return window.self !== window.top
|
converse: {
|
||||||
} catch (e) {
|
initialize: (args: any) => void
|
||||||
return true
|
plugins: {
|
||||||
|
add: (name: string, plugin: any) => void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initConverse: (args: InitConverseParams) => Promise<void>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AuthentInfos {
|
window.initConverse = async function initConverse (initConverseParams: InitConverseParams): Promise<void> {
|
||||||
jid: string
|
// First, fixing relative websocket urls.
|
||||||
password: string
|
if (initConverseParams.localWebsocketServiceUrl?.startsWith('/')) {
|
||||||
nickname?: string
|
initConverseParams.localWebsocketServiceUrl = new URL(
|
||||||
}
|
initConverseParams.localWebsocketServiceUrl,
|
||||||
async function authenticatedMode (authenticationUrl: string): Promise<false | AuthentInfos> {
|
|
||||||
try {
|
|
||||||
if (!window.fetch) {
|
|
||||||
console.error('Your browser has not the fetch api, we cant log you in')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if (!window.localStorage) {
|
|
||||||
// FIXME: is the Peertube token always in localStorage?
|
|
||||||
console.error('Your browser has no localStorage, we cant log you in')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
const tokenType = window.localStorage.getItem('token_type') ?? ''
|
|
||||||
const accessToken = window.localStorage.getItem('access_token') ?? ''
|
|
||||||
const refreshToken = window.localStorage.getItem('refresh_token') ?? ''
|
|
||||||
if (tokenType === '' && accessToken === '' && refreshToken === '') {
|
|
||||||
console.info('User seems not to be logged in.')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await window.fetch(authenticationUrl, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: new Headers({
|
|
||||||
Authorization: tokenType + ' ' + accessToken,
|
|
||||||
'content-type': 'application/json;charset=UTF-8'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
console.error('Failed fetching user informations')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
const data = await response.json()
|
|
||||||
if ((typeof data) !== 'object') {
|
|
||||||
console.error('Failed reading user informations')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.jid || !data.password) {
|
|
||||||
console.error('User informations does not contain required fields')
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
jid: data.jid,
|
|
||||||
password: data.password,
|
|
||||||
nickname: data.nickname
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function randomNick (base: string): string {
|
|
||||||
// using a 6 digit random number to generate a nickname with low colision risk
|
|
||||||
const n = 100000 + Math.floor(Math.random() * 900000)
|
|
||||||
return base + ' ' + n.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface InitConverseParams {
|
|
||||||
jid: string
|
|
||||||
remoteAnonymousXMPPServer: boolean
|
|
||||||
assetsPath: string
|
|
||||||
room: string
|
|
||||||
boshServiceUrl: string
|
|
||||||
websocketServiceUrl: string
|
|
||||||
authenticationUrl: string
|
|
||||||
autoViewerMode: boolean
|
|
||||||
forceReadonly: boolean | 'noscroll'
|
|
||||||
noScroll: boolean
|
|
||||||
theme: string
|
|
||||||
transparent: boolean
|
|
||||||
}
|
|
||||||
window.initConverse = async function initConverse ({
|
|
||||||
jid,
|
|
||||||
remoteAnonymousXMPPServer,
|
|
||||||
assetsPath,
|
|
||||||
room,
|
|
||||||
boshServiceUrl,
|
|
||||||
websocketServiceUrl,
|
|
||||||
authenticationUrl,
|
|
||||||
autoViewerMode,
|
|
||||||
forceReadonly,
|
|
||||||
theme,
|
|
||||||
transparent
|
|
||||||
}: InitConverseParams) {
|
|
||||||
const isInIframe = inIframe()
|
|
||||||
const converse = window.converse
|
|
||||||
|
|
||||||
const body = document.querySelector('body')
|
|
||||||
if (isInIframe) {
|
|
||||||
if (body) {
|
|
||||||
body.classList.add('livechat-iframe')
|
|
||||||
// prevent horizontal scrollbar when in iframe. (don't know why, but does not work if done by CSS)
|
|
||||||
body.style.overflowX = 'hidden'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (forceReadonly) {
|
|
||||||
body?.classList.add('livechat-readonly')
|
|
||||||
if (forceReadonly === 'noscroll') {
|
|
||||||
body?.classList.add('livechat-noscroll')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (transparent) {
|
|
||||||
body?.classList.add('livechat-transparent')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (websocketServiceUrl?.startsWith('/')) {
|
|
||||||
websocketServiceUrl = new URL(
|
|
||||||
websocketServiceUrl,
|
|
||||||
(window.location.protocol === 'http:' ? 'ws://' : 'wss://') + window.location.host
|
(window.location.protocol === 'http:' ? 'ws://' : 'wss://') + window.location.host
|
||||||
).toString()
|
).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
const mucShowInfoMessages = forceReadonly
|
const {
|
||||||
? [
|
isRemoteChat,
|
||||||
// in readonly mode, show only following info messages:
|
remoteAnonymousXMPPServer,
|
||||||
'301', '307', '321', '322', '332', '333' // disconnected
|
remoteAuthenticatedXMPPServer,
|
||||||
]
|
authenticationUrl,
|
||||||
: [
|
autoViewerMode,
|
||||||
// FIXME: wait for a response here, and rewrite: https://github.com/conversejs/converse.js/issues/3125
|
forceReadonly
|
||||||
'100', '102', '103', '172', '173', '174', // visibility_changes
|
} = initConverseParams
|
||||||
'110', // self
|
|
||||||
'104', '201', // non_privacy_changes
|
|
||||||
'170', '171', // muc_logging_changes
|
|
||||||
'210', '303', // nickname_changes
|
|
||||||
'301', '307', '321', '322', '332', '333', // disconnected
|
|
||||||
'owner', 'admin', 'member', 'exadmin', 'exowner', 'exoutcast', 'exmember', // affiliation_changes
|
|
||||||
// 'entered', 'exited', // join_leave_events
|
|
||||||
'op', 'deop', 'voice', 'mute' // role_changes
|
|
||||||
]
|
|
||||||
|
|
||||||
const params: any = {
|
const converse = window.converse
|
||||||
assets_path: assetsPath,
|
|
||||||
|
|
||||||
authentication: 'anonymous',
|
const isInIframe = inIframe()
|
||||||
ping_interval: 25, // must be set accordingly to c2s_close_timeout backend websocket settings and nginx timeout
|
initDom(initConverseParams, isInIframe)
|
||||||
auto_login: true,
|
const params = defaultConverseParams(initConverseParams, isInIframe)
|
||||||
auto_join_rooms: [
|
|
||||||
room
|
|
||||||
],
|
|
||||||
keepalive: true,
|
|
||||||
discover_connection_methods: false, // this parameter seems buggy with converseJS 7.0.4
|
|
||||||
bosh_service_url: boshServiceUrl === '' ? undefined : boshServiceUrl,
|
|
||||||
websocket_url: websocketServiceUrl === '' ? undefined : websocketServiceUrl,
|
|
||||||
jid: jid,
|
|
||||||
notify_all_room_messages: [
|
|
||||||
room
|
|
||||||
],
|
|
||||||
show_desktop_notifications: false,
|
|
||||||
show_tab_notifications: false,
|
|
||||||
singleton: true,
|
|
||||||
auto_focus: !isInIframe,
|
|
||||||
hide_muc_participants: isInIframe,
|
|
||||||
play_sounds: false,
|
|
||||||
muc_mention_autocomplete_min_chars: 2,
|
|
||||||
muc_mention_autocomplete_filter: 'contains',
|
|
||||||
muc_instant_rooms: true,
|
|
||||||
show_client_info: false,
|
|
||||||
allow_adhoc_commands: false,
|
|
||||||
allow_contact_requests: false,
|
|
||||||
allow_logout: false,
|
|
||||||
show_controlbox_by_default: false,
|
|
||||||
view_mode: 'fullscreen',
|
|
||||||
allow_message_corrections: 'all',
|
|
||||||
allow_message_retraction: 'all',
|
|
||||||
visible_toolbar_buttons: {
|
|
||||||
call: false,
|
|
||||||
spoiler: false,
|
|
||||||
emoji: true,
|
|
||||||
toggle_occupants: true
|
|
||||||
},
|
|
||||||
theme: theme || 'peertube',
|
|
||||||
dark_theme: theme || 'peertube', // dark theme should be the same as theme
|
|
||||||
persistent_store: 'sessionStorage',
|
|
||||||
show_images_inline: false, // for security reason, and to avoid bugs when image is larger that iframe
|
|
||||||
render_media: false, // for security reason, and to avoid bugs when image is larger that iframe
|
|
||||||
whitelisted_plugins: ['livechatWindowTitlePlugin', 'livechatViewerModePlugin', 'livechatDisconnectOnUnloadPlugin'],
|
|
||||||
show_retraction_warning: false, // No need to use this warning (except if we open to external clients?)
|
|
||||||
muc_show_info_messages: mucShowInfoMessages,
|
|
||||||
send_chat_state_notifications: false // don't send this for performance reason
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: params.clear_messages_on_reconnection = true when muc_mam will be available.
|
|
||||||
|
|
||||||
let isAuthenticated: boolean = false
|
let isAuthenticated: boolean = false
|
||||||
let isRemoteWithNicknameSet: boolean = false
|
let isRemoteWithNicknameSet: boolean = false
|
||||||
if (authenticationUrl === '') {
|
|
||||||
throw new Error('Missing authenticationUrl')
|
|
||||||
}
|
|
||||||
|
|
||||||
// The user will never se the «trusted browser» checkbox (that allows to save credentials).
|
const auth = await getLocalAuthentInfos(authenticationUrl)
|
||||||
// So we have to disable it
|
|
||||||
// (and ensure clear_cache_on_logout is true,
|
|
||||||
// see https://conversejs.org/docs/html/configuration.html#allow-user-trust-override).
|
|
||||||
params.clear_cache_on_logout = true
|
|
||||||
params.allow_user_trust_override = false
|
|
||||||
|
|
||||||
const auth = await authenticatedMode(authenticationUrl)
|
|
||||||
if (auth) {
|
if (auth) {
|
||||||
if (remoteAnonymousXMPPServer) {
|
if (!isRemoteChat) {
|
||||||
// Spécial case: anonymous connection to remote XMPP server.
|
localRoomAuthenticatedParams(initConverseParams, auth, params)
|
||||||
if (auth.nickname) {
|
|
||||||
params.nickname = auth.nickname
|
|
||||||
isRemoteWithNicknameSet = true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
params.authentication = 'login'
|
|
||||||
params.auto_login = true
|
|
||||||
params.jid = auth.jid
|
|
||||||
params.password = auth.password
|
|
||||||
if (auth.nickname) {
|
|
||||||
params.nickname = auth.nickname
|
|
||||||
} else {
|
|
||||||
params.muc_nickname_from_jid = true
|
|
||||||
}
|
|
||||||
// We dont need the keepalive. And I suppose it is related to some bugs when opening a previous chat window.
|
|
||||||
params.keepalive = false
|
|
||||||
isAuthenticated = true
|
isAuthenticated = true
|
||||||
// FIXME: use params.oauth_providers?
|
} else if (remoteAuthenticatedXMPPServer) {
|
||||||
|
remoteRoomAuthenticatedParams(initConverseParams, auth, params)
|
||||||
|
isAuthenticated = true
|
||||||
|
} else if (remoteAnonymousXMPPServer) {
|
||||||
|
// remote server does not allow remote authenticated users, falling back to anonymous mode
|
||||||
|
remoteRoomAnonymousParams(initConverseParams, auth, params)
|
||||||
|
isRemoteWithNicknameSet = true
|
||||||
|
} else {
|
||||||
|
throw new Error('Remote server does not allow remote connection')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isRemoteChat) {
|
||||||
|
localRoomAnonymousParams(initConverseParams, params)
|
||||||
|
} else if (remoteAnonymousXMPPServer) {
|
||||||
|
remoteRoomAnonymousParams(initConverseParams, null, params)
|
||||||
|
} else {
|
||||||
|
throw new Error('Remote server does not allow remote connection')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,9 +131,9 @@ window.initConverse = async function initConverse ({
|
|||||||
function refreshViewerMode (canChat: boolean): void {
|
function refreshViewerMode (canChat: boolean): void {
|
||||||
console.log('[livechatViewerModePlugin] refreshViewerMode: ' + (canChat ? 'off' : 'on'))
|
console.log('[livechatViewerModePlugin] refreshViewerMode: ' + (canChat ? 'off' : 'on'))
|
||||||
if (canChat) {
|
if (canChat) {
|
||||||
body?.setAttribute('livechat-viewer-mode', 'off')
|
document.querySelector('body')?.setAttribute('livechat-viewer-mode', 'off')
|
||||||
} else {
|
} else {
|
||||||
body?.setAttribute('livechat-viewer-mode', 'on')
|
document.querySelector('body')?.setAttribute('livechat-viewer-mode', 'on')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,12 +15,17 @@
|
|||||||
<div id="conversejs-bg" class="theme-peertube"></div>
|
<div id="conversejs-bg" class="theme-peertube"></div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
initConverse({
|
initConverse({
|
||||||
jid: '{{JID}}',
|
isRemoteChat: '{{IS_REMOTE_CHAT}}' === 'true',
|
||||||
|
localAnonymousJID: '{{LOCAL_ANONYMOUS_JID}}',
|
||||||
|
remoteAnonymousJID: '{{REMOTE_ANONYMOUS_JID}}' === '' ? null : '{{REMOTE_ANONYMOUS_JID}}',
|
||||||
remoteAnonymousXMPPServer: '{{REMOTE_ANONYMOUS_XMPP_SERVER}}' === 'true',
|
remoteAnonymousXMPPServer: '{{REMOTE_ANONYMOUS_XMPP_SERVER}}' === 'true',
|
||||||
|
remoteAuthenticatedXMPPServer: '{{REMOTE_AUTHENTICATED_XMPP_SERVER}}' === 'true',
|
||||||
assetsPath : '{{BASE_STATIC_URL}}conversejs/',
|
assetsPath : '{{BASE_STATIC_URL}}conversejs/',
|
||||||
room: '{{ROOM}}',
|
room: '{{ROOM}}',
|
||||||
boshServiceUrl: '{{BOSH_SERVICE_URL}}',
|
localBoshServiceUrl: '{{LOCAL_BOSH_SERVICE_URL}}' === '' ? null : '{{LOCAL_BOSH_SERVICE_URL}}',
|
||||||
websocketServiceUrl: '{{WS_SERVICE_URL}}',
|
localWebsocketServiceUrl: '{{LOCAL_WS_SERVICE_URL}}' === '' ? null : '{{LOCAL_WS_SERVICE_URL}}',
|
||||||
|
remoteBoshServiceUrl: '{{REMOTE_BOSH_SERVICE_URL}}' === '' ? null : '{{REMOTE_BOSH_SERVICE_URL}}',
|
||||||
|
remoteWebsocketServiceUrl: '{{REMOTE_WS_SERVICE_URL}}' === '' ? null : '{{REMOTE_WS_SERVICE_URL}}',
|
||||||
authenticationUrl: '{{AUTHENTICATION_URL}}',
|
authenticationUrl: '{{AUTHENTICATION_URL}}',
|
||||||
autoViewerMode: '{{AUTOVIEWERMODE}}' === 'true',
|
autoViewerMode: '{{AUTOVIEWERMODE}}' === 'true',
|
||||||
theme: '{{CONVERSEJS_THEME}}',
|
theme: '{{CONVERSEJS_THEME}}',
|
||||||
|
65
conversejs/lib/auth.ts
Normal file
65
conversejs/lib/auth.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
interface AuthentInfos {
|
||||||
|
jid: string
|
||||||
|
password: string
|
||||||
|
nickname?: string
|
||||||
|
}
|
||||||
|
async function getLocalAuthentInfos (authenticationUrl: string): Promise<false | AuthentInfos> {
|
||||||
|
try {
|
||||||
|
if (authenticationUrl === '') {
|
||||||
|
console.error('Missing authenticationUrl')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!window.fetch) {
|
||||||
|
console.error('Your browser has not the fetch api, we cant log you in')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!window.localStorage) {
|
||||||
|
// FIXME: is the Peertube token always in localStorage?
|
||||||
|
console.error('Your browser has no localStorage, we cant log you in')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const tokenType = window.localStorage.getItem('token_type') ?? ''
|
||||||
|
const accessToken = window.localStorage.getItem('access_token') ?? ''
|
||||||
|
const refreshToken = window.localStorage.getItem('refresh_token') ?? ''
|
||||||
|
if (tokenType === '' && accessToken === '' && refreshToken === '') {
|
||||||
|
console.info('User seems not to be logged in.')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await window.fetch(authenticationUrl, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: new Headers({
|
||||||
|
Authorization: tokenType + ' ' + accessToken,
|
||||||
|
'content-type': 'application/json;charset=UTF-8'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
console.error('Failed fetching user informations')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const data = await response.json()
|
||||||
|
if ((typeof data) !== 'object') {
|
||||||
|
console.error('Failed reading user informations')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.jid || !data.password) {
|
||||||
|
console.error('User informations does not contain required fields')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
jid: data.jid,
|
||||||
|
password: data.password,
|
||||||
|
nickname: data.nickname
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
AuthentInfos,
|
||||||
|
getLocalAuthentInfos
|
||||||
|
}
|
174
conversejs/lib/converse-params.ts
Normal file
174
conversejs/lib/converse-params.ts
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
import type { InitConverseParams } from './types'
|
||||||
|
import type { AuthentInfos } from './auth'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instanciate defaults params to use for ConverseJS.
|
||||||
|
* Note: these parameters must be completed with one of the other function present in this module.
|
||||||
|
* @param param0 global parameters
|
||||||
|
* @param isInIframe true if we are in iframe mode (inside Peertube, beside video)
|
||||||
|
* @returns default parameters to provide to ConverseJS.
|
||||||
|
*/
|
||||||
|
function defaultConverseParams (
|
||||||
|
{ forceReadonly, theme, assetsPath, room }: InitConverseParams,
|
||||||
|
isInIframe: boolean
|
||||||
|
): any {
|
||||||
|
const mucShowInfoMessages = forceReadonly
|
||||||
|
? [
|
||||||
|
// in readonly mode, show only following info messages:
|
||||||
|
'301', '307', '321', '322', '332', '333' // disconnected
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
// FIXME: wait for a response here, and rewrite: https://github.com/conversejs/converse.js/issues/3125
|
||||||
|
'100', '102', '103', '172', '173', '174', // visibility_changes
|
||||||
|
'110', // self
|
||||||
|
'104', '201', // non_privacy_changes
|
||||||
|
'170', '171', // muc_logging_changes
|
||||||
|
'210', '303', // nickname_changes
|
||||||
|
'301', '307', '321', '322', '332', '333', // disconnected
|
||||||
|
'owner', 'admin', 'member', 'exadmin', 'exowner', 'exoutcast', 'exmember', // affiliation_changes
|
||||||
|
// 'entered', 'exited', // join_leave_events
|
||||||
|
'op', 'deop', 'voice', 'mute' // role_changes
|
||||||
|
]
|
||||||
|
|
||||||
|
const params: any = {
|
||||||
|
assets_path: assetsPath,
|
||||||
|
|
||||||
|
authentication: 'anonymous',
|
||||||
|
ping_interval: 25, // must be set accordingly to c2s_close_timeout backend websocket settings and nginx timeout
|
||||||
|
auto_login: true,
|
||||||
|
auto_join_rooms: [
|
||||||
|
room
|
||||||
|
],
|
||||||
|
keepalive: true,
|
||||||
|
discover_connection_methods: false, // this parameter seems buggy with converseJS 7.0.4
|
||||||
|
notify_all_room_messages: [
|
||||||
|
room
|
||||||
|
],
|
||||||
|
show_desktop_notifications: false,
|
||||||
|
show_tab_notifications: false,
|
||||||
|
singleton: true,
|
||||||
|
auto_focus: !isInIframe,
|
||||||
|
hide_muc_participants: isInIframe,
|
||||||
|
play_sounds: false,
|
||||||
|
muc_mention_autocomplete_min_chars: 2,
|
||||||
|
muc_mention_autocomplete_filter: 'contains',
|
||||||
|
muc_instant_rooms: true,
|
||||||
|
show_client_info: false,
|
||||||
|
allow_adhoc_commands: false,
|
||||||
|
allow_contact_requests: false,
|
||||||
|
allow_logout: false,
|
||||||
|
show_controlbox_by_default: false,
|
||||||
|
view_mode: 'fullscreen',
|
||||||
|
allow_message_corrections: 'all',
|
||||||
|
allow_message_retraction: 'all',
|
||||||
|
visible_toolbar_buttons: {
|
||||||
|
call: false,
|
||||||
|
spoiler: false,
|
||||||
|
emoji: true,
|
||||||
|
toggle_occupants: true
|
||||||
|
},
|
||||||
|
theme: theme || 'peertube',
|
||||||
|
dark_theme: theme || 'peertube', // dark theme should be the same as theme
|
||||||
|
persistent_store: 'sessionStorage',
|
||||||
|
show_images_inline: false, // for security reason, and to avoid bugs when image is larger that iframe
|
||||||
|
render_media: false, // for security reason, and to avoid bugs when image is larger that iframe
|
||||||
|
whitelisted_plugins: ['livechatWindowTitlePlugin', 'livechatViewerModePlugin', 'livechatDisconnectOnUnloadPlugin'],
|
||||||
|
show_retraction_warning: false, // No need to use this warning (except if we open to external clients?)
|
||||||
|
muc_show_info_messages: mucShowInfoMessages,
|
||||||
|
send_chat_state_notifications: false // don't send this for performance reason
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: params.clear_messages_on_reconnection = true when muc_mam will be available.
|
||||||
|
|
||||||
|
// The user will never se the «trusted browser» checkbox (that allows to save credentials).
|
||||||
|
// So we have to disable it
|
||||||
|
// (and ensure clear_cache_on_logout is true,
|
||||||
|
// see https://conversejs.org/docs/html/configuration.html#allow-user-trust-override).
|
||||||
|
params.clear_cache_on_logout = true
|
||||||
|
params.allow_user_trust_override = false
|
||||||
|
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The room is local, and we are an authenticated local user
|
||||||
|
* @param initConverseParams global parameters
|
||||||
|
* @param auth authent infos.
|
||||||
|
* @param params ConverseJS parameters to fill
|
||||||
|
*/
|
||||||
|
function localRoomAuthenticatedParams (initConverseParams: InitConverseParams, auth: AuthentInfos, params: any): void {
|
||||||
|
_fillAuthenticatedParams(initConverseParams, auth, params)
|
||||||
|
_fillLocalProtocols(initConverseParams, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The room is local, and we are an anonymous local user
|
||||||
|
* @param initConverseParams global parameters
|
||||||
|
* @param params ConverseJS parameters to fill
|
||||||
|
*/
|
||||||
|
function localRoomAnonymousParams (initConverseParams: InitConverseParams, params: any): void {
|
||||||
|
params.jid = initConverseParams.localAnonymousJID
|
||||||
|
_fillLocalProtocols(initConverseParams, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The room is remote, and we are an authenticated local user
|
||||||
|
* @param initConverseParams global parameters
|
||||||
|
* @param auth authent infos.
|
||||||
|
* @param params ConverseJS parameters to fill
|
||||||
|
*/
|
||||||
|
function remoteRoomAuthenticatedParams (initConverseParams: InitConverseParams, auth: AuthentInfos, params: any): void {
|
||||||
|
_fillAuthenticatedParams(initConverseParams, auth, params)
|
||||||
|
_fillLocalProtocols(initConverseParams, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The room is remote, and we are an anonymous local user
|
||||||
|
* @param initConverseParams global parameters
|
||||||
|
* @param auth optionnal authent infos. Used to get the default nickname
|
||||||
|
* @param params ConverseJS parameters to fill
|
||||||
|
*/
|
||||||
|
function remoteRoomAnonymousParams (
|
||||||
|
initConverseParams: InitConverseParams,
|
||||||
|
auth: AuthentInfos | null,
|
||||||
|
params: any
|
||||||
|
): void {
|
||||||
|
params.jid = initConverseParams.remoteAnonymousJID
|
||||||
|
if (auth?.nickname) {
|
||||||
|
params.nickname = auth.nickname
|
||||||
|
}
|
||||||
|
_fillRemoteProtocols(initConverseParams, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
function _fillAuthenticatedParams (initConverseParams: InitConverseParams, auth: AuthentInfos, params: any): void {
|
||||||
|
params.authentication = 'login'
|
||||||
|
params.auto_login = true
|
||||||
|
params.jid = auth.jid
|
||||||
|
params.password = auth.password
|
||||||
|
if (auth.nickname) {
|
||||||
|
params.nickname = auth.nickname
|
||||||
|
} else {
|
||||||
|
params.muc_nickname_from_jid = true
|
||||||
|
}
|
||||||
|
// We dont need the keepalive. And I suppose it is related to some bugs when opening a previous chat window.
|
||||||
|
params.keepalive = false
|
||||||
|
// FIXME: use params.oauth_providers?
|
||||||
|
}
|
||||||
|
|
||||||
|
function _fillLocalProtocols (initConverseParams: InitConverseParams, params: any): void {
|
||||||
|
params.bosh_service_url = initConverseParams.localBoshServiceUrl
|
||||||
|
params.websocket_url = initConverseParams.localWebsocketServiceUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
function _fillRemoteProtocols (initConverseParams: InitConverseParams, params: any): void {
|
||||||
|
params.bosh_service_url = initConverseParams.remoteBoshServiceUrl
|
||||||
|
params.websocket_url = initConverseParams.remoteWebsocketServiceUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
defaultConverseParams,
|
||||||
|
localRoomAuthenticatedParams,
|
||||||
|
localRoomAnonymousParams,
|
||||||
|
remoteRoomAnonymousParams,
|
||||||
|
remoteRoomAuthenticatedParams
|
||||||
|
}
|
25
conversejs/lib/dom.ts
Normal file
25
conversejs/lib/dom.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import type { InitConverseParams } from './types'
|
||||||
|
|
||||||
|
function initDom ({ forceReadonly, transparent }: InitConverseParams, isInIframe: boolean): void {
|
||||||
|
const body = document.querySelector('body')
|
||||||
|
if (isInIframe) {
|
||||||
|
if (body) {
|
||||||
|
body.classList.add('livechat-iframe')
|
||||||
|
// prevent horizontal scrollbar when in iframe. (don't know why, but does not work if done by CSS)
|
||||||
|
body.style.overflowX = 'hidden'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (forceReadonly) {
|
||||||
|
body?.classList.add('livechat-readonly')
|
||||||
|
if (forceReadonly === 'noscroll') {
|
||||||
|
body?.classList.add('livechat-noscroll')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (transparent) {
|
||||||
|
body?.classList.add('livechat-transparent')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
initDom
|
||||||
|
}
|
9
conversejs/lib/nick.ts
Normal file
9
conversejs/lib/nick.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
function randomNick (base: string): string {
|
||||||
|
// using a 6 digit random number to generate a nickname with low colision risk
|
||||||
|
const n = 100000 + Math.floor(Math.random() * 900000)
|
||||||
|
return base + ' ' + n.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
randomNick
|
||||||
|
}
|
23
conversejs/lib/types.ts
Normal file
23
conversejs/lib/types.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
interface InitConverseParams {
|
||||||
|
isRemoteChat: boolean
|
||||||
|
localAnonymousJID: string
|
||||||
|
remoteAnonymousJID: string | null
|
||||||
|
remoteAnonymousXMPPServer: boolean
|
||||||
|
remoteAuthenticatedXMPPServer: boolean
|
||||||
|
assetsPath: string
|
||||||
|
room: string
|
||||||
|
localBoshServiceUrl: string | null
|
||||||
|
localWebsocketServiceUrl: string | null
|
||||||
|
remoteBoshServiceUrl: string | null
|
||||||
|
remoteWebsocketServiceUrl: string | null
|
||||||
|
authenticationUrl: string
|
||||||
|
autoViewerMode: boolean
|
||||||
|
forceReadonly: boolean | 'noscroll'
|
||||||
|
noScroll: boolean
|
||||||
|
theme: string
|
||||||
|
transparent: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
InitConverseParams
|
||||||
|
}
|
11
conversejs/lib/utils.ts
Normal file
11
conversejs/lib/utils.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
function inIframe (): boolean {
|
||||||
|
try {
|
||||||
|
return window.self !== window.top
|
||||||
|
} catch (e) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
inIframe
|
||||||
|
}
|
@ -31,6 +31,17 @@ function anonymousConnectionInfos (livechatInfos: LiveChatJSONLDAttribute | fals
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
function remoteAuthenticatedConnectionEnabled (livechatInfos: LiveChatJSONLDAttribute | false): boolean {
|
||||||
anonymousConnectionInfos
|
if (!livechatInfos) { return false }
|
||||||
|
if (!livechatInfos.links) { return false }
|
||||||
|
if (livechatInfos.type !== 'xmpp') { return false }
|
||||||
|
for (const link of livechatInfos.links) {
|
||||||
|
if (link.type === 'xmpp-s2s') { return true }
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
anonymousConnectionInfos,
|
||||||
|
remoteAuthenticatedConnectionEnabled
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,8 @@ async function videoBuildJSONLD (
|
|||||||
'disable-websocket',
|
'disable-websocket',
|
||||||
'prosody-room-type',
|
'prosody-room-type',
|
||||||
'federation-dont-publish-remotely',
|
'federation-dont-publish-remotely',
|
||||||
'chat-no-anonymous'
|
'chat-no-anonymous',
|
||||||
|
'prosody-room-allow-s2s'
|
||||||
])
|
])
|
||||||
|
|
||||||
if (settings['federation-dont-publish-remotely']) {
|
if (settings['federation-dont-publish-remotely']) {
|
||||||
@ -70,6 +71,11 @@ async function videoBuildJSONLD (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const links: LiveChatJSONLDLink[] = []
|
const links: LiveChatJSONLDLink[] = []
|
||||||
|
if (settings['prosody-room-allow-s2s']) {
|
||||||
|
links.push({
|
||||||
|
type: 'xmpp-s2s'
|
||||||
|
})
|
||||||
|
}
|
||||||
if (!settings['chat-no-anonymous']) {
|
if (!settings['chat-no-anonymous']) {
|
||||||
links.push({
|
links.push({
|
||||||
type: 'xmpp-bosh-anonymous',
|
type: 'xmpp-bosh-anonymous',
|
||||||
|
@ -36,6 +36,11 @@ function sanitizePeertubeLiveChatInfos (chatInfos: any): LiveChatJSONLDAttribute
|
|||||||
url: link.url
|
url: link.url
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
if (link.type === 'xmpp-s2s') {
|
||||||
|
r.links.push({
|
||||||
|
type: link.type
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,10 @@ interface VideoBuildResultContext {
|
|||||||
video: MVideoAP
|
video: MVideoAP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface LiveChatJSONLDS2SLink {
|
||||||
|
type: 'xmpp-s2s'
|
||||||
|
}
|
||||||
|
|
||||||
interface LiveChatJSONLDAnonymousWebsocketLink {
|
interface LiveChatJSONLDAnonymousWebsocketLink {
|
||||||
type: 'xmpp-websocket-anonymous'
|
type: 'xmpp-websocket-anonymous'
|
||||||
url: string
|
url: string
|
||||||
@ -16,7 +20,7 @@ interface LiveChatJSONLDAnonymousBOSHLink {
|
|||||||
jid: string
|
jid: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type LiveChatJSONLDLink = LiveChatJSONLDAnonymousBOSHLink | LiveChatJSONLDAnonymousWebsocketLink
|
type LiveChatJSONLDLink = LiveChatJSONLDS2SLink | LiveChatJSONLDAnonymousBOSHLink | LiveChatJSONLDAnonymousWebsocketLink
|
||||||
|
|
||||||
interface LiveChatJSONLDInfos {
|
interface LiveChatJSONLDInfos {
|
||||||
type: 'xmpp'
|
type: 'xmpp'
|
||||||
|
@ -156,6 +156,7 @@ async function getProsodyConfig (options: RegisterServerOptionsV5): Promise<Pros
|
|||||||
const prosodyDomain = await getProsodyDomain(options)
|
const prosodyDomain = await getProsodyDomain(options)
|
||||||
const paths = await getProsodyFilePaths(options)
|
const paths = await getProsodyFilePaths(options)
|
||||||
const roomType = settings['prosody-room-type'] === 'channel' ? 'channel' : 'video'
|
const roomType = settings['prosody-room-type'] === 'channel' ? 'channel' : 'video'
|
||||||
|
const enableUserS2S = enableRoomS2S && !(settings['federation-no-remote-chat'] as boolean)
|
||||||
let certificates: ProsodyConfigCertificates = false
|
let certificates: ProsodyConfigCertificates = false
|
||||||
|
|
||||||
const apikey = await getAPIKey(options)
|
const apikey = await getAPIKey(options)
|
||||||
@ -203,7 +204,7 @@ async function getProsodyConfig (options: RegisterServerOptionsV5): Promise<Pros
|
|||||||
config.useExternalComponents(componentsPort, components)
|
config.useExternalComponents(componentsPort, components)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enableRoomS2S) {
|
if (enableRoomS2S || enableUserS2S) {
|
||||||
certificates = 'generate-self-signed'
|
certificates = 'generate-self-signed'
|
||||||
if (config.paths.certsDirIsCustom) {
|
if (config.paths.certsDirIsCustom) {
|
||||||
certificates = 'use-from-dir'
|
certificates = 'use-from-dir'
|
||||||
@ -223,7 +224,7 @@ async function getProsodyConfig (options: RegisterServerOptionsV5): Promise<Pros
|
|||||||
if (networkInterface.match(/^[a-f0-9:]+$/)) return
|
if (networkInterface.match(/^[a-f0-9:]+$/)) return
|
||||||
throw new Error('Invalid s2s interfaces')
|
throw new Error('Invalid s2s interfaces')
|
||||||
})
|
})
|
||||||
config.useRoomS2S(s2sPort, s2sInterfaces)
|
config.useS2S(s2sPort, s2sInterfaces, !enableUserS2S)
|
||||||
}
|
}
|
||||||
|
|
||||||
const logExpiration = readLogExpiration(options, logExpirationSetting)
|
const logExpiration = readLogExpiration(options, logExpirationSetting)
|
||||||
|
@ -258,13 +258,17 @@ class ProsodyConfigContent {
|
|||||||
this.global.set('c2s_ports', [c2sPort])
|
this.global.set('c2s_ports', [c2sPort])
|
||||||
}
|
}
|
||||||
|
|
||||||
useRoomS2S (s2sPort: string, s2sInterfaces: string[]): void {
|
useS2S (s2sPort: string, s2sInterfaces: string[], mucOnly: boolean): void {
|
||||||
this.global.set('s2s_ports', [s2sPort])
|
this.global.set('s2s_ports', [s2sPort])
|
||||||
this.global.set('s2s_interfaces', s2sInterfaces)
|
this.global.set('s2s_interfaces', s2sInterfaces)
|
||||||
this.global.set('s2s_secure_auth', false)
|
this.global.set('s2s_secure_auth', false)
|
||||||
this.global.add('modules_enabled', 'tls') // required for s2s and co
|
this.global.add('modules_enabled', 'tls') // required for s2s and co
|
||||||
this.muc.add('modules_enabled', 's2s')
|
this.muc.add('modules_enabled', 's2s')
|
||||||
this.muc.add('modules_enabled', 'dialback') // This allows s2s connections without certicicates!
|
this.muc.add('modules_enabled', 'dialback') // This allows s2s connections without certicicates!
|
||||||
|
if (!mucOnly && this.authenticated) {
|
||||||
|
this.authenticated.add('modules_enabled', 's2s')
|
||||||
|
this.authenticated.add('modules_enabled', 'dialback') // This allows s2s connections without certicicates!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useExternalComponents (componentsPort: string, components: ExternalComponent[]): void {
|
useExternalComponents (componentsPort: string, components: ExternalComponent[]): void {
|
||||||
|
@ -15,7 +15,7 @@ import { isAutoColorsAvailable, areAutoColorsValid, AutoColors } from '../../../
|
|||||||
import { getBoshUri, getWSUri } from '../uri/webchat'
|
import { getBoshUri, getWSUri } from '../uri/webchat'
|
||||||
import { getVideoLiveChatInfos } from '../federation/storage'
|
import { getVideoLiveChatInfos } from '../federation/storage'
|
||||||
import { LiveChatJSONLDAttribute } from '../federation/types'
|
import { LiveChatJSONLDAttribute } from '../federation/types'
|
||||||
import { anonymousConnectionInfos } from '../federation/connection-infos'
|
import { anonymousConnectionInfos, remoteAuthenticatedConnectionEnabled } from '../federation/connection-infos'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
const got = require('got')
|
const got = require('got')
|
||||||
|
|
||||||
@ -50,7 +50,8 @@ async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Rou
|
|||||||
'prosody-room-type',
|
'prosody-room-type',
|
||||||
'disable-websocket',
|
'disable-websocket',
|
||||||
'converse-theme', 'converse-autocolors',
|
'converse-theme', 'converse-autocolors',
|
||||||
'federation-no-remote-chat'
|
'federation-no-remote-chat',
|
||||||
|
'prosody-room-allow-s2s'
|
||||||
])
|
])
|
||||||
|
|
||||||
let autoViewerMode: boolean = false
|
let autoViewerMode: boolean = false
|
||||||
@ -110,26 +111,38 @@ async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Rou
|
|||||||
const baseStaticUrl = getBaseStaticRoute(options)
|
const baseStaticUrl = getBaseStaticRoute(options)
|
||||||
page = page.replace(/{{BASE_STATIC_URL}}/g, baseStaticUrl)
|
page = page.replace(/{{BASE_STATIC_URL}}/g, baseStaticUrl)
|
||||||
|
|
||||||
let connectionInfos: ConnectionInfos | null
|
const prosodyDomain = await getProsodyDomain(options)
|
||||||
|
const localAnonymousJID = 'anon.' + prosodyDomain
|
||||||
|
const localBoshUri = getBoshUri(options)
|
||||||
|
const localWsUri = settings['disable-websocket']
|
||||||
|
? ''
|
||||||
|
: (getWSUri(options) ?? '')
|
||||||
|
|
||||||
|
let remoteConnectionInfos: WCRemoteConnectionInfos | undefined
|
||||||
|
let roomJID: string
|
||||||
if (video?.remote) {
|
if (video?.remote) {
|
||||||
connectionInfos = await _remoteConnectionInfos(remoteChatInfos ?? false)
|
remoteConnectionInfos = await _remoteConnectionInfos(remoteChatInfos ?? false)
|
||||||
|
if (!remoteConnectionInfos) {
|
||||||
|
res.status(404)
|
||||||
|
res.send('No compatible way to connect to remote chat')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
roomJID = remoteConnectionInfos.roomJID
|
||||||
} else {
|
} else {
|
||||||
connectionInfos = await _localConnectionInfos(
|
roomJID = await _localRoomJID(
|
||||||
options,
|
options,
|
||||||
settings,
|
settings,
|
||||||
|
prosodyDomain,
|
||||||
roomKey,
|
roomKey,
|
||||||
video,
|
video,
|
||||||
channelId,
|
channelId,
|
||||||
req.query.forcetype === '1'
|
req.query.forcetype === '1'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (!connectionInfos) {
|
|
||||||
res.status(404)
|
|
||||||
res.send('No compatible way to connect to remote chat')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page = page.replace(/{{JID}}/g, connectionInfos.userJID)
|
page = page.replace(/{{IS_REMOTE_CHAT}}/g, video?.remote ? 'true' : 'false')
|
||||||
|
page = page.replace(/{{LOCAL_ANONYMOUS_JID}}/g, localAnonymousJID)
|
||||||
|
page = page.replace(/{{REMOTE_ANONYMOUS_JID}}/g, remoteConnectionInfos?.anonymous?.userJID ?? '')
|
||||||
|
|
||||||
let autocolorsStyles = ''
|
let autocolorsStyles = ''
|
||||||
if (
|
if (
|
||||||
@ -183,10 +196,20 @@ async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Rou
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ... then inject it in the page.
|
// ... then inject it in the page.
|
||||||
page = page.replace(/{{ROOM}}/g, connectionInfos.roomJID)
|
page = page.replace(/{{ROOM}}/g, roomJID)
|
||||||
page = page.replace(/{{BOSH_SERVICE_URL}}/g, connectionInfos.boshUri)
|
page = page.replace(/{{LOCAL_BOSH_SERVICE_URL}}/g, localBoshUri)
|
||||||
page = page.replace(/{{WS_SERVICE_URL}}/g, connectionInfos.wsUri ?? '')
|
page = page.replace(/{{LOCAL_WS_SERVICE_URL}}/g, localWsUri ?? '')
|
||||||
page = page.replace(/{{REMOTE_ANONYMOUS_XMPP_SERVER}}/g, connectionInfos.remoteXMPPServer ? 'true' : 'false')
|
page = page.replace(/{{REMOTE_BOSH_SERVICE_URL}}/g, remoteConnectionInfos?.anonymous?.boshUri ?? '')
|
||||||
|
page = page.replace(/{{REMOTE_WS_SERVICE_URL}}/g, remoteConnectionInfos?.anonymous?.wsUri ?? '')
|
||||||
|
page = page.replace(/{{REMOTE_ANONYMOUS_XMPP_SERVER}}/g, remoteConnectionInfos?.anonymous ? 'true' : 'false')
|
||||||
|
// Note: to be able to connect to remote XMPP server, with a local account,
|
||||||
|
// we must enable prosody-room-allow-s2s
|
||||||
|
// (which is required, so we can use outgoing S2S from the authenticated virtualhost).
|
||||||
|
// TODO: There should be another settings, rather than prosody-room-allow-s2s
|
||||||
|
page = page.replace(
|
||||||
|
/{{REMOTE_AUTHENTICATED_XMPP_SERVER}}/g,
|
||||||
|
settings['prosody-room-allow-s2s'] && remoteConnectionInfos?.authenticated ? 'true' : 'false'
|
||||||
|
)
|
||||||
page = page.replace(/{{AUTHENTICATION_URL}}/g, authenticationUrl)
|
page = page.replace(/{{AUTHENTICATION_URL}}/g, authenticationUrl)
|
||||||
page = page.replace(/{{AUTOVIEWERMODE}}/g, autoViewerMode ? 'true' : 'false')
|
page = page.replace(/{{AUTOVIEWERMODE}}/g, autoViewerMode ? 'true' : 'false')
|
||||||
page = page.replace(/{{CONVERSEJS_THEME}}/g, converseJSTheme)
|
page = page.replace(/{{CONVERSEJS_THEME}}/g, converseJSTheme)
|
||||||
@ -382,44 +405,45 @@ async function enableProxyRoute (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConnectionInfos {
|
interface WCRemoteConnectionInfos {
|
||||||
userJID: string
|
|
||||||
roomJID: string
|
roomJID: string
|
||||||
boshUri: string
|
anonymous?: {
|
||||||
wsUri?: string
|
userJID: string
|
||||||
remoteXMPPServer: boolean
|
boshUri: string
|
||||||
|
wsUri?: string
|
||||||
|
}
|
||||||
|
authenticated?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _remoteConnectionInfos (remoteChatInfos: LiveChatJSONLDAttribute): Promise<ConnectionInfos | null> {
|
async function _remoteConnectionInfos (remoteChatInfos: LiveChatJSONLDAttribute): Promise<WCRemoteConnectionInfos> {
|
||||||
if (!remoteChatInfos) { throw new Error('Should have remote chat infos for remote videos') }
|
if (!remoteChatInfos) { throw new Error('Should have remote chat infos for remote videos') }
|
||||||
const connectionInfos = anonymousConnectionInfos(remoteChatInfos ?? false)
|
if (remoteChatInfos.type !== 'xmpp') { throw new Error('Should have remote xmpp chat infos for remote videos') }
|
||||||
if (!connectionInfos || !connectionInfos.boshUri) {
|
const connectionInfos: WCRemoteConnectionInfos = {
|
||||||
return null
|
roomJID: remoteChatInfos.jid
|
||||||
}
|
}
|
||||||
return {
|
if (remoteAuthenticatedConnectionEnabled(remoteChatInfos)) {
|
||||||
userJID: connectionInfos.userJID,
|
connectionInfos.authenticated = true
|
||||||
roomJID: connectionInfos.roomJID,
|
|
||||||
boshUri: connectionInfos.boshUri,
|
|
||||||
wsUri: connectionInfos.wsUri,
|
|
||||||
remoteXMPPServer: true
|
|
||||||
}
|
}
|
||||||
|
const anonymousCI = anonymousConnectionInfos(remoteChatInfos ?? false)
|
||||||
|
if (anonymousCI?.boshUri) {
|
||||||
|
connectionInfos.anonymous = {
|
||||||
|
userJID: anonymousCI.userJID,
|
||||||
|
boshUri: anonymousCI.boshUri,
|
||||||
|
wsUri: anonymousCI.wsUri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return connectionInfos
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _localConnectionInfos (
|
async function _localRoomJID (
|
||||||
options: RegisterServerOptions,
|
options: RegisterServerOptions,
|
||||||
settings: SettingEntries,
|
settings: SettingEntries,
|
||||||
|
prosodyDomain: string,
|
||||||
roomKey: string,
|
roomKey: string,
|
||||||
video: MVideoThumbnail | undefined,
|
video: MVideoThumbnail | undefined,
|
||||||
channelId: number,
|
channelId: number,
|
||||||
forceType: boolean
|
forceType: boolean
|
||||||
): Promise<ConnectionInfos> {
|
): Promise<string> {
|
||||||
const prosodyDomain = await getProsodyDomain(options)
|
|
||||||
const jid = 'anon.' + prosodyDomain
|
|
||||||
const boshUri = getBoshUri(options)
|
|
||||||
const wsUri = settings['disable-websocket']
|
|
||||||
? ''
|
|
||||||
: (getWSUri(options) ?? '')
|
|
||||||
|
|
||||||
// Computing the room name...
|
// Computing the room name...
|
||||||
let room: string
|
let room: string
|
||||||
if (forceType) {
|
if (forceType) {
|
||||||
@ -462,13 +486,7 @@ async function _localConnectionInfos (
|
|||||||
room = room.replace(/{{CHANNEL_NAME}}/g, channelName)
|
room = room.replace(/{{CHANNEL_NAME}}/g, channelName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return room
|
||||||
userJID: jid,
|
|
||||||
roomJID: room,
|
|
||||||
boshUri,
|
|
||||||
wsUri,
|
|
||||||
remoteXMPPServer: false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
Loading…
Reference in New Issue
Block a user