summary refs log tree commit diff
path: root/nixos/modules/services/networking/supybot.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/networking/supybot.nix')
-rw-r--r--nixos/modules/services/networking/supybot.nix109
1 files changed, 92 insertions, 17 deletions
diff --git a/nixos/modules/services/networking/supybot.nix b/nixos/modules/services/networking/supybot.nix
index d5b9a97a1c1..dc9fb31ffd0 100644
--- a/nixos/modules/services/networking/supybot.nix
+++ b/nixos/modules/services/networking/supybot.nix
@@ -3,32 +3,35 @@
 with lib;
 
 let
-
   cfg  = config.services.supybot;
-
+  isStateDirHome = hasPrefix "/home/" cfg.stateDir;
+  isStateDirVar = cfg.stateDir == "/var/lib/supybot";
+  pyEnv = pkgs.python3.withPackages (p: [ p.limnoria ] ++ (cfg.extraPackages p));
 in
-
 {
-
   options = {
 
     services.supybot = {
 
       enable = mkOption {
+        type = types.bool;
         default = false;
-        description = "Enable Supybot, an IRC bot";
+        description = "Enable Supybot, an IRC bot (also known as Limnoria).";
       };
 
       stateDir = mkOption {
-        # Setting this to /var/lib/supybot caused useradd to fail
-        default = "/home/supybot";
+        type = types.path;
+        default = if versionAtLeast config.system.stateVersion "20.09"
+          then "/var/lib/supybot"
+          else "/home/supybot";
+        defaultText = "/var/lib/supybot";
         description = "The root directory, logs and plugins are stored here";
       };
 
       configFile = mkOption {
         type = types.path;
         description = ''
-          Path to a supybot config file. This can be generated by
+          Path to initial supybot config file. This can be generated by
           running supybot-wizard.
 
           Note: all paths should include the full path to the stateDir
@@ -36,21 +39,54 @@ in
         '';
       };
 
+      plugins = mkOption {
+        type = types.attrsOf types.path;
+        default = {};
+        description = ''
+          Attribute set of additional plugins that will be symlinked to the
+          <filename>plugin</filename> subdirectory.
+
+          Please note that you still need to add the plugins to the config
+          file (or with <literal>!load</literal>) using their attribute name.
+        '';
+        example = literalExample ''
+          let
+            plugins = pkgs.fetchzip {
+              url = "https://github.com/ProgVal/Supybot-plugins/archive/57c2450c.zip";
+              sha256 = "077snf84ibnva3sbpzdfpfma6hcdw7dflwnhg6pw7mgnf0nd84qd";
+            };
+          in
+          {
+            Wikipedia = "''${plugins}/Wikipedia";
+            Decide = ./supy-decide;
+          }
+        '';
+      };
+
+      extraPackages = mkOption {
+        default = p: [];
+        description = ''
+          Extra Python packages available to supybot plugins. The
+          value must be a function which receives the attrset defined
+          in <varname>python3Packages</varname> as the sole argument.
+        '';
+        example = literalExample ''p: [ p.lxml p.requests ]'';
+      };
+
     };
 
   };
 
-
   config = mkIf cfg.enable {
 
-    environment.systemPackages = [ pkgs.pythonPackages.limnoria ];
+    environment.systemPackages = [ pkgs.python3Packages.limnoria ];
 
     users.users.supybot = {
       uid = config.ids.uids.supybot;
       group = "supybot";
       description = "Supybot IRC bot user";
       home = cfg.stateDir;
-      createHome = true;
+      isSystemUser = true;
     };
 
     users.groups.supybot = {
@@ -59,19 +95,16 @@ in
 
     systemd.services.supybot = {
       description = "Supybot, an IRC bot";
+      documentation = [ "https://limnoria.readthedocs.io/" ];
       after = [ "network.target" ];
       wantedBy = [ "multi-user.target" ];
-      path = [ pkgs.pythonPackages.limnoria ];
       preStart = ''
-        cd ${cfg.stateDir}
-        mkdir -p backup conf data plugins logs/plugins tmp web
-        ln -sf ${cfg.configFile} supybot.cfg
         # This needs to be created afresh every time
-        rm -f supybot.cfg.bak
+        rm -f '${cfg.stateDir}/supybot.cfg.bak'
       '';
 
       serviceConfig = {
-        ExecStart = "${pkgs.pythonPackages.limnoria}/bin/supybot ${cfg.stateDir}/supybot.cfg";
+        ExecStart = "${pyEnv}/bin/supybot ${cfg.stateDir}/supybot.cfg";
         PIDFile = "/run/supybot.pid";
         User = "supybot";
         Group = "supybot";
@@ -79,8 +112,50 @@ in
         Restart = "on-abort";
         StartLimitInterval = "5m";
         StartLimitBurst = "1";
+
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        PrivateMounts = true;
+        PrivateTmp = true;
+        ProtectControlGroups = true;
+        ProtectKernelModules = true;
+        ProtectKernelTunables = true;
+        RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
+        RestrictSUIDSGID = true;
+        SystemCallArchitectures = "native";
+        RestrictNamespaces = true;
+        RestrictRealtime = true;
+        LockPersonality = true;
+        MemoryDenyWriteExecute = true;
+        RemoveIPC = true;
+        ProtectHostname = true;
+        CapabilityBoundingSet = "";
+        ProtectSystem = "full";
+      }
+      // optionalAttrs isStateDirVar {
+        StateDirectory = "supybot";
+        ProtectSystem = "strict";
+      }
+      // optionalAttrs (!isStateDirHome) {
+        ProtectHome = true;
       };
     };
 
+    systemd.tmpfiles.rules = [
+      "d '${cfg.stateDir}'              0700 supybot supybot - -"
+      "d '${cfg.stateDir}/backup'       0750 supybot supybot - -"
+      "d '${cfg.stateDir}/conf'         0750 supybot supybot - -"
+      "d '${cfg.stateDir}/data'         0750 supybot supybot - -"
+      "d '${cfg.stateDir}/plugins'      0750 supybot supybot - -"
+      "d '${cfg.stateDir}/logs'         0750 supybot supybot - -"
+      "d '${cfg.stateDir}/logs/plugins' 0750 supybot supybot - -"
+      "d '${cfg.stateDir}/tmp'          0750 supybot supybot - -"
+      "d '${cfg.stateDir}/web'          0750 supybot supybot - -"
+      "L '${cfg.stateDir}/supybot.cfg'  -    -       -       - ${cfg.configFile}"
+    ]
+    ++ (flip mapAttrsToList cfg.plugins (name: dest:
+      "L+ '${cfg.stateDir}/plugins/${name}' - - - - ${dest}"
+    ));
+
   };
 }