15b7e102b6
* Safer defaults for immutable znc config I just lost all the options I configured in ZNC, because the mutable config was overwritten. I accept any suggestions on the way to implement this, but overwriting a mutable config by default seems weird. If we want to do this, we should ensure that ZNC does not allow to edit the config via the webmin when cfg.mutable is false. * Do not backup old config files. There seems to be little need for backups if mutable becomes a voluntary opt-out. * fixup
421 lines
12 KiB
Nix
421 lines
12 KiB
Nix
{ config, lib, pkgs, ...}:
|
|
|
|
with lib;
|
|
|
|
let
|
|
cfg = config.services.znc;
|
|
|
|
defaultUser = "znc"; # Default user to own process.
|
|
|
|
# Default user and pass:
|
|
# un=znc
|
|
# pw=nixospass
|
|
|
|
defaultUserName = "znc";
|
|
defaultPassBlock = "
|
|
<Pass password>
|
|
Method = sha256
|
|
Hash = e2ce303c7ea75c571d80d8540a8699b46535be6a085be3414947d638e48d9e93
|
|
Salt = l5Xryew4g*!oa(ECfX2o
|
|
</Pass>
|
|
";
|
|
|
|
modules = pkgs.buildEnv {
|
|
name = "znc-modules";
|
|
paths = cfg.modulePackages;
|
|
};
|
|
|
|
# Keep znc.conf in nix store, then symlink or copy into `dataDir`, depending on `mutable`.
|
|
notNull = a: ! isNull a;
|
|
mkZncConf = confOpts: ''
|
|
Version = 1.6.3
|
|
${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.modules}
|
|
|
|
<Listener l>
|
|
Port = ${toString confOpts.port}
|
|
IPv4 = true
|
|
IPv6 = true
|
|
SSL = ${boolToString confOpts.useSSL}
|
|
</Listener>
|
|
|
|
<User ${confOpts.userName}>
|
|
${confOpts.passBlock}
|
|
Admin = true
|
|
Nick = ${confOpts.nick}
|
|
AltNick = ${confOpts.nick}_
|
|
Ident = ${confOpts.nick}
|
|
RealName = ${confOpts.nick}
|
|
${concatMapStrings (n: "LoadModule = ${n}\n") confOpts.userModules}
|
|
|
|
${ lib.concatStringsSep "\n" (lib.mapAttrsToList (name: net: ''
|
|
<Network ${name}>
|
|
${concatMapStrings (m: "LoadModule = ${m}\n") net.modules}
|
|
Server = ${net.server} ${lib.optionalString net.useSSL "+"}${toString net.port} ${net.password}
|
|
${concatMapStrings (c: "<Chan #${c}>\n</Chan>\n") net.channels}
|
|
${lib.optionalString net.hasBitlbeeControlChannel ''
|
|
<Chan &bitlbee>
|
|
</Chan>
|
|
''}
|
|
${net.extraConf}
|
|
</Network>
|
|
'') confOpts.networks) }
|
|
</User>
|
|
${confOpts.extraZncConf}
|
|
'';
|
|
|
|
zncConfFile = pkgs.writeTextFile {
|
|
name = "znc.conf";
|
|
text = if cfg.zncConf != ""
|
|
then cfg.zncConf
|
|
else mkZncConf cfg.confOptions;
|
|
};
|
|
|
|
networkOpts = { ... }: {
|
|
options = {
|
|
server = mkOption {
|
|
type = types.str;
|
|
example = "chat.freenode.net";
|
|
description = ''
|
|
IRC server address.
|
|
'';
|
|
};
|
|
|
|
port = mkOption {
|
|
type = types.int;
|
|
default = 6697;
|
|
example = 6697;
|
|
description = ''
|
|
IRC server port.
|
|
'';
|
|
};
|
|
|
|
userName = mkOption {
|
|
default = "";
|
|
example = "johntron";
|
|
type = types.string;
|
|
description = ''
|
|
A nick identity specific to the IRC server.
|
|
'';
|
|
};
|
|
|
|
password = mkOption {
|
|
type = types.str;
|
|
default = "";
|
|
description = ''
|
|
IRC server password, such as for a Slack gateway.
|
|
'';
|
|
};
|
|
|
|
useSSL = mkOption {
|
|
type = types.bool;
|
|
default = true;
|
|
description = ''
|
|
Whether to use SSL to connect to the IRC server.
|
|
'';
|
|
};
|
|
|
|
modulePackages = mkOption {
|
|
type = types.listOf types.package;
|
|
default = [];
|
|
example = [ "pkgs.zncModules.push" "pkgs.zncModules.fish" ];
|
|
description = ''
|
|
External ZNC modules to build.
|
|
'';
|
|
};
|
|
|
|
modules = mkOption {
|
|
type = types.listOf types.str;
|
|
default = [ "simple_away" ];
|
|
example = literalExample "[ simple_away sasl ]";
|
|
description = ''
|
|
ZNC modules to load.
|
|
'';
|
|
};
|
|
|
|
channels = mkOption {
|
|
type = types.listOf types.str;
|
|
default = [];
|
|
example = [ "nixos" ];
|
|
description = ''
|
|
IRC channels to join.
|
|
'';
|
|
};
|
|
|
|
hasBitlbeeControlChannel = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = ''
|
|
Whether to add the special Bitlbee operations channel.
|
|
'';
|
|
};
|
|
|
|
extraConf = mkOption {
|
|
default = "";
|
|
type = types.lines;
|
|
example = ''
|
|
Encoding = ^UTF-8
|
|
FloodBurst = 4
|
|
FloodRate = 1.00
|
|
IRCConnectEnabled = true
|
|
Ident = johntron
|
|
JoinDelay = 0
|
|
Nick = johntron
|
|
'';
|
|
description = ''
|
|
Extra config for the network.
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
in
|
|
|
|
{
|
|
|
|
###### Interface
|
|
|
|
options = {
|
|
services.znc = {
|
|
enable = mkOption {
|
|
default = false;
|
|
type = types.bool;
|
|
description = ''
|
|
Enable a ZNC service for a user.
|
|
'';
|
|
};
|
|
|
|
user = mkOption {
|
|
default = "znc";
|
|
example = "john";
|
|
type = types.string;
|
|
description = ''
|
|
The name of an existing user account to use to own the ZNC server process.
|
|
If not specified, a default user will be created to own the process.
|
|
'';
|
|
};
|
|
|
|
group = mkOption {
|
|
default = "";
|
|
example = "users";
|
|
type = types.string;
|
|
description = ''
|
|
Group to own the ZNCserver process.
|
|
'';
|
|
};
|
|
|
|
dataDir = mkOption {
|
|
default = "/var/lib/znc/";
|
|
example = "/home/john/.znc/";
|
|
type = types.path;
|
|
description = ''
|
|
The data directory. Used for configuration files and modules.
|
|
'';
|
|
};
|
|
|
|
openFirewall = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = ''
|
|
Whether to open ports in the firewall for ZNC.
|
|
'';
|
|
};
|
|
|
|
zncConf = mkOption {
|
|
default = "";
|
|
example = "See: http://wiki.znc.in/Configuration";
|
|
type = types.lines;
|
|
description = ''
|
|
Config file as generated with `znc --makeconf` to use for the whole ZNC configuration.
|
|
If specified, `confOptions` will be ignored, and this value, as-is, will be used.
|
|
If left empty, a conf file with default values will be used.
|
|
'';
|
|
};
|
|
|
|
confOptions = {
|
|
modules = mkOption {
|
|
type = types.listOf types.str;
|
|
default = [ "webadmin" "adminlog" ];
|
|
example = [ "partyline" "webadmin" "adminlog" "log" ];
|
|
description = ''
|
|
A list of modules to include in the `znc.conf` file.
|
|
'';
|
|
};
|
|
|
|
userModules = mkOption {
|
|
type = types.listOf types.str;
|
|
default = [ "chansaver" "controlpanel" ];
|
|
example = [ "chansaver" "controlpanel" "fish" "push" ];
|
|
description = ''
|
|
A list of user modules to include in the `znc.conf` file.
|
|
'';
|
|
};
|
|
|
|
userName = mkOption {
|
|
default = defaultUserName;
|
|
example = "johntron";
|
|
type = types.string;
|
|
description = ''
|
|
The user name used to log in to the ZNC web admin interface.
|
|
'';
|
|
};
|
|
|
|
networks = mkOption {
|
|
default = { };
|
|
type = with types; attrsOf (submodule networkOpts);
|
|
description = ''
|
|
IRC networks to connect the user to.
|
|
'';
|
|
example = {
|
|
"freenode" = {
|
|
server = "chat.freenode.net";
|
|
port = 6697;
|
|
useSSL = true;
|
|
modules = [ "simple_away" ];
|
|
};
|
|
};
|
|
};
|
|
|
|
nick = mkOption {
|
|
default = "znc-user";
|
|
example = "john";
|
|
type = types.string;
|
|
description = ''
|
|
The IRC nick.
|
|
'';
|
|
};
|
|
|
|
passBlock = mkOption {
|
|
example = defaultPassBlock;
|
|
type = types.string;
|
|
description = ''
|
|
Generate with `nix-shell -p znc --command "znc --makepass"`.
|
|
This is the password used to log in to the ZNC web admin interface.
|
|
'';
|
|
};
|
|
|
|
port = mkOption {
|
|
default = 5000;
|
|
example = 5000;
|
|
type = types.int;
|
|
description = ''
|
|
Specifies the port on which to listen.
|
|
'';
|
|
};
|
|
|
|
useSSL = mkOption {
|
|
default = true;
|
|
type = types.bool;
|
|
description = ''
|
|
Indicates whether the ZNC server should use SSL when listening on the specified port. A self-signed certificate will be generated.
|
|
'';
|
|
};
|
|
|
|
extraZncConf = mkOption {
|
|
default = "";
|
|
type = types.lines;
|
|
description = ''
|
|
Extra config to `znc.conf` file.
|
|
'';
|
|
};
|
|
};
|
|
|
|
modulePackages = mkOption {
|
|
type = types.listOf types.package;
|
|
default = [ ];
|
|
example = literalExample "[ pkgs.zncModules.fish pkgs.zncModules.push ]";
|
|
description = ''
|
|
A list of global znc module packages to add to znc.
|
|
'';
|
|
};
|
|
|
|
mutable = mkOption {
|
|
default = true;
|
|
type = types.bool;
|
|
description = ''
|
|
Indicates whether to allow the contents of the `dataDir` directory to be changed
|
|
by the user at run-time.
|
|
If true, modifications to the ZNC configuration after its initial creation are not
|
|
overwritten by a NixOS system rebuild.
|
|
If false, the ZNC configuration is rebuilt by every system rebuild.
|
|
If the user wants to manage the ZNC service using the web admin interface, this value
|
|
should be set to true.
|
|
'';
|
|
};
|
|
|
|
extraFlags = mkOption {
|
|
default = [ ];
|
|
example = [ "--debug" ];
|
|
type = types.listOf types.str;
|
|
description = ''
|
|
Extra flags to use when executing znc command.
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
|
|
###### Implementation
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
networking.firewall = mkIf cfg.openFirewall {
|
|
allowedTCPPorts = [ cfg.confOptions.port ];
|
|
};
|
|
|
|
systemd.services.znc = {
|
|
description = "ZNC Server";
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network.service" ];
|
|
serviceConfig = {
|
|
User = cfg.user;
|
|
Group = cfg.group;
|
|
Restart = "always";
|
|
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
|
ExecStop = "${pkgs.coreutils}/bin/kill -INT $MAINPID";
|
|
};
|
|
preStart = ''
|
|
${pkgs.coreutils}/bin/mkdir -p ${cfg.dataDir}/configs
|
|
|
|
# If mutable, regenerate conf file every time.
|
|
${optionalString (!cfg.mutable) ''
|
|
${pkgs.coreutils}/bin/echo "znc is set to be system-managed. Now deleting old znc.conf file to be regenerated."
|
|
${pkgs.coreutils}/bin/rm -f ${cfg.dataDir}/configs/znc.conf
|
|
''}
|
|
|
|
# Ensure essential files exist.
|
|
if [[ ! -f ${cfg.dataDir}/configs/znc.conf ]]; then
|
|
${pkgs.coreutils}/bin/echo "No znc.conf file found in ${cfg.dataDir}. Creating one now."
|
|
${pkgs.coreutils}/bin/cp --no-clobber ${zncConfFile} ${cfg.dataDir}/configs/znc.conf
|
|
${pkgs.coreutils}/bin/chmod u+rw ${cfg.dataDir}/configs/znc.conf
|
|
${pkgs.coreutils}/bin/chown ${cfg.user} ${cfg.dataDir}/configs/znc.conf
|
|
fi
|
|
|
|
if [[ ! -f ${cfg.dataDir}/znc.pem ]]; then
|
|
${pkgs.coreutils}/bin/echo "No znc.pem file found in ${cfg.dataDir}. Creating one now."
|
|
${pkgs.znc}/bin/znc --makepem --datadir ${cfg.dataDir}
|
|
fi
|
|
|
|
# Symlink modules
|
|
rm ${cfg.dataDir}/modules || true
|
|
ln -fs ${modules}/lib/znc ${cfg.dataDir}/modules
|
|
'';
|
|
script = "${pkgs.znc}/bin/znc --foreground --datadir ${cfg.dataDir} ${toString cfg.extraFlags}";
|
|
};
|
|
|
|
users.extraUsers = optional (cfg.user == defaultUser)
|
|
{ name = defaultUser;
|
|
description = "ZNC server daemon owner";
|
|
group = defaultUser;
|
|
uid = config.ids.uids.znc;
|
|
home = cfg.dataDir;
|
|
createHome = true;
|
|
};
|
|
|
|
users.extraGroups = optional (cfg.user == defaultUser)
|
|
{ name = defaultUser;
|
|
gid = config.ids.gids.znc;
|
|
members = [ defaultUser ];
|
|
};
|
|
|
|
};
|
|
}
|