more updates march

This commit is contained in:
Nathan root
2026-03-01 17:38:47 +00:00
parent ceee62f62c
commit a085ba9714
810 changed files with 27066 additions and 6471 deletions

78
jitsi/prosody/Dockerfile Normal file
View File

@@ -0,0 +1,78 @@
ARG JITSI_REPO=jitsi
ARG BASE_TAG=latest
FROM ${JITSI_REPO}/base:${BASE_TAG} AS builder
RUN apt-dpkg-wrap apt-get update && \
apt-dpkg-wrap apt-get install -y \
build-essential \
lua5.4 \
liblua5.4-dev \
libreadline-dev \
git \
unzip \
wget && \
mkdir /tmp/luarocks && \
wget -qO - https://luarocks.github.io/luarocks/releases/luarocks-3.8.0.tar.gz | tar xfz - --strip-components 1 -C /tmp/luarocks && \
cd /tmp/luarocks && ./configure && make && make install && cd - && \
luarocks install basexx 0.4.1-1 && \
luarocks install lua-cjson 2.1.0-1 && \
luarocks install net-url 0.9-1
FROM ${JITSI_REPO}/base:${BASE_TAG}
LABEL org.opencontainers.image.title="Prosody IM"
LABEL org.opencontainers.image.description="XMPP server used for signalling."
LABEL org.opencontainers.image.url="https://prosody.im/"
LABEL org.opencontainers.image.source="https://github.com/jitsi/docker-jitsi-meet"
LABEL org.opencontainers.image.documentation="https://jitsi.github.io/handbook/"
ARG VERSION_JITSI_CONTRIB_PROSODY_PLUGINS="20250923"
ARG VERSION_MATRIX_USER_VERIFICATION_SERVICE_PLUGIN="1.8.0"
ARG PROSODY_PACKAGE="prosody"
RUN set -x && \
wget -qO /etc/apt/trusted.gpg.d/prosody.gpg https://prosody.im/files/prosody-debian-packages.key && \
echo "deb http://packages.prosody.im/debian bookworm main" > /etc/apt/sources.list.d/prosody.list && \
apt-dpkg-wrap apt-get update && \
apt-dpkg-wrap apt-get install -y \
lua5.4 \
$PROSODY_PACKAGE \
libldap-common \
sasl2-bin \
libsasl2-modules-ldap \
lua-cyrussasl \
lua-inspect \
lua-ldap \
lua-luaossl \
lua-sec \
lua-unbound && \
apt-dpkg-wrap apt-get -d install -y jitsi-meet-prosody && \
dpkg -x /var/cache/apt/archives/jitsi-meet-prosody*.deb /tmp/pkg && \
mv /tmp/pkg/usr/share/jitsi-meet/prosody-plugins /prosody-plugins && \
rm -rf /tmp/pkg /var/cache/apt && \
apt-cleanup && \
rm -rf /etc/prosody && \
mv /usr/share/lua/5.3/inspect.lua /usr/share/lua/5.4/ && \
rm -rf /usr/lib/lua/{5.1,5.2,5.3} && \
rm -rf /usr/share/lua/{5.1,5.2,5.3} && \
wget https://github.com/matrix-org/prosody-mod-auth-matrix-user-verification/archive/refs/tags/v$VERSION_MATRIX_USER_VERIFICATION_SERVICE_PLUGIN.tar.gz && \
tar -xf v$VERSION_MATRIX_USER_VERIFICATION_SERVICE_PLUGIN.tar.gz && \
mv prosody-mod-auth-matrix-user-verification-$VERSION_MATRIX_USER_VERIFICATION_SERVICE_PLUGIN/mod_auth_matrix_user_verification.lua /prosody-plugins && \
mv prosody-mod-auth-matrix-user-verification-$VERSION_MATRIX_USER_VERIFICATION_SERVICE_PLUGIN/mod_matrix_power_sync.lua /prosody-plugins && \
rm -rf prosody-mod-auth-matrix-user-verification-$VERSION_MATRIX_USER_VERIFICATION_SERVICE_PLUGIN v$VERSION_MATRIX_USER_VERIFICATION_SERVICE_PLUGIN.tar.gz && \
wget -q https://github.com/jitsi-contrib/prosody-plugins/archive/refs/tags/v$VERSION_JITSI_CONTRIB_PROSODY_PLUGINS.tar.gz && \
tar -xf v$VERSION_JITSI_CONTRIB_PROSODY_PLUGINS.tar.gz && \
mkdir /prosody-plugins-contrib && \
cp -a prosody-plugins-$VERSION_JITSI_CONTRIB_PROSODY_PLUGINS/* /prosody-plugins-contrib && \
rm -rf prosody-plugins-$VERSION_JITSI_CONTRIB_PROSODY_PLUGINS v$VERSION_JITSI_CONTRIB_PROSODY_PLUGINS.tar.gz && \
(apt-cache policy prosody | grep -q "13\.0\.3" && sed -i '/idna_to_ascii/d' /usr/share/lua/5.4/prosody/util/jid.lua) || true
COPY rootfs/ /
COPY --from=builder /usr/local/lib/lua/5.4 /usr/local/lib/lua/5.4
COPY --from=builder /usr/local/share/lua/5.4 /usr/local/share/lua/5.4
EXPOSE 5222 5280
VOLUME ["/config", "/prosody-plugins-custom"]

View File

@@ -0,0 +1,36 @@
{{ $REGION_NAME := .Env.PROSODY_REGION_NAME | default "default" -}}
{{ $RELEASE_NUMBER := .Env.RELEASE_NUMBER | default "" -}}
{{ $SHARD_NAME := .Env.SHARD | default "default" -}}
{{ $JVB_XMPP_AUTH_DOMAIN := .Env.JVB_XMPP_AUTH_DOMAIN | default "auth.jvb.meet.jitsi" -}}
{{ $JVB_XMPP_INTERNAL_MUC_DOMAIN := .Env.JVB_XMPP_INTERNAL_MUC_DOMAIN | default "muc.jvb.meet.jitsi" -}}
{{ $JVB_AUTH_USER := .Env.JVB_AUTH_USER | default "jvb" -}}
admins = {
"focus@{{ $JVB_XMPP_AUTH_DOMAIN }}",
"{{ $JVB_AUTH_USER }}@{{ $JVB_XMPP_AUTH_DOMAIN }}"
}
plugin_paths = { "/prosody-plugins/", "/prosody-plugins-custom", "/prosody-plugins-contrib" }
VirtualHost "{{ $JVB_XMPP_AUTH_DOMAIN }}"
modules_enabled = {
"smacks";
}
authentication = "internal_hashed"
ssl = {
key = "/config/certs/{{ $JVB_XMPP_AUTH_DOMAIN }}.key";
certificate = "/config/certs/{{ $JVB_XMPP_AUTH_DOMAIN }}.crt";
}
smacks_hibernation_time = 15;
Component "{{ $JVB_XMPP_INTERNAL_MUC_DOMAIN }}" "muc"
modules_enabled = {
"muc_hide_all";
"muc_filter_access";
}
storage = "memory"
muc_room_cache_size = 10000
muc_filter_whitelist="{{ $JVB_XMPP_AUTH_DOMAIN }}"
muc_room_locking = false
muc_room_default_public_jids = true

View File

@@ -0,0 +1,477 @@
{{ $AUTH_TYPE := .Env.AUTH_TYPE | default "internal" -}}
{{ $C2S_REQUIRE_ENCRYPTION := .Env.PROSODY_C2S_REQUIRE_ENCRYPTION | default "1" | toBool -}}
{{ $DISABLE_POLLS := .Env.DISABLE_POLLS | default "false" | toBool -}}
{{ $ENABLE_APP_SECRET := .Env.JWT_APP_SECRET | default "false" | toBool -}}
{{ $ENABLE_AUTH := .Env.ENABLE_AUTH | default "0" | toBool -}}
{{ $ENABLE_AV_MODERATION := .Env.ENABLE_AV_MODERATION | default "true" | toBool -}}
{{ $ENABLE_BREAKOUT_ROOMS := .Env.ENABLE_BREAKOUT_ROOMS | default "true" | toBool -}}
{{ $ENABLE_END_CONFERENCE := .Env.ENABLE_END_CONFERENCE | default "true" | toBool -}}
{{ $ENABLE_FILTER_MESSAGES := .Env.PROSODY_ENABLE_FILTER_MESSAGES | default "false" | toBool -}}
{{ $ENABLE_GUEST_DOMAIN := and $ENABLE_AUTH (.Env.ENABLE_GUESTS | default "0" | toBool) -}}
{{ $ENABLE_JAAS_COMPONENTS := .Env.ENABLE_JAAS_COMPONENTS | default "0" | toBool -}}
{{ $ENABLE_LOBBY := .Env.ENABLE_LOBBY | default "true" | toBool -}}
{{ $ENABLE_RATE_LIMITS := .Env.PROSODY_ENABLE_RATE_LIMITS | default "0" | toBool -}}
{{ $ENABLE_RECORDING := .Env.ENABLE_RECORDING | default "0" | toBool -}}
{{ $ENABLE_RECORDING_METADATA := .Env.PROSODY_ENABLE_RECORDING_METADATA | default "1" | toBool -}}
{{ $ENABLE_SUBDOMAINS := .Env.ENABLE_SUBDOMAINS | default "true" | toBool -}}
{{ $ENABLE_TRANSCRIPTIONS := .Env.ENABLE_TRANSCRIPTIONS | default "0" | toBool -}}
{{ $ENABLE_VISITORS := .Env.ENABLE_VISITORS | default "0" | toBool -}}
{{ $ENABLE_XMPP_WEBSOCKET := .Env.ENABLE_XMPP_WEBSOCKET | default "1" | toBool -}}
{{ $ENV := .Env -}}
{{ $GUEST_AUTH_TYPE := .Env.PROSODY_GUEST_AUTH_TYPE | default "jitsi-anonymous" -}}
{{ $JIBRI_RECORDER_USER := .Env.JIBRI_RECORDER_USER | default "recorder" -}}
{{ $JIBRI_XMPP_USER := .Env.JIBRI_XMPP_USER | default "jibri" -}}
{{ $JIGASI_TRANSCRIBER_USER := .Env.JIGASI_TRANSCRIBER_USER | default "transcriber" -}}
{{ $JIGASI_XMPP_USER := .Env.JIGASI_XMPP_USER | default "jigasi" -}}
{{ $JVB_AUTH_USER := .Env.JVB_AUTH_USER | default "jvb" -}}
{{ $JWT_ALLOW_EMPTY := .Env.JWT_ALLOW_EMPTY | default "0" | toBool -}}
{{ $JWT_ASAP_KEYSERVER := .Env.JWT_ASAP_KEYSERVER | default "" -}}
{{ $JWT_AUTH_TYPE := .Env.JWT_AUTH_TYPE | default "token" -}}
{{ $JWT_ENABLE_DOMAIN_VERIFICATION := .Env.JWT_ENABLE_DOMAIN_VERIFICATION | default "false" | toBool -}}
{{ $JWT_TOKEN_AUTH_MODULE := .Env.JWT_TOKEN_AUTH_MODULE | default "token_verification" -}}
{{ $MATRIX_LOBBY_BYPASS := .Env.MATRIX_LOBBY_BYPASS | default "0" | toBool -}}
{{ $MATRIX_UVS_ISSUER := .Env.MATRIX_UVS_ISSUER | default "issuer" -}}
{{ $MATRIX_UVS_SYNC_POWER_LEVELS := .Env.MATRIX_UVS_SYNC_POWER_LEVELS | default "0" | toBool -}}
{{ $PROSODY_AUTH_TYPE := .Env.PROSODY_AUTH_TYPE | default $AUTH_TYPE -}}
{{ $PROSODY_RESERVATION_ENABLED := .Env.PROSODY_RESERVATION_ENABLED | default "false" | toBool -}}
{{ $PROSODY_RESERVATION_REST_BASE_URL := .Env.PROSODY_RESERVATION_REST_BASE_URL | default "" -}}
{{ $PUBLIC_URL := .Env.PUBLIC_URL | default "https://localhost:8443" -}}
{{ $PUBLIC_URL_DOMAIN := $PUBLIC_URL | trimPrefix "https://" | trimSuffix "/" -}}
{{ $RATE_LIMIT_ALLOW_RANGES := .Env.PROSODY_RATE_LIMIT_ALLOW_RANGES | default "10.0.0.0/8" -}}
{{ $RATE_LIMIT_CACHE_SIZE := .Env.PROSODY_RATE_LIMIT_CACHE_SIZE | default "10000" -}}
{{ $RATE_LIMIT_LOGIN_RATE := .Env.PROSODY_RATE_LIMIT_LOGIN_RATE | default "3" -}}
{{ $RATE_LIMIT_SESSION_RATE := .Env.PROSODY_RATE_LIMIT_SESSION_RATE | default "200" -}}
{{ $RATE_LIMIT_TIMEOUT := .Env.PROSODY_RATE_LIMIT_TIMEOUT | default "60" -}}
{{ $WAIT_FOR_HOST_DISABLE_AUTO_OWNERS := .Env.WAIT_FOR_HOST_DISABLE_AUTO_OWNERS | default "false" | toBool -}}
{{ $XMPP_AUTH_DOMAIN := .Env.XMPP_AUTH_DOMAIN | default "auth.meet.jitsi" -}}
{{ $XMPP_DOMAIN := .Env.XMPP_DOMAIN | default "meet.jitsi" -}}
{{ $XMPP_GUEST_DOMAIN := .Env.XMPP_GUEST_DOMAIN | default "guest.meet.jitsi" -}}
{{ $XMPP_INTERNAL_MUC_DOMAIN := .Env.XMPP_INTERNAL_MUC_DOMAIN | default "internal-muc.meet.jitsi" -}}
{{ $XMPP_MUC_DOMAIN := .Env.XMPP_MUC_DOMAIN | default "muc.meet.jitsi" -}}
{{ $XMPP_MUC_DOMAIN_PREFIX := (split "." $XMPP_MUC_DOMAIN)._0 -}}
{{ $XMPP_HIDDEN_DOMAIN := .Env.XMPP_HIDDEN_DOMAIN | default "hidden.meet.jitsi" -}}
admins = {
{{ if .Env.JIGASI_XMPP_PASSWORD }}
"{{ $JIGASI_XMPP_USER }}@{{ $XMPP_AUTH_DOMAIN }}",
{{ end }}
{{ if .Env.JIBRI_XMPP_PASSWORD }}
"{{ $JIBRI_XMPP_USER }}@{{ $XMPP_AUTH_DOMAIN }}",
{{ end }}
"focus@{{ $XMPP_AUTH_DOMAIN }}",
"{{ $JVB_AUTH_USER }}@{{ $XMPP_AUTH_DOMAIN }}"
}
unlimited_jids = {
"focus@{{ $XMPP_AUTH_DOMAIN }}",
"{{ $JVB_AUTH_USER }}@{{ $XMPP_AUTH_DOMAIN }}"
}
plugin_paths = { "/prosody-plugins-custom", "/prosody-plugins/", "/prosody-plugins-contrib" }
muc_mapper_domain_base = "{{ $XMPP_DOMAIN }}";
muc_mapper_domain_prefix = "{{ $XMPP_MUC_DOMAIN_PREFIX }}";
recorder_prefixes = { "{{ $JIBRI_RECORDER_USER }}@{{ $XMPP_HIDDEN_DOMAIN }}" };
transcriber_prefixes = { "{{ $JIGASI_TRANSCRIBER_USER }}@{{ $XMPP_HIDDEN_DOMAIN }}" };
http_default_host = "{{ $XMPP_DOMAIN }}"
{{ if and $ENABLE_AUTH (or (eq $PROSODY_AUTH_TYPE "jwt") (eq $PROSODY_AUTH_TYPE "hybrid_matrix_token")) .Env.JWT_ACCEPTED_ISSUERS }}
asap_accepted_issuers = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_ISSUERS | compact) }}" }
{{ end }}
{{ if and $ENABLE_AUTH (or (eq $PROSODY_AUTH_TYPE "jwt") (eq $PROSODY_AUTH_TYPE "hybrid_matrix_token")) .Env.JWT_ACCEPTED_AUDIENCES }}
asap_accepted_audiences = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_AUDIENCES | compact) }}" }
{{ end }}
{{ if and $ENABLE_AUTH (or (eq $PROSODY_AUTH_TYPE "jwt") (eq $PROSODY_AUTH_TYPE "hybrid_matrix_token")) .Env.JWT_ACCEPTED_ALLOWNER_ISSUERS }}
allowner_issuers = { "{{ join "\",\"" (splitList "," .Env.JWT_ACCEPTED_ALLOWNER_ISSUERS | compact) }}" }
{{ end }}
consider_bosh_secure = true;
consider_websocket_secure = true;
{{ if $ENABLE_XMPP_WEBSOCKET }}
smacks_max_unacked_stanzas = 5;
smacks_hibernation_time = 60;
smacks_max_old_sessions = 1;
{{ end }}
{{ if $ENABLE_JAAS_COMPONENTS }}
VirtualHost "jigasi.meet.jitsi"
modules_enabled = {
"bosh";
"muc_password_check";
}
authentication = "token"
app_id = "jitsi";
asap_key_server = "https://jaas-public-keys.jitsi.net/jitsi-components/prod-8x8"
asap_accepted_issuers = { "jaas-components" }
asap_accepted_audiences = { "jigasi.{{ $PUBLIC_URL_DOMAIN }}" }
{{ end }}
VirtualHost "{{ $XMPP_DOMAIN }}"
{{ if $ENABLE_AUTH }}
{{ if eq $PROSODY_AUTH_TYPE "jwt" }}
{{ if .Env.JWT_SIGN_TYPE }}
signature_algorithm = "{{ .Env.JWT_SIGN_TYPE }}"
{{ end -}}
authentication = "{{ $JWT_AUTH_TYPE }}"
app_id = "{{ .Env.JWT_APP_ID }}"
{{ if $ENABLE_APP_SECRET }}
app_secret = "{{ .Env.JWT_APP_SECRET }}"
{{ end }}
allow_empty_token = {{ $JWT_ALLOW_EMPTY }}
{{ if $JWT_ASAP_KEYSERVER }}
asap_key_server = "{{ .Env.JWT_ASAP_KEYSERVER }}"
{{ end }}
enable_domain_verification = {{ $JWT_ENABLE_DOMAIN_VERIFICATION }}
{{ else if eq $PROSODY_AUTH_TYPE "ldap" }}
authentication = "cyrus"
cyrus_application_name = "xmpp"
allow_unencrypted_plain_auth = true
{{ else if eq $PROSODY_AUTH_TYPE "matrix" }}
authentication = "matrix_user_verification"
app_id = "{{ $MATRIX_UVS_ISSUER }}"
uvs_base_url = "{{ .Env.MATRIX_UVS_URL }}"
{{ if .Env.MATRIX_UVS_AUTH_TOKEN }}
uvs_auth_token = "{{ .Env.MATRIX_UVS_AUTH_TOKEN }}"
{{ end }}
{{ if $MATRIX_UVS_SYNC_POWER_LEVELS }}
uvs_sync_power_levels = true
{{ end }}
{{ else if eq $PROSODY_AUTH_TYPE "hybrid_matrix_token" }}
authentication = "hybrid_matrix_token"
app_id = "{{ .Env.JWT_APP_ID }}"
{{ if $ENABLE_APP_SECRET }}
app_secret = "{{ .Env.JWT_APP_SECRET }}"
{{ end }}
allow_empty_token = {{ $JWT_ALLOW_EMPTY }}
enable_domain_verification = {{ $JWT_ENABLE_DOMAIN_VERIFICATION }}
uvs_base_url = "{{ .Env.MATRIX_UVS_URL }}"
{{ if .Env.MATRIX_UVS_ISSUER }}
uvs_issuer = "{{ .Env.MATRIX_UVS_ISSUER }}"
{{ end }}
{{ if .Env.MATRIX_UVS_AUTH_TOKEN }}
uvs_auth_token = "{{ .Env.MATRIX_UVS_AUTH_TOKEN }}"
{{ end }}
{{ else if eq $PROSODY_AUTH_TYPE "internal" }}
authentication = "internal_hashed"
disable_sasl_mechanisms={ "DIGEST-MD5", "OAUTHBEARER" }
{{ end }}
{{ else }}
authentication = "jitsi-anonymous"
{{ end }}
ssl = {
key = "/config/certs/{{ $XMPP_DOMAIN }}.key";
certificate = "/config/certs/{{ $XMPP_DOMAIN }}.crt";
}
modules_enabled = {
"bosh";
"features_identity";
{{ if $ENABLE_XMPP_WEBSOCKET }}
"websocket";
"smacks"; -- XEP-0198: Stream Management
{{ end }}
"conference_duration";
{{ if $ENABLE_LOBBY }}
"muc_lobby_rooms";
{{ end }}
{{ if $ENABLE_BREAKOUT_ROOMS }}
"muc_breakout_rooms";
{{ end }}
{{ if .Env.XMPP_MODULES }}
"{{ join "\";\n \"" (splitList "," .Env.XMPP_MODULES | compact) }}";
{{ end }}
{{ if and $ENABLE_AUTH (eq $PROSODY_AUTH_TYPE "ldap") }}
"auth_cyrus";
{{end}}
{{ if $PROSODY_RESERVATION_ENABLED }}
"reservations";
{{ end }}
{{ if $ENABLE_VISITORS }}
"visitors";
{{ end }}
{{- if and $ENABLE_RECORDING_METADATA $ENABLE_AUTH (eq $PROSODY_AUTH_TYPE "jwt") $ENABLE_RECORDING }}
"jibri_session";
{{- end }}
}
main_muc = "{{ $XMPP_MUC_DOMAIN }}"
{{ if $ENABLE_LOBBY }}
lobby_muc = "lobby.{{ $XMPP_DOMAIN }}"
{{ if or $ENABLE_RECORDING $ENABLE_TRANSCRIPTIONS }}
muc_lobby_whitelist = { "{{ $XMPP_HIDDEN_DOMAIN }}" }
{{ end }}
{{ end }}
{{ if $PROSODY_RESERVATION_ENABLED }}
reservations_api_prefix = "{{ $PROSODY_RESERVATION_REST_BASE_URL }}"
{{ end }}
{{ if $ENABLE_BREAKOUT_ROOMS }}
breakout_rooms_muc = "breakout.{{ $XMPP_DOMAIN }}"
{{ end }}
c2s_require_encryption = {{ $C2S_REQUIRE_ENCRYPTION }}
{{ if $ENABLE_VISITORS -}}
visitors_ignore_list = { "{{ $XMPP_HIDDEN_DOMAIN }}" }
{{ end }}
{{ if .Env.XMPP_CONFIGURATION -}}
{{ join "\n " (splitList "," .Env.XMPP_CONFIGURATION | compact) }}
{{ end -}}
{{ if $ENABLE_GUEST_DOMAIN }}
VirtualHost "{{ $XMPP_GUEST_DOMAIN }}"
authentication = "{{ $GUEST_AUTH_TYPE }}"
modules_enabled = {
{{ if $ENABLE_XMPP_WEBSOCKET }}
"smacks"; -- XEP-0198: Stream Management
{{ end }}
{{ if .Env.XMPP_MODULES }}
"{{ join "\";\n \"" (splitList "," .Env.XMPP_MODULES | compact) }}";
{{ end }}
}
main_muc = "{{ $XMPP_MUC_DOMAIN }}"
c2s_require_encryption = {{ $C2S_REQUIRE_ENCRYPTION }}
{{ if $ENABLE_VISITORS }}
allow_anonymous_s2s = true
{{ end }}
{{ if $ENABLE_LOBBY }}
lobby_muc = "lobby.{{ $XMPP_DOMAIN }}"
{{ end }}
{{ if $ENABLE_BREAKOUT_ROOMS }}
breakout_rooms_muc = "breakout.{{ $XMPP_DOMAIN }}"
{{ end }}
{{ if .Env.XMPP_CONFIGURATION -}}
{{ join "\n " (splitList "," .Env.XMPP_CONFIGURATION | compact) }}
{{ end -}}
{{ end }}
VirtualHost "{{ $XMPP_AUTH_DOMAIN }}"
ssl = {
key = "/config/certs/{{ $XMPP_AUTH_DOMAIN }}.key";
certificate = "/config/certs/{{ $XMPP_AUTH_DOMAIN }}.crt";
}
modules_enabled = {
"limits_exception";
{{- if and $ENABLE_RECORDING_METADATA $ENABLE_AUTH (eq $PROSODY_AUTH_TYPE "jwt") $ENABLE_RECORDING }}
"jibri_session";
{{- end }}
"smacks";
}
authentication = "internal_hashed"
smacks_hibernation_time = 15;
{{ if or $ENABLE_RECORDING $ENABLE_TRANSCRIPTIONS }}
VirtualHost "{{ $XMPP_HIDDEN_DOMAIN }}"
modules_enabled = {
"smacks";
}
authentication = "internal_hashed"
{{ end }}
Component "{{ $XMPP_INTERNAL_MUC_DOMAIN }}" "muc"
storage = "memory"
modules_enabled = {
"muc_hide_all";
"muc_filter_access";
{{ if .Env.XMPP_INTERNAL_MUC_MODULES -}}
"{{ join "\";\n\"" (splitList "," .Env.XMPP_INTERNAL_MUC_MODULES | compact) }}";
{{ end -}}
}
restrict_room_creation = true
muc_filter_whitelist="{{ $XMPP_AUTH_DOMAIN }}"
muc_room_locking = false
muc_room_default_public_jids = true
muc_room_cache_size = 1000
muc_tombstones = false
muc_room_allow_persistent = false
Component "{{ $XMPP_MUC_DOMAIN }}" "muc"
restrict_room_creation = true
storage = "memory"
modules_enabled = {
"muc_hide_all";
"muc_meeting_id";
{{ if .Env.XMPP_MUC_MODULES -}}
"{{ join "\";\n \"" (splitList "," .Env.XMPP_MUC_MODULES | compact) }}";
{{ end -}}
{{ if and $ENABLE_AUTH (or (eq $PROSODY_AUTH_TYPE "jwt") (eq $PROSODY_AUTH_TYPE "hybrid_matrix_token")) -}}
"{{ $JWT_TOKEN_AUTH_MODULE }}";
{{ end }}
{{ if and $ENABLE_AUTH (eq $PROSODY_AUTH_TYPE "matrix") $MATRIX_UVS_SYNC_POWER_LEVELS -}}
"matrix_power_sync";
{{ end -}}
{{ if and $ENABLE_AUTH (eq $PROSODY_AUTH_TYPE "hybrid_matrix_token") $MATRIX_UVS_SYNC_POWER_LEVELS -}}
"matrix_affiliation";
{{ end -}}
{{ if and $ENABLE_AUTH (eq $PROSODY_AUTH_TYPE "hybrid_matrix_token") $MATRIX_LOBBY_BYPASS -}}
"matrix_lobby_bypass";
{{ end -}}
{{ if $ENABLE_SUBDOMAINS -}}
"muc_domain_mapper";
{{ end -}}
{{ if $ENABLE_RATE_LIMITS -}}
"muc_rate_limit";
"rate_limit";
{{ end -}}
{{ if .Env.MAX_PARTICIPANTS }}
"muc_max_occupants";
{{ end }}
"muc_password_whitelist";
{{ if $ENABLE_FILTER_MESSAGES }}
"filter_messages";
{{ end }}
}
{{ if $ENABLE_RATE_LIMITS -}}
-- Max allowed join/login rate in events per second.
rate_limit_login_rate = {{ $RATE_LIMIT_LOGIN_RATE }};
-- The rate to which sessions from IPs exceeding the join rate will be limited, in bytes per second.
rate_limit_session_rate = {{ $RATE_LIMIT_SESSION_RATE }};
-- The time in seconds, after which the limit for an IP address is lifted.
rate_limit_timeout = {{ $RATE_LIMIT_TIMEOUT }};
-- List of regular expressions for IP addresses that are not limited by this module.
rate_limit_whitelist = {
"127.0.0.1";
{{ range $index, $cidr := (splitList "," $RATE_LIMIT_ALLOW_RANGES | compact) }}
"{{ $cidr }}";
{{ end }}
};
rate_limit_whitelist_hosts = {
"{{ $XMPP_HIDDEN_DOMAIN }}";
}
{{ end -}}
-- The size of the cache that saves state for IP addresses
rate_limit_cache_size = {{ $RATE_LIMIT_CACHE_SIZE }};
muc_room_cache_size = 10000
muc_room_locking = false
muc_room_default_public_jids = true
{{ if .Env.XMPP_MUC_CONFIGURATION -}}
{{ join "\n " (splitList "," .Env.XMPP_MUC_CONFIGURATION | compact) }}
{{ end -}}
{{ if .Env.MAX_PARTICIPANTS }}
muc_access_whitelist = {
"focus@{{ $XMPP_AUTH_DOMAIN }}";
{{- if $ENABLE_RECORDING }}
"{{ $JIBRI_RECORDER_USER }}@{{ $XMPP_HIDDEN_DOMAIN }}";
{{- end }}
{{- if $ENABLE_TRANSCRIPTIONS }}
"{{ $JIGASI_TRANSCRIBER_USER }}@{{ $XMPP_HIDDEN_DOMAIN }}";
{{- end }}
}
muc_max_occupants = "{{ .Env.MAX_PARTICIPANTS }}"
{{ end }}
muc_password_whitelist = {
"focus@{{ $XMPP_AUTH_DOMAIN }}";
{{- if $ENABLE_RECORDING }}
"{{ $JIBRI_RECORDER_USER }}@{{ $XMPP_HIDDEN_DOMAIN }}";
{{- end }}
{{- if $ENABLE_TRANSCRIPTIONS }}
"{{ $JIGASI_TRANSCRIBER_USER }}@{{ $XMPP_HIDDEN_DOMAIN }}";
{{- end }}
}
muc_tombstones = false
muc_room_allow_persistent = false
{{- if $WAIT_FOR_HOST_DISABLE_AUTO_OWNERS }}
wait_for_host_disable_auto_owners = true
{{- end }}
Component "focus.{{ $XMPP_DOMAIN }}" "client_proxy"
target_address = "focus@{{ $XMPP_AUTH_DOMAIN }}"
Component "speakerstats.{{ $XMPP_DOMAIN }}" "speakerstats_component"
muc_component = "{{ $XMPP_MUC_DOMAIN }}"
{{- if .Env.XMPP_SPEAKERSTATS_MODULES }}
modules_enabled = {
"{{ join "\";\n \"" (splitList "," .Env.XMPP_SPEAKERSTATS_MODULES | compact) }}";
}
{{- end }}
{{ if $ENABLE_END_CONFERENCE }}
Component "endconference.{{ $XMPP_DOMAIN }}" "end_conference"
muc_component = "{{ $XMPP_MUC_DOMAIN }}"
{{ end }}
{{ if $ENABLE_AV_MODERATION }}
Component "avmoderation.{{ $XMPP_DOMAIN }}" "av_moderation_component"
muc_component = "{{ $XMPP_MUC_DOMAIN }}"
{{ end }}
{{ if $ENABLE_LOBBY }}
Component "lobby.{{ $XMPP_DOMAIN }}" "muc"
storage = "memory"
restrict_room_creation = true
muc_tombstones = false
muc_room_allow_persistent = false
muc_room_cache_size = 10000
muc_room_locking = false
muc_room_default_public_jids = true
{{- if .Env.MAX_PARTICIPANTS }}
muc_max_occupants = "{{ .Env.MAX_PARTICIPANTS }}"
{{- end }}
modules_enabled = {
"muc_hide_all";
{{- if $ENABLE_RATE_LIMITS }}
"muc_rate_limit";
{{- end }}
{{- if .Env.MAX_PARTICIPANTS }}
"muc_max_occupants";
{{- end }}
{{- if .Env.XMPP_LOBBY_MUC_MODULES }}
"{{ join "\";\n \"" (splitList "," .Env.XMPP_LOBBY_MUC_MODULES | compact) }}";
{{- end }}
}
{{ end }}
{{ if $ENABLE_BREAKOUT_ROOMS }}
Component "breakout.{{ $XMPP_DOMAIN }}" "muc"
storage = "memory"
restrict_room_creation = true
muc_room_cache_size = 10000
muc_room_locking = false
muc_room_default_public_jids = true
muc_tombstones = false
muc_room_allow_persistent = false
modules_enabled = {
"muc_hide_all";
"muc_meeting_id";
{{ if $ENABLE_RATE_LIMITS -}}
"muc_rate_limit";
{{ end -}}
{{ if .Env.XMPP_BREAKOUT_MUC_MODULES -}}
"{{ join "\";\n \"" (splitList "," .Env.XMPP_BREAKOUT_MUC_MODULES | compact) }}";
{{ end -}}
}
{{ end }}
Component "metadata.{{ $XMPP_DOMAIN }}" "room_metadata_component"
muc_component = "{{ $XMPP_MUC_DOMAIN }}"
breakout_rooms_component = "breakout.{{ $XMPP_DOMAIN }}"
{{ if $ENABLE_VISITORS }}
Component "visitors.{{ $XMPP_DOMAIN }}" "visitors_component"
auto_allow_visitor_promotion = true
always_visitors_enabled = true
{{ end }}
{{ if not $DISABLE_POLLS -}}
Component "polls.{{ $XMPP_DOMAIN }}" "polls_component"
{{ end -}}

View File

@@ -0,0 +1,197 @@
{{ $DISABLE_POLLS := .Env.DISABLE_POLLS | default "false" | toBool -}}
{{ $ENABLE_AUTH := .Env.ENABLE_AUTH | default "0" | toBool -}}
{{ $ENABLE_GUEST_DOMAIN := and $ENABLE_AUTH (.Env.ENABLE_GUESTS | default "0" | toBool) -}}
{{ $ENABLE_RATE_LIMITS := .Env.PROSODY_ENABLE_RATE_LIMITS | default "0" | toBool -}}
{{ $ENABLE_RECORDING := .Env.ENABLE_RECORDING | default "0" | toBool -}}
{{ $ENABLE_SUBDOMAINS := .Env.ENABLE_SUBDOMAINS | default "true" | toBool -}}
{{ $ENABLE_TRANSCRIPTIONS := .Env.ENABLE_TRANSCRIPTIONS | default "0" | toBool -}}
{{ $ENABLE_XMPP_WEBSOCKET := .Env.ENABLE_XMPP_WEBSOCKET | default "1" | toBool -}}
{{ $JIBRI_RECORDER_USER := .Env.JIBRI_RECORDER_USER | default "recorder" -}}
{{ $JIGASI_TRANSCRIBER_USER := .Env.JIGASI_TRANSCRIBER_USER | default "transcriber" -}}
{{ $LIMIT_MESSAGES_CHECK_TOKEN := .Env.PROSODY_LIMIT_MESSAGES_CHECK_TOKEN | default "0" | toBool -}}
{{ $RATE_LIMIT_LOGIN_RATE := .Env.PROSODY_RATE_LIMIT_LOGIN_RATE | default "3" -}}
{{ $RATE_LIMIT_SESSION_RATE := .Env.PROSODY_RATE_LIMIT_SESSION_RATE | default "200" -}}
{{ $RATE_LIMIT_TIMEOUT := .Env.PROSODY_RATE_LIMIT_TIMEOUT | default "60" -}}
{{ $RATE_LIMIT_ALLOW_RANGES := .Env.PROSODY_RATE_LIMIT_ALLOW_RANGES | default "10.0.0.0/8" -}}
{{ $RATE_LIMIT_CACHE_SIZE := .Env.PROSODY_RATE_LIMIT_CACHE_SIZE | default "10000" -}}
{{ $REGION_NAME := .Env.PROSODY_REGION_NAME | default "default" -}}
{{ $RELEASE_NUMBER := .Env.RELEASE_NUMBER | default "" -}}
{{ $SHARD_NAME := .Env.SHARD | default "default" -}}
{{ $S2S_PORT := .Env.PROSODY_S2S_PORT | default "5269" -}}
{{ $VISITOR_INDEX := .Env.PROSODY_VISITOR_INDEX | default "0" -}}
{{ $VISITORS_MUC_PREFIX := .Env.PROSODY_VISITORS_MUC_PREFIX | default "muc" -}}
{{ $VISITORS_MAX_VISITORS_PER_NODE := .Env.VISITORS_MAX_VISITORS_PER_NODE | default "250" }}
{{ $VISITORS_XMPP_DOMAIN := .Env.VISITORS_XMPP_DOMAIN | default "meet.jitsi" -}}
{{ $XMPP_AUTH_DOMAIN := .Env.XMPP_AUTH_DOMAIN | default "auth.meet.jitsi" -}}
{{ $XMPP_DOMAIN := .Env.XMPP_DOMAIN | default "meet.jitsi" -}}
{{ $XMPP_GUEST_DOMAIN := .Env.XMPP_GUEST_DOMAIN | default "guest.meet.jitsi" -}}
{{ $XMPP_MUC_DOMAIN := .Env.XMPP_MUC_DOMAIN | default "muc.meet.jitsi" -}}
{{ $XMPP_MUC_DOMAIN_PREFIX := (split "." $XMPP_MUC_DOMAIN)._0 -}}
{{ $XMPP_SERVER := .Env.XMPP_SERVER | default "xmpp.meet.jitsi" -}}
{{ $XMPP_SERVER_S2S_PORT := .Env.XMPP_SERVER_S2S_PORT | default $S2S_PORT -}}
{{ $XMPP_HIDDEN_DOMAIN := .Env.XMPP_HIDDEN_DOMAIN | default "hidden.meet.jitsi" -}}
plugin_paths = { "/prosody-plugins/", "/prosody-plugins-custom", "/prosody-plugins-contrib" }
muc_mapper_domain_base = "v{{ $VISITOR_INDEX }}.{{ $VISITORS_XMPP_DOMAIN }}";
muc_mapper_domain_prefix = "{{ $XMPP_MUC_DOMAIN_PREFIX }}";
http_default_host = "v{{ $VISITOR_INDEX }}.{{ $VISITORS_XMPP_DOMAIN }}"
main_domain = '{{ $XMPP_DOMAIN }}';
-- https://prosody.im/doc/modules/mod_smacks
smacks_max_unacked_stanzas = 5;
smacks_hibernation_time = 60;
-- this is dropped in 0.12
smacks_max_hibernated_sessions = 1;
smacks_max_old_sessions = 1;
unlimited_jids = { "focus@{{ $XMPP_AUTH_DOMAIN }}" }
limits = {
c2s = {
rate = "512kb/s";
};
s2sin = {
rate = "512kb/s";
};
}
authentication = 'internal_hashed'
storage = 'internal'
consider_websocket_secure = true;
consider_bosh_secure = true;
bosh_max_inactivity = 60;
-- this is added to make certs_s2soutinjection work
s2sout_override = {
["{{ $XMPP_MUC_DOMAIN }}"] = "tcp://{{ $XMPP_SERVER }}:{{ $XMPP_SERVER_S2S_PORT }}"; -- needed for visitors to send messages to main room
["{{ $XMPP_DOMAIN }}"] = "tcp://{{ $XMPP_SERVER }}:{{ $XMPP_SERVER_S2S_PORT }}";
["visitors.{{ $XMPP_DOMAIN }}"] = "tcp://{{ $XMPP_SERVER }}:{{ $XMPP_SERVER_S2S_PORT }}";
{{ if $ENABLE_GUEST_DOMAIN -}}
["{{ $XMPP_GUEST_DOMAIN }}"] = "tcp://{{ $XMPP_SERVER }}:{{ $XMPP_SERVER_S2S_PORT }}";
{{ end -}}
{{ if or $ENABLE_RECORDING $ENABLE_TRANSCRIPTIONS -}}
["{{ $XMPP_HIDDEN_DOMAIN }}"] = "tcp://{{ $XMPP_SERVER }}:{{ $XMPP_SERVER_S2S_PORT }}";
{{ end -}}
{{ if .Env.PROSODY_VISITORS_S2S_VHOSTS -}}
{{- range $index, $vhost := (splitList "," .Env.PROSODY_VISITORS_S2S_VHOSTS | compact) }}
["{{ $vhost }}"] = "tcp://{{ $XMPP_SERVER }}:{{ $XMPP_SERVER_S2S_PORT }}";
{{ end -}}
{{ end -}}
{{ if not $DISABLE_POLLS -}}
['polls.{{ $XMPP_DOMAIN }}'] = "tcp://{{ $XMPP_SERVER }}:{{ $XMPP_SERVER_S2S_PORT }}";
{{ end -}}
}
muc_limit_messages_count = 10;
muc_limit_messages_check_token = {{ $LIMIT_MESSAGES_CHECK_TOKEN }};
----------- Virtual hosts -----------
VirtualHost 'v{{ $VISITOR_INDEX }}.{{ $VISITORS_XMPP_DOMAIN }}'
authentication = 'jitsi-anonymous'
ssl = {
key = "/config/certs/v{{ $VISITOR_INDEX }}.{{ $VISITORS_XMPP_DOMAIN }}.key";
certificate = "/config/certs/v{{ $VISITOR_INDEX }}.{{ $VISITORS_XMPP_DOMAIN }}.crt";
}
modules_enabled = {
'bosh';
"external_services";
{{ if $ENABLE_XMPP_WEBSOCKET -}}
"websocket";
"smacks"; -- XEP-0198: Stream Management
{{ end -}}
{{ if .Env.XMPP_MODULES }}
"{{ join "\";\n\"" (splitList "," .Env.XMPP_MODULES | compact) }}";
{{ end }}
'features_identity';
}
main_muc = '{{ $VISITORS_MUC_PREFIX }}.v{{ $VISITOR_INDEX }}.{{ $VISITORS_XMPP_DOMAIN }}';
shard_name = "{{ $SHARD_NAME }}"
region_name = "{{ $REGION_NAME }}"
release_number = "{{ $RELEASE_NUMBER }}"
{{ if .Env.XMPP_CONFIGURATION -}}
{{ join "\n " (splitList "," .Env.XMPP_CONFIGURATION | compact) }}
{{- end }}
VirtualHost '{{ $XMPP_AUTH_DOMAIN }}'
modules_enabled = {
'limits_exception';
'smacks';
}
authentication = 'internal_hashed'
smacks_hibernation_time = 15;
Component '{{ $VISITORS_MUC_PREFIX }}.v{{ $VISITOR_INDEX }}.{{ $VISITORS_XMPP_DOMAIN }}' 'muc'
storage = 'memory'
muc_room_cache_size = 10000
restrict_room_creation = true
modules_enabled = {
"muc_hide_all";
"muc_meeting_id";
'fmuc';
's2s_bidi';
's2s_whitelist';
's2sout_override';
'muc_max_occupants';
{{ if $ENABLE_SUBDOMAINS -}}
"muc_domain_mapper";
{{ end -}}
{{ if $ENABLE_RATE_LIMITS -}}
"muc_rate_limit";
"rate_limit";
{{ end -}}
{{ if .Env.XMPP_MUC_MODULES -}}
"{{ join "\";\n\"" (splitList "," .Env.XMPP_MUC_MODULES | compact) }}";
{{ end -}}
}
muc_room_default_presence_broadcast = {
visitor = false;
participant = true;
moderator = true;
};
muc_room_locking = false
muc_room_default_public_jids = true
muc_max_occupants = {{ $VISITORS_MAX_VISITORS_PER_NODE}}
muc_access_whitelist = {
"{{ $XMPP_DOMAIN }}";
}
muc_tombstones = false
muc_room_allow_persistent = false
{{ if $ENABLE_RATE_LIMITS -}}
-- Max allowed join/login rate in events per second.
rate_limit_login_rate = {{ $RATE_LIMIT_LOGIN_RATE }};
-- The rate to which sessions from IPs exceeding the join rate will be limited, in bytes per second.
rate_limit_session_rate = {{ $RATE_LIMIT_SESSION_RATE }};
-- The time in seconds, after which the limit for an IP address is lifted.
rate_limit_timeout = {{ $RATE_LIMIT_TIMEOUT }};
-- List of regular expressions for IP addresses that are not limited by this module.
rate_limit_whitelist = {
"127.0.0.1";
{{ range $index, $cidr := (splitList "," $RATE_LIMIT_ALLOW_RANGES) -}}
"{{ $cidr }}";
{{ end -}}
};
rate_limit_whitelist_jids = {
"{{ $JIBRI_RECORDER_USER }}@{{ $XMPP_HIDDEN_DOMAIN }}",
"{{ $JIGASI_TRANSCRIBER_USER }}@{{ $XMPP_HIDDEN_DOMAIN }}"
}
{{ end -}}
-- The size of the cache that saves state for IP addresses
rate_limit_cache_size = {{ $RATE_LIMIT_CACHE_SIZE }};
muc_rate_joins = 30;
{{ if .Env.XMPP_MUC_CONFIGURATION -}}
{{ join "\n" (splitList "," .Env.XMPP_MUC_CONFIGURATION | compact) }}
{{ end -}}
{{ if not $DISABLE_POLLS -}}
Component 'polls.v{{ $VISITOR_INDEX }}.{{ $VISITORS_XMPP_DOMAIN }}' 'polls_component'
{{ end -}}

View File

@@ -0,0 +1,439 @@
{{ $C2S_REQUIRE_ENCRYPTION := .Env.PROSODY_C2S_REQUIRE_ENCRYPTION | default "1" | toBool -}}
{{ $DISABLE_C2S_LIMIT := .Env.PROSODY_DISABLE_C2S_LIMIT | default "0" | toBool -}}
{{ $DISABLE_POLLS := .Env.DISABLE_POLLS | default "false" | toBool -}}
{{ $DISABLE_S2S_LIMIT := .Env.PROSODY_DISABLE_S2S_LIMIT | default "0" | toBool -}}
{{ $ENABLE_AUTH := .Env.ENABLE_AUTH | default "0" | toBool -}}
{{ $ENABLE_GUEST_DOMAIN := and $ENABLE_AUTH (.Env.ENABLE_GUESTS | default "0" | toBool) -}}
{{ $ENABLE_IPV6 := .Env.ENABLE_IPV6 | default "true" | toBool -}}
{{ $ENABLE_RECORDING := .Env.ENABLE_RECORDING | default "0" | toBool -}}
{{ $ENABLE_TRANSCRIPTIONS := .Env.ENABLE_TRANSCRIPTIONS | default "0" | toBool -}}
{{ $ENABLE_VISITORS := .Env.ENABLE_VISITORS | default "0" | toBool -}}
{{ $ENABLE_S2S := or $ENABLE_VISITORS ( .Env.PROSODY_ENABLE_S2S | default "0" | toBool ) }}
{{ $GC_TYPE := .Env.GC_TYPE | default "incremental" -}}
{{ $GC_INC_TH := .Env.GC_INC_TH | default 400 -}}
{{ $GC_INC_SPEED := .Env.GC_INC_SPEED | default 250 -}}
{{ $GC_INC_STEP_SIZE := .Env.GC_INC_STEP_SIZE | default 13 -}}
{{ $GC_GEN_MIN_TH := .Env.GC_GEN_MIN_TH | default 20 -}}
{{ $GC_GEN_MAX_TH := .Env.GC_GEN_MAX_TH | default 100 -}}
{{ $LOG_LEVEL := .Env.LOG_LEVEL | default "info" }}
{{ $PROSODY_C2S_LIMIT := .Env.PROSODY_C2S_LIMIT | default "10kb/s" -}}
{{ $PROSODY_METRICS_ALLOWED_CIDR := .Env.PROSODY_METRICS_ALLOWED_CIDR | default "172.16.0.0/12" -}}
{{ $PROSODY_HTTP_PORT := .Env.PROSODY_HTTP_PORT | default "5280" -}}
{{ $PROSODY_ENABLE_METRICS := .Env.PROSODY_ENABLE_METRICS | default "false" | toBool -}}
{{ $PROSODY_ENABLE_STANZA_COUNTS := .Env.PROSODY_ENABLE_STANZA_COUNTS | default "false" | toBool -}}
{{ $PROSODY_ADMINS := .Env.PROSODY_ADMINS | default "" -}}
{{ $PROSODY_ADMIN_LIST := splitList "," $PROSODY_ADMINS | compact -}}
{{ $PROSODY_MODE := .Env.PROSODY_MODE | default "client" -}}
{{ $TRUSTED_PROXIES := .Env.PROSODY_TRUSTED_PROXIES | default "127.0.0.1,::1" -}}
{{ $TRUSTED_PROXY_LIST := splitList "," $TRUSTED_PROXIES | compact -}}
{{ $PROSODY_S2S_LIMIT := .Env.PROSODY_S2S_LIMIT | default "30kb/s" -}}
{{ $S2S_PORT := .Env.PROSODY_S2S_PORT | default "5269" }}
{{ $STUN_HOST := .Env.STUN_HOST | default "" -}}
{{ $STUN_PORT := .Env.STUN_PORT | default "443" -}}
{{ $TURNS_HOST := .Env.TURNS_HOST | default "" -}}
{{ $TURNS_HOSTS := splitList "," $TURNS_HOST | compact -}}
{{ $TURNS_PORT := .Env.TURNS_PORT | default "443" -}}
{{ $TURN_HOST := .Env.TURN_HOST | default "" -}}
{{ $TURN_HOSTS := splitList "," $TURN_HOST | compact -}}
{{ $TURN_PORT := .Env.TURN_PORT | default "443" -}}
{{ $TURN_TRANSPORT := .Env.TURN_TRANSPORT | default "tcp" -}}
{{ $TURN_TRANSPORTS := splitList "," $TURN_TRANSPORT | compact -}}
{{ $TURN_TTL := .Env.TURN_TTL | default "86400" -}}
{{ $VISITORS_MUC_PREFIX := .Env.PROSODY_VISITORS_MUC_PREFIX | default "muc" -}}
{{ $VISITORS_XMPP_DOMAIN := .Env.VISITORS_XMPP_DOMAIN | default "meet.jitsi" -}}
{{ $VISITORS_XMPP_SERVER := .Env.VISITORS_XMPP_SERVER | default "" -}}
{{ $VISITORS_XMPP_SERVERS := splitList "," $VISITORS_XMPP_SERVER | compact -}}
{{ $VISITORS_XMPP_PORT := .Env.VISITORS_XMPP_PORT | default 52220 }}
{{ $XMPP_DOMAIN := .Env.XMPP_DOMAIN | default "meet.jitsi" -}}
{{ $XMPP_GUEST_DOMAIN := .Env.XMPP_GUEST_DOMAIN | default "guest.meet.jitsi" -}}
{{ $XMPP_MUC_DOMAIN := .Env.XMPP_MUC_DOMAIN | default "muc.meet.jitsi" -}}
{{ $XMPP_PORT := .Env.XMPP_PORT | default "5222" -}}
{{ $XMPP_HIDDEN_DOMAIN := .Env.XMPP_HIDDEN_DOMAIN | default "hidden.meet.jitsi" -}}
-- Prosody Example Configuration File
--
-- Information on configuring Prosody can be found on our
-- website at http://prosody.im/doc/configure
--
-- Tip: You can check that the syntax of this file is correct
-- when you have finished by running: luac -p prosody.cfg.lua
-- If there are any errors, it will let you know what and where
-- they are, otherwise it will keep quiet.
--
-- The only thing left to do is rename this file to remove the .dist ending, and fill in the
-- blanks. Good luck, and happy Jabbering!
---------- Server-wide settings ----------
-- Settings in this section apply to the whole server and are the default settings
-- for any virtual hosts
-- This is a (by default, empty) list of accounts that are admins
-- for the server. Note that you must create the accounts separately
-- (see http://prosody.im/doc/creating_accounts for info)
-- Example: admins = { "user1@example.com", "user2@example.net" }
admins = { {{ if .Env.PROSODY_ADMINS }}{{ range $index, $element := $PROSODY_ADMIN_LIST -}}{{ if $index }}, {{ end }}"{{ $element }}"{{ end }}{{ end }} }
component_admins_as_room_owners = true
-- Enable use of libevent for better performance under high load
-- For more information see: http://prosody.im/doc/libevent
--use_libevent = true;
-- This is the list of modules Prosody will load on startup.
-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
-- Documentation on modules can be found at: http://prosody.im/doc/modules
modules_enabled = {
-- Generally required
"roster"; -- Allow users to have a roster. Recommended ;)
"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
"tls"; -- Add support for secure TLS on c2s/s2s connections
"disco"; -- Service discovery
{{- if eq $PROSODY_MODE "client" }}
-- Not essential, but recommended
"private"; -- Private XML storage (for room bookmarks, etc.)
"limits"; -- Enable bandwidth limiting for XMPP connections
-- These are commented by default as they have a performance impact
--"privacy"; -- Support privacy lists
--"compression"; -- Stream compression (Debian: requires lua-zlib module to work)
-- Admin interfaces
-- "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
--"admin_telnet"; -- Opens telnet console interface on localhost port 5582
-- Nice to have
"version"; -- Replies to server version requests
{{- end }}
"ping"; -- Replies to XMPP pings with pongs
{{- if eq $PROSODY_MODE "visitors" }}
"limits"; -- Enable bandwidth limiting for XMPP connections
{{- end }}
-- HTTP modules
--"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
--"http_files"; -- Serve static files from a directory over HTTP
-- Other specific functionality
"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
--"groups"; -- Shared roster support
--"announce"; -- Send announcement to all online users
--"welcome"; -- Welcome users who register accounts
--"watchregistrations"; -- Alert admins of registrations
--"motd"; -- Send a message to users when they log in
--"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
"http_health";
{{ if eq $PROSODY_MODE "brewery" -}}
"firewall"; -- Enable firewalling
"secure_interfaces";
{{ end -}}
{{ if $ENABLE_S2S -}}
"s2s_bidi";
"certs_s2soutinjection";
"s2sout_override";
"s2s_whitelist";
{{ end -}}
{{- if or .Env.TURN_HOST .Env.TURNS_HOST }}
"external_services";
{{- end }}
{{ if $PROSODY_ENABLE_METRICS }}
-- metrics collection functionality
"http_openmetrics";
{{ end -}}
{{ if $PROSODY_ENABLE_STANZA_COUNTS }}
-- Stanza count metrics for monitoring
"measure_stanza_counts";
{{ end -}}
{{ if .Env.GLOBAL_MODULES }}
"{{ join "\";\n\"" (splitList "," .Env.GLOBAL_MODULES | compact) }}";
{{ end }}
};
component_ports = { }
https_ports = { }
trusted_proxies = {
{{ range $index, $proxy := $TRUSTED_PROXY_LIST }}
"{{ $proxy }}";
{{ end }}
}
{{ if eq $PROSODY_MODE "brewery" -}}
firewall_scripts = {
"/config/rules.d/jvb_muc_presence_filter.pfw";
};
{{ end -}}
-- These modules are auto-loaded, but should you want
-- to disable them then uncomment them here:
modules_disabled = {
"offline"; -- Store offline messages
"register";
-- "c2s"; -- Handle client connections
{{ if not $ENABLE_S2S -}}
"s2s"; -- Handle server-to-server connections
{{ end -}}
};
-- Disable account creation by default, for security
-- For more information see http://prosody.im/doc/creating_accounts
allow_registration = false;
{{ if and (ne $PROSODY_MODE "brewery") (or (not $DISABLE_C2S_LIMIT) (not $DISABLE_S2S_LIMIT)) -}}
-- Enable rate limits for incoming connections
limits = {
{{ if not $DISABLE_C2S_LIMIT }}
-- Limit incoming client connections
c2s = {
rate = "{{ $PROSODY_C2S_LIMIT }}";
};
{{ end }}
{{ if not $DISABLE_S2S_LIMIT }}
-- Limit incoming server connections
s2sin = {
rate = "{{ $PROSODY_S2S_LIMIT }}";
};
{{ end }}
}
{{ end -}}
--Prosody garbage collector settings
--For more information see https://prosody.im/doc/advanced_gc
{{ if eq $GC_TYPE "generational" }}
gc = {
mode = "generational";
minor_threshold = {{ $GC_GEN_MIN_TH }};
major_threshold = {{ $GC_GEN_MAX_TH }};
}
{{ else }}
gc = {
mode = "incremental";
threshold = {{ $GC_INC_TH }};
speed = {{ $GC_INC_SPEED }};
step_size = {{ $GC_INC_STEP_SIZE }};
}
{{ end }}
pidfile = "/config/data/prosody.pid";
-- Force clients to use encrypted connections? This option will
-- prevent clients from authenticating unless they are using encryption.
c2s_require_encryption = {{ $C2S_REQUIRE_ENCRYPTION }};
-- set c2s port
c2s_ports = { {{ $XMPP_PORT }} } -- Listen on specific c2s port
{{ if $ENABLE_IPV6 }}
c2s_interfaces = { "*", "::" }
{{ else }}
c2s_interfaces = { "*" }
{{ end }}
{{ if $ENABLE_S2S -}}
-- set s2s port
s2s_ports = { {{ $S2S_PORT }} } -- Listen on specific s2s port
{{ if eq $PROSODY_MODE "visitors" -}}
s2s_whitelist = {
{{- if $ENABLE_VISITORS }}
'{{ $XMPP_MUC_DOMAIN }}'; -- needed for visitors to send messages to main room
'visitors.{{ $XMPP_DOMAIN }}'; -- needed for sending promotion request to visitors.{{ $XMPP_DOMAIN }} component
'{{ $XMPP_DOMAIN }}'; -- unavailable presences back to main room
{{- if not $DISABLE_POLLS }}
'polls.{{ $XMPP_DOMAIN }}';
{{- end }}
{{- end }}
{{- if $ENABLE_GUEST_DOMAIN }}
'{{ $XMPP_GUEST_DOMAIN }}';
{{- end }}
{{ if or $ENABLE_RECORDING $ENABLE_TRANSCRIPTIONS -}}
'{{ $XMPP_HIDDEN_DOMAIN }}';
{{- end }}
{{- if .Env.PROSODY_VISITORS_S2S_VHOSTS }}
'{{ join "';\n '" (splitList "," .Env.PROSODY_VISITORS_S2S_VHOSTS | compact) }}';
{{- end }}
}
{{ end -}}
{{ end -}}
{{ if $ENABLE_VISITORS -}}
{{ if $.Env.VISITORS_XMPP_SERVER -}}
s2sout_override = {
{{ range $index, $element := $VISITORS_XMPP_SERVERS -}}
{{ $SERVER := splitn ":" 2 $element }}
{{ $DEFAULT_PORT := add $VISITORS_XMPP_PORT $index }}
["{{ $VISITORS_MUC_PREFIX }}.v{{ $index }}.{{ $VISITORS_XMPP_DOMAIN }}"] = "tcp://{{ $SERVER._0 }}:{{ $SERVER._1 | default $DEFAULT_PORT }}";
["v{{ $index }}.{{ $VISITORS_XMPP_DOMAIN }}"] = "tcp://{{ $SERVER._0 }}:{{ $SERVER._1 | default $DEFAULT_PORT }}";
["polls.v{{ $index }}.{{ $VISITORS_XMPP_DOMAIN }}"] = "tcp://{{ $SERVER._0 }}:{{ $SERVER._1 | default $DEFAULT_PORT }}";
{{ end -}}
};
{{ if ne $PROSODY_MODE "visitors" -}}
s2s_whitelist = {
{{ range $index, $element := $VISITORS_XMPP_SERVERS -}}
"{{ $VISITORS_MUC_PREFIX }}.v{{ $index }}.{{ $VISITORS_XMPP_DOMAIN }}";
"polls.v{{ $index }}.{{ $VISITORS_XMPP_DOMAIN }}";
{{ end -}}
};
{{ end -}}
{{ end -}}
{{ end -}}
-- Force certificate authentication for server-to-server connections?
-- This provides ideal security, but requires servers you communicate
-- with to support encryption AND present valid, trusted certificates.
-- NOTE: Your version of LuaSec must support certificate verification!
-- For more information see http://prosody.im/doc/s2s#security
s2s_secure_auth = false
-- Many servers don't support encryption or have invalid or self-signed
-- certificates. You can list domains here that will not be required to
-- authenticate using certificates. They will be authenticated using DNS.
--s2s_insecure_domains = { "gmail.com" }
-- Even if you leave s2s_secure_auth disabled, you can still require valid
-- certificates for some domains by specifying a list here.
--s2s_secure_domains = { "jabber.org" }
-- Select the authentication backend to use. The 'internal' providers
-- use Prosody's configured data storage to store the authentication data.
-- To allow Prosody to offer secure authentication mechanisms to clients, the
-- default provider stores passwords in plaintext. If you do not trust your
-- server please see http://prosody.im/doc/modules/mod_auth_internal_hashed
-- for information about using the hashed backend.
authentication = "internal_hashed"
-- Select the storage backend to use. By default Prosody uses flat files
-- in its configured data directory, but it also supports more backends
-- through modules. An "sql" backend is included by default, but requires
-- additional dependencies. See http://prosody.im/doc/storage for more info.
--storage = "sql" -- Default is "internal" (Debian: "sql" requires one of the
-- lua-dbi-sqlite3, lua-dbi-mysql or lua-dbi-postgresql packages to work)
-- For the "sql" backend, you can uncomment *one* of the below to configure:
--sql = { driver = "SQLite3", database = "prosody.sqlite" } -- Default. 'database' is the filename.
--sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
--sql = { driver = "PostgreSQL", database = "prosody", username = "prosody", password = "secret", host = "localhost" }
-- Logging configuration
-- For advanced logging see http://prosody.im/doc/logging
--
-- Debian:
-- Logs info and higher to /var/log
-- Logs errors to syslog also
log = {
{ levels = {min = "{{ $LOG_LEVEL }}"}, timestamps = "%Y-%m-%d %X", to = "console"};
{{ if .Env.PROSODY_LOG_CONFIG }}
{{ join "\n" (splitList "\\n" .Env.PROSODY_LOG_CONFIG | compact) }}
{{ end }}
}
{{ if $PROSODY_ENABLE_METRICS }}
-- Statistics Provider configuration
statistics = "internal"
statistics_interval = "manual"
openmetrics_allow_cidr = "{{ $PROSODY_METRICS_ALLOWED_CIDR }}"
{{ end }}
{{ if .Env.TURN_CREDENTIALS -}}
external_service_secret = "{{.Env.TURN_CREDENTIALS}}";
{{- end }}
{{ if or .Env.STUN_HOST .Env.TURN_HOST .Env.TURNS_HOST -}}
external_services = {
{{- if $STUN_HOST }}
{ type = "stun", host = "{{ $STUN_HOST }}", port = {{ $STUN_PORT }}, transport = "udp" }
{{- end }}
{{- if $TURN_HOST -}}
{{- range $idx1, $host := $TURN_HOSTS -}}
{{- range $idx2, $transport := $TURN_TRANSPORTS -}}
{{- if or $STUN_HOST $idx1 $idx2 -}},{{- end }}
{
type = "turn",
host = "{{ $host }}",
port = {{ $TURN_PORT }},
transport = "{{ $transport }}",
ttl = {{ $TURN_TTL }},
{{ if $.Env.TURN_CREDENTIALS -}}
secret = true,
algorithm = "turn",
{{- end }}
{{ if $.Env.TURN_USERNAME -}}
username = "{{$.Env.TURN_USERNAME}}",
{{- end }}
{{ if $.Env.TURN_PASSWORD -}}
password = "{{$.Env.TURN_PASSWORD}}",
{{- end }}
}
{{- end -}}
{{- end -}}
{{- end -}}
{{- if $TURNS_HOST -}}
{{- range $idx, $host := $TURNS_HOSTS -}}
{{- if or $STUN_HOST $TURN_HOST $idx -}},{{- end }}
{
type = "turns",
host = "{{ $host }}",
port = {{ $TURNS_PORT }},
transport = "tcp",
ttl = {{ $TURN_TTL }},
{{ if $.Env.TURN_CREDENTIALS -}}
secret = true,
algorithm = "turn",
{{- end }}
{{ if $.Env.TURN_USERNAME -}}
username = "{{$.Env.TURN_USERNAME}}",
{{- end }}
{{ if $.Env.TURN_PASSWORD -}}
password = "{{$.Env.TURN_PASSWORD}}",
{{- end }}
}
{{- end }}
{{- end }}
};
{{- end }}
{{ if .Env.GLOBAL_CONFIG }}
{{ join "\n" (splitList "\\n" .Env.GLOBAL_CONFIG | compact) }}
{{ end }}
-- Enable use of native prosody 0.11 support for epoll over select
network_backend = "epoll";
-- Set the TCP backlog to 511 since the kernel rounds it up to the next power of 2: 512.
network_settings = {
tcp_backlog = 511;
}
unbound = {
resolvconf = true
}
http_ports = { {{ $PROSODY_HTTP_PORT }} }
{{ if $ENABLE_IPV6 }}
http_interfaces = { "*", "::" }
{{ else }}
http_interfaces = { "*" }
{{ end }}
data_path = "/config/data"
Include "conf.d/*.cfg.lua"

View File

@@ -0,0 +1,13 @@
{{ $JVB_XMPP_AUTH_DOMAIN := .Env.JVB_XMPP_AUTH_DOMAIN | default "auth.jvb.meet.jitsi" -}}
{{ $JVB_XMPP_INTERNAL_MUC_DOMAIN := .Env.JVB_XMPP_INTERNAL_MUC_DOMAIN | default "muc.jvb.meet.jitsi" -}}
{{ $JVB_AUTH_USER := .Env.JVB_AUTH_USER | default "jvb" -}}
{{ $JVB_BREWERY_MUC := .Env.JVB_BREWERY_MUC | default "jvbbrewery" -}}
# Drop all presence from a jvb in a MUC to a jvb
FROM: {{ $JVB_BREWERY_MUC }}@{{ $JVB_XMPP_INTERNAL_MUC_DOMAIN }}
TO: {{ $JVB_AUTH_USER }}@{{ $JVB_XMPP_AUTH_DOMAIN }}
KIND: presence
# Seems safer to allow all "unavailable" to pass
TYPE: available
# Allow self-presence (code=110)
NOT INSPECT: {http://jabber.org/protocol/muc#user}x/status@code=110
DROP.

View File

@@ -0,0 +1,30 @@
{{ $AUTH_TYPE := .Env.AUTH_TYPE | default "internal" -}}
{{ $PROSODY_AUTH_TYPE := .Env.PROSODY_AUTH_TYPE | default $AUTH_TYPE }}
{{ $XMPP_DOMAIN := .Env.XMPP_DOMAIN | default "meet.jitsi" -}}
{{ if eq $PROSODY_AUTH_TYPE "ldap" }}
ldap_servers: {{ .Env.LDAP_URL }}
ldap_search_base: {{ .Env.LDAP_BASE }}
{{ if .Env.LDAP_BINDDN | default "" }}
ldap_bind_dn: {{ .Env.LDAP_BINDDN }}
ldap_bind_pw: {{ .Env.LDAP_BINDPW }}
{{ end }}
ldap_filter: {{ .Env.LDAP_FILTER | default "uid=%u" }}
ldap_version: {{ .Env.LDAP_VERSION | default "3" }}
ldap_auth_method: {{ .Env.LDAP_AUTH_METHOD | default "bind" }}
{{ if .Env.LDAP_USE_TLS | default "0" | toBool }}
ldap_tls_key: /config/certs/{{ $XMPP_DOMAIN }}.key
ldap_tls_cert: /config/certs/{{ $XMPP_DOMAIN }}.crt
{{ if .Env.LDAP_TLS_CHECK_PEER | default "0" | toBool }}
ldap_tls_check_peer: yes
ldap_tls_cacert_file: {{ .Env.LDAP_TLS_CACERT_FILE | default "/etc/ssl/certs/ca-certificates.crt" }}
ldap_tls_cacert_dir: {{ .Env.LDAP_TLS_CACERT_DIR | default "/etc/ssl/certs" }}
{{ end }}
{{ if .Env.LDAP_TLS_CIPHERS }}
ldap_tls_ciphers: {{ .Env.LDAP_TLS_CIPHERS }}
{{ end }}
{{ end }}
{{ end }}
{{ if .Env.LDAP_START_TLS | default "0" | toBool }}
ldap_start_tls: yes
{{ end }}

View File

@@ -0,0 +1,168 @@
#!/usr/bin/with-contenv bash
if [[ ! -f /etc/saslauthd.conf ]] && [[ "$AUTH_TYPE" == "ldap" ]]; then
tpl /defaults/saslauthd.conf > /etc/saslauthd.conf
mkdir -pm777 /var/run/saslauthd
adduser prosody sasl
echo >> /etc/ldap/ldap.conf "TLS_REQCERT allow"
fi
PROSODY_CFG="/config/prosody.cfg.lua"
if [[ ! -d /config/data ]]; then
mkdir -pm 750 /config/data
fi
if [[ "$(stat -c %U /config)" != "prosody" ]]; then
chown -R prosody /config
fi
if [[ "$(stat -c %U /prosody-plugins)" != "prosody" ]]; then
chown -R prosody /prosody-plugins
fi
if [[ "$(stat -c %U /prosody-plugins-custom)" != "prosody" ]]; then
chown -R prosody /prosody-plugins-custom
fi
if [[ "$(stat -c %U /prosody-plugins-contrib)" != "prosody" ]]; then
chown -R prosody /prosody-plugins-contrib
fi
mkdir /config/certs
cp -r /defaults/* /config
[ -z "$PROSODY_MODE" ] && export PROSODY_MODE="client"
if [[ "$PROSODY_MODE" == "visitors" ]]; then
echo "Prosody visitor mode, using alternate config"
PROSODY_SITE_CFG="visitors.cfg.lua"
rm /config/conf.d/jitsi-meet.cfg.lua
rm /config/conf.d/brewery.cfg.lua
# force jicofo into auth domain for visitor-mode prosody
[ -z "$XMPP_AUTH_DOMAIN" ] && XMPP_AUTH_DOMAIN="auth.meet.jitsi"
export PROSODY_ADMINS="focus@$XMPP_AUTH_DOMAIN"
elif [[ "$PROSODY_MODE" == "brewery" ]]; then
echo "Prosody brewery mode, using alternate config"
PROSODY_SITE_CFG="brewery.cfg.lua"
rm /config/conf.d/jitsi-meet.cfg.lua
rm /config/conf.d/visitors.cfg.lua
# force jicofo into auth domain for brewer prosody
[ -z "$JVB_XMPP_AUTH_DOMAIN" ] && JVB_XMPP_AUTH_DOMAIN="auth.meet.jitsi"
# ensure proper certs are generated
export XMPP_AUTH_DOMAIN="$JVB_XMPP_AUTH_DOMAIN"
# brewery mode requires C2S encryption
export PROSODY_C2S_REQUIRE_ENCRYPTION="true"
mkdir -p /config/rules.d
tpl /defaults/rules.d/jvb_muc_presence_filter.pfw > /config/rules.d/jvb_muc_presence_filter.pfw
else
echo "Prosody normal mode, using default config"
PROSODY_SITE_CFG="jitsi-meet.cfg.lua"
rm /config/conf.d/visitors.cfg.lua
rm /config/conf.d/brewery.cfg.lua
fi
tpl /defaults/prosody.cfg.lua > $PROSODY_CFG
tpl /defaults/conf.d/$PROSODY_SITE_CFG > /config/conf.d/$PROSODY_SITE_CFG
if [[ -z $JICOFO_AUTH_PASSWORD ]]; then
echo 'FATAL ERROR: Jicofo auth password must be set'
exit 1
fi
# Defaults
[ -z "${JIBRI_RECORDER_USER}" ] && export JIBRI_RECORDER_USER=recorder
[ -z "${JIBRI_XMPP_USER}" ] && export JIBRI_XMPP_USER=jibri
[ -z "${JIGASI_XMPP_USER}" ] && export JIGASI_XMPP_USER=jigasi
[ -z "${JVB_AUTH_USER}" ] && export JVB_AUTH_USER=jvb
[ -z "${XMPP_DOMAIN}" ] && export XMPP_DOMAIN=meet.jitsi
[ -z "${XMPP_AUTH_DOMAIN}" ] && export XMPP_AUTH_DOMAIN=auth.meet.jitsi
# maintain backward compatibility with older variable
[ -z "${XMPP_HIDDEN_DOMAIN}" ] && export XMPP_HIDDEN_DOMAIN="$XMPP_RECORDER_DOMAIN"
[ -z "${XMPP_HIDDEN_DOMAIN}" ] && export XMPP_HIDDEN_DOMAIN=hidden.meet.jitsi
prosodyctl --config $PROSODY_CFG register focus $XMPP_AUTH_DOMAIN $JICOFO_AUTH_PASSWORD
# if we are in client mode, we need to subscribe the focus user to the focus component proxy
if [[ "$PROSODY_MODE" == "client" ]]; then
prosodyctl --config $PROSODY_CFG mod_roster_command subscribe focus.$XMPP_DOMAIN focus@$XMPP_AUTH_DOMAIN
fi
if [[ -z $JVB_AUTH_PASSWORD ]]; then
echo 'FATAL ERROR: JVB auth password must be set'
exit 1
fi
OLD_JVB_AUTH_PASSWORD=passw0rd
if [[ "$JVB_AUTH_PASSWORD" == "$OLD_JVB_AUTH_PASSWORD" ]]; then
echo 'FATAL ERROR: JVB auth password must be changed, check the README'
exit 1
fi
# we see the next register command to hang from time to time, suspect it's a race with mod_roster_command
# Once this is released: https://issues.prosody.im/1908 we can remove this sleep and make sure prosody is running
# and then use 'prosodyctl shell user create' to add user live and 'prosodyctl shell roster' to modify their roster live.
sleep 1
prosodyctl --config $PROSODY_CFG register $JVB_AUTH_USER $XMPP_AUTH_DOMAIN $JVB_AUTH_PASSWORD
if [[ ! -z $JIBRI_XMPP_PASSWORD ]]; then
OLD_JIBRI_XMPP_PASSWORD=passw0rd
if [[ "$JIBRI_XMPP_PASSWORD" == "$OLD_JIBRI_XMPP_PASSWORD" ]]; then
echo 'FATAL ERROR: Jibri auth password must be changed, check the README'
exit 1
fi
prosodyctl --config $PROSODY_CFG register $JIBRI_XMPP_USER $XMPP_AUTH_DOMAIN $JIBRI_XMPP_PASSWORD
fi
if [[ "$PROSODY_MODE" == "client" ]]; then
if [[ ! -z $JIBRI_RECORDER_PASSWORD ]]; then
OLD_JIBRI_RECORDER_PASSWORD=passw0rd
if [[ "$JIBRI_RECORDER_PASSWORD" == "$OLD_JIBRI_RECORDER_PASSWORD" ]]; then
echo 'FATAL ERROR: Jibri recorder password must be changed, check the README'
exit 1
fi
prosodyctl --config $PROSODY_CFG register $JIBRI_RECORDER_USER $XMPP_HIDDEN_DOMAIN $JIBRI_RECORDER_PASSWORD
fi
if [[ "$(echo "$ENABLE_TRANSCRIPTIONS" | tr '[:upper:]' '[:lower:]')" == "true" ]] || [[ "$ENABLE_TRANSCRIPTIONS" == "1" ]]; then
if [[ ! -z $JIGASI_TRANSCRIBER_PASSWORD ]]; then
[ -z "$JIGASI_TRANSCRIBER_USER" ] && JIGASI_TRANSCRIBER_USER="transcriber"
prosodyctl --config $PROSODY_CFG register $JIGASI_TRANSCRIBER_USER $XMPP_HIDDEN_DOMAIN $JIGASI_TRANSCRIBER_PASSWORD
fi
fi
fi
if [[ ! -z $JIGASI_XMPP_PASSWORD ]]; then
OLD_JIGASI_XMPP_PASSWORD=passw0rd
if [[ "$JIGASI_XMPP_PASSWORD" == "$OLD_JIGASI_XMPP_PASSWORD" ]]; then
echo 'FATAL ERROR: Jigasi auth password must be changed, check the README'
exit 1
fi
prosodyctl --config $PROSODY_CFG register $JIGASI_XMPP_USER $XMPP_AUTH_DOMAIN $JIGASI_XMPP_PASSWORD
fi
if [[ "$PROSODY_MODE" == "visitors" ]]; then
[ -z "$VISITORS_XMPP_DOMAIN" ] && VISITORS_XMPP_DOMAIN="meet.jitsi"
[ -z "$PROSODY_VISITOR_INDEX" ] && PROSODY_VISITOR_INDEX=0
FULL_VISITORS_XMPP_DOMAIN="v$PROSODY_VISITOR_INDEX.$VISITORS_XMPP_DOMAIN"
if [[ ! -f /config/certs/$FULL_VISITORS_XMPP_DOMAIN.crt ]]; then
# echo for using all default values
echo | prosodyctl --config $PROSODY_CFG cert generate $FULL_VISITORS_XMPP_DOMAIN
fi
elif [[ "$PROSODY_MODE" == "brewery" ]]; then
echo "No need to generate certs for main XMPP domain in brewery mode"
else
if [[ ! -f /config/certs/$XMPP_DOMAIN.crt ]]; then
# echo for using all default values
echo | prosodyctl --config $PROSODY_CFG cert generate $XMPP_DOMAIN
fi
fi
if [[ ! -f /config/certs/$XMPP_AUTH_DOMAIN.crt ]]; then
# echo for using all default values
echo | prosodyctl --config $PROSODY_CFG cert generate $XMPP_AUTH_DOMAIN
fi
# certs will be created in /config/data
mv /config/data/*.{crt,key} /config/certs/ || true
rm -f /config/data/*.cnf

View File

@@ -0,0 +1,2 @@
pwcheck_method: saslauthd
mech_list: PLAIN

View File

@@ -0,0 +1,8 @@
#!/usr/bin/with-contenv bash
if [[ -f /etc/saslauthd.conf ]]; then
exec s6-setuidgid root saslauthd -a ldap -O /etc/saslauthd.conf -c -m /var/run/saslauthd -n 5 -d
else
# if saslauthd should not be started,
# prevent s6 from restarting this script again and again
s6-svc -O /var/run/s6/services/10-saslauthd
fi

View File

@@ -0,0 +1,2 @@
#!/usr/bin/with-contenv bash
exec s6-setuidgid prosody prosody --config /config/prosody.cfg.lua -F

View File

@@ -0,0 +1,85 @@
-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
-- luacheck: ignore 212
local log = require "util.logger".init("auth_cyrus");
local usermanager_user_exists = require "core.usermanager".user_exists;
local cyrus_service_realm = module:get_option("cyrus_service_realm");
local cyrus_service_name = module:get_option("cyrus_service_name");
local cyrus_application_name = module:get_option("cyrus_application_name");
local require_provisioning = module:get_option("cyrus_require_provisioning") or false;
local host_fqdn = module:get_option("cyrus_server_fqdn");
prosody.unlock_globals(); --FIXME: Figure out why this is needed and
-- why cyrussasl isn't caught by the sandbox
local cyrus_new = module:require "sasl_cyrus".new;
prosody.lock_globals();
local new_sasl = function(realm)
return cyrus_new(
cyrus_service_realm or realm,
cyrus_service_name or "xmpp",
cyrus_application_name or "prosody",
host_fqdn
);
end
do -- diagnostic
local list;
for mechanism in pairs(new_sasl(module.host):mechanisms()) do
list = (not(list) and mechanism) or (list..", "..mechanism);
end
if not list then
module:log("error", "No Cyrus SASL mechanisms available");
else
module:log("debug", "Available Cyrus SASL mechanisms: %s", list);
end
end
local host = module.host;
-- define auth provider
local provider = {};
log("debug", "initializing default authentication provider for host '%s'", host);
function provider.test_password(username, password)
return nil, "Legacy auth not supported with Cyrus SASL.";
end
function provider.get_password(username)
return nil, "Passwords unavailable for Cyrus SASL.";
end
function provider.set_password(username, password)
return nil, "Passwords unavailable for Cyrus SASL.";
end
function provider.user_exists(username)
if require_provisioning then
return usermanager_user_exists(username, host);
end
return true;
end
function provider.create_user(username, password)
return nil, "Account creation/modification not available with Cyrus SASL.";
end
function provider.get_sasl_handler()
local handler = new_sasl(host);
if require_provisioning then
function handler.require_provisioning(username)
return usermanager_user_exists(username, host);
end
end
return handler;
end
module:provides("auth", provider);

View File

@@ -0,0 +1,39 @@
module:set_global();
local ip = require "util.ip";
local modulemanager = require "core.modulemanager";
local permitted_ips = module:get_option_set("http_health_allow_ips", { "::1", "127.0.0.1" });
local permitted_cidr = module:get_option_string("http_health_allow_cidr");
local function is_permitted(request)
local ip_raw = request.ip;
if permitted_ips:contains(ip_raw) or
(permitted_cidr and ip.match(ip.new_ip(ip_raw), ip.parse_cidr(permitted_cidr))) then
return true;
end
return false;
end
module:provides("http", {
route = {
GET = function(event)
local request = event.request;
if not is_permitted(request) then
return 403; -- Forbidden
end
for host in pairs(prosody.hosts) do
local mods = modulemanager.get_modules(host);
for _, mod in pairs(mods) do
if mod.module.status_type == "error" then
return { status_code = 500; headers = { content_type = "text/plain" }; body = "HAS ERRORS\n" };
end
end
end
return { status_code = 200; headers = { content_type = "text/plain" }; body = "OK\n" };
end;
};
});

View File

@@ -0,0 +1,242 @@
-- mod_muc_moderation
--
-- Copyright (C) 2015-2021 Kim Alvefur
--
-- This file is MIT licensed.
--
-- Implements: XEP-0425: Message Moderation
--
-- Imports
local dt = require "util.datetime";
local id = require "util.id";
local jid = require "util.jid";
local st = require "util.stanza";
-- Plugin dependencies
local mod_muc = module:depends "muc";
local muc_util = module:require "muc/util";
local valid_roles = muc_util.valid_roles;
local muc_log_archive = module:open_store("muc_log", "archive");
if not muc_log_archive.set then
module:log("warn", "Selected archive storage module does not support message replacement, no tombstones will be saved");
end
-- Namespaces
local xmlns_fasten = "urn:xmpp:fasten:0";
local xmlns_moderate = "urn:xmpp:message-moderate:0";
local xmlns_moderate_1 = "urn:xmpp:message-moderate:1";
local xmlns_occupant_id = "urn:xmpp:occupant-id:0";
local xmlns_retract = "urn:xmpp:message-retract:0";
local xmlns_retract_1 = "urn:xmpp:message-retract:1";
-- Discovering support
module:hook("muc-disco#info", function (event)
event.reply:tag("feature", { var = xmlns_moderate }):up();
event.reply:tag("feature", { var = xmlns_moderate_1 }):up();
end);
-- TODO error registry, requires Prosody 0.12+
-- moderate : function (string, string, string, boolean, string) : boolean, enum, enum, string
local function moderate(actor, room_jid, stanza_id, retract, reason)
local room_node = jid.split(room_jid);
local room = mod_muc.get_room_from_jid(room_jid);
-- Permissions is based on role, which is a property of a current occupant,
-- so check if the actor is an occupant, otherwise if they have a reserved
-- nickname that can be used to retrieve the role.
local actor_nick = room:get_occupant_jid(actor);
if not actor_nick then
local reserved_nickname = room:get_affiliation_data(jid.bare(actor), "reserved_nickname");
if reserved_nickname then
actor_nick = room.jid .. "/" .. reserved_nickname;
end
end
-- Retrieve their current role, iff they are in the room, otherwise what they
-- would have based on affiliation.
local affiliation = room:get_affiliation(actor);
local role = room:get_role(actor_nick) or room:get_default_role(affiliation);
if valid_roles[role or "none"] < valid_roles.moderator then
return false, "auth", "forbidden", "You need a role of at least 'moderator'";
end
-- Original stanza to base tombstone on
local original, err;
if muc_log_archive.get then
original, err = muc_log_archive:get(room_node, stanza_id);
else
-- COMPAT missing :get API
err = "item-not-found";
for i, item in muc_log_archive:find(room_node, { key = stanza_id, limit = 1 }) do
if i == stanza_id then
original, err = item, nil;
end
end
end
if not original then
if err == "item-not-found" then
return false, "modify", "item-not-found";
else
return false, "wait", "internal-server-error";
end
end
local actor_occupant = room:get_occupant_by_real_jid(actor) or room:new_occupant(jid.bare(actor), actor_nick);
local announcement = st.message({ from = room_jid, type = "groupchat", id = id.medium(), })
:tag("apply-to", { xmlns = xmlns_fasten, id = stanza_id })
:tag("moderated", { xmlns = xmlns_moderate, by = actor_nick })
if room.get_occupant_id then
-- This isn't a regular broadcast message going through the events occupant_id.lib hooks so we do this here
announcement:add_child(st.stanza("occupant-id", { xmlns = xmlns_occupant_id; id = room:get_occupant_id(actor_occupant) }));
end
if retract then
announcement:tag("retract", { xmlns = xmlns_retract }):up();
end
if reason then
announcement:text_tag("reason", reason);
end
local moderated_occupant_id = original:get_child("occupant-id", xmlns_occupant_id);
if room.get_occupant_id and moderated_occupant_id then
announcement:add_direct_child(moderated_occupant_id);
end
-- XEP 0425 v0.3.0
announcement:reset();
if retract then
announcement:tag("retract", { xmlns = xmlns_retract_1; id = stanza_id })
:tag("moderated", { xmlns = xmlns_moderate_1 })
:tag("occupant-id", { xmlns = xmlns_occupant_id; id = room:get_occupant_id(actor_occupant) });
if reason then
announcement:up():up():text_tag("reason", reason);
end
end
local tombstone = nil;
if muc_log_archive.set and retract then
tombstone = st.message({ from = original.attr.from, type = "groupchat", id = original.attr.id })
:tag("moderated", { xmlns = xmlns_moderate, by = actor_nick })
:tag("retracted", { xmlns = xmlns_retract, stamp = dt.datetime() }):up();
if reason then
tombstone:text_tag("reason", reason);
end
if room.get_occupant_id then
if actor_occupant then
tombstone:add_child(st.stanza("occupant-id", { xmlns = xmlns_occupant_id; id = room:get_occupant_id(actor_occupant) }));
end
if moderated_occupant_id then
-- Copy occupant id from moderated message
tombstone:add_direct_child(moderated_occupant_id);
end
end
tombstone:reset();
end
-- fire an event, that can be used to cancel the moderation, or modify stanzas.
local event = {
room = room;
announcement = announcement;
tombstone = tombstone;
stanza_id = stanza_id;
retract = retract;
reason = reason;
actor = actor;
actor_nick = actor_nick;
};
if module:fire_event("muc-moderate-message", event) then
-- TODO: allow to change the error message?
return false, "wait", "internal-server-error";
end
if tombstone then
local was_replaced = muc_log_archive:set(room_node, stanza_id, tombstone);
if not was_replaced then
return false, "wait", "internal-server-error";
end
end
-- Done, tell people about it
module:log("info", "Message with id '%s' in room %s moderated by %s, reason: %s", stanza_id, room_jid, actor, reason);
room:broadcast_message(announcement);
return true;
end
-- Main handling
module:hook("iq-set/bare/" .. xmlns_fasten .. ":apply-to", function (event)
local stanza, origin = event.stanza, event.origin;
local actor = stanza.attr.from;
local room_jid = stanza.attr.to;
-- Collect info we need
local apply_to = stanza.tags[1];
local moderate_tag = apply_to:get_child("moderate", xmlns_moderate);
if not moderate_tag then return end -- some other kind of fastening?
local reason = moderate_tag:get_child_text("reason");
local retract = moderate_tag:get_child("retract", xmlns_retract);
local stanza_id = apply_to.attr.id;
local ok, error_type, error_condition, error_text = moderate(actor, room_jid, stanza_id, retract, reason);
if not ok then
origin.send(st.error_reply(stanza, error_type, error_condition, error_text));
return true;
end
origin.send(st.reply(stanza));
return true;
end);
module:hook("iq-set/bare/" .. xmlns_moderate_1 .. ":moderate", function (event)
local stanza, origin = event.stanza, event.origin;
local actor = stanza.attr.from;
local room_jid = stanza.attr.to;
local moderate_tag = stanza:get_child("moderate", xmlns_moderate_1)
local retract_tag = moderate_tag:get_child("retract", xmlns_retract_1)
if not retract_tag then return end -- other kind of moderation?
local reason = moderate_tag:get_child_text("reason");
local stanza_id = moderate_tag.attr.id
local ok, error_type, error_condition, error_text = moderate(
actor,
room_jid,
stanza_id,
retract_tag,
reason
);
if not ok then
origin.send(st.error_reply(stanza, error_type, error_condition, error_text));
return true;
end
origin.send(st.reply(stanza));
return true;
end);
module:hook("muc-message-is-historic", function (event)
-- Ensure moderation messages are stored
if event.stanza.attr.from == event.room.jid then
return event.stanza:get_child("apply-to", xmlns_fasten);
end
end, 1);

View File

@@ -0,0 +1,169 @@
-- sasl.lua v0.4
-- Copyright (C) 2008-2009 Tobias Markmann
--
-- All rights reserved.
--
-- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
--
-- * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-- * Neither the name of Tobias Markmann nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
local cyrussasl = require "cyrussasl";
local log = require "util.logger".init("sasl_cyrus");
local setmetatable = setmetatable
local pcall = pcall
local s_match, s_gmatch = string.match, string.gmatch
local sasl_errstring = {
-- SASL result codes --
[1] = "another step is needed in authentication";
[0] = "successful result";
[-1] = "generic failure";
[-2] = "memory shortage failure";
[-3] = "overflowed buffer";
[-4] = "mechanism not supported";
[-5] = "bad protocol / cancel";
[-6] = "can't request info until later in exchange";
[-7] = "invalid parameter supplied";
[-8] = "transient failure (e.g., weak key)";
[-9] = "integrity check failed";
[-12] = "SASL library not initialized";
-- client only codes --
[2] = "needs user interaction";
[-10] = "server failed mutual authentication step";
[-11] = "mechanism doesn't support requested feature";
-- server only codes --
[-13] = "authentication failure";
[-14] = "authorization failure";
[-15] = "mechanism too weak for this user";
[-16] = "encryption needed to use mechanism";
[-17] = "One time use of a plaintext password will enable requested mechanism for user";
[-18] = "passphrase expired, has to be reset";
[-19] = "account disabled";
[-20] = "user not found";
[-23] = "version mismatch with plug-in";
[-24] = "remote authentication server unavailable";
[-26] = "user exists, but no verifier for user";
-- codes for password setting --
[-21] = "passphrase locked";
[-22] = "requested change was not needed";
[-27] = "passphrase is too weak for security policy";
[-28] = "user supplied passwords not permitted";
};
setmetatable(sasl_errstring, { __index = function() return "undefined error!" end });
local _ENV = nil;
-- luacheck: std none
local method = {};
method.__index = method;
local initialized = false;
local function init(service_name)
if not initialized then
local st, errmsg = pcall(cyrussasl.server_init, service_name);
if st then
initialized = true;
else
log("error", "Failed to initialize Cyrus SASL: %s", errmsg);
end
end
end
-- create a new SASL object which can be used to authenticate clients
-- host_fqdn may be nil in which case gethostname() gives the value.
-- For GSSAPI, this determines the hostname in the service ticket (after
-- reverse DNS canonicalization, only if [libdefaults] rdns = true which
-- is the default).
local function new(realm, service_name, app_name, host_fqdn)
init(app_name or service_name);
local st, ret = pcall(cyrussasl.server_new, service_name, host_fqdn, realm, nil, nil)
if not st then
log("error", "Creating SASL server connection failed: %s", ret);
return nil;
end
local sasl_i = { realm = realm, service_name = service_name, cyrus = ret };
if cyrussasl.set_canon_cb then
local c14n_cb = function (user)
local node = s_match(user, "^([^@]+)");
log("debug", "Canonicalizing username %s to %s", user, node)
return node
end
cyrussasl.set_canon_cb(sasl_i.cyrus, c14n_cb);
end
cyrussasl.setssf(sasl_i.cyrus, 0, 0xffffffff)
local mechanisms = {};
local cyrus_mechs = cyrussasl.listmech(sasl_i.cyrus, nil, "", " ", "");
for w in s_gmatch(cyrus_mechs, "[^ ]+") do
mechanisms[w] = true;
end
sasl_i.mechs = mechanisms;
return setmetatable(sasl_i, method);
end
-- get a fresh clone with the same realm and service name
function method:clean_clone()
return new(self.realm, self.service_name)
end
-- get a list of possible SASL mechanims to use
function method:mechanisms()
return self.mechs;
end
-- select a mechanism to use
function method:select(mechanism)
if not self.selected and self.mechs[mechanism] then
self.selected = mechanism;
return true;
end
end
-- feed new messages to process into the library
function method:process(message)
local err;
local data;
if not self.first_step_done then
err, data = cyrussasl.server_start(self.cyrus, self.selected, message or "")
self.first_step_done = true;
else
err, data = cyrussasl.server_step(self.cyrus, message or "")
end
self.username = cyrussasl.get_username(self.cyrus)
if (err == 0) then -- SASL_OK
if self.require_provisioning and not self.require_provisioning(self.username) then
return "failure", "not-authorized", "User authenticated successfully, but not provisioned for XMPP";
end
return "success", data
elseif (err == 1) then -- SASL_CONTINUE
return "challenge", data
elseif (err == -4) then -- SASL_NOMECH
log("debug", "SASL mechanism not available from remote end")
return "failure", "invalid-mechanism", "SASL mechanism not available"
elseif (err == -13) then -- SASL_BADAUTH
return "failure", "not-authorized", sasl_errstring[err];
else
log("debug", "Got SASL error condition %d: %s", err, sasl_errstring[err]);
return "failure", "undefined-condition", sasl_errstring[err];
end
end
return {
new = new;
};

View File

@@ -0,0 +1,3 @@
#!/bin/bash
curl --fail-with-body http://127.0.0.1:5280/health