diff --git a/nixos/modules/services/misc/redlib.nix b/nixos/modules/services/misc/redlib.nix index 0da85df46bf7..3e3cd31a814c 100644 --- a/nixos/modules/services/misc/redlib.nix +++ b/nixos/modules/services/misc/redlib.nix @@ -1,18 +1,44 @@ -{ config, lib, pkgs, ... }: - -with lib; +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) + concatStringsSep + isBool + mapAttrs + mkEnableOption + mkIf + mkOption + mkPackageOption + mkRenamedOptionModule + types + ; + cfg = config.services.redlib; args = concatStringsSep " " ([ "--port ${toString cfg.port}" "--address ${cfg.address}" ]); + + boolToString' = b: if b then "on" else "off"; in { imports = [ - (mkRenamedOptionModule [ "services" "libreddit" ] [ "services" "redlib" ]) + (mkRenamedOptionModule + [ + "services" + "libreddit" + ] + [ + "services" + "redlib" + ] + ) ]; options = { @@ -24,7 +50,7 @@ in address = mkOption { default = "0.0.0.0"; example = "127.0.0.1"; - type = types.str; + type = types.str; description = "The address to listen on"; }; @@ -41,50 +67,60 @@ in description = "Open ports in the firewall for the redlib web interface"; }; + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = + with types; + attrsOf ( + nullOr (oneOf [ + bool + int + str + ]) + ); + options = { }; + }; + default = { }; + description = '' + See [GitHub](https://github.com/redlib-org/redlib/tree/main?tab=readme-ov-file#configuration) for available settings. + ''; + }; }; }; config = mkIf cfg.enable { + systemd.packages = [ cfg.package ]; systemd.services.redlib = { - description = "Private front-end for Reddit"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - serviceConfig = { - DynamicUser = true; - ExecStart = "${lib.getExe cfg.package} ${args}"; - AmbientCapabilities = lib.mkIf (cfg.port < 1024) [ "CAP_NET_BIND_SERVICE" ]; - Restart = "on-failure"; - RestartSec = "2s"; - # Hardening - CapabilityBoundingSet = if (cfg.port < 1024) then [ "CAP_NET_BIND_SERVICE" ] else [ "" ]; - DeviceAllow = [ "" ]; - LockPersonality = true; - MemoryDenyWriteExecute = true; - PrivateDevices = true; - # A private user cannot have process capabilities on the host's user - # namespace and thus CAP_NET_BIND_SERVICE has no effect. - PrivateUsers = (cfg.port >= 1024); - ProcSubset = "pid"; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectProc = "invisible"; - RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - SystemCallArchitectures = "native"; - SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ]; - UMask = "0077"; - }; + wantedBy = [ "default.target" ]; + environment = mapAttrs (_: v: if isBool v then boolToString' v else toString v) cfg.settings; + serviceConfig = + { + ExecStart = [ + "" + "${lib.getExe cfg.package} ${args}" + ]; + } + // ( + if (cfg.port < 1024) then + { + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; + } + else + { + # A private user cannot have process capabilities on the host's user + # namespace and thus CAP_NET_BIND_SERVICE has no effect. + PrivateUsers = true; + } + ); }; networking.firewall = mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; }; }; + + meta = { + maintainers = with lib.maintainers; [ Guanran928 ]; + }; } diff --git a/nixos/tests/redlib.nix b/nixos/tests/redlib.nix index 808f857aed19..c3a948c43795 100644 --- a/nixos/tests/redlib.nix +++ b/nixos/tests/redlib.nix @@ -1,20 +1,31 @@ -import ./make-test-python.nix ({ lib, pkgs, ... }: { - name = "redlib"; - meta.maintainers = with lib.maintainers; [ soispha ]; +import ./make-test-python.nix ( + { lib, pkgs, ... }: + { + name = "redlib"; + meta.maintainers = with lib.maintainers; [ + soispha + Guanran928 + ]; - nodes.machine = { - services.redlib = { - package = pkgs.redlib; - enable = true; - # Test CAP_NET_BIND_SERVICE - port = 80; + nodes.machine = { + services.redlib = { + package = pkgs.redlib; + enable = true; + # Test CAP_NET_BIND_SERVICE + port = 80; + + settings = { + REDLIB_DEFAULT_USE_HLS = true; + }; + }; }; - }; - testScript = '' - machine.wait_for_unit("redlib.service") - machine.wait_for_open_port(80) - # Query a page that does not require Internet access - machine.succeed("curl --fail http://localhost:80/settings") - ''; -}) + testScript = '' + machine.wait_for_unit("redlib.service") + machine.wait_for_open_port(80) + # Query a page that does not require Internet access + machine.succeed("curl --fail http://localhost:80/settings") + machine.succeed("curl --fail http://localhost:80/info | grep '