1{ lib, config, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.znc;
8
9 networkOpts = {
10 options = {
11
12 server = mkOption {
13 type = types.str;
14 example = "irc.libera.chat";
15 description = ''
16 IRC server address.
17 '';
18 };
19
20 port = mkOption {
21 type = types.port;
22 default = 6697;
23 description = ''
24 IRC server port.
25 '';
26 };
27
28 password = mkOption {
29 type = types.str;
30 default = "";
31 description = ''
32 IRC server password, such as for a Slack gateway.
33 '';
34 };
35
36 useSSL = mkOption {
37 type = types.bool;
38 default = true;
39 description = ''
40 Whether to use SSL to connect to the IRC server.
41 '';
42 };
43
44 modules = mkOption {
45 type = types.listOf types.str;
46 default = [ "simple_away" ];
47 example = literalExpression ''[ "simple_away" "sasl" ]'';
48 description = ''
49 ZNC network modules to load.
50 '';
51 };
52
53 channels = mkOption {
54 type = types.listOf types.str;
55 default = [ ];
56 example = [ "nixos" ];
57 description = ''
58 IRC channels to join.
59 '';
60 };
61
62 hasBitlbeeControlChannel = mkOption {
63 type = types.bool;
64 default = false;
65 description = ''
66 Whether to add the special Bitlbee operations channel.
67 '';
68 };
69
70 extraConf = mkOption {
71 default = "";
72 type = types.lines;
73 example = ''
74 Encoding = ^UTF-8
75 FloodBurst = 4
76 FloodRate = 1.00
77 IRCConnectEnabled = true
78 Ident = johntron
79 JoinDelay = 0
80 Nick = johntron
81 '';
82 description = ''
83 Extra config for the network. Consider using
84 {option}`services.znc.config` instead.
85 '';
86 };
87 };
88 };
89
90in
91
92{
93
94 options = {
95 services.znc = {
96
97 useLegacyConfig = mkOption {
98 default = true;
99 type = types.bool;
100 description = ''
101 Whether to propagate the legacy options under
102 {option}`services.znc.confOptions.*` to the znc config. If this
103 is turned on, the znc config will contain a user with the default name
104 "znc", global modules "webadmin" and "adminlog" will be enabled by
105 default, and more, all controlled through the
106 {option}`services.znc.confOptions.*` options.
107 You can use {command}`nix-instantiate --eval --strict '<nixpkgs/nixos>' -A config.services.znc.config`
108 to view the current value of the config.
109
110 In any case, if you need more flexibility,
111 {option}`services.znc.config` can be used to override/add to
112 all of the legacy options.
113 '';
114 };
115
116 confOptions = {
117 modules = mkOption {
118 type = types.listOf types.str;
119 default = [
120 "webadmin"
121 "adminlog"
122 ];
123 example = [
124 "partyline"
125 "webadmin"
126 "adminlog"
127 "log"
128 ];
129 description = ''
130 A list of modules to include in the `znc.conf` file.
131 '';
132 };
133
134 userModules = mkOption {
135 type = types.listOf types.str;
136 default = [
137 "chansaver"
138 "controlpanel"
139 ];
140 example = [
141 "chansaver"
142 "controlpanel"
143 "fish"
144 "push"
145 ];
146 description = ''
147 A list of user modules to include in the `znc.conf` file.
148 '';
149 };
150
151 userName = mkOption {
152 default = "znc";
153 example = "johntron";
154 type = types.str;
155 description = ''
156 The user name used to log in to the ZNC web admin interface.
157 '';
158 };
159
160 networks = mkOption {
161 default = { };
162 type = with types; attrsOf (submodule networkOpts);
163 description = ''
164 IRC networks to connect the user to.
165 '';
166 example = literalExpression ''
167 {
168 "libera" = {
169 server = "irc.libera.chat";
170 port = 6697;
171 useSSL = true;
172 modules = [ "simple_away" ];
173 };
174 };
175 '';
176 };
177
178 nick = mkOption {
179 default = "znc-user";
180 example = "john";
181 type = types.str;
182 description = ''
183 The IRC nick.
184 '';
185 };
186
187 passBlock = mkOption {
188 example = ''
189 <Pass password>
190 Method = sha256
191 Hash = e2ce303c7ea75c571d80d8540a8699b46535be6a085be3414947d638e48d9e93
192 Salt = l5Xryew4g*!oa(ECfX2o
193 </Pass>
194 '';
195 type = types.str;
196 description = ''
197 Generate with {command}`nix-shell -p znc --command "znc --makepass"`.
198 This is the password used to log in to the ZNC web admin interface.
199 You can also set this through
200 {option}`services.znc.config.User.<username>.Pass.Method`
201 and co.
202 '';
203 };
204
205 port = mkOption {
206 default = 5000;
207 type = types.port;
208 description = ''
209 Specifies the port on which to listen.
210 '';
211 };
212
213 useSSL = mkOption {
214 default = true;
215 type = types.bool;
216 description = ''
217 Indicates whether the ZNC server should use SSL when listening on
218 the specified port. A self-signed certificate will be generated.
219 '';
220 };
221
222 uriPrefix = mkOption {
223 type = types.nullOr types.str;
224 default = null;
225 example = "/znc/";
226 description = ''
227 An optional URI prefix for the ZNC web interface. Can be
228 used to make ZNC available behind a reverse proxy.
229 '';
230 };
231
232 extraZncConf = mkOption {
233 default = "";
234 type = types.lines;
235 description = ''
236 Extra config to `znc.conf` file.
237 '';
238 };
239 };
240
241 };
242 };
243
244 config = mkIf cfg.useLegacyConfig {
245
246 services.znc.config =
247 let
248 c = cfg.confOptions;
249 # defaults here should override defaults set in the non-legacy part
250 mkDefault = mkOverride 900;
251 in
252 {
253 LoadModule = mkDefault c.modules;
254 Listener.l = {
255 Port = mkDefault c.port;
256 IPv4 = mkDefault true;
257 IPv6 = mkDefault true;
258 SSL = mkDefault c.useSSL;
259 URIPrefix = c.uriPrefix;
260 };
261 User.${c.userName} = {
262 Admin = mkDefault true;
263 Nick = mkDefault c.nick;
264 AltNick = mkDefault "${c.nick}_";
265 Ident = mkDefault c.nick;
266 RealName = mkDefault c.nick;
267 LoadModule = mkDefault c.userModules;
268 Network = mapAttrs (name: net: {
269 LoadModule = mkDefault net.modules;
270 Server = mkDefault "${net.server} ${optionalString net.useSSL "+"}${toString net.port} ${net.password}";
271 Chan =
272 optionalAttrs net.hasBitlbeeControlChannel { "&bitlbee" = mkDefault { }; }
273 // listToAttrs (map (n: nameValuePair "#${n}" (mkDefault { })) net.channels);
274 extraConfig = if net.extraConf == "" then mkDefault null else net.extraConf;
275 }) c.networks;
276 extraConfig = [ c.passBlock ];
277 };
278 extraConfig = optional (c.extraZncConf != "") c.extraZncConf;
279 };
280 };
281
282 imports = [
283 (mkRemovedOptionModule [ "services" "znc" "zncConf" ] ''
284 Instead of `services.znc.zncConf = "... foo ...";`, use
285 `services.znc.configFile = pkgs.writeText "znc.conf" "... foo ...";`.
286 '')
287 ];
288}