1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6 cfg = config.services.murmur;
7 configFile = pkgs.writeText "murmurd.ini" ''
8 database=/var/lib/murmur/murmur.sqlite
9 dbDriver=QSQLITE
10
11 autobanAttempts=${toString cfg.autobanAttempts}
12 autobanTimeframe=${toString cfg.autobanTimeframe}
13 autobanTime=${toString cfg.autobanTime}
14
15 logfile=/var/log/murmur/murmurd.log
16 pidfile=${cfg.pidfile}
17
18 welcome="${cfg.welcome}"
19 port=${toString cfg.port}
20
21 ${if cfg.hostName == "" then "" else "host="+cfg.hostName}
22 ${if cfg.password == "" then "" else "serverpassword="+cfg.password}
23
24 bandwidth=${toString cfg.bandwidth}
25 users=${toString cfg.users}
26
27 textmessagelength=${toString cfg.textMsgLength}
28 imagemessagelength=${toString cfg.imgMsgLength}
29 allowhtml=${if cfg.allowHtml then "true" else "false"}
30 logdays=${toString cfg.logDays}
31 bonjour=${if cfg.bonjour then "true" else "false"}
32 sendversion=${if cfg.sendVersion then "true" else "false"}
33
34 ${if cfg.registerName == "" then "" else "registerName="+cfg.registerName}
35 ${if cfg.registerPassword == "" then "" else "registerPassword="+cfg.registerPassword}
36 ${if cfg.registerUrl == "" then "" else "registerUrl="+cfg.registerUrl}
37 ${if cfg.registerHostname == "" then "" else "registerHostname="+cfg.registerHostname}
38
39 certrequired=${if cfg.clientCertRequired then "true" else "false"}
40 ${if cfg.sslCert == "" then "" else "sslCert="+cfg.sslCert}
41 ${if cfg.sslKey == "" then "" else "sslKey="+cfg.sslKey}
42 '';
43in
44{
45 options = {
46 services.murmur = {
47 enable = mkOption {
48 type = types.bool;
49 default = false;
50 description = "If enabled, start the Murmur Service.";
51 };
52
53 autobanAttempts = mkOption {
54 type = types.int;
55 default = 10;
56 description = ''
57 Number of attempts a client is allowed to make in
58 <literal>autobanTimeframe</literal> seconds, before being
59 banned for <literal>autobanTime</literal>.
60 '';
61 };
62
63 autobanTimeframe = mkOption {
64 type = types.int;
65 default = 120;
66 description = ''
67 Timeframe in which a client can connect without being banned
68 for repeated attempts (in seconds).
69 '';
70 };
71
72 autobanTime = mkOption {
73 type = types.int;
74 default = 300;
75 description = "The amount of time an IP ban lasts (in seconds).";
76 };
77
78 pidfile = mkOption {
79 type = types.path;
80 default = "/tmp/murmurd.pid";
81 description = "Path to PID file for Murmur daemon.";
82 };
83
84 welcome = mkOption {
85 type = types.str;
86 default = "";
87 description = "Welcome message for connected clients.";
88 };
89
90 port = mkOption {
91 type = types.int;
92 default = 64738;
93 description = "Ports to bind to (UDP and TCP).";
94 };
95
96 hostName = mkOption {
97 type = types.str;
98 default = "";
99 description = "Host to bind to. Defaults binding on all addresses.";
100 };
101
102 password = mkOption {
103 type = types.str;
104 default = "";
105 description = "Required password to join server, if specified.";
106 };
107
108 bandwidth = mkOption {
109 type = types.int;
110 default = 72000;
111 description = ''
112 Maximum bandwidth (in bits per second) that clients may send
113 speech at.
114 '';
115 };
116
117 users = mkOption {
118 type = types.int;
119 default = 100;
120 description = "Maximum number of concurrent clients allowed.";
121 };
122
123 textMsgLength = mkOption {
124 type = types.int;
125 default = 5000;
126 description = "Max length of text messages. Set 0 for no limit.";
127 };
128
129 imgMsgLength = mkOption {
130 type = types.int;
131 default = 131072;
132 description = "Max length of image messages. Set 0 for no limit.";
133 };
134
135 allowHtml = mkOption {
136 type = types.bool;
137 default = true;
138 description = ''
139 Allow HTML in client messages, comments, and channel
140 descriptions.
141 '';
142 };
143
144 logDays = mkOption {
145 type = types.int;
146 default = 31;
147 description = ''
148 How long to store RPC logs for in the database. Set 0 to
149 keep logs forever, or -1 to disable DB logging.
150 '';
151 };
152
153 bonjour = mkOption {
154 type = types.bool;
155 default = false;
156 description = ''
157 Enable Bonjour auto-discovery, which allows clients over
158 your LAN to automatically discover Murmur servers.
159 '';
160 };
161
162 sendVersion = mkOption {
163 type = types.bool;
164 default = true;
165 description = "Send Murmur version in UDP response.";
166 };
167
168 registerName = mkOption {
169 type = types.str;
170 default = "";
171 description = ''
172 Public server registration name, and also the name of the
173 Root channel. Even if you don't publicly register your
174 server, you probably still want to set this.
175 '';
176 };
177
178 registerPassword = mkOption {
179 type = types.str;
180 default = "";
181 description = ''
182 Public server registry password, used authenticate your
183 server to the registry to prevent impersonation; required for
184 subsequent registry updates.
185 '';
186 };
187
188 registerUrl = mkOption {
189 type = types.str;
190 default = "";
191 description = "URL website for your server.";
192 };
193
194 registerHostname = mkOption {
195 type = types.str;
196 default = "";
197 description = ''
198 DNS hostname where your server can be reached. This is only
199 needed if you want your server to be accessed by its
200 hostname and not IP - but the name *must* resolve on the
201 internet properly.
202 '';
203 };
204
205 clientCertRequired = mkOption {
206 type = types.bool;
207 default = false;
208 description = "Require clients to authenticate via certificates.";
209 };
210
211 sslCert = mkOption {
212 type = types.str;
213 default = "";
214 description = "Path to your SSL certificate.";
215 };
216
217 sslKey = mkOption {
218 type = types.str;
219 default = "";
220 description = "Path to your SSL key.";
221 };
222 };
223 };
224
225 config = mkIf cfg.enable {
226 users.extraUsers.murmur = {
227 description = "Murmur Service user";
228 home = "/var/lib/murmur";
229 createHome = true;
230 uid = config.ids.uids.murmur;
231 };
232
233 systemd.services.murmur = {
234 description = "Murmur Chat Service";
235 wantedBy = [ "multi-user.target" ];
236 after = [ "network.target "];
237
238 serviceConfig = {
239 Type = "forking";
240 PIDFile = cfg.pidfile;
241 Restart = "always";
242 User = "murmur";
243 ExecStart = "${pkgs.murmur}/bin/murmurd -ini ${configFile}";
244 PermissionsStartOnly = true;
245 };
246
247 preStart = ''
248 mkdir -p /var/log/murmur
249 chown -R murmur /var/log/murmur
250 '';
251 };
252 };
253}