1{ config, lib, pkgs, ...}: 2 3with lib; 4 5let 6 cfg = config.services.znc; 7 8 defaultUser = "znc"; # Default user to own process. 9 10 # Default user and pass: 11 # un=znc 12 # pw=nixospass 13 14 defaultUserName = "znc"; 15 defaultPassBlock = " 16 <Pass password> 17 Method = sha256 18 Hash = e2ce303c7ea75c571d80d8540a8699b46535be6a085be3414947d638e48d9e93 19 Salt = l5Xryew4g*!oa(ECfX2o 20 </Pass> 21 "; 22 23 modules = pkgs.buildEnv { 24 name = "znc-modules"; 25 paths = cfg.modulePackages; 26 }; 27 28 # Keep znc.conf in nix store, then symlink or copy into `dataDir`, depending on `mutable`. 29 mkZncConf = confOpts: '' 30 // Also check http://en.znc.in/wiki/Configuration 31 32 AnonIPLimit = 10 33 ConnectDelay = 5 34 # Add `LoadModule = x` for each module... 35 ${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.modules} 36 MaxBufferSize = 500 37 ProtectWebSessions = true 38 SSLCertFile = ${cfg.dataDir}/znc.pem 39 ServerThrottle = 30 40 Skin = dark-clouds 41 StatusPrefix = * 42 Version = 1.2 43 44 <Listener listener0> 45 AllowIRC = true 46 AllowWeb = true 47 IPv4 = true 48 IPv6 = false 49 Port = ${if confOpts.useSSL then "+" else ""}${toString confOpts.port} 50 SSL = ${if confOpts.useSSL then "true" else "false"} 51 </Listener> 52 53 <User ${confOpts.userName}> 54 Admin = true 55 Allow = * 56 AltNick = ${confOpts.nick}_ 57 AppendTimestamp = false 58 AutoClearChanBuffer = false 59 Buffer = 150 60 ChanModes = +stn 61 DenyLoadMod = false 62 DenySetBindHost = false 63 Ident = ident 64 JoinTries = 10 65 MaxJoins = 0 66 MaxNetworks = 1 67 MultiClients = true 68 Nick = ${confOpts.nick} 69 PrependTimestamp = true 70 QuitMsg = Quit 71 RealName = ${confOpts.nick} 72 TimestampFormat = [%H:%M:%S] 73 ${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.userModules} 74 75 ${confOpts.passBlock} 76 </User> 77 ${confOpts.extraZncConf} 78 ''; 79 80 zncConfFile = pkgs.writeTextFile { 81 name = "znc.conf"; 82 text = if cfg.zncConf != "" 83 then cfg.zncConf 84 else mkZncConf cfg.confOptions; 85 }; 86 87in 88 89{ 90 91 ###### Interface 92 93 options = { 94 services.znc = { 95 enable = mkOption { 96 default = false; 97 example = true; 98 type = types.bool; 99 description = '' 100 Enable a ZNC service for a user. 101 ''; 102 }; 103 104 user = mkOption { 105 default = "znc"; 106 example = "john"; 107 type = types.string; 108 description = '' 109 The name of an existing user account to use to own the ZNC server process. 110 If not specified, a default user will be created to own the process. 111 ''; 112 }; 113 114 dataDir = mkOption { 115 default = "/var/lib/znc/"; 116 example = "/home/john/.znc/"; 117 type = types.path; 118 description = '' 119 The data directory. Used for configuration files and modules. 120 ''; 121 }; 122 123 zncConf = mkOption { 124 default = ""; 125 example = "See: http://wiki.znc.in/Configuration"; 126 type = types.lines; 127 description = '' 128 The contents of the `znc.conf` file to use when creating it. 129 If specified, `confOptions` will be ignored, and this value, as-is, will be used. 130 If left empty, a conf file with default values will be used. 131 Recommended to generate with `znc --makeconf` command. 132 ''; 133 }; 134 135 /* TODO: add to the documentation of the current module: 136 137 Values to use when creating a `znc.conf` file. 138 139 confOptions = { 140 modules = [ "log" ]; 141 userName = "john"; 142 nick = "johntron"; 143 }; 144 */ 145 confOptions = { 146 modules = mkOption { 147 type = types.listOf types.str; 148 default = [ "partyline" "webadmin" "adminlog" "log" ]; 149 example = [ "partyline" "webadmin" "adminlog" "log" ]; 150 description = '' 151 A list of modules to include in the `znc.conf` file. 152 ''; 153 }; 154 155 userModules = mkOption { 156 type = types.listOf types.str; 157 default = [ ]; 158 example = [ "fish" "push" ]; 159 description = '' 160 A list of user modules to include in the `znc.conf` file. 161 ''; 162 }; 163 164 userName = mkOption { 165 default = defaultUserName; 166 example = "johntron"; 167 type = types.string; 168 description = '' 169 The user name to use when generating the `znc.conf` file. 170 This is the user name used by the user logging into the ZNC web admin. 171 ''; 172 }; 173 174 nick = mkOption { 175 default = "znc-user"; 176 example = "john"; 177 type = types.string; 178 description = '' 179 The IRC nick to use when generating the `znc.conf` file. 180 ''; 181 }; 182 183 passBlock = mkOption { 184 default = defaultPassBlock; 185 example = "Must be the block generated by the `znc --makepass` command."; 186 type = types.string; 187 description = '' 188 The pass block to use when generating the `znc.conf` file. 189 This is the password used by the user logging into the ZNC web admin. 190 This is the block generated by the `znc --makepass` command. 191 !!! If not specified, please change this after starting the service. !!! 192 ''; 193 }; 194 195 port = mkOption { 196 default = 5000; 197 example = 5000; 198 type = types.int; 199 description = '' 200 Specifies the port on which to listen. 201 ''; 202 }; 203 204 useSSL = mkOption { 205 default = true; 206 example = true; 207 type = types.bool; 208 description = '' 209 Indicates whether the ZNC server should use SSL when listening on the specified port. 210 ''; 211 }; 212 213 extraZncConf = mkOption { 214 default = ""; 215 type = types.lines; 216 description = '' 217 Extra config to `znc.conf` file 218 ''; 219 }; 220 }; 221 222 modulePackages = mkOption { 223 type = types.listOf types.package; 224 default = [ ]; 225 example = literalExample "[ pkgs.zncModules.fish pkgs.zncModules.push ]"; 226 description = '' 227 A list of global znc module packages to add to znc. 228 ''; 229 }; 230 231 mutable = mkOption { 232 default = false; 233 example = true; 234 type = types.bool; 235 description = '' 236 Indicates whether to allow the contents of the `dataDir` directory to be changed 237 by the user at run-time. 238 If true, modifications to the ZNC configuration after its initial creation are not 239 overwritten by a NixOS system rebuild. 240 If false, the ZNC configuration is rebuilt by every system rebuild. 241 If the user wants to manage the ZNC service using the web admin interface, this value 242 should be set to true. 243 ''; 244 }; 245 246 extraFlags = mkOption { 247 default = [ ]; 248 example = [ "--debug" ]; 249 type = types.listOf types.str; 250 description = '' 251 Extra flags to use when executing znc command. 252 ''; 253 }; 254 }; 255 }; 256 257 258 ###### Implementation 259 260 config = mkIf cfg.enable { 261 262 systemd.services.znc = { 263 description = "ZNC Server"; 264 wantedBy = [ "multi-user.target" ]; 265 after = [ "network.service" ]; 266 serviceConfig = { 267 User = cfg.user; 268 Restart = "always"; 269 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 270 ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID"; 271 }; 272 preStart = '' 273 ${pkgs.coreutils}/bin/mkdir -p ${cfg.dataDir}/configs 274 275 # If mutable, regenerate conf file every time. 276 ${optionalString (!cfg.mutable) '' 277 ${pkgs.coreutils}/bin/echo "znc is set to be system-managed. Now deleting old znc.conf file to be regenerated." 278 ${pkgs.coreutils}/bin/rm -f ${cfg.dataDir}/configs/znc.conf 279 ''} 280 281 # Ensure essential files exist. 282 if [[ ! -f ${cfg.dataDir}/configs/znc.conf ]]; then 283 ${pkgs.coreutils}/bin/echo "No znc.conf file found in ${cfg.dataDir}. Creating one now." 284 ${pkgs.coreutils}/bin/cp --no-clobber ${zncConfFile} ${cfg.dataDir}/configs/znc.conf 285 ${pkgs.coreutils}/bin/chmod u+rw ${cfg.dataDir}/configs/znc.conf 286 ${pkgs.coreutils}/bin/chown ${cfg.user} ${cfg.dataDir}/configs/znc.conf 287 fi 288 289 if [[ ! -f ${cfg.dataDir}/znc.pem ]]; then 290 ${pkgs.coreutils}/bin/echo "No znc.pem file found in ${cfg.dataDir}. Creating one now." 291 ${pkgs.znc}/bin/znc --makepem --datadir ${cfg.dataDir} 292 fi 293 294 # Symlink modules 295 rm ${cfg.dataDir}/modules || true 296 ln -fs ${modules}/lib/znc ${cfg.dataDir}/modules 297 ''; 298 script = "${pkgs.znc}/bin/znc --foreground --datadir ${cfg.dataDir} ${toString cfg.extraFlags}"; 299 }; 300 301 users.extraUsers = optional (cfg.user == defaultUser) 302 { name = defaultUser; 303 description = "ZNC server daemon owner"; 304 group = defaultUser; 305 uid = config.ids.uids.znc; 306 home = cfg.dataDir; 307 createHome = true; 308 }; 309 310 users.extraGroups = optional (cfg.user == defaultUser) 311 { name = defaultUser; 312 gid = config.ids.gids.znc; 313 members = [ defaultUser ]; 314 }; 315 316 }; 317}