{ config, lib, pkgs, ... }: with lib; let cfg = config.services.namecoind; dataDir = "/var/lib/namecoind"; useSSL = (cfg.rpc.certificate != null) && (cfg.rpc.key != null); useRPC = (cfg.rpc.user != null) && (cfg.rpc.password != null); listToConf = option: list: concatMapStrings (value :"${option}=${value}\n") list; configFile = pkgs.writeText "namecoin.conf" ('' server=1 daemon=0 txindex=1 txprevcache=1 walletpath=${cfg.wallet} gen=${if cfg.generate then "1" else "0"} ${listToConf "addnode" cfg.extraNodes} ${listToConf "connect" cfg.trustedNodes} '' + optionalString useRPC '' rpcbind=${cfg.rpc.address} rpcport=${toString cfg.rpc.port} rpcuser=${cfg.rpc.user} rpcpassword=${cfg.rpc.password} ${listToConf "rpcallowip" cfg.rpc.allowFrom} '' + optionalString useSSL '' rpcssl=1 rpcsslcertificatechainfile=${cfg.rpc.certificate} rpcsslprivatekeyfile=${cfg.rpc.key} rpcsslciphers=TLSv1.2+HIGH:TLSv1+HIGH:!SSLv2:!aNULL:!eNULL:!3DES:@STRENGTH ''); in { ###### interface options = { services.namecoind = { enable = mkEnableOption "namecoind, Namecoin client."; wallet = mkOption { type = types.path; default = "${dataDir}/wallet.dat"; description = '' Wallet file. The ownership of the file has to be namecoin:namecoin, and the permissions must be 0640. ''; }; generate = mkOption { type = types.bool; default = false; description = '' Whether to generate (mine) Namecoins. ''; }; extraNodes = mkOption { type = types.listOf types.str; default = [ ]; description = '' List of additional peer IP addresses to connect to. ''; }; trustedNodes = mkOption { type = types.listOf types.str; default = [ ]; description = '' List of the only peer IP addresses to connect to. If specified no other connection will be made. ''; }; rpc.user = mkOption { type = types.nullOr types.str; default = null; description = '' User name for RPC connections. ''; }; rpc.password = mkOption { type = types.str; default = null; description = '' Password for RPC connections. ''; }; rpc.address = mkOption { type = types.str; default = "0.0.0.0"; description = '' IP address the RPC server will bind to. ''; }; rpc.port = mkOption { type = types.int; default = 8332; description = '' Port the RPC server will bind to. ''; }; rpc.certificate = mkOption { type = types.nullOr types.path; default = null; example = "/var/lib/namecoind/server.cert"; description = '' Certificate file for securing RPC connections. ''; }; rpc.key = mkOption { type = types.nullOr types.path; default = null; example = "/var/lib/namecoind/server.pem"; description = '' Key file for securing RPC connections. ''; }; rpc.allowFrom = mkOption { type = types.listOf types.str; default = [ "127.0.0.1" ]; description = '' List of IP address ranges allowed to use the RPC API. Wiledcards (*) can be user to specify a range. ''; }; }; }; ###### implementation config = mkIf cfg.enable { services.dnschain.extraConfig = '' [namecoin] config = ${configFile} ''; users.users = singleton { name = "namecoin"; uid = config.ids.uids.namecoin; description = "Namecoin daemon user"; home = dataDir; createHome = true; }; users.groups = singleton { name = "namecoin"; gid = config.ids.gids.namecoin; }; systemd.services.namecoind = { description = "Namecoind daemon"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { User = "namecoin"; Group = "namecoin"; ExecStart = "${pkgs.altcoins.namecoind}/bin/namecoind -conf=${configFile} -datadir=${dataDir} -printtoconsole"; ExecStop = "${pkgs.coreutils}/bin/kill -KILL $MAINPID"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; Nice = "10"; PrivateTmp = true; TimeoutStopSec = "60s"; TimeoutStartSec = "2s"; Restart = "always"; StartLimitInterval = "120s"; StartLimitBurst = "5"; }; preStart = optionalString (cfg.wallet != "${dataDir}/wallet.dat") '' # check wallet file permissions if [ "$(stat --printf '%u' ${cfg.wallet})" != "${toString config.ids.uids.namecoin}" \ -o "$(stat --printf '%g' ${cfg.wallet})" != "${toString config.ids.gids.namecoin}" \ -o "$(stat --printf '%a' ${cfg.wallet})" != "640" ]; then echo "ERROR: bad ownership or rights on ${cfg.wallet}" >&2 exit 1 fi ''; }; }; }