Fix #48: Proper 404 and 403 pages when trying to open non-existant chatroom (WIP).

This commit is contained in:
John Livingston 2024-04-04 10:58:16 +02:00
parent 972306aa3e
commit 0719d25f35
No known key found for this signature in database
GPG Key ID: B17B5640CE66CDBC
12 changed files with 198 additions and 104 deletions

View File

@ -20,6 +20,7 @@ TODO: https://github.com/JohnXLivingston/peertube-plugin-livechat/issues/48
* Some code refactoring.
* New translations: Galician.
* Fix slow mode: focus was lost when textarea got disabled, so it could trigger some Peertube events if the user type some text.
* #48: Proper 404 and 403 pages when trying to open non-existant chatroom.
## 8.4.0

View File

@ -207,3 +207,18 @@ table.peertube-plugin-livechat-prosody-list-rooms td {
}
}
}
.peertube-plugin-livechat-error-message {
/* display an error block (page not found, ...) */
display: block;
font-size: 20px;
padding-top: 50px;
text-align: center;
width: 100%;
}
.peertube-plugin-livechat-container {
.peertube-plugin-livechat-error-message {
max-width: 30vw;
}
}

View File

@ -76,3 +76,4 @@ declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_BOT_NICKNAME: string
declare const LOC_LIVECHAT_CONFIGURATION_CHANNEL_FOR_MORE_INFO: string
declare const LOC_INVALID_VALUE: string
declare const LOC_CHATROOM_NOT_ACCESSIBLE: string

View File

@ -26,8 +26,12 @@ async function registerRoom (clientOptions: RegisterClientOptions): Promise<void
await displayConverseJS(clientOptions, container, roomKey, 'peertube-fullpage', forceType)
} catch (err) {
console.error('[peertube-plugin-livechat] ' + (err as string))
// FIXME: do a better error page.
rootEl.innerText = await peertubeHelpers.translate(LOC_NOT_FOUND)
// Displaying an error page.
rootEl.innerHTML = ''
const message = document.createElement('div')
message.classList.add('peertube-plugin-livechat-error-message')
message.innerText = await peertubeHelpers.translate(LOC_CHATROOM_NOT_ACCESSIBLE)
rootEl.append(message)
}
}
})

View File

@ -155,7 +155,7 @@ async function displayConverseJS (
}
)
if (!response.ok) {
throw new Error('Can\'t get channel configuration options.')
throw new Error('Can\'t get room configuration.')
}
const converseJSParams: InitConverseJSParams = await (response).json()

View File

