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