1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.prosody;
8
9 sslOpts = { ... }: {
10
11 options = {
12
13 # TODO: require attribute
14 key = mkOption {
15 type = types.str;
16 description = "Path to the key file";
17 };
18
19 # TODO: require attribute
20 cert = mkOption {
21 type = types.str;
22 description = "Path to the certificate file";
23 };
24 };
25 };
26
27 moduleOpts = {
28
29 roster = mkOption {
30 default = true;
31 description = "Allow users to have a roster";
32 };
33
34 saslauth = mkOption {
35 default = true;
36 description = "Authentication for clients and servers. Recommended if you want to log in.";
37 };
38
39 tls = mkOption {
40 default = true;
41 description = "Add support for secure TLS on c2s/s2s connections";
42 };
43
44 dialback = mkOption {
45 default = true;
46 description = "s2s dialback support";
47 };
48
49 disco = mkOption {
50 default = true;
51 description = "Service discovery";
52 };
53
54 legacyauth = mkOption {
55 default = true;
56 description = "Legacy authentication. Only used by some old clients and bots";
57 };
58
59 version = mkOption {
60 default = true;
61 description = "Replies to server version requests";
62 };
63
64 uptime = mkOption {
65 default = true;
66 description = "Report how long server has been running";
67 };
68
69 time = mkOption {
70 default = true;
71 description = "Let others know the time here on this server";
72 };
73
74 ping = mkOption {
75 default = true;
76 description = "Replies to XMPP pings with pongs";
77 };
78
79 console = mkOption {
80 default = false;
81 description = "telnet to port 5582";
82 };
83
84 bosh = mkOption {
85 default = false;
86 description = "Enable BOSH clients, aka 'Jabber over HTTP'";
87 };
88
89 httpserver = mkOption {
90 default = false;
91 description = "Serve static files from a directory over HTTP";
92 };
93
94 websocket = mkOption {
95 default = false;
96 description = "Enable WebSocket support";
97 };
98
99 };
100
101 createSSLOptsStr = o:
102 if o ? key && o ? cert then
103 ''ssl = { key = "${o.key}"; certificate = "${o.cert}"; };''
104 else "";
105
106 vHostOpts = { ... }: {
107
108 options = {
109
110 # TODO: require attribute
111 domain = mkOption {
112 type = types.str;
113 description = "Domain name";
114 };
115
116 enabled = mkOption {
117 default = false;
118 description = "Whether to enable the virtual host";
119 };
120
121 ssl = mkOption {
122 description = "Paths to SSL files";
123 default = null;
124 options = [ sslOpts ];
125 };
126
127 extraConfig = mkOption {
128 default = '''';
129 description = "Additional virtual host specific configuration";
130 };
131
132 };
133
134 };
135
136in
137
138{
139
140 ###### interface
141
142 options = {
143
144 services.prosody = {
145
146 enable = mkOption {
147 default = false;
148 description = "Whether to enable the prosody server";
149 };
150
151 allowRegistration = mkOption {
152 default = false;
153 description = "Allow account creation";
154 };
155
156 modules = moduleOpts;
157
158 extraModules = mkOption {
159 description = "Enable custom modules";
160 default = [];
161 };
162
163 virtualHosts = mkOption {
164
165 description = "Define the virtual hosts";
166
167 type = with types; loaOf (submodule vHostOpts);
168
169 example = {
170 myhost = {
171 domain = "my-xmpp-example-host.org";
172 enabled = true;
173 };
174 };
175
176 default = {
177 localhost = {
178 domain = "localhost";
179 enabled = true;
180 };
181 };
182
183 };
184
185 ssl = mkOption {
186 description = "Paths to SSL files";
187 default = null;
188 options = [ sslOpts ];
189 };
190
191 admins = mkOption {
192 description = "List of administrators of the current host";
193 example = [ "admin1@example.com" "admin2@example.com" ];
194 default = [];
195 };
196
197 extraConfig = mkOption {
198 type = types.lines;
199 default = '''';
200 description = "Additional prosody configuration";
201 };
202
203 };
204 };
205
206
207 ###### implementation
208
209 config = mkIf cfg.enable {
210
211 environment.systemPackages = [ pkgs.prosody ];
212
213 environment.etc."prosody/prosody.cfg.lua".text = ''
214
215 pidfile = "/var/lib/prosody/prosody.pid"
216
217
218 log = "*syslog"
219
220 data_path = "/var/lib/prosody"
221
222 allow_registration = ${boolToString cfg.allowRegistration};
223
224 ${ optionalString cfg.modules.console "console_enabled = true;" }
225
226 ${ optionalString (cfg.ssl != null) (createSSLOptsStr cfg.ssl) }
227
228 admins = { ${lib.concatStringsSep ", " (map (n: "\"${n}\"") cfg.admins) } };
229
230 modules_enabled = {
231
232 ${ lib.concatStringsSep "\n\ \ " (lib.mapAttrsToList
233 (name: val: optionalString val ''"${name}";'')
234 cfg.modules) }
235
236 ${ optionalString cfg.allowRegistration "\"register\"\;" }
237
238 ${ lib.concatStringsSep "\n" (map (x: "\"${x}\";") cfg.extraModules)}
239
240 "posix";
241 };
242
243 ${ cfg.extraConfig }
244
245 ${ lib.concatStringsSep "\n" (lib.mapAttrsToList (n: v: ''
246 VirtualHost "${v.domain}"
247 enabled = ${boolToString v.enabled};
248 ${ optionalString (v.ssl != null) (createSSLOptsStr v.ssl) }
249 ${ v.extraConfig }
250 '') cfg.virtualHosts) }
251 '';
252
253 users.extraUsers.prosody = {
254 uid = config.ids.uids.prosody;
255 description = "Prosody user";
256 createHome = true;
257 group = "prosody";
258 home = "/var/lib/prosody";
259 };
260
261 users.extraGroups.prosody = {
262 gid = config.ids.gids.prosody;
263 };
264
265 systemd.services.prosody = {
266
267 description = "Prosody XMPP server";
268 after = [ "network-online.target" ];
269 wants = [ "network-online.target" ];
270 wantedBy = [ "multi-user.target" ];
271 serviceConfig = {
272 User = "prosody";
273 PIDFile = "/var/lib/prosody/prosody.pid";
274 ExecStart = "${pkgs.prosody}/bin/prosodyctl start";
275 };
276
277 };
278
279 };
280
281}