@ -214,7 +214,15 @@ function register (registerOptions: RegisterClientOptions): void {
// Loading converseJS...
await displayConverseJS(registerOptions, container, roomkey, 'peertube-video', false)
} catch (err) {
// Displaying an error page.
if (container) {
const message = document.createElement('div')
message.classList.add('peertube-plugin-livechat-error-message')
message.innerText = await peertubeHelpers.translate(LOC_CHATROOM_NOT_ACCESSIBLE)
container.append(message)
}
hackStyles(false)
}
}
@ -229,7 +237,9 @@ function register (registerOptions: RegisterClientOptions): void {
if (window.converse?.livechatDisconnect) { window.converse.livechatDisconnect() }
// Removing from the DOM
container.querySelectorAll('converse-root, .livechat-spinner').forEach(dom => dom.remove())
container.querySelectorAll(
'converse-root, .livechat-spinner, .peertube-plugin-livechat-error-message'
).forEach(dom => dom.remove())
container.setAttribute('peertube-plugin-livechat-state', 'closed')

View File

@ -390,3 +390,5 @@ livechat_configuration_channel_bot_nickname: "Bot nickname"
invalid_value: "Invalid value."
slow_mode_info: "Slow mode is enabled, users can send a message every %1$s seconds."
chatroom_not_accessible: "This chatroom does not exist, or is not accessible to you."

20
package-lock.json generated
View File

@ -11,6 +11,7 @@
"dependencies": {
"async": "^3.2.2",
"decache": "^4.6.0",
"escape-html": "^1.0.3",
"got": "^11.8.2",
"http-proxy": "^1.18.1",
"log-rotate": "^0.2.8",
@ -22,6 +23,7 @@
"@peertube/peertube-types": "^5.2.0",
"@tsconfig/node12": "^1.0.9",
"@types/async": "^3.2.9",
"@types/escape-html": "^1.0.4",
"@types/express": "^4.17.13",
"@types/got": "^9.6.12",
"@types/http-proxy": "^1.17.9",
@ -3896,6 +3898,12 @@
"@types/ms": "*"
}
},
"node_modules/@types/escape-html": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.4.tgz",
"integrity": "sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==",
"dev": true
},
"node_modules/@types/express": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
@ -6441,8 +6449,7 @@
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"dev": true
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
},
"node_modules/escape-string-regexp": {
"version": "1.0.5",
@ -15300,6 +15307,12 @@
"@types/ms": "*"
}
},
"@types/escape-html": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.4.tgz",
"integrity": "sha512-qZ72SFTgUAZ5a7Tj6kf2SHLetiH5S6f8G5frB2SPQ3EyF02kxdyBFf4Tz4banE3xCgGnKgWLt//a6VuYHKYJTg==",
"dev": true
},
"@types/express": {
"version": "4.17.13",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz",
@ -17251,8 +17264,7 @@
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"dev": true
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
},
"escape-string-regexp": {
"version": "1.0.5",

View File

@ -35,6 +35,7 @@
"dependencies": {
"async": "^3.2.2",
"decache": "^4.6.0",
"escape-html": "^1.0.3",
"got": "^11.8.2",
"http-proxy": "^1.18.1",
"log-rotate": "^0.2.8",
@ -46,6 +47,7 @@
"@peertube/peertube-types": "^5.2.0",
"@tsconfig/node12": "^1.0.9",
"@types/async": "^3.2.9",
"@types/escape-html": "^1.0.4",
"@types/express": "^4.17.13",
"@types/got": "^9.6.12",
"@types/http-proxy": "^1.17.9",

View File

@ -23,20 +23,32 @@ interface GetConverseJSParamsParams {
* Returns an object describing the error if access can not be granted.
* @param options server options
* @param roomKey chat room key: video UUID (or channel id when forcetype is true)
* @param params various parameters
* @param userIsConnected true if user is connected. If undefined, bypass access tests.
*/
async function getConverseJSParams (
options: RegisterServerOptionsV5,
roomKey: string,
params: GetConverseJSParamsParams
params: GetConverseJSParamsParams,
userIsConnected?: boolean
): Promise<InitConverseJSParams | InitConverseJSParamsError> {
const settings = await options.settingsManager.getSettings([
'prosody-room-type',
'disable-websocket',
'converse-theme',
'federation-no-remote-chat',
'prosody-room-allow-s2s'
'prosody-room-allow-s2s',
'chat-no-anonymous'
])
if (settings['chat-no-anonymous'] && userIsConnected === false) {
return {
isError: true,
code: 403,
message: 'You must be connected'
}
}
const {
autoViewerMode, forceReadonly, transparent, converseJSTheme
} = _interfaceParams(options, settings, params)
@ -337,5 +349,6 @@ async function _localRoomJID (
}
export {
getConverseJSParams
getConverseJSParams,
InitConverseJSParamsError
}

View File

@ -18,9 +18,17 @@ async function initConfigurationApiRouter (options: RegisterServerOptions, route
router.get('/configuration/room/:roomKey', asyncMiddleware(
async (req: Request, res: Response, _next: NextFunction): Promise<void> => {
const roomKey = req.params.roomKey
const initConverseJSParam = await getConverseJSParams(options, roomKey, {
const user = await options.peertubeHelpers.user.getAuthUser(res)
const initConverseJSParam = await getConverseJSParams(
options,
roomKey,
{
forcetype: req.query.forcetype === '1'
})
},
!!user
)
if (('isError' in initConverseJSParam) && initConverseJSParam.isError) {
res.sendStatus(initConverseJSParam.code)
return

View File

@ -1,6 +1,8 @@
import type { RegisterServerOptions } from '@peertube/peertube-types'
import type { Router, Request, Response, NextFunction } from 'express'
import type { ProsodyListRoomsResult, ProsodyListRoomsResultRoom } from '../../../shared/lib/types'
import type {
InitConverseJSParamsError, ProsodyListRoomsResult, ProsodyListRoomsResultRoom
} from '../../../shared/lib/types'
import { createProxyServer } from 'http-proxy'
import { RegisterServerOptionsV5, isUserAdmin } from '../helpers'
import { asyncMiddleware } from '../middlewares/async'
@ -10,8 +12,11 @@ import { getConverseJSParams } from '../conversejs/params'
import { setCurrentProsody, delCurrentProsody } from '../prosody/api/host'
import { getChannelInfosById } from '../database/channel'
import { listProsodyRooms } from '../prosody/api/manage-rooms'
import { loc } from '../loc'
import * as path from 'path'
const escapeHTML = require('escape-html')
const fs = require('fs').promises
interface ProsodyProxyInfo {
@ -22,6 +27,14 @@ let currentHttpBindProxy: ReturnType<typeof createProxyServer> | null = null
let currentWebsocketProxy: ReturnType<typeof createProxyServer> | null = null
let currentS2SWebsocketProxy: ReturnType<typeof createProxyServer> | null = null
class LivechatError extends Error {
livechatError: InitConverseJSParamsError
constructor (e: InitConverseJSParamsError) {
super(e.message)
this.livechatError = e
}
}
async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Router> {
const {
getRouter,
@ -33,8 +46,9 @@ async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Rou
const router: Router = getRouter()
// eslint-disable-next-line @typescript-eslint/no-misused-promises
router.get('/room/:roomKey', asyncMiddleware(
async (req: Request, res: Response, _next: NextFunction): Promise<void> => {
router.get('/room/:roomKey',
asyncMiddleware(async (req: Request, res: Response, _next: NextFunction): Promise<void> => {
try {
res.removeHeader('X-Frame-Options') // this route can be opened in an iframe
const roomKey = req.params.roomKey
@ -53,9 +67,7 @@ async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Rou
})
if (('isError' in initConverseJSParam)) {
res.status(initConverseJSParam.code)
res.send(initConverseJSParam.message)
return
throw new LivechatError(initConverseJSParam)
}
let page = '' + (converseJSIndex as string)
@ -125,8 +137,22 @@ async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Rou
res.status(200)
res.type('html')
res.send(page)
} catch (err: LivechatError | any) {
const code = err.livechatError?.code ?? 500
const additionnalMessage: string = escapeHTML(err.livechatError?.message as string ?? '')
const message: string = escapeHTML(loc('chatroom_not_accessible'))
res.status(code)
res.send(`<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN"><html>
<head><title>${message}</title></head>
<body>
<h1>${message}</h1>
<p>${additionnalMessage}</p>
</body>
</html>`)
}
))
})
)
await disableProxyRoute(options)
router.post('/http-bind',