From d8c7f8de81d0a74271f7db306594ffc6edaaa0f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BC=D1=8F=D0=BD=20=D0=9C=D0=B8=D0=BD=D0=BA?= =?UTF-8?q?=D0=BE=D0=B2?= Date: Mon, 15 May 2023 14:52:27 -0500 Subject: [PATCH] feat: Jaas example that uses local jitsi-meet (#13350) * feat: Adds an example to convert a deployment to use jaas. * squash: Generates the daily asap token with expiration of 1 day. The default is 1 hour. * squash: Use local deployment UI with jaas, not 8x8.vc one. - We load config.js from 8x8.vc with the tenant, to allow release pinning to work. - We sed the vpass_cookie in the custom nginx conf as variables are not allowed in location matching. - The jaas-vars need to be global as it will overwrite config.js location and index html. * squash: Enables e2ee for the meetings. * squash: Bump node version check. * squash: Fix filename. * squash: Updates the readme. * squash: Checks whether node is installed. * squash: Fixes initial configuration. The jaas-vars is required to reload nginx, done by update-asap-daily script. * squash: More fixes of misspelled config file. * squash: Fixes serving the pub key. --- .eslintignore | 2 + debian/jitsi-meet-web-config.install | 3 ++ debian/jitsi-meet-web.install | 2 + doc/debian/jitsi-meet/jitsi-meet.example | 16 ++++-- doc/jaas/8x8.vc-config.js | 7 +++ doc/jaas/README.md | 22 +++++++++ doc/jaas/api_keys_kid.png | Bin 0 -> 23287 bytes doc/jaas/generated_key_dialog.png | Bin 0 -> 55518 bytes doc/jaas/index-jaas.html | 33 +++++++++++++ doc/jaas/move-to-jaas.sh | 59 +++++++++++++++++++++++ doc/jaas/nginx-jaas.conf | 23 +++++++++ doc/jaas/update-asap-daily.sh | 9 ++++ modules/API/external/external_api.js | 18 ++++++- 13 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 doc/jaas/8x8.vc-config.js create mode 100644 doc/jaas/README.md create mode 100644 doc/jaas/api_keys_kid.png create mode 100644 doc/jaas/generated_key_dialog.png create mode 100644 doc/jaas/index-jaas.html create mode 100755 doc/jaas/move-to-jaas.sh create mode 100644 doc/jaas/nginx-jaas.conf create mode 100755 doc/jaas/update-asap-daily.sh diff --git a/.eslintignore b/.eslintignore index 0f012cd781..ab02099b5d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,6 +1,8 @@ # The build artifacts of the jitsi-meet project. build/* +doc/* + # Third-party source code which we (1) do not want to modify or (2) try to # modify as little as possible. libs/* diff --git a/debian/jitsi-meet-web-config.install b/debian/jitsi-meet-web-config.install index 1e912017a8..75c8210de4 100644 --- a/debian/jitsi-meet-web-config.install +++ b/debian/jitsi-meet-web-config.install @@ -1,3 +1,6 @@ doc/debian/jitsi-meet/jitsi-meet.example /usr/share/jitsi-meet-web-config/ doc/debian/jitsi-meet/jitsi-meet.example-apache /usr/share/jitsi-meet-web-config/ config.js /usr/share/jitsi-meet-web-config/ +doc/jaas/nginx-jaas.conf /usr/share/jitsi-meet-web-config/ +doc/jaas/index-jaas.html /usr/share/jitsi-meet-web-config/ +doc/jaas/8x8.vc-config.js /usr/share/jitsi-meet-web-config/ diff --git a/debian/jitsi-meet-web.install b/debian/jitsi-meet-web.install index 67965926ff..452713bc63 100644 --- a/debian/jitsi-meet-web.install +++ b/debian/jitsi-meet-web.install @@ -12,3 +12,5 @@ resources/robots.txt /usr/share/jitsi-meet/ resources/*.sh /usr/share/jitsi-meet/scripts/ pwa-worker.js /usr/share/jitsi-meet/ manifest.json /usr/share/jitsi-meet/ +doc/jaas/move-to-jaas.sh /usr/share/jitsi-meet/scripts/ +doc/jaas/update-asap-daily.sh /usr/share/jitsi-meet/scripts/ diff --git a/doc/debian/jitsi-meet/jitsi-meet.example b/doc/debian/jitsi-meet/jitsi-meet.example index 1df9e15a79..eb2e685e70 100644 --- a/doc/debian/jitsi-meet/jitsi-meet.example +++ b/doc/debian/jitsi-meet/jitsi-meet.example @@ -58,6 +58,8 @@ server { add_header Strict-Transport-Security "max-age=63072000" always; set $prefix ""; + set $custom_index ""; + set $config_js_location /etc/jitsi/meet/jitsi-meet.example.com-config.js; ssl_certificate /etc/jitsi/meet/jitsi-meet.example.com.crt; ssl_certificate_key /etc/jitsi/meet/jitsi-meet.example.com.key; @@ -77,8 +79,10 @@ server { gzip_proxied no-cache no-store private expired auth; gzip_min_length 512; + include /etc/jitsi/meet/jaas/*.conf; + location = /config.js { - alias /etc/jitsi/meet/jitsi-meet.example.com-config.js; + alias $config_js_location; } location = /external_api.js { @@ -92,6 +96,11 @@ server { proxy_set_header Host $http_host; } + location ~ ^/_api/public/(.*)$ { + autoindex off; + alias /etc/jitsi/meet/public/$1; + } + # ensure all static content can always be found first location ~ ^/(libs|css|static|images|fonts|lang|sounds|.well-known)/(.*)$ { @@ -142,11 +151,12 @@ server { #} location ~ ^/([^/?&:'"]+)$ { + set $roomname "$1"; try_files $uri @root_path; } location @root_path { - rewrite ^/(.*)$ / break; + rewrite ^/(.*)$ /$custom_index break; } location ~ ^/([^/?&:'"]+)/config.js$ @@ -154,7 +164,7 @@ server { set $subdomain "$1."; set $subdir "$1/"; - alias /etc/jitsi/meet/jitsi-meet.example.com-config.js; + alias $config_js_location; } # Matches /(TENANT)/pwa-worker.js or /(TENANT)/manifest.json to rewrite to / and look for file diff --git a/doc/jaas/8x8.vc-config.js b/doc/jaas/8x8.vc-config.js new file mode 100644 index 0000000000..47e8a8f3a8 --- /dev/null +++ b/doc/jaas/8x8.vc-config.js @@ -0,0 +1,7 @@ + + + + + + +
+ + diff --git a/doc/jaas/move-to-jaas.sh b/doc/jaas/move-to-jaas.sh new file mode 100755 index 0000000000..3d6af3f669 --- /dev/null +++ b/doc/jaas/move-to-jaas.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +set -e + +PRIVATE_KEY=$1 +JAAS_KEY_ID=$2 + +if [ ! -f "${PRIVATE_KEY}" ] ; then + echo "You need to specify a correct path for the private key as a first argument." + exit 1; +fi + +if [[ ! "${JAAS_KEY_ID}" =~ ^vpaas-magic-cookie-[0-9a-z]+/[0-9a-z]+$ ]]; then + echo "Invalid key id passed as a second argument." + exit 2; +fi + +command -v node >/dev/null 2>&1 || { echo >&2 "You must install node first, go to https://nodejs.org. Aborting."; exit 4; } + +NODE_VER=$(node -v); +NODE_MAJOR_VER=$(echo ${NODE_VER:1} | cut -d. -f1); + +if [ "$NODE_MAJOR_VER" -lt "18" ]; then + echo "Please install latest LTS version of node (18+)"; + exit 3; +fi + +# we need this util for debconf-set-selections +sudo apt install debconf-utils + +# Let's pre-set some settings for token-generator +cat << EOF | sudo debconf-set-selections +token-generator token-generator/private-key string ${PRIVATE_KEY} +token-generator token-generator/kid string ${JAAS_KEY_ID} +EOF + +apt install token-generator + +mkdir -p /etc/jitsi/meet/jaas + +VPASS_COOKIE=$(echo -n ${JAAS_KEY_ID}| cut -d/ -f1) +cp /usr/share/jitsi-meet-web-config/nginx-jaas.conf /etc/jitsi/meet/jaas +sed -i "s/jaas_magic_cookie/${VPASS_COOKIE}/g" /etc/jitsi/meet/jaas/nginx-jaas.conf + +cp /usr/share/jitsi-meet-web-config/8x8.vc-config.js /etc/jitsi/meet/jaas/ +echo "set \$config_js_location /etc/jitsi/meet/jaas/8x8.vc-config.js;" >> /etc/jitsi/meet/jaas/jaas-vars +echo "set \$custom_index index-jaas.html;" >> /etc/jitsi/meet/jaas/jaas-vars + +ln -s /usr/share/jitsi-meet-web-config/index-jaas.html /usr/share/jitsi-meet/index-jaas.html + +# let's create the daily key now +/usr/share/jitsi-meet/scripts/update-asap-daily.sh + +# let's add to cron daily the update of the asap key +if [ -d /etc/cron.daily ]; then + ln -s /usr/share/jitsi-meet/scripts/update-asap-daily.sh /etc/cron.daily/update-jaas-asap.sh +else + echo "No /etc/cron.daily. Please add to your cron jobs to execute as root daily the script: /usr/share/jitsi-meet/scripts/update-asap-daily.sh" +fi diff --git a/doc/jaas/nginx-jaas.conf b/doc/jaas/nginx-jaas.conf new file mode 100644 index 0000000000..a82bcb047e --- /dev/null +++ b/doc/jaas/nginx-jaas.conf @@ -0,0 +1,23 @@ +include /etc/jitsi/meet/jaas/jaas-vars; +location = /jaas-jwt { + include /etc/jitsi/token-generator/daily-key; + ssi on; + proxy_method POST; + proxy_set_header content-type "application/json"; + proxy_set_header Accept-Encoding ""; + proxy_set_header Authorization "Bearer $jaas_asap_key"; + proxy_pass_request_body off; + proxy_set_body '{"sub":"jaas_magic_cookie","context":{"features":{"livestreaming":false,"outbound-call":false,"sip-outbound-call":false,"transcription":false,"recording":false},"user":{"moderator":true}},"room": "$roomname"}'; + proxy_pass http://127.0.0.1:8017/generate/client?e2eeKey=true; +} + +location @magic_root_path { + rewrite ^/(.*)$ /index.html break; +} + +# Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to / +location ~ ^/jaas_magic_cookie/(.*)$ { + set $subdomain "jaas_magic_cookie."; + set $subdir "jaas_magic_cookie/"; + try_files $1 @magic_root_path; +} diff --git a/doc/jaas/update-asap-daily.sh b/doc/jaas/update-asap-daily.sh new file mode 100755 index 0000000000..f7c3e1d3e5 --- /dev/null +++ b/doc/jaas/update-asap-daily.sh @@ -0,0 +1,9 @@ +JWT_KID=$(cat /etc/jitsi/token-generator/config | grep SYSTEM_ASAP_BASE_URL_MAPPINGS | cut -d= -f2- | jq -r .[].kid) +JWT_DATE=$(echo -n $JWT_KID | cut -d/ -f2-) +JWT_DATE=${JWT_DATE#jwt-} +KEY_FILE=/etc/jitsi/token-generator/daily-key +echo -n "set \$jaas_asap_key " > ${KEY_FILE} +ASAP_KEY=$(ASAP_SIGNING_KEY_FILE=/etc/jitsi/token-generator/asap-${JWT_DATE}.key ASAP_JWT_KID="${JWT_KID}" ASAP_EXPIRES_IN="1 day" node /usr/share/token-generator/jwt.js| tail -n1) +echo -n "${ASAP_KEY};" >> ${KEY_FILE} + +service nginx reload diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 6a09be962f..9b0b71a35e 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -36,7 +36,6 @@ const commands = { cancelPrivateChat: 'cancel-private-chat', closeBreakoutRoom: 'close-breakout-room', displayName: 'display-name', - e2eeKey: 'e2ee-key', endConference: 'end-conference', email: 'email', grantModerator: 'grant-moderator', @@ -561,7 +560,22 @@ export default class JitsiMeetExternalAPI extends EventEmitter { switch (name) { case 'video-conference-joined': { if (typeof this._tmpE2EEKey !== 'undefined') { - this.executeCommand(commands.e2eeKey, this._tmpE2EEKey); + + const hexToBytes = hex => { + const bytes = []; + + for (let c = 0; c < hex.length; c += 2) { + bytes.push(parseInt(hex.substring(c, c + 2), 16)); + } + + return bytes; + }; + + this.executeCommand('setMediaEncryptionKey', JSON.stringify({ + exportedKey: hexToBytes(this._tmpE2EEKey), + index: 0 + })); + this._tmpE2EEKey = undefined; }