{ config, lib, pkgs, ... }: with lib; let cfg = config.local.sys.task-force-beta-bot; allowedChatsFile = pkgs.writeText "task-force-beta-bot-allowed-chats" ( lib.concatMapStringsSep "\n" toString cfg.allowedChats ); package = pkgs.rustPlatform.buildRustPackage { pname = "task-force-beta-bot"; version = "0.1.0"; src = pkgs.fetchgit { url = "https://git.posixlycorrect.com/fabian/task-force-beta-bot"; rev = "3ff112b1cd123d89023a9ba08ffee450ce2a88d9"; hash = "sha256-4BIjcLZ/E5k8NLoYNN6yF2xHr8qSHGXCP0Vk3JTB/q0="; }; cargoHash = "sha256-IMa45oJZuYL14+ZWYPCmXquBntBIZU+fe6J0Rx8KdjU="; meta = { description = "General-purpose modular Telegram bot"; mainProgram = "task_force_beta_bot"; }; }; in { options.local.sys.task-force-beta-bot = { enable = lib.mkEnableOption "the Task Force Beta Telegram bot"; tokenFile = lib.mkOption { type = lib.types.path; description = "Path to the Telegram bot token file."; }; allowedChats = lib.mkOption { type = lib.types.listOf lib.types.int; description = "List of Telegram chat IDs allowed to use the bot."; }; user = lib.mkOption { type = lib.types.str; default = "task-force-beta-bot"; description = "User to run the bot as."; }; group = lib.mkOption { type = lib.types.str; default = "task-force-beta-bot"; description = "Group for the bot service."; }; }; config = lib.mkIf cfg.enable { systemd.services.task-force-beta-bot = { after = ["network.target"]; wantedBy = ["multi-user.target"]; serviceConfig = { ExecStart = "${lib.getExe package} ${cfg.tokenFile} ${allowedChatsFile}"; User = cfg.user; Group = cfg.group; Restart = "on-failure"; RestartSec = "5s"; # Hardening CapabilityBoundingSet = ""; LockPersonality = true; MemoryDenyWriteExecute = true; NoNewPrivileges = true; PrivateDevices = true; PrivateTmp = true; PrivateUsers = true; ProtectClock = true; ProtectControlGroups = true; ProtectHome = true; ProtectHostname = true; ProtectKernelLogs = true; ProtectKernelModules = true; ProtectKernelTunables = true; ProtectSystem = "strict"; RestrictAddressFamilies = ["AF_INET" "AF_INET6"]; RestrictNamespaces = true; RestrictRealtime = true; RestrictSUIDSGID = true; SystemCallArchitectures = "native"; SystemCallFilter = ["@system-service" "~@privileged"]; # Token and allowed chats file access BindReadOnlyPaths = [builtins.storeDir cfg.tokenFile "${allowedChatsFile}"]; }; }; users = { users.task-force-beta-bot = lib.mkIf (cfg.user == "task-force-beta-bot") { group = cfg.group; isSystemUser = true; }; groups.task-force-beta-bot = lib.mkIf (cfg.group == "task-force-beta-bot") {}; }; }; }