1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.jicofo;
7
8 format = pkgs.formats.hocon { };
9
10 configFile = format.generate "jicofo.conf" cfg.config;
11in
12{
13 options.services.jicofo = with types; {
14 enable = mkEnableOption "Jitsi Conference Focus - component of Jitsi Meet";
15
16 xmppHost = mkOption {
17 type = str;
18 example = "localhost";
19 description = ''
20 Hostname of the XMPP server to connect to.
21 '';
22 };
23
24 xmppDomain = mkOption {
25 type = nullOr str;
26 example = "meet.example.org";
27 description = ''
28 Domain name of the XMMP server to which to connect as a component.
29
30 If null, {option}`xmppHost` is used.
31 '';
32 };
33
34 componentPasswordFile = mkOption {
35 type = str;
36 example = "/run/keys/jicofo-component";
37 description = ''
38 Path to file containing component secret.
39 '';
40 };
41
42 userName = mkOption {
43 type = str;
44 default = "focus";
45 description = ''
46 User part of the JID for XMPP user connection.
47 '';
48 };
49
50 userDomain = mkOption {
51 type = str;
52 example = "auth.meet.example.org";
53 description = ''
54 Domain part of the JID for XMPP user connection.
55 '';
56 };
57
58 userPasswordFile = mkOption {
59 type = str;
60 example = "/run/keys/jicofo-user";
61 description = ''
62 Path to file containing password for XMPP user connection.
63 '';
64 };
65
66 bridgeMuc = mkOption {
67 type = str;
68 example = "jvbbrewery@internal.meet.example.org";
69 description = ''
70 JID of the internal MUC used to communicate with Videobridges.
71 '';
72 };
73
74 config = mkOption {
75 type = format.type;
76 default = { };
77 example = literalExpression ''
78 {
79 jicofo.bridge.max-bridge-participants = 42;
80 }
81 '';
82 description = ''
83 Contents of the {file}`jicofo.conf` configuration file.
84 '';
85 };
86 };
87
88 config = mkIf cfg.enable {
89 services.jicofo.config = {
90 jicofo = {
91 bridge.brewery-jid = cfg.bridgeMuc;
92 xmpp = rec {
93 client = {
94 hostname = cfg.xmppHost;
95 username = cfg.userName;
96 domain = cfg.userDomain;
97 password = format.lib.mkSubstitution "JICOFO_AUTH_PASS";
98 xmpp-domain = if cfg.xmppDomain == null then cfg.xmppHost else cfg.xmppDomain;
99 };
100 service = client;
101 };
102 };
103 };
104
105 users.groups.jitsi-meet = {};
106
107 systemd.services.jicofo = let
108 jicofoProps = {
109 "-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi";
110 "-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "jicofo";
111 "-Djava.util.logging.config.file" = "/etc/jitsi/jicofo/logging.properties";
112 "-Dconfig.file" = configFile;
113 };
114 in
115 {
116 description = "JItsi COnference FOcus";
117 wantedBy = [ "multi-user.target" ];
118 after = [ "network.target" ];
119
120 restartTriggers = [
121 configFile
122 ];
123 environment.JAVA_SYS_PROPS = concatStringsSep " " (mapAttrsToList (k: v: "${k}=${toString v}") jicofoProps);
124
125 script = ''
126 export JICOFO_AUTH_PASS="$(<${cfg.userPasswordFile})"
127 exec "${pkgs.jicofo}/bin/jicofo"
128 '';
129
130 serviceConfig = {
131 Type = "exec";
132
133 DynamicUser = true;
134 User = "jicofo";
135 Group = "jitsi-meet";
136
137 CapabilityBoundingSet = "";
138 NoNewPrivileges = true;
139 ProtectSystem = "strict";
140 ProtectHome = true;
141 PrivateTmp = true;
142 PrivateDevices = true;
143 ProtectHostname = true;
144 ProtectKernelTunables = true;
145 ProtectKernelModules = true;
146 ProtectControlGroups = true;
147 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
148 RestrictNamespaces = true;
149 LockPersonality = true;
150 RestrictRealtime = true;
151 RestrictSUIDSGID = true;
152 };
153 };
154
155 environment.etc."jitsi/jicofo/sip-communicator.properties".text = "";
156 environment.etc."jitsi/jicofo/logging.properties".source =
157 mkDefault "${pkgs.jicofo}/etc/jitsi/jicofo/logging.properties-journal";
158 };
159
160 meta.maintainers = lib.teams.jitsi.members;
161}