diff --git a/nixos/doc/manual/release-notes/rl-2611.section.md b/nixos/doc/manual/release-notes/rl-2611.section.md index 32f2bab23a62..b8a10ea95106 100644 --- a/nixos/doc/manual/release-notes/rl-2611.section.md +++ b/nixos/doc/manual/release-notes/rl-2611.section.md @@ -24,6 +24,8 @@ - [Freescout](https://freescout.net/), a free, open source Helpdesk and shared mailbox. Available as [services.freescout](#opt-services.freescout.enable). +- [Koito](https://koito.io/), a modern, themeable scrobbler that you can use with any program that scrobbles to a custom ListenBrainz URL. Available as [services.koito](#opt-services.koito.enable). + - [FlapAlerted](https://github.com/Kioubit/FlapAlerted), detects BGP flapping events and provides statistics based on BGP update messages. Available as [services.flap-alerted](#opt-services.flap-alerted.enable). - [Unpackerr](https://unpackerr.zip), extracts downloads for Radarr, Sonarr, Lidarr, Readarr, and/or a Watch folder. Available as [services.unpackerr](#opt-services.unpackerr.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 6c9f8c03dc5e..9431d4f768e0 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1707,6 +1707,7 @@ ./services/web-apps/kavita.nix ./services/web-apps/keycloak.nix ./services/web-apps/kimai.nix + ./services/web-apps/koito.nix ./services/web-apps/komga.nix ./services/web-apps/lanraragi.nix ./services/web-apps/lasuite-docs.nix diff --git a/nixos/modules/services/web-apps/koito.nix b/nixos/modules/services/web-apps/koito.nix new file mode 100644 index 000000000000..f4b78770aed5 --- /dev/null +++ b/nixos/modules/services/web-apps/koito.nix @@ -0,0 +1,140 @@ +{ + lib, + config, + pkgs, + ... +}: +let + cfg = config.services.koito; + + inherit (lib) + getExe + mkEnableOption + mkIf + mkOption + mkPackageOption + types + ; +in +{ + options.services.koito = { + enable = mkEnableOption "koito"; + + package = mkPackageOption pkgs "koito" { }; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = "Open the appropriate ports in the firewall for Koito."; + }; + + environment = mkOption { + type = types.submodule { + freeformType = types.attrsOf types.str; + options = { + KOITO_BIND_ADDR = mkOption { + type = types.str; + default = "127.0.0.1"; + example = "0.0.0.0"; + description = "The IP address to bind the Koito server to."; + }; + KOITO_LISTEN_PORT = mkOption { + type = types.port; + default = 4110; + description = "TCP port for the Koito server."; + }; + KOITO_CONFIG_DIR = mkOption { + type = types.path; + default = "/var/lib/koito"; + description = "Directory for Koito import folders and image caches."; + }; + }; + }; + default = { }; + example = { + KOITO_DEFAULT_THEME = "black"; + KOITO_LOGIN_GATE = "true"; + }; + description = '' + Environment variables to pass to the Koito service. + See for available options. + ''; + }; + + environmentFile = mkOption { + type = types.nullOr types.path; + example = "/run/secrets/koito"; + default = null; + description = '' + Path of a file with extra environment variables to be loaded from disk. + This file is not added to the nix store, so it can be used to pass secrets to Koito. + See for available options. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.koito = { + description = "Koito - modern scrobbler"; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Environment = lib.mapAttrsToList (k: v: "${k}=${if builtins.isInt v then toString v else v}") ( + lib.filterAttrs (_: v: v != null) cfg.environment + ); + DynamicUser = true; + ExecStart = getExe cfg.package; + StateDirectory = "koito"; + EnvironmentFile = cfg.environmentFile; + + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateMounts = true; + ProtectControlGroups = true; + ProtectKernelTunables = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + UMask = "0077"; + + CapabilityBoundingSet = [ "" ]; + NoNewPrivileges = true; + + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectClock = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + "~@resources" + ]; + + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_UNIX" + ]; + + PrivateUsers = true; + + LockPersonality = true; + ProtectHostname = true; + RestrictRealtime = true; + RestrictNamespaces = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + DeviceAllow = [ "" ]; + }; + }; + networking.firewall = lib.mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.environment.KOITO_LISTEN_PORT ]; + }; + }; + + meta = { + maintainers = with lib.maintainers; [ iv-nn ]; + }; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 6a1c6f8e1065..5b3601d1822e 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -889,6 +889,7 @@ in kmonad = runTest ./kmonad.nix; kmscon = runTest ./kmscon.nix; knot = runTest ./knot.nix; + koito = runTest ./web-apps/koito.nix; komga = runTest ./komga.nix; komodo-periphery = runTest ./komodo-periphery.nix; krb5 = discoverTests (import ./krb5); diff --git a/nixos/tests/web-apps/koito.nix b/nixos/tests/web-apps/koito.nix new file mode 100644 index 000000000000..8839d4bfc57f --- /dev/null +++ b/nixos/tests/web-apps/koito.nix @@ -0,0 +1,20 @@ +{ ... }: +{ + name = "koito"; + + nodes.machine = { + services.koito.enable = true; + }; + + testScript = + { nodes, ... }: + let + port = toString nodes.machine.services.koito.environment.KOITO_LISTEN_PORT; + in + '' + machine.wait_for_unit('koito.service') + + machine.wait_for_open_port(${port}) + machine.succeed('curl --fail http://localhost:${port}') + ''; +} diff --git a/pkgs/by-name/ko/koito/package.nix b/pkgs/by-name/ko/koito/package.nix index a95823d4b7c7..1b088365b8f8 100644 --- a/pkgs/by-name/ko/koito/package.nix +++ b/pkgs/by-name/ko/koito/package.nix @@ -6,6 +6,7 @@ pkg-config, vips, makeWrapper, + nixosTests, }: buildGoModule (finalAttrs: { pname = "koito"; @@ -44,10 +45,15 @@ buildGoModule (finalAttrs: { ''; passthru = { - updateScript = ./update.sh; client = callPackage ./client.nix { inherit (finalAttrs) src version; }; + + tests = { + inherit (nixosTests) koito; + }; + + updateScript = ./update.sh; }; meta = {