# Taken from https://git.tempest.dev/ashe/nixos-wrapper-pounce/src/branch/main/flake.nix # I have removed a lot of the things I didn't need, and modified a few things to fit # my preferences (specifically, simplified the cert situation) { config, lib, pkgs, ... }: with lib; let cfg = config.services.pounce; pkg = pkgs.pounce; defaultUser = "pounce"; # {{{ systemd hardening flags hardeningFlags = { CapabilityBoundingSet = [ "" ]; NoNewPrivileges = true; PrivateDevices = true; PrivateMounts = true; PrivateTmp = true; PrivateUsers = true; ProtectClock = true; ProtectControlGroups = true; ProtectKernelLogs = true; ProtectKernelModules = true; ProtectKernelTunables = true; ProtectProc = "invisible"; RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; RestrictNamespaces = true; RestrictSUIDSGID = true; SystemCallArchitectures = "native"; SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; }; # }}} in { # {{{ Options options.services.pounce = { # {{{ general options enable = mkEnableOption "the Pounce IRC bouncer and Calico dispatcher"; user = mkOption { type = types.str; default = defaultUser; description = lib.mdDoc '' User account under which Pounce runs. If not specified, a default user will be created. ''; }; dataDir = mkOption { type = types.str; default = "/run/pounce"; description = lib.mdDoc '' Directory where each Pounce instance's UNIX-domain socket is stored for Calico to route to. ''; }; externalHost = mkOption { type = types.str; example = "example.org"; description = lib.mdDoc '' Base domain name Calico will be accessible at. Each instance will be at a subdomain of this. ''; }; bindHost = mkOption { type = types.str; default = "localhost"; description = lib.mdDoc '' The IP or host for Calico to bind to. ''; }; port = mkOption { type = types.port; default = 6697; description = lib.mdDoc "Port for Calico to listen on."; }; openFirewall = mkOption { type = types.bool; default = false; description = lib.mdDoc "Open port in the firewall for Calico."; }; timeout = mkOption { type = types.ints.positive; default = 1000; description = lib.mdDoc '' Timeout parameter (in milliseconds) for Calico to close a connection if no `ClientHello` message is sent. ''; }; certDir = mkOption { type = types.str; example = "/var/lib/acme/wildcard-irc.exmaple.com"; description = lib.mdDoc '' Directory where each Pounce instance's TLS certificates and private keys are stored. The folder must contain wildcard certs as generated by acme. ''; }; # }}} # {{{ networks networks = mkOption { type = types.attrsOf (types.submodule { options = { config = mkOption { type = types.path; description = lib.mdDoc '' Location to load pounce configuration from ''; }; }; }); default = { }; description = lib.mdDoc "Attribute set of IRC networks to connect to."; }; }; # }}} # }}} # {{{ config config = mkIf cfg.enable { systemd.tmpfiles.rules = [ "d ${cfg.dataDir} 0700 ${cfg.user} ${cfg.user} -" ]; systemd.services = mkMerge ( # {{{ calico service [ { calico = { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; description = "Calico dispatcher for Pounce IRC bouncer."; serviceConfig = { User = cfg.user; Group = cfg.user; ExecStart = '' ${pkg}/bin/calico \ -H ${cfg.bindHost} -P ${toString cfg.port} \ -t ${toString cfg.timeout} ${cfg.dataDir} ''; Restart = "on-failure"; } // hardeningFlags; }; } ] ++ # }}} # {{{ pounce service (mapAttrsToList (name: value: mkMerge [ { "pounce-${name}" = { wantedBy = [ "calico.service" ]; after = [ "network.target" ]; before = [ "calico.service" ]; description = "Pounce IRC bouncer for the ${name} network."; serviceConfig = { User = cfg.user; Group = cfg.user; ExecStart = '' ${pkg}/bin/pounce \ -C ${cfg.certDir}/fullchain.pem \ -K ${cfg.certDir}/key.pem \ -U ${cfg.dataDir} -H ${name}.${cfg.externalHost} \ ${value.config} ''; Restart = "on-failure"; } // hardeningFlags; }; } ]) cfg.networks) # }}} ); users = optionalAttrs (cfg.user == defaultUser) { users.${defaultUser} = { group = defaultUser; isSystemUser = true; }; groups.${defaultUser} = { }; }; networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; }; # }}} }