vuls: init at 0.27.0 (#348530)
[NixPkgs.git] / nixos / modules / services / web-apps / jitsi-meet.nix
blobf880691b55e9c9d1cc28a1520efa28a98c741948
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.jitsi-meet;
8   # The configuration files are JS of format "var <<string>> = <<JSON>>;". In order to
9   # override only some settings, we need to extract the JSON, use jq to merge it with
10   # the config provided by user, and then reconstruct the file.
11   overrideJs =
12     source: varName: userCfg: appendExtra:
13     let
14       extractor = pkgs.writeText "extractor.js" ''
15         var fs = require("fs");
16         eval(fs.readFileSync(process.argv[2], 'utf8'));
17         process.stdout.write(JSON.stringify(eval(process.argv[3])));
18       '';
19       userJson = pkgs.writeText "user.json" (builtins.toJSON userCfg);
20     in (pkgs.runCommand "${varName}.js" { } ''
21       ${pkgs.nodejs}/bin/node ${extractor} ${source} ${varName} > default.json
22       (
23         echo "var ${varName} = "
24         ${pkgs.jq}/bin/jq -s '.[0] * .[1]' default.json ${userJson}
25         echo ";"
26         echo ${escapeShellArg appendExtra}
27       ) > $out
28     '');
30   # Essential config - it's probably not good to have these as option default because
31   # types.attrs doesn't do merging. Let's merge explicitly, can still be overridden if
32   # user desires.
33   defaultCfg = {
34     hosts = {
35       domain = cfg.hostName;
36       muc = "conference.${cfg.hostName}";
37       focus = "focus.${cfg.hostName}";
38       jigasi = "jigasi.${cfg.hostName}";
39     };
40     bosh = "//${cfg.hostName}/http-bind";
41     websocket = "wss://${cfg.hostName}/xmpp-websocket";
43     fileRecordingsEnabled = true;
44     liveStreamingEnabled = true;
45     hiddenDomain = "recorder.${cfg.hostName}";
46   };
49   options.services.jitsi-meet = with types; {
50     enable = mkEnableOption "Jitsi Meet - Secure, Simple and Scalable Video Conferences";
52     hostName = mkOption {
53       type = str;
54       example = "meet.example.org";
55       description = ''
56         FQDN of the Jitsi Meet instance.
57       '';
58     };
60     config = mkOption {
61       type = attrs;
62       default = { };
63       example = literalExpression ''
64         {
65           enableWelcomePage = false;
66           defaultLang = "fi";
67         }
68       '';
69       description = ''
70         Client-side web application settings that override the defaults in {file}`config.js`.
72         See <https://github.com/jitsi/jitsi-meet/blob/master/config.js> for default
73         configuration with comments.
74       '';
75     };
77     extraConfig = mkOption {
78       type = lines;
79       default = "";
80       description = ''
81         Text to append to {file}`config.js` web application config file.
83         Can be used to insert JavaScript logic to determine user's region in cascading bridges setup.
84       '';
85     };
87     interfaceConfig = mkOption {
88       type = attrs;
89       default = { };
90       example = literalExpression ''
91         {
92           SHOW_JITSI_WATERMARK = false;
93           SHOW_WATERMARK_FOR_GUESTS = false;
94         }
95       '';
96       description = ''
97         Client-side web-app interface settings that override the defaults in {file}`interface_config.js`.
99         See <https://github.com/jitsi/jitsi-meet/blob/master/interface_config.js> for
100         default configuration with comments.
101       '';
102     };
104     videobridge = {
105       enable = mkOption {
106         type = bool;
107         default = true;
108         description = ''
109           Jitsi Videobridge instance and configure it to connect to Prosody.
111           Additional configuration is possible with {option}`services.jitsi-videobridge`
112         '';
113       };
115       passwordFile = mkOption {
116         type = nullOr str;
117         default = null;
118         example = "/run/keys/videobridge";
119         description = ''
120           File containing password to the Prosody account for videobridge.
122           If `null`, a file with password will be generated automatically. Setting
123           this option is useful if you plan to connect additional videobridges to the XMPP server.
124         '';
125       };
126     };
128     jicofo.enable = mkOption {
129       type = bool;
130       default = true;
131       description = ''
132         Whether to enable JiCoFo instance and configure it to connect to Prosody.
134         Additional configuration is possible with {option}`services.jicofo`.
135       '';
136     };
138     jibri.enable = mkOption {
139       type = bool;
140       default = false;
141       description = ''
142         Whether to enable a Jibri instance and configure it to connect to Prosody.
144         Additional configuration is possible with {option}`services.jibri`, and
145         {option}`services.jibri.finalizeScript` is especially useful.
146       '';
147     };
149     jigasi.enable = mkOption {
150       type = bool;
151       default = false;
152       description = ''
153         Whether to enable jigasi instance and configure it to connect to Prosody.
155         Additional configuration is possible with <option>services.jigasi</option>.
156       '';
157     };
159     nginx.enable = mkOption {
160       type = bool;
161       default = true;
162       description = ''
163         Whether to enable nginx virtual host that will serve the javascript application and act as
164         a proxy for the XMPP server. Further nginx configuration can be done by adapting
165         {option}`services.nginx.virtualHosts.<hostName>`.
166         When this is enabled, ACME will be used to retrieve a TLS certificate by default. To disable
167         this, set the {option}`services.nginx.virtualHosts.<hostName>.enableACME` to
168         `false` and if appropriate do the same for
169         {option}`services.nginx.virtualHosts.<hostName>.forceSSL`.
170       '';
171     };
173     caddy.enable = mkEnableOption "caddy reverse proxy to expose jitsi-meet";
175     prosody.enable = mkOption {
176       type = bool;
177       default = true;
178       example = false;
179       description = ''
180         Whether to configure Prosody to relay XMPP messages between Jitsi Meet components. Turn this
181         off if you want to configure it manually.
182       '';
183     };
184     prosody.lockdown = mkOption {
185       type = bool;
186       default = false;
187       example = true;
188       description = ''
189         Whether to disable Prosody features not needed by Jitsi Meet.
191         The default Prosody configuration assumes that it will be used as a
192         general-purpose XMPP server rather than as a companion service for
193         Jitsi Meet. This option reconfigures Prosody to only listen on
194         localhost without support for TLS termination, XMPP federation or
195         the file transfer proxy.
196       '';
197     };
199     excalidraw.enable = mkEnableOption "Excalidraw collaboration backend for Jitsi";
200     excalidraw.port = mkOption {
201       type = types.port;
202       default = 3002;
203       description = ''The port which the Excalidraw backend for Jitsi should listen to.'';
204     };
206     secureDomain = {
207       enable = mkEnableOption "Authenticated room creation";
208       authentication = mkOption {
209         type = types.str;
210         default = "internal_hashed";
211         description = ''The authentication type to be used by jitsi'';
212       };
213     };
214   };
216   config = mkIf cfg.enable {
217     services.prosody = mkIf cfg.prosody.enable {
218       enable = mkDefault true;
219       xmppComplianceSuite = mkDefault false;
220       modules = {
221         admin_adhoc = mkDefault false;
222         bosh = mkDefault true;
223         ping = mkDefault true;
224         roster = mkDefault true;
225         saslauth = mkDefault true;
226         smacks = mkDefault true;
227         tls = mkDefault true;
228         websocket = mkDefault true;
229         proxy65 = mkIf cfg.prosody.lockdown (mkDefault false);
230       };
231       httpInterfaces = mkIf cfg.prosody.lockdown (mkDefault [ "127.0.0.1" ]);
232       httpsPorts = mkIf cfg.prosody.lockdown (mkDefault []);
233       muc = [
234         {
235           domain = "conference.${cfg.hostName}";
236           name = "Jitsi Meet MUC";
237           roomLocking = false;
238           roomDefaultPublicJids = true;
239           extraConfig = ''
240             restrict_room_creation = true
241             storage = "memory"
242             admins = { "focus@auth.${cfg.hostName}" }
243           '';
244         }
245         {
246           domain = "breakout.${cfg.hostName}";
247           name = "Jitsi Meet Breakout MUC";
248           roomLocking = false;
249           roomDefaultPublicJids = true;
250           extraConfig = ''
251             restrict_room_creation = true
252             storage = "memory"
253             admins = { "focus@auth.${cfg.hostName}", "jvb@auth.${cfg.hostName}" }
254           '';
255         }
256         {
257           domain = "internal.auth.${cfg.hostName}";
258           name = "Jitsi Meet Videobridge MUC";
259           roomLocking = false;
260           roomDefaultPublicJids = true;
261           extraConfig = ''
262             storage = "memory"
263             admins = { "focus@auth.${cfg.hostName}", "jvb@auth.${cfg.hostName}", "jigasi@auth.${cfg.hostName}" }
264           '';
265           #-- muc_room_cache_size = 1000
266         }
267         {
268           domain = "lobby.${cfg.hostName}";
269           name = "Jitsi Meet Lobby MUC";
270           roomLocking = false;
271           roomDefaultPublicJids = true;
272           extraConfig = ''
273             restrict_room_creation = true
274             storage = "memory"
275           '';
276         }
277       ];
278       extraModules = [
279         "pubsub"
280         "smacks"
281         "speakerstats"
282         "external_services"
283         "conference_duration"
284         "end_conference"
285         "muc_lobby_rooms"
286         "muc_breakout_rooms"
287         "av_moderation"
288         "muc_hide_all"
289         "muc_meeting_id"
290         "muc_domain_mapper"
291         "muc_rate_limit"
292         "limits_exception"
293         "persistent_lobby"
294         "room_metadata"
295       ];
296       extraPluginPaths = [ "${pkgs.jitsi-meet-prosody}/share/prosody-plugins" ];
297       extraConfig = lib.mkMerge [
298         (mkAfter ''
299           Component "focus.${cfg.hostName}" "client_proxy"
300             target_address = "focus@auth.${cfg.hostName}"
302           Component "jigasi.${cfg.hostName}" "client_proxy"
303             target_address = "jigasi@auth.${cfg.hostName}"
305           Component "speakerstats.${cfg.hostName}" "speakerstats_component"
306             muc_component = "conference.${cfg.hostName}"
308           Component "conferenceduration.${cfg.hostName}" "conference_duration_component"
309             muc_component = "conference.${cfg.hostName}"
311           Component "endconference.${cfg.hostName}" "end_conference"
312             muc_component = "conference.${cfg.hostName}"
314           Component "avmoderation.${cfg.hostName}" "av_moderation_component"
315             muc_component = "conference.${cfg.hostName}"
317           Component "metadata.${cfg.hostName}" "room_metadata_component"
318             muc_component = "conference.${cfg.hostName}"
319             breakout_rooms_component = "breakout.${cfg.hostName}"
320         '')
321         (mkBefore (''
322           muc_mapper_domain_base = "${cfg.hostName}"
324           cross_domain_websocket = true;
325           consider_websocket_secure = true;
327           unlimited_jids = {
328             "focus@auth.${cfg.hostName}",
329             "jvb@auth.${cfg.hostName}"
330           }
331         '' + optionalString cfg.prosody.lockdown ''
332           c2s_interfaces = { "127.0.0.1" };
333           modules_disabled = { "s2s" };
334         ''))
335       ];
336       virtualHosts.${cfg.hostName} = {
337         enabled = true;
338         domain = cfg.hostName;
339         extraConfig = ''
340           authentication = ${if cfg.secureDomain.enable then "\"${cfg.secureDomain.authentication}\"" else "\"jitsi-anonymous\""}
341           c2s_require_encryption = false
342           admins = { "focus@auth.${cfg.hostName}" }
343           smacks_max_unacked_stanzas = 5
344           smacks_hibernation_time = 60
345           smacks_max_hibernated_sessions = 1
346           smacks_max_old_sessions = 1
348           av_moderation_component = "avmoderation.${cfg.hostName}"
349           speakerstats_component = "speakerstats.${cfg.hostName}"
350           conference_duration_component = "conferenceduration.${cfg.hostName}"
351           end_conference_component = "endconference.${cfg.hostName}"
353           c2s_require_encryption = false
354           lobby_muc = "lobby.${cfg.hostName}"
355           breakout_rooms_muc = "breakout.${cfg.hostName}"
356           room_metadata_component = "metadata.${cfg.hostName}"
357           main_muc = "conference.${cfg.hostName}"
358         '';
359         ssl = {
360           cert = "/var/lib/jitsi-meet/jitsi-meet.crt";
361           key = "/var/lib/jitsi-meet/jitsi-meet.key";
362         };
363       };
364       virtualHosts."auth.${cfg.hostName}" = {
365         enabled = true;
366         domain = "auth.${cfg.hostName}";
367         extraConfig = ''
368           authentication = "internal_hashed"
369         '';
370         ssl = {
371           cert = "/var/lib/jitsi-meet/jitsi-meet.crt";
372           key = "/var/lib/jitsi-meet/jitsi-meet.key";
373         };
374       };
375       virtualHosts."recorder.${cfg.hostName}" = {
376         enabled = true;
377         domain = "recorder.${cfg.hostName}";
378         extraConfig = ''
379           authentication = "internal_plain"
380           c2s_require_encryption = false
381         '';
382       };
383       virtualHosts."guest.${cfg.hostName}" = {
384         enabled = true;
385         domain = "guest.${cfg.hostName}";
386         extraConfig = ''
387           authentication = "anonymous"
388           c2s_require_encryption = false
389         '';
390       };
391     };
392     systemd.services.prosody = mkIf cfg.prosody.enable {
393       preStart = let
394         videobridgeSecret = if cfg.videobridge.passwordFile != null then cfg.videobridge.passwordFile else "/var/lib/jitsi-meet/videobridge-secret";
395       in ''
396         ${config.services.prosody.package}/bin/prosodyctl register focus auth.${cfg.hostName} "$(cat /var/lib/jitsi-meet/jicofo-user-secret)"
397         ${config.services.prosody.package}/bin/prosodyctl register jvb auth.${cfg.hostName} "$(cat ${videobridgeSecret})"
398         ${config.services.prosody.package}/bin/prosodyctl mod_roster_command subscribe focus.${cfg.hostName} focus@auth.${cfg.hostName}
399         ${config.services.prosody.package}/bin/prosodyctl register jibri auth.${cfg.hostName} "$(cat /var/lib/jitsi-meet/jibri-auth-secret)"
400         ${config.services.prosody.package}/bin/prosodyctl register recorder recorder.${cfg.hostName} "$(cat /var/lib/jitsi-meet/jibri-recorder-secret)"
401       '' + optionalString cfg.jigasi.enable ''
402         ${config.services.prosody.package}/bin/prosodyctl register jigasi auth.${cfg.hostName} "$(cat /var/lib/jitsi-meet/jigasi-user-secret)"
403       '';
405       serviceConfig = {
406         EnvironmentFile = [ "/var/lib/jitsi-meet/secrets-env" ];
407         SupplementaryGroups = [ "jitsi-meet" ];
408       };
409       reloadIfChanged = true;
410     };
412     users.groups.jitsi-meet = { };
413     systemd.tmpfiles.rules = [
414       "d '/var/lib/jitsi-meet' 0750 root jitsi-meet - -"
415     ];
417     systemd.services.jitsi-meet-init-secrets = {
418       wantedBy = [ "multi-user.target" ];
419       before = [ "jicofo.service" "jitsi-videobridge2.service" ] ++ (optional cfg.prosody.enable "prosody.service") ++ (optional cfg.jigasi.enable "jigasi.service");
420       serviceConfig = {
421         Type = "oneshot";
422         UMask = "027";
423         User = "root";
424         Group = "jitsi-meet";
425         WorkingDirectory = "/var/lib/jitsi-meet";
426       };
428       script = let
429         secrets = [ "jicofo-component-secret" "jicofo-user-secret" "jibri-auth-secret" "jibri-recorder-secret" ] ++ (optionals cfg.jigasi.enable [ "jigasi-user-secret" "jigasi-component-secret" ]) ++ (optional (cfg.videobridge.passwordFile == null) "videobridge-secret");
430       in
431       ''
432         ${concatMapStringsSep "\n" (s: ''
433           if [ ! -f ${s} ]; then
434             tr -dc a-zA-Z0-9 </dev/urandom | head -c 64 > ${s}
435           fi
436         '') secrets}
438         # for easy access in prosody
439         echo "JICOFO_COMPONENT_SECRET=$(cat jicofo-component-secret)" > secrets-env
440         echo "JIGASI_COMPONENT_SECRET=$(cat jigasi-component-secret)" >> secrets-env
441       ''
442       + optionalString cfg.prosody.enable ''
443         # generate self-signed certificates
444         if [ ! -f /var/lib/jitsi-meet/jitsi-meet.crt ]; then
445           ${getBin pkgs.openssl}/bin/openssl req \
446             -x509 \
447             -newkey rsa:4096 \
448             -keyout /var/lib/jitsi-meet/jitsi-meet.key \
449             -out /var/lib/jitsi-meet/jitsi-meet.crt \
450             -days 36500 \
451             -nodes \
452             -subj '/CN=${cfg.hostName}/CN=auth.${cfg.hostName}'
453           chmod 640 /var/lib/jitsi-meet/jitsi-meet.key
454         fi
455       '';
456     };
458     systemd.services.jitsi-excalidraw = mkIf cfg.excalidraw.enable {
459       description = "Excalidraw collaboration backend for Jitsi";
460       after = [ "network.target" ];
461       wantedBy = [ "multi-user.target" ];
462       environment.PORT = toString cfg.excalidraw.port;
464       serviceConfig = {
465         Type = "simple";
466         ExecStart = "${pkgs.jitsi-excalidraw}/bin/jitsi-excalidraw-backend";
467         Restart = "on-failure";
469         DynamicUser = true;
470         Group = "jitsi-meet";
471         CapabilityBoundingSet = "";
472         NoNewPrivileges = true;
473         ProtectSystem = "strict";
474         ProtectClock = true;
475         ProtectHome = true;
476         ProtectProc = true;
477         ProtectKernelLogs = true;
478         PrivateTmp = true;
479         PrivateDevices = true;
480         PrivateUsers = true;
481         ProtectHostname = true;
482         ProtectKernelTunables = true;
483         ProtectKernelModules = true;
484         ProtectControlGroups = true;
485         RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
486         RestrictNamespaces = true;
487         LockPersonality = true;
488         RestrictRealtime = true;
489         RestrictSUIDSGID = true;
490         SystemCallFilter = [ "@system-service @pkey" "~@privileged" ];
491       };
492     };
494     services.nginx = mkIf cfg.nginx.enable {
495       enable = mkDefault true;
496       virtualHosts.${cfg.hostName} = {
497         enableACME = mkDefault true;
498         forceSSL = mkDefault true;
499         root = pkgs.jitsi-meet;
500         extraConfig = ''
501           ssi on;
502         '';
503         locations."@root_path".extraConfig = ''
504           rewrite ^/(.*)$ / break;
505         '';
506         locations."~ ^/([^/\\?&:'\"]+)$".tryFiles = "$uri @root_path";
507         locations."^~ /xmpp-websocket" = {
508           priority = 100;
509           proxyPass = "http://localhost:5280/xmpp-websocket";
510           proxyWebsockets = true;
511         };
512         locations."=/http-bind" = {
513           proxyPass = "http://localhost:5280/http-bind";
514           extraConfig = ''
515             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
516             proxy_set_header Host $host;
517           '';
518         };
519         locations."=/external_api.js" = mkDefault {
520           alias = "${pkgs.jitsi-meet}/libs/external_api.min.js";
521         };
522         locations."=/_api/room-info" = {
523           proxyPass = "http://localhost:5280/room-info";
524           extraConfig = ''
525             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
526             proxy_set_header Host $host;
527           '';
528         };
529         locations."=/config.js" = mkDefault {
530           alias = overrideJs "${pkgs.jitsi-meet}/config.js" "config" (recursiveUpdate defaultCfg cfg.config) cfg.extraConfig;
531         };
532         locations."=/interface_config.js" = mkDefault {
533           alias = overrideJs "${pkgs.jitsi-meet}/interface_config.js" "interfaceConfig" cfg.interfaceConfig "";
534         };
535         locations."/socket.io/" = mkIf cfg.excalidraw.enable {
536           proxyPass = "http://127.0.0.1:${toString cfg.excalidraw.port}";
537           proxyWebsockets = true;
538         };
539       };
540     };
542     services.caddy = mkIf cfg.caddy.enable {
543       enable = mkDefault true;
544       virtualHosts.${cfg.hostName} = {
545         extraConfig =
546         let
547           templatedJitsiMeet = pkgs.runCommand "templated-jitsi-meet" { } ''
548             cp -R --no-preserve=all ${pkgs.jitsi-meet}/* .
549             for file in *.html **/*.html ; do
550               ${pkgs.sd}/bin/sd '<!--#include virtual="(.*)" -->' '{{ include "$1" }}' $file
551             done
552             rm config.js
553             rm interface_config.js
554             cp -R . $out
555             cp ${overrideJs "${pkgs.jitsi-meet}/config.js" "config" (recursiveUpdate defaultCfg cfg.config) cfg.extraConfig} $out/config.js
556             cp ${overrideJs "${pkgs.jitsi-meet}/interface_config.js" "interfaceConfig" cfg.interfaceConfig ""} $out/interface_config.js
557             cp ./libs/external_api.min.js $out/external_api.js
558           '';
559         in (optionalString cfg.excalidraw.enable ''
560           handle /socket.io/ {
561             reverse_proxy 127.0.0.1:${toString cfg.excalidraw.port}
562           }
563         '') + ''
564           handle /http-bind {
565             header Host ${cfg.hostName}
566             reverse_proxy 127.0.0.1:5280
567           }
568           handle /xmpp-websocket {
569             reverse_proxy 127.0.0.1:5280
570           }
571           handle {
572             templates
573             root * ${templatedJitsiMeet}
574             try_files {path} {path}
575             try_files {path} /index.html
576             file_server
577           }
578         '';
579       };
580     };
582     services.jitsi-meet.config = recursiveUpdate
583       (mkIf cfg.excalidraw.enable {
584         whiteboard = {
585           enabled = true;
586           collabServerBaseUrl = "https://${cfg.hostName}";
587         };
588       })
589       (mkIf cfg.secureDomain.enable {
590         hosts.anonymousdomain = "guest.${cfg.hostName}";
591       });
593     services.jitsi-videobridge = mkIf cfg.videobridge.enable {
594       enable = true;
595       xmppConfigs."localhost" = {
596         userName = "jvb";
597         domain = "auth.${cfg.hostName}";
598         passwordFile = "/var/lib/jitsi-meet/videobridge-secret";
599         mucJids = "jvbbrewery@internal.auth.${cfg.hostName}";
600         disableCertificateVerification = true;
601       };
602     };
604     services.jicofo = mkIf cfg.jicofo.enable {
605       enable = true;
606       xmppHost = "localhost";
607       xmppDomain = cfg.hostName;
608       userDomain = "auth.${cfg.hostName}";
609       userName = "focus";
610       userPasswordFile = "/var/lib/jitsi-meet/jicofo-user-secret";
611       componentPasswordFile = "/var/lib/jitsi-meet/jicofo-component-secret";
612       bridgeMuc = "jvbbrewery@internal.auth.${cfg.hostName}";
613       config = mkMerge [{
614         jicofo.xmpp.service.disable-certificate-verification = true;
615         jicofo.xmpp.client.disable-certificate-verification = true;
616       }
617         (lib.mkIf (config.services.jibri.enable || cfg.jibri.enable) {
618           jicofo.jibri = {
619             brewery-jid = "JibriBrewery@internal.auth.${cfg.hostName}";
620             pending-timeout = "90";
621           };
622         })
623         (lib.mkIf cfg.secureDomain.enable {
624           jicofo = {
625             authentication = {
626               enabled = "true";
627               type = "XMPP";
628               login-url = cfg.hostName;
629             };
630             xmpp.client.client-proxy = "focus.${cfg.hostName}";
631           };
632         })];
633     };
635     services.jibri = mkIf cfg.jibri.enable {
636       enable = true;
638       xmppEnvironments."jitsi-meet" = {
639         xmppServerHosts = [ "localhost" ];
640         xmppDomain = cfg.hostName;
642         control.muc = {
643           domain = "internal.auth.${cfg.hostName}";
644           roomName = "JibriBrewery";
645           nickname = "jibri";
646         };
648         control.login = {
649           domain = "auth.${cfg.hostName}";
650           username = "jibri";
651           passwordFile = "/var/lib/jitsi-meet/jibri-auth-secret";
652         };
654         call.login = {
655           domain = "recorder.${cfg.hostName}";
656           username = "recorder";
657           passwordFile = "/var/lib/jitsi-meet/jibri-recorder-secret";
658         };
660         usageTimeout = "0";
661         disableCertificateVerification = true;
662         stripFromRoomDomain = "conference.";
663       };
664     };
666     services.jigasi = mkIf cfg.jigasi.enable {
667       enable = true;
668       xmppHost = "localhost";
669       xmppDomain = cfg.hostName;
670       userDomain = "auth.${cfg.hostName}";
671       userName = "jigasi";
672       userPasswordFile = "/var/lib/jitsi-meet/jigasi-user-secret";
673       componentPasswordFile = "/var/lib/jitsi-meet/jigasi-component-secret";
674       bridgeMuc = "jigasibrewery@internal.${cfg.hostName}";
675       config = {
676         "org.jitsi.jigasi.ALWAYS_TRUST_MODE_ENABLED" = "true";
677       };
678     };
679   };
681   meta.doc = ./jitsi-meet.md;
682   meta.maintainers = lib.teams.jitsi.members;