forked from switnet/quick-jibri-installer
Compare commits
No commits in common. "cefb7361319836828206f36fb9620d8183d8d456" and "9e0264fe4a865ad1f299f12879a934a061cfb939" have entirely different histories.
cefb736131
...
9e0264fe4a
|
@ -1,24 +0,0 @@
|
||||||
-- Promotes to owner (real moderator) if the JWT has context.user.moderator = true
|
|
||||||
local util = module:require "util"
|
|
||||||
local is_admin = util.is_admin
|
|
||||||
local is_healthcheck_room = util.is_healthcheck_room
|
|
||||||
|
|
||||||
-- When a participant enters the room:
|
|
||||||
module:hook('muc-occupant-joined', function (event)
|
|
||||||
local room, occupant, session = event.room, event.occupant, event.origin
|
|
||||||
|
|
||||||
-- Ignores focus/healthcheck/etc.
|
|
||||||
if is_healthcheck_room(room.jid) or is_admin(occupant.bare_jid) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Requires moderator token and claim (accepts boolean or string "true")
|
|
||||||
local user = session and session.jitsi_meet_context_user
|
|
||||||
local has_token = session and session.auth_token
|
|
||||||
local wants_mod = user and (user.moderator == true or user.moderator == "true")
|
|
||||||
|
|
||||||
if has_token and wants_mod then
|
|
||||||
-- Assign owner affiliation -> Jicofo will see you as moderator
|
|
||||||
room:set_affiliation(true, occupant.bare_jid, 'owner')
|
|
||||||
end
|
|
||||||
end, 1)
|
|
|
@ -77,7 +77,7 @@ else
|
||||||
echo "Seems no nodejs repo installed"
|
echo "Seems no nodejs repo installed"
|
||||||
fi
|
fi
|
||||||
# True if $1 is greater than $2
|
# True if $1 is greater than $2
|
||||||
version_gt() { dpkg --compare-versions "$1" gt "$2"; }
|
version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; }
|
||||||
|
|
||||||
restart_jibri() {
|
restart_jibri() {
|
||||||
if [ "$(dpkg-query -W -f='${Status}' "jibri" 2>/dev/null | grep -c "ok installed")" == "1" ]
|
if [ "$(dpkg-query -W -f='${Status}' "jibri" 2>/dev/null | grep -c "ok installed")" == "1" ]
|
||||||
|
@ -116,7 +116,7 @@ update_google_repo() {
|
||||||
echo "Seems no chromedriver installed"
|
echo "Seems no chromedriver installed"
|
||||||
else
|
else
|
||||||
CHD_VER_LOCAL="$($CHDB -v | awk '{print $2}')"
|
CHD_VER_LOCAL="$($CHDB -v | awk '{print $2}')"
|
||||||
CHD_VER_2D="$(cut -d. -f1,2 <<< "$CHD_VER_LOCAL")"
|
CHD_VER_2D="$(awk '{printf "%.1f\n", $NF}' <<< "$CHD_VER_LOCAL")"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
update_nodejs_repo() {
|
update_nodejs_repo() {
|
||||||
|
@ -127,7 +127,7 @@ update_nodejs_repo() {
|
||||||
check_latest_gc() {
|
check_latest_gc() {
|
||||||
printwc "${Purple}" "Checking for Google Chrome\n"
|
printwc "${Purple}" "Checking for Google Chrome\n"
|
||||||
if [ -f /usr/bin/google-chrome ]; then
|
if [ -f /usr/bin/google-chrome ]; then
|
||||||
GOOGL_VER_2D="$(/usr/bin/google-chrome --product-version 2>/dev/null | cut -d. -f1,2)"
|
GOOGL_VER_2D="$(/usr/bin/google-chrome --version|awk '{printf "%.1f\n", $NF}')"
|
||||||
else
|
else
|
||||||
printwc "${Yellow}" " -> Seems there is no Google Chrome installed\n"
|
printwc "${Yellow}" " -> Seems there is no Google Chrome installed\n"
|
||||||
IS_GLG_CHRM="no"
|
IS_GLG_CHRM="no"
|
||||||
|
@ -139,14 +139,6 @@ if [ -n "$GOOGL_VER_2D" ]; then
|
||||||
check_latest_gc
|
check_latest_gc
|
||||||
if version_gt "$GOOGL_VER_2D" "$CHD_VER_2D" ; then
|
if version_gt "$GOOGL_VER_2D" "$CHD_VER_2D" ; then
|
||||||
echo "Upgrading Chromedriver to Google Chromes version"
|
echo "Upgrading Chromedriver to Google Chromes version"
|
||||||
if [ -x /usr/bin/google-chrome ]; then
|
|
||||||
G_CHROME="$(/usr/bin/google-chrome --product-version 2>/dev/null | cut -d. -f1-3)"
|
|
||||||
fi
|
|
||||||
CHD_LTST_DWNL=$(curl -s $CHROMELAB_URL/known-good-versions-with-downloads.json | \
|
|
||||||
jq -r ".versions[].downloads.chromedriver | select(. != null) | .[].url" | \
|
|
||||||
grep linux64 | grep "$G_CHROME" | tail -1)
|
|
||||||
CHD_LTST=$(awk -F '/' '{print$7}' <<< "$CHD_LTST_DWNL")
|
|
||||||
CHD_LTST_2D="$(cut -d. -f1,2 <<< "$CHD_LTST")"
|
|
||||||
wget -q "$CHD_LTST_DWNL" \
|
wget -q "$CHD_LTST_DWNL" \
|
||||||
-O /tmp/chromedriver_linux64.zip
|
-O /tmp/chromedriver_linux64.zip
|
||||||
unzip -o /tmp/chromedriver_linux64.zip -d /usr/local/bin/
|
unzip -o /tmp/chromedriver_linux64.zip -d /usr/local/bin/
|
||||||
|
@ -155,7 +147,7 @@ if [ -n "$GOOGL_VER_2D" ]; then
|
||||||
chmod 0755 "$CHDB"
|
chmod 0755 "$CHDB"
|
||||||
rm -rf /tpm/chromedriver_linux64.zip
|
rm -rf /tpm/chromedriver_linux64.zip
|
||||||
printf "Current version: "
|
printf "Current version: "
|
||||||
printwc "$Green" "$($CHDB -v | awk '{print $2}' | cut -d. -f1,2)"
|
printwc "$Green" "$($CHDB -v |awk '{print $2}'|awk '{printf "%.1f\n", $NF}')"
|
||||||
echo -e " (latest available)\n"
|
echo -e " (latest available)\n"
|
||||||
elif [ "$GOOGL_VER_2D" = "$CHD_LTST_2D" ]; then
|
elif [ "$GOOGL_VER_2D" = "$CHD_LTST_2D" ]; then
|
||||||
echo "No need to upgrade Chromedriver"
|
echo "No need to upgrade Chromedriver"
|
||||||
|
|
5
jm-bm.sh
5
jm-bm.sh
|
@ -23,7 +23,6 @@ if ! [ "$(id -u)" = 0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DOMAIN="$(find /etc/prosody/conf.d/ -name \*.lua|awk -F'.cfg' '!/localhost/{print $1}'|xargs basename)"
|
DOMAIN="$(find /etc/prosody/conf.d/ -name \*.lua|awk -F'.cfg' '!/localhost/{print $1}'|xargs basename)"
|
||||||
MEET_CONF="/etc/jitsi/meet/$DOMAIN-config.js"
|
|
||||||
CSS_FILE="/usr/share/jitsi-meet/css/all.css"
|
CSS_FILE="/usr/share/jitsi-meet/css/all.css"
|
||||||
TITLE_FILE="/usr/share/jitsi-meet/title.html"
|
TITLE_FILE="/usr/share/jitsi-meet/title.html"
|
||||||
INT_CONF="/usr/share/jitsi-meet/interface_config.js"
|
INT_CONF="/usr/share/jitsi-meet/interface_config.js"
|
||||||
|
@ -88,10 +87,10 @@ sed -i "s| powered by the Jitsi Videobridge||g" "$TITLE_FILE"
|
||||||
sed -i "/appNotInstalled/ s|{{app}}|$MOVILE_APP_NAME|g" /usr/share/jitsi-meet/lang/*
|
sed -i "/appNotInstalled/ s|{{app}}|$MOVILE_APP_NAME|g" /usr/share/jitsi-meet/lang/*
|
||||||
|
|
||||||
#Custom UI changes
|
#Custom UI changes
|
||||||
if [ -f "$INT_CONF" ] && [ -f "$INT_CONF_ETC" ]; then
|
if [ -f "$INT_CONF_ETC" ]; then
|
||||||
echo "Static interface_config.js exists, skipping modification..."
|
echo "Static interface_config.js exists, skipping modification..."
|
||||||
else
|
else
|
||||||
echo "This setup doesn't have a static interface_config.js, seting it up and applying changes..."
|
echo "This setup doesn't have a static interface_config.js, checking changes..."
|
||||||
echo -e "\nPlease note that brandless mode will also overwrite support links.\n"
|
echo -e "\nPlease note that brandless mode will also overwrite support links.\n"
|
||||||
sed -i "21,32 s|Jitsi Meet|$APP_NAME|g" "$INT_CONF"
|
sed -i "21,32 s|Jitsi Meet|$APP_NAME|g" "$INT_CONF"
|
||||||
sed -i "s|\([[:space:]]\)APP_NAME:.*| APP_NAME: \'$APP_NAME\',|" "$INT_CONF"
|
sed -i "s|\([[:space:]]\)APP_NAME:.*| APP_NAME: \'$APP_NAME\',|" "$INT_CONF"
|
||||||
|
|
|
@ -42,7 +42,7 @@ apt-get update -q2
|
||||||
# Manually add prerequisites.
|
# Manually add prerequisites.
|
||||||
apt-get install -y curl letsencrypt nginx
|
apt-get install -y curl letsencrypt nginx
|
||||||
|
|
||||||
MIN_PHP="8.3"
|
MIN_PHP="8.2"
|
||||||
DOMAIN="$(find /etc/prosody/conf.d/ -name \*.lua|awk -F'.cfg' '!/localhost/{print $1}'|xargs basename)"
|
DOMAIN="$(find /etc/prosody/conf.d/ -name \*.lua|awk -F'.cfg' '!/localhost/{print $1}'|xargs basename)"
|
||||||
PSGVER="$(apt-cache madison postgresql|tr -d '[:blank:]'|awk -F'[|+]' 'NR==1{print $2}')"
|
PSGVER="$(apt-cache madison postgresql|tr -d '[:blank:]'|awk -F'[|+]' 'NR==1{print $2}')"
|
||||||
NC_NGINX_SSL_PORT="$(grep "listen 44" /etc/nginx/sites-available/"$DOMAIN".conf | awk '{print$2}')"
|
NC_NGINX_SSL_PORT="$(grep "listen 44" /etc/nginx/sites-available/"$DOMAIN".conf | awk '{print$2}')"
|
||||||
|
|
112
mode/jwt.sh
112
mode/jwt.sh
|
@ -14,102 +14,83 @@ done
|
||||||
|
|
||||||
#DEBUG
|
#DEBUG
|
||||||
if [ "$MODE" = "debug" ]; then
|
if [ "$MODE" = "debug" ]; then
|
||||||
set -x
|
set -x
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DOMAIN="$(find /etc/prosody/conf.d/ -name \*.lua|awk -F'.cfg' '!/localhost/{print $1}'|xargs basename)"
|
DOMAIN="$(find /etc/prosody/conf.d/ -name \*.lua|awk -F'.cfg' '!/localhost/{print $1}'|xargs basename)"
|
||||||
MEET_CONF="/etc/jitsi/meet/$DOMAIN-config.js"
|
MEET_CONF="/etc/jitsi/meet/$DOMAIN-config.js"
|
||||||
JICOFO_SIP="/etc/jitsi/jicofo/sip-communicator.properties"
|
JICOFO_SIP="/etc/jitsi/jicofo/sip-communicator.properties"
|
||||||
JICOFO_CONF="/etc/jitsi/jicofo/jicofo.conf"
|
|
||||||
PROSODY_FILE="/etc/prosody/conf.d/$DOMAIN.cfg.lua"
|
PROSODY_FILE="/etc/prosody/conf.d/$DOMAIN.cfg.lua"
|
||||||
PROSODY_SYS="/etc/prosody/prosody.cfg.lua"
|
PROSODY_SYS="/etc/prosody/prosody.cfg.lua"
|
||||||
APP_ID="$(tr -dc "a-zA-Z0-9" < /dev/urandom | fold -w 16 | head -n1)"
|
APP_ID="$(tr -dc "a-zA-Z0-9" < /dev/urandom | fold -w 16 | head -n1)"
|
||||||
SECRET_APP="$(tr -dc "a-zA-Z0-9" < /dev/urandom | fold -w 64 | head -n1)"
|
SECRET_APP="$(tr -dc "a-zA-Z0-9" < /dev/urandom | fold -w 64 | head -n1)"
|
||||||
ROOM="Two-Hour-Test-Room"
|
|
||||||
SRP_STR="$(grep -n "VirtualHost \"$DOMAIN\"" "$PROSODY_FILE" | head -n1 | cut -d ":" -f1)"
|
SRP_STR="$(grep -n "VirtualHost \"$DOMAIN\"" "$PROSODY_FILE" | head -n1 | cut -d ":" -f1)"
|
||||||
SRP_END="$((SRP_STR + 10))"
|
SRP_END="$((SRP_STR + 10))"
|
||||||
|
|
||||||
# Prosody 0.12{,.*} only
|
## Required openssl for Focal 20.04
|
||||||
if command -v prosodyctl >/dev/null 2>&1; then
|
if [ "$(lsb_release -sc)" = "focal" ]; then
|
||||||
PROSODY_VER="$(prosodyctl about 2>/dev/null | sed -n 's/^Prosody //p' | awk '{print $1}')"
|
echo "deb http://ppa.launchpad.net/rael-gc/rvm/ubuntu focal main" | \
|
||||||
case "$PROSODY_VER" in
|
sudo tee /etc/apt/sources.list.d/rvm.list
|
||||||
0.12) : ;; # 22.04
|
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F4E3FBBE
|
||||||
0.12.*) : ;; # 24.04
|
apt-get update
|
||||||
*) echo "Prosody $PROSODY_VER NO supported for JWT mode (required 0.12.x)"
|
|
||||||
exit 1 ;;
|
|
||||||
esac
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Custom 5.4 lua workaround for prosody 0.12
|
apt-get -y install \
|
||||||
echo "Warning: Ubuntu 22.04/24.04 don't ship the required lua inspect module 5.4,"
|
lua5.2 \
|
||||||
echo " so, we work arround it, be careful on further upgrades or changes."
|
liblua5.2 \
|
||||||
install -d -m 755 /usr/share/lua/5.4
|
luarocks \
|
||||||
ln -sf /usr/share/lua/5.3/inspect.lua /usr/share/lua/5.4/inspect.lua
|
libssl1.0-dev \
|
||||||
systemctl restart prosody jicofo jitsi-videobridge2
|
python3-jwt
|
||||||
|
|
||||||
sleep .1
|
luarocks install basexx
|
||||||
|
luarocks install luacrypto
|
||||||
# Install dependencies
|
luarocks install lua-cjson 2.1.0-1
|
||||||
apt-get -y install python3-jwt
|
|
||||||
|
|
||||||
echo "set jitsi-meet-tokens/appid string $APP_ID" | debconf-set-selections
|
echo "set jitsi-meet-tokens/appid string $APP_ID" | debconf-set-selections
|
||||||
echo "set jitsi-meet-tokens/appsecret password $SECRET_APP" | debconf-set-selections
|
echo "set jitsi-meet-tokens/appsecret password $SECRET_APP" | debconf-set-selections
|
||||||
|
|
||||||
apt-get install -y jitsi-meet-tokens
|
apt-get install -y jitsi-meet-tokens
|
||||||
|
|
||||||
# Setting up prosody
|
#Setting up
|
||||||
sed -i "s|c2s_require_encryption = true|c2s_require_encryption = false|" "$PROSODY_SYS"
|
sed -i "s|c2s_require_encryption = true|c2s_require_encryption = false|" "$PROSODY_SYS"
|
||||||
#-
|
#-
|
||||||
sed -i "$SRP_STR,$SRP_END{s|authentication = \"jitsi-anonymous\"|authentication = \"token\"|}" "$PROSODY_FILE"
|
sed -i "$SRP_STR,$SRP_END{s|authentication = \"jitsi-anonymous\"|authentication = \"token\"|}" "$PROSODY_FILE"
|
||||||
sed -i "s|--app_id=\"example_app_id\"|app_id=\"$APP_ID\"|" "$PROSODY_FILE"
|
sed -i "s|--app_id=\"example_app_id\"|app_id=\"$APP_ID\"|" "$PROSODY_FILE"
|
||||||
sed -i "s|--app_secret=\"example_app_secret\"|app_secret=\"$SECRET_APP\"|" "$PROSODY_FILE"
|
sed -i "s|--app_secret=\"example_app_secret\"|app_secret=\"$SECRET_APP\"|" "$PROSODY_FILE"
|
||||||
sed -i "/app_secret/a \\\\" "$PROSODY_FILE"
|
sed -i "/app_secret/a \\\\" "$PROSODY_FILE"
|
||||||
## Only token owners can create, open the room and become moderators,
|
sed -i "/app_secret/a \ \ \ \ allow_empty_token = false" "$PROSODY_FILE"
|
||||||
## but require jibri: `allow_empty_token = true`
|
|
||||||
## other participants are redirected authentication to guest.
|
|
||||||
sed -i "/app_secret/a \ \ \ \ allow_empty_token = true" "$PROSODY_FILE"
|
|
||||||
sed -i "/app_secret/a \\\\" "$PROSODY_FILE"
|
sed -i "/app_secret/a \\\\" "$PROSODY_FILE"
|
||||||
sed -i "/app_secret/a \ \ \ \ asap_accepted_issuers = { \"$APP_ID\" }" "$PROSODY_FILE"
|
sed -i "/app_secret/a \ \ \ \ asap_accepted_issuers = { \"$APP_ID\" }" "$PROSODY_FILE"
|
||||||
sed -i "/app_secret/a \ \ \ \ asap_accepted_audiences = { \"$APP_ID\" }" "$PROSODY_FILE"
|
sed -i "/app_secret/a \ \ \ \ asap_accepted_audiences = { \"$APP_ID\", \"RocketChat\" }" "$PROSODY_FILE"
|
||||||
sed -i "/app_secret/a \\\\" "$PROSODY_FILE"
|
sed -i "/app_secret/a \\\\" "$PROSODY_FILE"
|
||||||
sed -i "s|--allow_empty_token =.*|allow_empty_token = true|" "$PROSODY_FILE"
|
sed -i "s|--allow_empty_token =.*|allow_empty_token = false|" "$PROSODY_FILE"
|
||||||
sed -i 's|--"token_verification"|"token_verification"|' "$PROSODY_FILE"
|
sed -i 's|--"token_verification"|"token_verification"|' "$PROSODY_FILE"
|
||||||
sed -i "/muc_lobby_rooms/a \ \ \ \ \ \ \ \ \"persistent_lobby\";" "$PROSODY_FILE"
|
|
||||||
sed -i "/token_verification/a \ \ \ \ \ \ \ \ \"muc_wait_for_host\";" "$PROSODY_FILE"
|
|
||||||
|
|
||||||
# Set JWT and Guest settings
|
#Request auth
|
||||||
## Harden JWT auth, preventing "free" moderator by racing into room,
|
sed -i "s|#org.jitsi.jicofo.auth.URL=EXT_JWT:|org.jitsi.jicofo.auth.URL=EXT_JWT:|" "$JICOFO_SIP"
|
||||||
## only participants with token with moderator:true.
|
|
||||||
# Custom 'token_moderator_owner' module for passing JWT claim
|
|
||||||
cp files/mod_token_moderator_owner.lua /usr/share/jitsi-meet/prosody-plugins/
|
|
||||||
sed -i '/"muc_password_whitelist"/a \ \ \ \ \ \ \ \ \"token_moderator_owner";' "$PROSODY_FILE"
|
|
||||||
envsubst < \
|
|
||||||
patches/prosody/001-enable_wait_for_host_disable_auto_owners.patch | \
|
|
||||||
patch --no-backup-if-mismatch -d / -p1
|
|
||||||
hocon set jicofo.conference.enable-auto-owner false -f "$JICOFO_CONF"
|
|
||||||
|
|
||||||
## config.js
|
|
||||||
sed -i "s|// anonymousdomain: 'guest.example.com'|anonymousdomain: \'guest.$DOMAIN\'|" "$MEET_CONF"
|
sed -i "s|// anonymousdomain: 'guest.example.com'|anonymousdomain: \'guest.$DOMAIN\'|" "$MEET_CONF"
|
||||||
awk '
|
|
||||||
BEGIN{done=0}
|
#Enable jibri recording
|
||||||
/^[[:space:]]*var[[:space:]]+config[[:space:]]*=[[:space:]]*{\s*$/ && !done{
|
cat << REC-JIBRI >> "$PROSODY_FILE"
|
||||||
print
|
|
||||||
print " enableFeaturesBasedOnToken: true,"
|
VirtualHost "recorder.$DOMAIN"
|
||||||
print " enableUserRolesBasedOnToken: true,"
|
modules_enabled = {
|
||||||
done=1
|
"ping";
|
||||||
next
|
|
||||||
}
|
}
|
||||||
{print}
|
authentication = "internal_hashed"
|
||||||
' "$MEET_CONF" > "${MEET_CONF}.new" && mv "${MEET_CONF}.new" "$MEET_CONF"
|
|
||||||
|
|
||||||
# Setup guests and lobby
|
REC-JIBRI
|
||||||
|
|
||||||
|
#Setup guests and lobby
|
||||||
cat << P_SR >> "$PROSODY_FILE"
|
cat << P_SR >> "$PROSODY_FILE"
|
||||||
|
-- #Change back lobby - https://community.jitsi.org/t/64769/136
|
||||||
-- jwt setup -QJI
|
|
||||||
VirtualHost "guest.$DOMAIN"
|
VirtualHost "guest.$DOMAIN"
|
||||||
authentication = "anonymous"
|
authentication = "token"
|
||||||
|
allow_empty_token = true
|
||||||
c2s_require_encryption = false
|
c2s_require_encryption = false
|
||||||
speakerstats_component = "speakerstats.$DOMAIN"
|
speakerstats_component = "speakerstats.$DOMAIN"
|
||||||
|
app_id="$APP_ID";
|
||||||
|
app_secret="$SECRET_APP";
|
||||||
|
|
||||||
modules_enabled = {
|
modules_enabled = {
|
||||||
"speakerstats";
|
"speakerstats";
|
||||||
|
@ -121,13 +102,14 @@ echo -e "\nUse the following for your App (e.g. Rocket.Chat):\n"
|
||||||
echo -e "\nAPP_ID: $APP_ID" && \
|
echo -e "\nAPP_ID: $APP_ID" && \
|
||||||
echo -e "SECRET_APP: $SECRET_APP\n"
|
echo -e "SECRET_APP: $SECRET_APP\n"
|
||||||
|
|
||||||
echo -e "You can test JWT authentication with the following token for the next 2 hours:\n"
|
echo -e "You can test JWT authentication with the following token:\n"
|
||||||
python3 tools/jwt/jitsi_token_maker_features.py \
|
pyjwt3 --key="$SECRET_APP" \
|
||||||
--app-id "$APP_ID" --secret "$SECRET_APP" \
|
encode \
|
||||||
--domain "$DOMAIN" --room "$ROOM" \
|
group="Rocket.Chat" \
|
||||||
--username "Moderator Token Test User"
|
aud="$APP_ID" \
|
||||||
--moderator --features-all \
|
iss="$APP_ID" \
|
||||||
--minutes 120 --nbf-offset 300 --include-iat \
|
sub="$DOMAIN" \
|
||||||
--url "https://$DOMAIN/"
|
room="*" \
|
||||||
|
algorithm="HS256"
|
||||||
|
|
||||||
read -n 1 -s -r -p $'\n'"Press any key to continue..."$'\n'
|
read -n 1 -s -r -p $'\n'"Press any key to continue..."$'\n'
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
# Quick Jibri Installer - *buntu (LTS) based systems.
|
|
||||||
# SwITNet Ltd © - 2025, https://switnet.net/
|
|
||||||
# GPLv3 or later.
|
|
||||||
|
|
||||||
Patch prosody (0.12) $DOMAIN.cfg.lua to enable wait_for_host_disable_auto_owners.
|
|
||||||
|
|
||||||
diff --git a/etc/prosody/conf.d/${DOMAIN}.cfg.lua b/etc/prosody/conf.d/${DOMAIN}.cfg.lua
|
|
||||||
index f2b647e..031a064 100644
|
|
||||||
--- a/etc/prosody/conf.d/${DOMAIN}.cfg.lua
|
|
||||||
+++ b/etc/prosody/conf.d/${DOMAIN}.cfg.lua
|
|
||||||
@@ -103,6 +103,7 @@ Component "conference.${DOMAIN}" "muc"
|
|
||||||
}
|
|
||||||
muc_room_locking = false
|
|
||||||
muc_room_default_public_jids = true
|
|
||||||
+ wait_for_host_disable_auto_owners = true
|
|
||||||
|
|
||||||
Component "breakout.${DOMAIN}" "muc"
|
|
||||||
restrict_room_creation = true
|
|
|
@ -303,12 +303,7 @@ do
|
||||||
done
|
done
|
||||||
sleep .1
|
sleep .1
|
||||||
#Prosody repository
|
#Prosody repository
|
||||||
if [ "$DIST" = "jammy" ]; then
|
add_prosody_repo
|
||||||
add_prosody_repo
|
|
||||||
prosody="prosody-0.12"
|
|
||||||
else
|
|
||||||
prosody='prosody'
|
|
||||||
fi
|
|
||||||
sleep .1
|
sleep .1
|
||||||
# Jitsi-Meet Repo
|
# Jitsi-Meet Repo
|
||||||
printf "\nAdd Jitsi repo\n"
|
printf "\nAdd Jitsi repo\n"
|
||||||
|
@ -437,7 +432,7 @@ echo "jitsi-meet-web-config jitsi-meet/jaas-choice boolean false" \
|
||||||
apt-get -y install \
|
apt-get -y install \
|
||||||
jitsi-meet \
|
jitsi-meet \
|
||||||
jibri \
|
jibri \
|
||||||
$prosody \
|
lua5.4 \
|
||||||
openjdk-11-jre-headless
|
openjdk-11-jre-headless
|
||||||
|
|
||||||
# Fix RAND_load_file error
|
# Fix RAND_load_file error
|
||||||
|
@ -766,27 +761,7 @@ INT_CONF_ETC="/etc/jitsi/meet/$DOMAIN-interface_config.js"
|
||||||
ssl_wa() {
|
ssl_wa() {
|
||||||
if [ "$LE_SSL" = "yes" ]; then
|
if [ "$LE_SSL" = "yes" ]; then
|
||||||
systemctl stop "$1"
|
systemctl stop "$1"
|
||||||
if certbot certonly --standalone --renew-by-default \
|
certbot certonly --standalone --renew-by-default --agree-tos --email "$5" -d "$6" --non-interactive
|
||||||
--agree-tos --email "$5" -d "$6" \
|
|
||||||
--non-interactive
|
|
||||||
then
|
|
||||||
echo "> SSL cert issued correctly!"
|
|
||||||
else
|
|
||||||
echo "> SSL cert issued failed!"
|
|
||||||
sleep .1
|
|
||||||
while [ "$SSL_FAILED" != "yes" ] && [ "$SSL_FAILED" != "no" ]
|
|
||||||
do
|
|
||||||
read -p "> Do you want to continue regardless? This might make the installer to fail later on: (yes or no)$NL" -r SSL_FAILED
|
|
||||||
if [ "$SSL_FAILED" = "yes" ]; then
|
|
||||||
printf " - Continuing installation regardless failure to retrieve SSL certs.\n\n"
|
|
||||||
elif [ "$SSL_FAILED" = "no" ]; then
|
|
||||||
printf " - Stoping the installer.You might want to take a look at:\n"
|
|
||||||
printf " - /var/log/letsencrypt/letsencrypt.log and / or\n"
|
|
||||||
printf " - https://letsencrypt.status.io/\n\n"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
sed -i "s|/etc/jitsi/meet/$3.crt|/etc/letsencrypt/live/$3/fullchain.pem|" "$4"
|
sed -i "s|/etc/jitsi/meet/$3.crt|/etc/letsencrypt/live/$3/fullchain.pem|" "$4"
|
||||||
sed -i "s|/etc/jitsi/meet/$3.key|/etc/letsencrypt/live/$3/privkey.pem|" "$4"
|
sed -i "s|/etc/jitsi/meet/$3.key|/etc/letsencrypt/live/$3/privkey.pem|" "$4"
|
||||||
systemctl restart "$1"
|
systemctl restart "$1"
|
||||||
|
@ -819,6 +794,9 @@ restart_services() {
|
||||||
check_jibri
|
check_jibri
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Configure Jvb2
|
||||||
|
sed -i "/shard.HOSTNAME/s|localhost|$DOMAIN|" "$JVB2_SIP"
|
||||||
|
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
print_title "Configure Jibri"
|
print_title "Configure Jibri"
|
||||||
#--------------------------------------------------
|
#--------------------------------------------------
|
||||||
|
@ -836,6 +814,16 @@ if [ "$ENABLE_SC" = "yes" ]; then
|
||||||
|
|
||||||
fi
|
fi
|
||||||
sleep .1
|
sleep .1
|
||||||
|
#Enable jibri recording
|
||||||
|
cat << REC-JIBRI >> "$PROSODY_FILE"
|
||||||
|
|
||||||
|
VirtualHost "recorder.$DOMAIN"
|
||||||
|
modules_enabled = {
|
||||||
|
"ping";
|
||||||
|
}
|
||||||
|
authentication = "internal_hashed"
|
||||||
|
|
||||||
|
REC-JIBRI
|
||||||
|
|
||||||
#Enable Jibri withelist
|
#Enable Jibri withelist
|
||||||
sed -i "s|-- muc_lobby_whitelist|muc_lobby_whitelist|" "$PROSODY_FILE"
|
sed -i "s|-- muc_lobby_whitelist|muc_lobby_whitelist|" "$PROSODY_FILE"
|
||||||
|
@ -961,17 +949,16 @@ JVB_SECRET=$(g_conf_value JVB_SECRET=)
|
||||||
JVB_OPTS=$(g_conf_value JVB_OPTS=)
|
JVB_OPTS=$(g_conf_value JVB_OPTS=)
|
||||||
JAVA_SYS_PROPS=$(g_conf_value JAVA_SYS_PROPS=)
|
JAVA_SYS_PROPS=$(g_conf_value JAVA_SYS_PROPS=)
|
||||||
|
|
||||||
#FIXME: - sip-communicator.properties - no longer exist
|
g_sip_value() {
|
||||||
#g_sip_value() {
|
grep "$1" "$JVB2_SIP" |cut -d "=" -f2
|
||||||
# grep "$1" "$JVB2_SIP" |cut -d "=" -f2
|
}
|
||||||
#}
|
DISABLE_AWS_HARVESTER=$(g_sip_value DISABLE_AWS_HARVESTER=)
|
||||||
#DISABLE_AWS_HARVESTER=$(g_sip_value DISABLE_AWS_HARVESTER=)
|
STUN_MAPPING_HARVESTER_ADDRESSES=$(g_sip_value STUN_MAPPING_HARVESTER_ADDRESSES=)
|
||||||
#STUN_MAPPING_HARVESTER_ADDRESSES=$(g_sip_value STUN_MAPPING_HARVESTER_ADDRESSES=)
|
ENABLE_STATISTICS=$(g_sip_value ENABLE_STATISTICS=)
|
||||||
#ENABLE_STATISTICS=$(g_sip_value ENABLE_STATISTICS=)
|
SHARD_HOSTNAME=$(g_sip_value shard.HOSTNAME=)
|
||||||
#SHARD_HOSTNAME=$(g_sip_value shard.HOSTNAME=)
|
SHARD_DOMAIN=$(g_sip_value shard.DOMAIN=)
|
||||||
#SHARD_DOMAIN=$(g_sip_value shard.DOMAIN=)
|
SHARD_PASSWORD=$(g_sip_value shard.PASSWORD=)
|
||||||
#SHARD_PASSWORD=$(g_sip_value shard.PASSWORD=)
|
MUC_JID=$(g_sip_value MUC_JIDS=)
|
||||||
#MUC_JID=$(g_sip_value MUC_JIDS=)
|
|
||||||
|
|
||||||
##-- Replacing on add-jvb2-node.sh
|
##-- Replacing on add-jvb2-node.sh
|
||||||
sed -i "s|JVB_HOSTNAME=.*|JVB_HOSTNAME=$JVB_HOSTNAME|" add-jvb2-node.sh
|
sed -i "s|JVB_HOSTNAME=.*|JVB_HOSTNAME=$JVB_HOSTNAME|" add-jvb2-node.sh
|
||||||
|
@ -980,14 +967,14 @@ sed -i "s|JVB_PORT=.*|JVB_PORT=$JVB_PORT|" add-jvb2-node.sh
|
||||||
sed -i "s|JVB_SECRET=.*|JVB_SECRET=$JVB_SECRET|" add-jvb2-node.sh
|
sed -i "s|JVB_SECRET=.*|JVB_SECRET=$JVB_SECRET|" add-jvb2-node.sh
|
||||||
sed -i "s|JVB_OPTS=.*|JVB_OPTS=$JVB_OPTS|" add-jvb2-node.sh
|
sed -i "s|JVB_OPTS=.*|JVB_OPTS=$JVB_OPTS|" add-jvb2-node.sh
|
||||||
sed -i "s|SYS_PROPS=.*|SYS_PROPS=$JAVA_SYS_PROPS|" add-jvb2-node.sh
|
sed -i "s|SYS_PROPS=.*|SYS_PROPS=$JAVA_SYS_PROPS|" add-jvb2-node.sh
|
||||||
#FIXME: - sip-communicator.properties - no longer exist
|
#-
|
||||||
#sed -i "s|AWS_HARVEST=.*|AWS_HARVEST=$DISABLE_AWS_HARVESTER|" add-jvb2-node.sh
|
sed -i "s|AWS_HARVEST=.*|AWS_HARVEST=$DISABLE_AWS_HARVESTER|" add-jvb2-node.sh
|
||||||
#sed -i "s|STUN_MAPPING=.*|STUN_MAPPING=$STUN_MAPPING_HARVESTER_ADDRESSES|" add-jvb2-node.sh
|
sed -i "s|STUN_MAPPING=.*|STUN_MAPPING=$STUN_MAPPING_HARVESTER_ADDRESSES|" add-jvb2-node.sh
|
||||||
#sed -i "s|ENABLE_STATISTICS=.*|ENABLE_STATISTICS=$ENABLE_STATISTICS|" add-jvb2-node.sh
|
sed -i "s|ENABLE_STATISTICS=.*|ENABLE_STATISTICS=$ENABLE_STATISTICS|" add-jvb2-node.sh
|
||||||
#sed -i "s|SHARD_HOSTNAME=.*|SHARD_HOSTNAME=$SHARD_HOSTNAME|" add-jvb2-node.sh
|
sed -i "s|SHARD_HOSTNAME=.*|SHARD_HOSTNAME=$SHARD_HOSTNAME|" add-jvb2-node.sh
|
||||||
#sed -i "s|SHARD_DOMAIN=.*|SHARD_DOMAIN=$SHARD_DOMAIN|" add-jvb2-node.sh
|
sed -i "s|SHARD_DOMAIN=.*|SHARD_DOMAIN=$SHARD_DOMAIN|" add-jvb2-node.sh
|
||||||
#sed -i "s|SHARD_PASS=.*|SHARD_PASS=$SHARD_PASSWORD|" add-jvb2-node.sh
|
sed -i "s|SHARD_PASS=.*|SHARD_PASS=$SHARD_PASSWORD|" add-jvb2-node.sh
|
||||||
#sed -i "s|MUC_JID=.*|MUC_JID=$MUC_JID|" add-jvb2-node.sh
|
sed -i "s|MUC_JID=.*|MUC_JID=$MUC_JID|" add-jvb2-node.sh
|
||||||
|
|
||||||
sed -i "s|MAIN_SRV_DIST=.*|MAIN_SRV_DIST=\"$DIST\"|" add-jvb2-node.sh
|
sed -i "s|MAIN_SRV_DIST=.*|MAIN_SRV_DIST=\"$DIST\"|" add-jvb2-node.sh
|
||||||
sed -i "s|MAIN_SRV_REPO=.*|MAIN_SRV_REPO=\"$JITSI_REPO\"|" add-jvb2-node.sh
|
sed -i "s|MAIN_SRV_REPO=.*|MAIN_SRV_REPO=\"$JITSI_REPO\"|" add-jvb2-node.sh
|
||||||
|
|
|
@ -1,158 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
JWT generator for self‑hosted Jitsi (also compatible with JAAS if desired)
|
|
||||||
- HS256 (HMAC) signing using only Python standard library (no external deps).
|
|
||||||
- Flags to omit exp/nbf (test tokens), include iat, and read secret from file/STDIN.
|
|
||||||
- Flags to populate context.features: recording, livestreaming, transcription, sip-in/out.
|
|
||||||
- Robust URL construction (escapes the room name).
|
|
||||||
"""
|
|
||||||
import argparse, base64, hashlib, hmac, json, time, sys
|
|
||||||
from urllib.parse import quote
|
|
||||||
|
|
||||||
def b64url(data: bytes) -> str:
|
|
||||||
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii")
|
|
||||||
|
|
||||||
def sign_hs256(secret: str, signing_input: str) -> str:
|
|
||||||
sig = hmac.new(secret.encode("utf-8"), signing_input.encode("ascii"), hashlib.sha256).digest()
|
|
||||||
return b64url(sig)
|
|
||||||
|
|
||||||
def main():
|
|
||||||
p = argparse.ArgumentParser(description="JWT generator for Jitsi (HS256)")
|
|
||||||
# Identity / target
|
|
||||||
p.add_argument("--app-id", required=True, help="app_id configured in Prosody/JAAS")
|
|
||||||
p.add_argument("--secret", required=False, help="app_secret (HMAC/HS256)")
|
|
||||||
p.add_argument("--secret-file", help="Read secret from file or '-' for STDIN")
|
|
||||||
p.add_argument("--domain", help="Jitsi domain (e.g. meet.example.com) used as 'sub' in self-hosted")
|
|
||||||
p.add_argument("--room", default="*", help="Target room (or '*' for all)")
|
|
||||||
# Time
|
|
||||||
p.add_argument("--minutes", type=int, default=60, help="Validity (minutes). Ignored if --no-exp")
|
|
||||||
p.add_argument("--no-exp", action="store_true", help="Do not include 'exp' (tests only)")
|
|
||||||
p.add_argument("--nbf-offset", type=int, default=10, help="Backdating seconds for 'nbf' (default: 10)")
|
|
||||||
p.add_argument("--no-nbf", action="store_true", help="Do not include 'nbf' (tests only)")
|
|
||||||
p.add_argument("--include-iat", action="store_true", help="Include 'iat'=now")
|
|
||||||
# User
|
|
||||||
p.add_argument("--user-name", default=None, help="User display name")
|
|
||||||
p.add_argument("--user-email", default=None, help="User email")
|
|
||||||
p.add_argument("--user-id", default=None, help="User unique ID")
|
|
||||||
p.add_argument("--avatar", default=None, help="Avatar URL")
|
|
||||||
p.add_argument("--moderator", action="store_true", help="Grant moderator role via token")
|
|
||||||
p.add_argument("--moderator-as-string", action="store_true",
|
|
||||||
help="Use 'moderator': 'true'/'false' (string) instead of boolean")
|
|
||||||
# Features (self-hosted with enableFeaturesBasedOnToken)
|
|
||||||
p.add_argument("--feature-recording", action="store_true", help="Enable 'recording' in context.features")
|
|
||||||
p.add_argument("--feature-livestreaming", action="store_true", help="Enable 'livestreaming' in context.features")
|
|
||||||
p.add_argument("--feature-transcription", action="store_true", help="Enable 'transcription' in context.features")
|
|
||||||
p.add_argument("--feature-sip-in", action="store_true", help="Enable 'sip-inbound-call' in context.features")
|
|
||||||
p.add_argument("--feature-sip-out", action="store_true", help="Enable 'sip-outbound-call' in context.features")
|
|
||||||
p.add_argument("--features-all", action="store_true", help="Enable all the features above")
|
|
||||||
# Overrides / modes
|
|
||||||
p.add_argument("--aud", default=None, help="Override 'aud' (default: app_id in self-hosted)")
|
|
||||||
p.add_argument("--iss", default=None, help="Override 'iss' (default: app_id in self-hosted)")
|
|
||||||
p.add_argument("--jaas", action="store_true",
|
|
||||||
help="JAAS mode: aud='jitsi', iss='chat', sub=app_id (ignores --domain for 'sub')")
|
|
||||||
# Output
|
|
||||||
p.add_argument("--url", default=None,
|
|
||||||
help="If provided (e.g. 'https://meet.example.com/'), prints full join URL with ?jwt=")
|
|
||||||
p.add_argument("--print-json", action="store_true", help="Print payload JSON to STDERR (debug)")
|
|
||||||
|
|
||||||
args = p.parse_args()
|
|
||||||
|
|
||||||
# Secret: --secret-file takes precedence
|
|
||||||
secret = args.secret
|
|
||||||
if args.secret_file:
|
|
||||||
if args.secret_file == "-":
|
|
||||||
secret = sys.stdin.read().strip()
|
|
||||||
else:
|
|
||||||
with open(args.secret_file, "r", encoding="utf-8") as fh:
|
|
||||||
secret = fh.read().strip()
|
|
||||||
if not secret:
|
|
||||||
p.error("You must provide --secret or --secret-file (or --secret-file - for STDIN).")
|
|
||||||
|
|
||||||
now = int(time.time())
|
|
||||||
exp = None if args.no_exp else (now + args.minutes * 60)
|
|
||||||
nbf = None if args.no_nbf else (now - max(args.nbf_offset, 0))
|
|
||||||
|
|
||||||
# Header
|
|
||||||
header = {"typ": "JWT", "alg": "HS256"}
|
|
||||||
|
|
||||||
# Base claims by mode
|
|
||||||
if args.jaas:
|
|
||||||
aud = "jitsi"
|
|
||||||
iss = "chat"
|
|
||||||
sub = args.app_id
|
|
||||||
else:
|
|
||||||
if not args.domain:
|
|
||||||
p.error("--domain is required in self-hosted mode (without --jaas).")
|
|
||||||
aud = args.aud or args.app_id
|
|
||||||
iss = args.iss or args.app_id
|
|
||||||
sub = args.domain
|
|
||||||
|
|
||||||
# User / contexto
|
|
||||||
user = {}
|
|
||||||
if args.user_id: user["id"] = args.user_id
|
|
||||||
if args.user_name: user["name"] = args.user_name
|
|
||||||
if args.user_email: user["email"] = args.user_email
|
|
||||||
if args.avatar: user["avatar"] = args.avatar
|
|
||||||
if args.moderator:
|
|
||||||
if args.moderator_as_string:
|
|
||||||
user["moderator"] = "true"
|
|
||||||
else:
|
|
||||||
user["moderator"] = True
|
|
||||||
|
|
||||||
# Features
|
|
||||||
features = {}
|
|
||||||
if args.features_all:
|
|
||||||
features = {
|
|
||||||
"recording": True,
|
|
||||||
"livestreaming": True,
|
|
||||||
"transcription": True,
|
|
||||||
"sip-inbound-call": True,
|
|
||||||
"sip-outbound-call": True
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
if args.feature_recording: features["recording"] = True
|
|
||||||
if args.feature_livestreaming: features["livestreaming"] = True
|
|
||||||
if args.feature_transcription: features["transcription"] = True
|
|
||||||
if args.feature_sip_in: features["sip-inbound-call"] = True
|
|
||||||
if args.feature_sip_out: features["sip-outbound-call"] = True
|
|
||||||
|
|
||||||
context = {}
|
|
||||||
if user: context["user"] = user
|
|
||||||
if features: context["features"] = features
|
|
||||||
|
|
||||||
payload = {
|
|
||||||
"aud": aud,
|
|
||||||
"iss": iss,
|
|
||||||
"sub": sub,
|
|
||||||
"room": args.room,
|
|
||||||
}
|
|
||||||
if context:
|
|
||||||
payload["context"] = context
|
|
||||||
if exp is not None:
|
|
||||||
payload["exp"] = exp
|
|
||||||
if nbf is not None:
|
|
||||||
payload["nbf"] = nbf
|
|
||||||
if args.include_iat:
|
|
||||||
payload["iat"] = now
|
|
||||||
|
|
||||||
# Build JWT manually
|
|
||||||
signing_input = f"{b64url(json.dumps(header, separators=(',', ':'), ensure_ascii=False).encode())}." \
|
|
||||||
f"{b64url(json.dumps(payload, separators=(',', ':'), ensure_ascii=False).encode())}"
|
|
||||||
signature = sign_hs256(secret, signing_input)
|
|
||||||
token = f"{signing_input}.{signature}"
|
|
||||||
|
|
||||||
if args.print_json:
|
|
||||||
print(json.dumps(payload, indent=2, ensure_ascii=False), file=sys.stderr)
|
|
||||||
|
|
||||||
if args.url:
|
|
||||||
base = args.url if args.url.endswith("/") else args.url + "/"
|
|
||||||
room_path = "" if args.room == "*" else quote(args.room, safe="")
|
|
||||||
join_url = base + room_path
|
|
||||||
sep = "&" if "?" in join_url else "?"
|
|
||||||
print(f"{join_url}{sep}jwt={token}")
|
|
||||||
else:
|
|
||||||
print(token)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
|
@ -128,7 +128,6 @@ echo "opcache.revalidate_freq=1"
|
||||||
echo "opcache.validate_timestamps=1"
|
echo "opcache.validate_timestamps=1"
|
||||||
} >> "$PHP_INI"
|
} >> "$PHP_INI"
|
||||||
|
|
||||||
echo "# Stick to default system php version to avoid breaking any other system application"
|
|
||||||
update-alternatives --set php /usr/bin/php"$STABLE_PHP"
|
update-alternatives --set php /usr/bin/php"$STABLE_PHP"
|
||||||
update-alternatives --set php-fpm.sock /run/php/php"$STABLE_PHP"-fpm.sock
|
update-alternatives --set php-fpm.sock /run/php/php"$STABLE_PHP"-fpm.sock
|
||||||
update-alternatives --set php-cgi /usr/bin/php-cgi"$STABLE_PHP"
|
update-alternatives --set php-cgi /usr/bin/php-cgi"$STABLE_PHP"
|
||||||
|
|
Loading…
Reference in New Issue