The world's most clever kitty cat
1{
2 lib,
3 config,
4 ...
5}: let
6 cfg = config.services.bingus-bot;
7in {
8 options.services.bingus-bot = {
9 enable = lib.mkEnableOption "Bingus, a Discord bot that uses Markov Chains";
10
11 package = lib.mkOption {
12 description = "Package to use for bingus";
13 type = lib.types.package;
14 };
15
16 tokenFile = lib.mkOption {
17 default = "/etc/bingus/token";
18 type = lib.types.path;
19 description = "Path to a file containing the bot token that the service will authenticate to Discord with";
20 };
21
22 replyChannels = lib.mkOption {
23 default = [];
24 type = lib.types.listOf lib.types.number;
25 description = "List of Discord channel IDs that the bot should have a chance to reply in";
26 };
27 };
28
29 config = lib.mkIf cfg.enable {
30 systemd.services.bingus = let
31 replyChannelsStr = lib.strings.concatStrings (
32 lib.strings.intersperse "," (builtins.map builtins.toString cfg.replyChannels)
33 );
34 in {
35 wantedBy = ["multi-user.target"];
36 after = [
37 "network-online.target"
38 ];
39 wants = [
40 "network-online.target"
41 ];
42
43 environment = {
44 REPLY_CHANNELS = replyChannelsStr;
45 TOKEN_FILE = "%d/token";
46 BRAIN_FILE = "%S/bingus/brain.msgpackz";
47 };
48
49 serviceConfig = {
50 ExecStart = lib.getExe cfg.package;
51 Restart = "always";
52 RestartSec = "5s";
53 StateDirectory = "bingus";
54 StateDirectoryMode = "0755";
55 LoadCredential = "token:${cfg.tokenFile}";
56
57 # Hardening
58 RemoveIPC = true;
59 CapabilityBoundingSet = ["CAP_NET_BIND_SERVICE"];
60 NoNewPrivileges = true;
61 PrivateDevices = true;
62 ProtectClock = true;
63 ProtectKernelLogs = true;
64 ProtectControlGroups = true;
65 ProtectKernelModules = true;
66 PrivateMounts = true;
67 SystemCallArchitectures = ["native"];
68 MemoryDenyWriteExecute = true;
69 RestrictNamespaces = true;
70 RestrictSUIDSGID = true;
71 ProtectHostname = true;
72 LockPersonality = true;
73 ProtectKernelTunables = true;
74 RestrictAddressFamilies = [
75 "AF_UNIX"
76 "AF_INET"
77 "AF_INET6"
78 ];
79 RestrictRealtime = true;
80 DeviceAllow = [""];
81 ProtectSystem = "strict";
82 ProtectProc = "invisible";
83 ProcSubset = "pid";
84 ProtectHome = true;
85 PrivateUsers = true;
86 PrivateTmp = true;
87 UMask = "0077";
88 };
89 };
90 };
91}