From 30d70e033e574046d081f03aaab7cd52f75b81c2 Mon Sep 17 00:00:00 2001 From: John Livingston Date: Sat, 12 Jun 2021 03:52:45 +0200 Subject: [PATCH] Retrieving list rooms from prosody. --- CHANGELOG.md | 4 +- assets/style.css | 4 + client/admin-plugin-client-plugin.ts | 24 +- documentation/prosody.md | 6 + package-lock.json | 243 +++++++++++++++++- package.json | 2 + .../README.md | 5 + .../mod_http_peertubelivechat_list_rooms.lua | 56 ++++ server/lib/prosody/config.ts | 2 + server/lib/prosody/config/content.ts | 5 + server/lib/routers/settings.ts | 33 --- server/lib/routers/webchat.ts | 57 +++- shared/lib/types.ts | 5 +- 13 files changed, 397 insertions(+), 49 deletions(-) create mode 100644 prosody-modules/mod_http_peertubelivechat_list_rooms/README.md create mode 100644 prosody-modules/mod_http_peertubelivechat_list_rooms/mod_http_peertubelivechat_list_rooms.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a821705..c42cf75c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * New simpler settings screen. * New field in live video form, to activate the webchat per video. There is a setting for enabling this new feature. +* When using the builtin prosody, there is a button to list existing chatrooms in the settings screen. ### Changes @@ -18,9 +19,6 @@ * New settings * By default, the «activate chat for all lives» is disabled (now that we can enable the webchat per video) -### Fixes - -* ... ## v2.3.1 diff --git a/assets/style.css b/assets/style.css index be88360a..e3219162 100644 --- a/assets/style.css +++ b/assets/style.css @@ -58,3 +58,7 @@ .peertube-plugin-livechat-error { color: red; } + +table.peertube-plugin-livechat-prosody-list-rooms { + border: 1px solid black; +} diff --git a/client/admin-plugin-client-plugin.ts b/client/admin-plugin-client-plugin.ts index 5391cc45..604c4fb8 100644 --- a/client/admin-plugin-client-plugin.ts +++ b/client/admin-plugin-client-plugin.ts @@ -51,7 +51,7 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re container.textContent = '...' listRoomsButton.after(container) - const response = await fetch(getBaseRoute() + '/settings/prosody-list-rooms', { + const response = await fetch(getBaseRoute() + '/webchat/prosody-list-rooms', { method: 'GET', headers: peertubeHelpers.getAuthHeader() }) @@ -63,18 +63,36 @@ function register ({ registerHook, registerSettingsScript, peertubeHelpers }: Re container.textContent = json.error container.classList.add('peertube-plugin-livechat-error') } else { + const rooms = json.rooms.sort((a, b) => a.name.localeCompare(b.name)) + container.textContent = '' const table = document.createElement('table') + table.classList.add('peertube-plugin-livechat-prosody-list-rooms') container.append(table) - json.rooms.forEach(room => { + // TODO: translate labels. + const titleLineEl = document.createElement('tr') + const titleNameEl = document.createElement('th') + titleNameEl.textContent = 'Name' + const titleDescriptionEl = document.createElement('th') + titleDescriptionEl.textContent = 'Description' + titleLineEl.append(titleNameEl) + titleLineEl.append(titleDescriptionEl) + table.append(titleLineEl) + rooms.forEach(room => { + // TODO: get some informations about the video. + const uuid = room.localpart + const href = getBaseRoute() + '/webchat/room/' + encodeURIComponent(uuid) const lineEl = document.createElement('tr') const nameEl = document.createElement('td') const aEl = document.createElement('a') aEl.textContent = room.name - aEl.href = room.href + aEl.href = href aEl.target = '_blank' + const descriptionEl = document.createElement('td') + descriptionEl.textContent = room.description nameEl.append(aEl) lineEl.append(nameEl) + lineEl.append(descriptionEl) table.append(lineEl) }) } diff --git a/documentation/prosody.md b/documentation/prosody.md index 10dc4656..b6433950 100644 --- a/documentation/prosody.md +++ b/documentation/prosody.md @@ -61,6 +61,12 @@ This is the port that the Prosody server will use. By default it is set to 52800 These settings are common with other chat modes. Here is the documentation: [common settings](./common.md). +## Moderation + +You can list all existing chatrooms: in the plugin settings screen, there is a button «List rooms». + +You can delete old rooms: join the room, and use the menu on the top to destroy the room. + ## Notes All instance moderators and admins will be owner for created chat rooms. diff --git a/package-lock.json b/package-lock.json index e549c955..61f77d30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -129,6 +129,19 @@ "webpack-sources": "^1.0.0" } }, + "@sindresorhus/is": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.0.1.tgz", + "integrity": "sha512-Qm9hBEBu18wt1PO2flE7LPb30BHMQt1eQgbV76YntdNk73XZGpn3izvGTYxbGgzXKgbCjiia0uxTd3aTNQrY/g==" + }, + "@szmarczak/http-timer": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.5.tgz", + "integrity": "sha512-PyRA9sm1Yayuj5OIoJ1hGt2YISX45w9WcFbh6ddT0Z/0yaFxOtGLInr4jUfU1EAFVs0Yfyfev4RNwBlUaHdlDQ==", + "requires": { + "defer-to-connect": "^2.0.0" + } + }, "@trysound/sax": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz", @@ -157,6 +170,17 @@ "@types/node": "*" } }, + "@types/cacheable-request": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.1.tgz", + "integrity": "sha512-ykFq2zmBGOCbpIXtoVbz4SKY5QriWPh3AjyU4G74RYbtt5yOc5OfaY75ftjg7mikMOla1CTGpX3lLbuJh8DTrQ==", + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "*", + "@types/node": "*", + "@types/responselike": "*" + } + }, "@types/connect": { "version": "3.4.34", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", @@ -198,6 +222,22 @@ "@types/range-parser": "*" } }, + "@types/got": { + "version": "9.6.11", + "resolved": "https://registry.npmjs.org/@types/got/-/got-9.6.11.tgz", + "integrity": "sha512-dr3IiDNg5TDesGyuwTrN77E1Cd7DCdmCFtEfSGqr83jMMtcwhf/SGPbN2goY4JUWQfvxwY56+e5tjfi+oXeSdA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", + "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==" + }, "@types/json-schema": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", @@ -210,6 +250,14 @@ "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", "dev": true }, + "@types/keyv": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.1.tgz", + "integrity": "sha512-MPtoySlAZQ37VoLaPcTHCu1RWJ4llDkULYZIzOYxlhxBqYPB0RsRlmMU0R6tahtFe27mIdkHV+551ZWV4PLmVw==", + "requires": { + "@types/node": "*" + } + }, "@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -219,8 +267,7 @@ "@types/node": { "version": "14.14.37", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz", - "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==", - "dev": true + "integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw==" }, "@types/qs": { "version": "6.9.6", @@ -234,6 +281,14 @@ "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", "dev": true }, + "@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "requires": { + "@types/node": "*" + } + }, "@types/serve-static": { "version": "1.13.9", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", @@ -244,6 +299,12 @@ "@types/node": "*" } }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", + "dev": true + }, "@types/winston": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz", @@ -851,6 +912,12 @@ "dev": true, "optional": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, "atob": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", @@ -1192,6 +1259,35 @@ "unset-value": "^1.0.0" } }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" + }, + "cacheable-request": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", + "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + } + } + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -1356,6 +1452,14 @@ "wrap-ansi": "^5.1.0" } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, "collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -1417,6 +1521,15 @@ "text-hex": "1.0.x" } }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -1649,12 +1762,32 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } + } + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -1705,6 +1838,12 @@ } } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -1868,7 +2007,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "requires": { "once": "^1.4.0" } @@ -2869,6 +3007,17 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -3046,6 +3195,24 @@ } } }, + "got": { + "version": "11.8.2", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.2.tgz", + "integrity": "sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ==", + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.1", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, "graceful-fs": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", @@ -3151,6 +3318,11 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, "http-errors": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", @@ -3163,6 +3335,15 @@ "toidentifier": "1.0.0" } }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, "https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", @@ -3509,6 +3690,11 @@ "esprima": "^4.0.0" } }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, "json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -3536,6 +3722,14 @@ "minimist": "^1.2.0" } }, + "keyv": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.3.tgz", + "integrity": "sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==", + "requires": { + "json-buffer": "3.0.1" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -3646,6 +3840,11 @@ } } }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3800,6 +3999,11 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -3989,6 +4193,11 @@ "dev": true, "optional": true }, + "normalize-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.0.1.tgz", + "integrity": "sha512-VU4pzAuh7Kip71XEmO9aNREYAdMHFGTVj/i+CaTImS8x0i1d3jUZkXhqluy/PRgjPLMgsLQulYY3PJ/aSbSjpQ==" + }, "npm-run-all": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", @@ -4177,7 +4386,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -4222,6 +4430,11 @@ "mem": "^4.0.0" } }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" + }, "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", @@ -4479,7 +4692,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -4537,6 +4749,11 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -4721,6 +4938,11 @@ "path-parse": "^1.0.6" } }, + "resolve-alpn": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.1.2.tgz", + "integrity": "sha512-8OyfzhAtA32LVUsJSke3auIyINcwdh5l3cvYKdKO0nvsYSKuiLfTM5i78PJswFPT8y6cPW+L1v6/hE95chcpDA==" + }, "resolve-cwd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", @@ -4765,6 +4987,14 @@ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", "dev": true }, + "responselike": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", + "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", + "requires": { + "lowercase-keys": "^2.0.0" + } + }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", @@ -6348,8 +6578,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "xtend": { "version": "4.0.2", diff --git a/package.json b/package.json index 8b163f98..5cbfce8c 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "body-parser": "^1.19.0", "decache": "^4.6.0", "express-http-proxy": "^1.6.2", + "got": "^11.8.2", "log-rotate": "^0.2.8" }, "devDependencies": { @@ -40,6 +41,7 @@ "@types/async": "^3.2.6", "@types/express": "^4.17.11", "@types/express-http-proxy": "^1.6.1", + "@types/got": "^9.6.11", "@types/node": "^14.14.37", "@types/winston": "^2.4.4", "@typescript-eslint/eslint-plugin": "^4.21.0", diff --git a/prosody-modules/mod_http_peertubelivechat_list_rooms/README.md b/prosody-modules/mod_http_peertubelivechat_list_rooms/README.md new file mode 100644 index 00000000..6c4fe736 --- /dev/null +++ b/prosody-modules/mod_http_peertubelivechat_list_rooms/README.md @@ -0,0 +1,5 @@ +# mod_http_peertubelivechat_list_rooms + +This module is a custom module that allows Peertube server to list chat rooms. + +This module is part of peertube-plugin-livechat, and is under the same LICENSE. diff --git a/prosody-modules/mod_http_peertubelivechat_list_rooms/mod_http_peertubelivechat_list_rooms.lua b/prosody-modules/mod_http_peertubelivechat_list_rooms/mod_http_peertubelivechat_list_rooms.lua new file mode 100644 index 00000000..c7bff171 --- /dev/null +++ b/prosody-modules/mod_http_peertubelivechat_list_rooms/mod_http_peertubelivechat_list_rooms.lua @@ -0,0 +1,56 @@ +local json = require "util.json"; +local jid_split = require"util.jid".split; +local array = require "util.array"; + +local mod_muc = module:depends"muc"; +local all_rooms = rawget(mod_muc, "all_rooms") + +module:depends"http"; + +function check_auth(routes) + local function check_request_auth(event) + local apikey = module:get_option_string("peertubelivechat_list_rooms_apikey", "") + if apikey == "" then + return false, 500; + end + if event.request.headers.authorization ~= "Bearer " .. apikey then + return false, 401; + end + return true; + end + + for route, handler in pairs(routes) do + routes[route] = function (event, ...) + local permit, code = check_request_auth(event); + if not permit then + return code; + end + return handler(event, ...); + end; + end + return routes; +end + +local function list_rooms(event) + local request, response = event.request, event.response; + local rooms_json = array(); + for room in all_rooms() do + local localpart = jid_split(room.jid); + rooms_json:push({ + jid = room.jid; + localpart = localpart; + name = room:get_name() or localpart; + lang = room.get_language and room:get_language(); + description = room:get_description(); + }) + end + + event.response.headers["Content-Type"] = "application/json"; + return json.encode_array(rooms_json); +end + +module:provides("http", { + route = check_auth { + ["GET /list-rooms"] = list_rooms; + }; +}); diff --git a/server/lib/prosody/config.ts b/server/lib/prosody/config.ts index 75c96bf6..33c15a00 100644 --- a/server/lib/prosody/config.ts +++ b/server/lib/prosody/config.ts @@ -96,6 +96,8 @@ async function getProsodyConfig (options: RegisterServerOptions): Promise { - if (!res.locals.authenticated) { - res.sendStatus(403) - return - } - if (!await isUserAdmin(options, res)) { - res.sendStatus(403) - return - } - - const chatType: ChatType = await options.settingsManager.getSetting('chat-type') as ChatType - if (chatType !== 'builtin-prosody') { - const message = 'Please save the settings first.' // TODO: translate? - res.status(200) - const r: ProsodyListRoomsResult = { - ok: false, - error: message - } - res.json(r) - return - } - - res.status(200) - const r: ProsodyListRoomsResult = { - ok: true, - rooms: [] // TODO: get room list from Prosody - } - res.json(r) - } - )) - return router } diff --git a/server/lib/routers/webchat.ts b/server/lib/routers/webchat.ts index 636d04e9..584099af 100644 --- a/server/lib/routers/webchat.ts +++ b/server/lib/routers/webchat.ts @@ -1,16 +1,19 @@ import type { Router, RequestHandler, Request, Response, NextFunction } from 'express' import type { ProxyOptions } from 'express-http-proxy' -import type { ChatType } from '../../../shared/lib/types' -import { getBaseRouterRoute, getBaseStaticRoute } from '../helpers' +import type { ChatType, ProsodyListRoomsResult } from '../../../shared/lib/types' +import { getBaseRouterRoute, getBaseStaticRoute, isUserAdmin } from '../helpers' import { asyncMiddleware } from '../middlewares/async' import { getProsodyDomain } from '../prosody/config/domain' +import { getAPIKey } from '../apikey' import * as path from 'path' const bodyParser = require('body-parser') +const got = require('got') const fs = require('fs').promises const proxy = require('express-http-proxy') let httpBindRoute: RequestHandler +let prosodyPort: string | undefined async function initWebchatRouter (options: RegisterServerOptions): Promise { const { @@ -97,6 +100,54 @@ async function initWebchatRouter (options: RegisterServerOptions): Promise { + if (!res.locals.authenticated) { + res.sendStatus(403) + return + } + if (!await isUserAdmin(options, res)) { + res.sendStatus(403) + return + } + + const chatType: ChatType = await options.settingsManager.getSetting('chat-type') as ChatType + if (chatType !== 'builtin-prosody') { + const message = 'Please save the settings first.' // TODO: translate? + res.status(200) + const r: ProsodyListRoomsResult = { + ok: false, + error: message + } + res.json(r) + return + } + + if (!prosodyPort) { + throw new Error('It seems that prosody is not binded... Cant list rooms.') + } + // FIXME: can the api be on http://localhost instead of http://room.localhost? + const apiUrl = `http://room.localhost:${prosodyPort}/peertubelivechat_list_rooms/list-rooms` + peertubeHelpers.logger.debug('Calling list rooms API on url: ' + apiUrl) + const rooms = await got(apiUrl, { + method: 'GET', + headers: { + authorization: 'Bearer ' + await getAPIKey(options) + }, + responseType: 'json', + resolveBodyOnly: true + }) + + res.status(200) + const r: ProsodyListRoomsResult = { + ok: true, + rooms: rooms + } + res.json(r) + } + )) + return router } @@ -108,6 +159,7 @@ function changeHttpBindRoute ({ peertubeHelpers }: RegisterServerOptions, port: port = null } if (port === null) { + prosodyPort = undefined httpBindRoute = (_req: Request, res: Response, _next: NextFunction) => { res.status(404) res.send('Not found') @@ -122,6 +174,7 @@ function changeHttpBindRoute ({ peertubeHelpers }: RegisterServerOptions, port: parseReqBody: true // Note that setting this to false overrides reqAsBuffer and reqBodyEncoding below. // FIXME: should we remove cookies? } + prosodyPort = port httpBindRoute = proxy('http://localhost:' + port, options) } } diff --git a/shared/lib/types.ts b/shared/lib/types.ts index 8fefdd23..9e00f40a 100644 --- a/shared/lib/types.ts +++ b/shared/lib/types.ts @@ -8,8 +8,11 @@ interface ProsodyListRoomsResultError { interface ProsodyListRoomsResultSuccess { ok: true rooms: Array<{ + jid: string + localpart: string name: string - href: string + lang: string + description: string }> }