From a839e2fbcc2f0eaef439d9469fe16b23ee7b7a3a Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Sun, 31 Mar 2024 10:27:23 -0400 Subject: [PATCH 01/24] create usenet user + group --- nixarr/nixarr.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nixarr/nixarr.nix b/nixarr/nixarr.nix index 6990ff0..5e4a720 100644 --- a/nixarr/nixarr.nix +++ b/nixarr/nixarr.nix @@ -231,6 +231,7 @@ in { media.members = cfg.mediaUsers; streamer = {}; torrenter = {}; + usenet = {}; }; users.users = { streamer = { @@ -241,6 +242,10 @@ in { isSystemUser = true; group = "torrenter"; }; + usenet = { + isSystemUser = true; + group = "usenet"; + }; }; systemd.tmpfiles.rules = [ From ec8314301aede667121078689f543676eb750c1f Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Sun, 31 Mar 2024 10:28:01 -0400 Subject: [PATCH 02/24] usenet mediaDir creation + permissions fixes --- nixarr/nixarr.nix | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/nixarr/nixarr.nix b/nixarr/nixarr.nix index 5e4a720..608c57b 100644 --- a/nixarr/nixarr.nix +++ b/nixarr/nixarr.nix @@ -27,6 +27,7 @@ with lib; let fi chown -R torrenter:media "${cfg.mediaDir}/torrents" + chown -R usenet:media "${cfg.mediaDir}/usenet" chown -R streamer:media "${cfg.mediaDir}/library" find "${cfg.mediaDir}" \( -type d -exec chmod 0775 {} + -true \) -o \( -exec chmod 0664 {} + \) '' + strings.optionalString cfg.jellyfin.enable '' @@ -35,6 +36,9 @@ with lib; let '' + strings.optionalString cfg.transmission.enable '' chown -R torrenter:cross-seed "${cfg.transmission.stateDir}" find "${cfg.transmission.stateDir}" \( -type d -exec chmod 0750 {} + -true \) -o \( -exec chmod 0640 {} + \) + '' + strings.optionalString cfg.sabnzbd.enable '' + chown -R usenet:root "${cfg.sabnzbd.stateDir}" + find "${cfg.sabnzbd.stateDir}" \( -type d -exec chmod 0750 {} + -true \) -o \( -exec chmod 0640 {} + \) '' + strings.optionalString cfg.transmission.privateTrackers.cross-seed.enable '' chown -R cross-seed:root "${cfg.transmission.privateTrackers.cross-seed.stateDir}" find "${cfg.transmission.privateTrackers.cross-seed.stateDir}" \( -type d -exec chmod 0700 {} + -true \) -o \( -exec chmod 0600 {} + \) @@ -264,6 +268,15 @@ in { "d '${cfg.mediaDir}/torrents/radarr' 0755 torrenter media - -" "d '${cfg.mediaDir}/torrents/sonarr' 0755 torrenter media - -" "d '${cfg.mediaDir}/torrents/readarr' 0755 torrenter media - -" + # TODO: consider conditional dir creation for torrents and usenet + "d '${cfg.mediaDir}/usenet' 0755 usenet media - -" + "d '${cfg.mediaDir}/usenet/.incomplete' 0755 usenet media - -" + "d '${cfg.mediaDir}/usenet/.watch' 0755 usenet media - -" + "d '${cfg.mediaDir}/usenet/manual' 0755 usenet media - -" + "d '${cfg.mediaDir}/usenet/liadarr' 0755 usenet media - -" + "d '${cfg.mediaDir}/usenet/radarr' 0755 usenet media - -" + "d '${cfg.mediaDir}/usenet/sonarr' 0755 usenet media - -" + "d '${cfg.mediaDir}/usenet/readarr' 0755 usenet media - -" ]; environment.systemPackages = with pkgs; [ From 3e5a11ca06b7f5014460a8c23bdb790acbc98b7b Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Tue, 23 Apr 2024 14:42:22 -0400 Subject: [PATCH 03/24] init sabnzbd module --- nixarr/sabnzbd/default.nix | 71 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 nixarr/sabnzbd/default.nix diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix new file mode 100644 index 0000000..3cfc8af --- /dev/null +++ b/nixarr/sabnzbd/default.nix @@ -0,0 +1,71 @@ +{ + config, + lib, + pkgs, + ... +}: +with lib; let + cfg = config.nixarr.sabnzbd; + defaultPort = 8080; + nixarr = config.nixarr; + # downloadDir = "${nixarr.mediaDir}/usenet"; +in { + options.nixarr.sabnzbd = { + enable = mkEnableOption "Enable the SABnzbd service."; + + stateDir = mkOption { + type = types.path; + default = "${nixarr.stateDir}/sabnzbd"; + defaultText = literalExpression ''"''${nixarr.stateDir}/sabnzbd"''; + example = "/nixarr/.state/sabnzbd"; + description = '' + The location of the state directory for the SABnzbd service. + + **Warning:** Setting this to any path, where the subpath is not + owned by root, will fail! For example: + + ```nix + stateDir = /home/user/nixarr/.state/sabnzbd + ``` + + Is not supported, because `/home/user` is owned by `user`. + ''; + }; + + openFirewall = mkOption { + type = types.bool; + defaultText = literalExpression ''!nixarr.SABnzbd.vpn.enable''; + default = !cfg.vpn.enable; + example = true; + description = "Open firewall for SABnzbd"; + }; + + vpn.enable = mkOption { + type = types.bool; + default = false; + example = true; + description = '' + **Required options:** [`nixarr.vpn.enable`](#nixarr.vpn.enable) + + Route SABnzbd traffic through the VPN. + ''; + }; + }; + + imports = []; + + config = mkIf cfg.enable { + systemd.tmpfiles.rules = [ + "d '${cfg.stateDir}' 0750 usenet root - -" + ]; + + services.sabnzbd = { + enable = true; + user = "usenet"; + group = "media"; + configFile = /. + "${cfg.stateDir}/sabnzbd.ini"; + }; + + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ defaultPort ]; + }; +} \ No newline at end of file From 1b7e27d9e5b1182d102dee93d90c89968957b94e Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Tue, 23 Apr 2024 15:08:14 -0400 Subject: [PATCH 04/24] integrate sabnzbd module --- nixarr/nixarr.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nixarr/nixarr.nix b/nixarr/nixarr.nix index 608c57b..19a6d20 100644 --- a/nixarr/nixarr.nix +++ b/nixarr/nixarr.nix @@ -74,6 +74,7 @@ in { ./openssh ./prowlarr ./transmission + ./sabnzbd ../util ]; @@ -109,6 +110,7 @@ in { - [Readarr](#nixarr.readarr.enable) - [Sonarr](#nixarr.sonarr.enable) - [Transmission](#nixarr.transmission.enable) + - [SABnzbd](#nixarr.sabnzbd.enable) Remember to read the options. ''; From 593bb4ce8ff492cf239a0c20e4e1d3a4e8a83423 Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Tue, 23 Apr 2024 15:12:02 -0400 Subject: [PATCH 05/24] conditionally create usenet dl dirs --- nixarr/nixarr.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nixarr/nixarr.nix b/nixarr/nixarr.nix index 19a6d20..41dad4a 100644 --- a/nixarr/nixarr.nix +++ b/nixarr/nixarr.nix @@ -270,7 +270,8 @@ in { "d '${cfg.mediaDir}/torrents/radarr' 0755 torrenter media - -" "d '${cfg.mediaDir}/torrents/sonarr' 0755 torrenter media - -" "d '${cfg.mediaDir}/torrents/readarr' 0755 torrenter media - -" - # TODO: consider conditional dir creation for torrents and usenet + ] ++ lists.optionals cfg.sabnzbd.enable [ + # only create usenet dirs if sabnzbd is enabled "d '${cfg.mediaDir}/usenet' 0755 usenet media - -" "d '${cfg.mediaDir}/usenet/.incomplete' 0755 usenet media - -" "d '${cfg.mediaDir}/usenet/.watch' 0755 usenet media - -" From 77b2a589ce714284ca191d2f91bb0dfbef576e00 Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Tue, 23 Apr 2024 15:12:47 -0400 Subject: [PATCH 06/24] add sabnzbd vpn config --- nixarr/sabnzbd/default.nix | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index 3cfc8af..6cda433 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -67,5 +67,43 @@ in { }; networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ defaultPort ]; + + # Enable and specify VPN namespace to confine service in. + systemd.services.sabnzbd.vpnconfinement = mkIf cfg.vpn.enable { + enable = true; + vpnnamespace = "wg"; + }; + + # Port mappings + vpnnamespaces.wg = mkIf cfg.vpn.enable { + portMappings = [ + { + from = defaultPort; + to = defaultPort; + } + ]; + }; + + services.nginx = mkIf cfg.vpn.enable { + enable = true; + + recommendedTlsSettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + + virtualHosts."127.0.0.1:${builtins.toString defaultPort}" = { + listen = [ + { + addr = "0.0.0.0"; + port = defaultPort; + } + ]; + locations."/" = { + recommendedProxySettings = true; + proxyWebsockets = true; + proxyPass = "http://192.168.15.1:${builtins.toString defaultPort}"; + }; + }; + }; }; } \ No newline at end of file From a3d0d94500e670c10e14b652afa3a9d02701ebf6 Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Tue, 23 Apr 2024 19:46:09 -0400 Subject: [PATCH 07/24] try not to use path type when it may not exist at build --- nixarr/sabnzbd/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index 6cda433..403a097 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -63,7 +63,7 @@ in { enable = true; user = "usenet"; group = "media"; - configFile = /. + "${cfg.stateDir}/sabnzbd.ini"; + configFile = "${cfg.stateDir}/sabnzbd.ini"; }; networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ defaultPort ]; @@ -106,4 +106,4 @@ in { }; }; }; -} \ No newline at end of file +} From b4e816dbdf9e084008ad8438632be4826946521f Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Fri, 26 Apr 2024 19:01:28 -0400 Subject: [PATCH 08/24] pre-exec script to handle necessary directory and network config --- nixarr/sabnzbd/default.nix | 104 ++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index 403a097..430664b 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -8,7 +8,62 @@ with lib; let cfg = config.nixarr.sabnzbd; defaultPort = 8080; nixarr = config.nixarr; - # downloadDir = "${nixarr.mediaDir}/usenet"; + + setDirsCmds = '' + | initool set - misc download_dir ${nixarr.mediaDir}/usenet/.incomplete \ + | initool set - misc complete_dir ${nixarr.mediaDir}/usenet/manual \ + | initool set - misc dirscan_dir ${nixarr.mediaDir}/usenet/.watch \ + ''; + + mkSetHostWhitelistCmd = with lib.strings; (hosts: '' + | initool set - misc host_whitelist ${concatStringsSep "," hosts} \ + ''); + + mkSetRangeWhitelistCmd = with lib.strings; (ranges: '' + | initool set - misc local_ranges ${concatStringsSep "," ranges} \ + ''); + + # todo: need to figure out what to do on first sabnzbd boot when no config file exists + + mkINIInitScript = ( + { + sabnzbd-state-dir, + access-externally ? true, + whitelist-hosts ? [], + whitelist-ranges ? [] + }: + pkgs.writeShellApplication { + name = "set-sabnzbd-ini-values"; + runtimeInputs = with pkgs; [initool]; + text = with lib.strings; ( + '' + cat ${sabnzbd-state-dir}/sabnzbd.ini \ + '' + + + # set download dirs + setDirsCmds + + + # set host to 0.0.0.0 if remote access needed + optionalString access-externally '' + | initool set - misc host 0.0.0.0 \ + '' + + + # set hostname whitelist + optionalString (builtins.length whitelist-hosts > 0) ( + mkSetHostWhitelistCmd whitelist-hosts + ) + + + # set ip range whitelist + optionalString (builtins.length whitelist-ranges > 0) ( + mkSetRangeWhitelistCmd whitelist-ranges + ) + + + '' + > ${sabnzbd-state-dir}/sabnzbd.ini + '' + ); + } + ); in { options.nixarr.sabnzbd = { enable = mkEnableOption "Enable the SABnzbd service."; @@ -40,6 +95,40 @@ in { description = "Open firewall for SABnzbd"; }; + whitelistHostnames = mkOption { + type = types.listOf types.str; + default = [ config.networking.hostName ]; + defaultText = "[ config.networking.hostName ]"; + example = ''[ "mediaserv" "media.example.com" ]''; + description = '' + A list that specifies what URLs that are allowed to represent your + SABnzbd instance. If you see an error message like this when + trying to connect to SABnzbd from another device... + + ``` + Refused connection with hostname "your.hostname.com" + ``` + + ...then you should add your hostname(s) to this list. + + SABnzbd only allows connections matching these URLs in order to prevent + DNS hijacking. See + for more info. + ''; + }; + + whitelistRanges = mkOption { + type = types.listOf types.str; + default = [ ]; + defaultText = "[ ]"; + example = ''[ "192.168.1.0/24" "10.0.0.0/23" ]''; + description = '' + A list of IP ranges that will be allowed to connect to SABnzbd's + web GUI. This only needs to be set if SABnzbd needs to be accessed + from another machine besides its host. + ''; + }; + vpn.enable = mkOption { type = types.bool; default = false; @@ -68,6 +157,19 @@ in { networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ defaultPort ]; + systemd.services.sabnzbd.serviceConfig = { + ExecStartPre = mkBefore [ + ( + "+" + mkINIInitScript { + sabnzbd-state-dir = cfg.stateDir; + access-externally = cfg.openFirewall; + whitelist-hosts = cfg.whitelistHostnames; + whitelist-ranges = cfg.whitelistRanges; + } + "/bin/set-sabnzbd-ini-values" + ) + ]; + }; + # Enable and specify VPN namespace to confine service in. systemd.services.sabnzbd.vpnconfinement = mkIf cfg.vpn.enable { enable = true; From 3594605256ad31037ae7789d805a220eea416da3 Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Mon, 29 Apr 2024 08:02:47 -0400 Subject: [PATCH 09/24] restart sabnzbd service after init config generation --- nixarr/sabnzbd/default.nix | 50 +++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index 430664b..0af75c1 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -9,11 +9,7 @@ with lib; let defaultPort = 8080; nixarr = config.nixarr; - setDirsCmds = '' - | initool set - misc download_dir ${nixarr.mediaDir}/usenet/.incomplete \ - | initool set - misc complete_dir ${nixarr.mediaDir}/usenet/manual \ - | initool set - misc dirscan_dir ${nixarr.mediaDir}/usenet/.watch \ - ''; + edited-flag = "edited by nixarr"; mkSetHostWhitelistCmd = with lib.strings; (hosts: '' | initool set - misc host_whitelist ${concatStringsSep "," hosts} \ @@ -23,8 +19,6 @@ with lib; let | initool set - misc local_ranges ${concatStringsSep "," ranges} \ ''); - # todo: need to figure out what to do on first sabnzbd boot when no config file exists - mkINIInitScript = ( { sabnzbd-state-dir, @@ -36,13 +30,18 @@ with lib; let name = "set-sabnzbd-ini-values"; runtimeInputs = with pkgs; [initool]; text = with lib.strings; ( + # set download dirs '' - cat ${sabnzbd-state-dir}/sabnzbd.ini \ + if [ ! -f ${sabnzbd-state-dir}/sabnzbd.ini ]; then + exit 0 + fi + + initool set ${sabnzbd-state-dir}/sabnzbd.ini "" __comment__ '${edited-flag}' \ + | initool set - misc download_dir "${nixarr.mediaDir}/usenet/.incomplete" \ + | initool set - misc complete_dir "${nixarr.mediaDir}/usenet/manual" \ + | initool set - misc dirscan_dir "${nixarr.mediaDir}/usenet/.watch" \ '' + - # set download dirs - setDirsCmds + - # set host to 0.0.0.0 if remote access needed optionalString access-externally '' | initool set - misc host 0.0.0.0 \ @@ -59,7 +58,8 @@ with lib; let ) + '' - > ${sabnzbd-state-dir}/sabnzbd.ini + > ${sabnzbd-state-dir}/sabnzbd.ini.tmp \ + && mv ${sabnzbd-state-dir}/sabnzbd.ini{.tmp,} '' ); } @@ -168,6 +168,32 @@ in { } + "/bin/set-sabnzbd-ini-values" ) ]; + + ExecStartPost = mkBefore [ + ( + "+" + pkgs.writeShellApplication { + name = "ensure-sabnzbd-config-edits"; + runtimeInputs = with pkgs; [initool coreutils systemd]; + text = '' + until [ -f "${cfg.stateDir}/sabnzbd.ini" ] + do + sleep 1 + done + + if ! initool get "${cfg.stateDir}/sabnzbd.ini" "" __comment__; then + # force sabnzbd.service restart for ExecStartPre to run now + # that sabnzbd.ini has been created by the instance + systemctl restart -f sabnzbd.service + fi + + exit + ''; + } + "/bin/ensure-sabnzbd-config-edits" + ) + ]; + Restart = "on-failure"; + StartLimitInterval = 15; + StartLimitBurst = 5; }; # Enable and specify VPN namespace to confine service in. From e96666189bc681e2ed4d9dd006488c9efc93c24b Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Tue, 7 May 2024 04:49:26 -0400 Subject: [PATCH 10/24] run temp instance of sabnzbd to generate config file --- nixarr/sabnzbd/default.nix | 58 ++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index 0af75c1..53e0f81 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -28,13 +28,21 @@ with lib; let }: pkgs.writeShellApplication { name = "set-sabnzbd-ini-values"; - runtimeInputs = with pkgs; [initool]; + runtimeInputs = with pkgs; [initool sabnzbd sudo coreutils]; text = with lib.strings; ( # set download dirs '' if [ ! -f ${sabnzbd-state-dir}/sabnzbd.ini ]; then - exit 0 - fi + sudo -u usenet -g media sabnzbd -p -d -f ${sabnzbd-state-dir}/sabnzbd.ini + sab_pid=$! + + until [ -f "${sabnzbd-state-dir}/sabnzbd.ini" ] + do + sleep 1 + done + + kill -INT $sab_pid + fi initool set ${sabnzbd-state-dir}/sabnzbd.ini "" __comment__ '${edited-flag}' \ | initool set - misc download_dir "${nixarr.mediaDir}/usenet/.incomplete" \ @@ -169,28 +177,28 @@ in { ) ]; - ExecStartPost = mkBefore [ - ( - "+" + pkgs.writeShellApplication { - name = "ensure-sabnzbd-config-edits"; - runtimeInputs = with pkgs; [initool coreutils systemd]; - text = '' - until [ -f "${cfg.stateDir}/sabnzbd.ini" ] - do - sleep 1 - done - - if ! initool get "${cfg.stateDir}/sabnzbd.ini" "" __comment__; then - # force sabnzbd.service restart for ExecStartPre to run now - # that sabnzbd.ini has been created by the instance - systemctl restart -f sabnzbd.service - fi - - exit - ''; - } + "/bin/ensure-sabnzbd-config-edits" - ) - ]; + # ExecStartPost = mkBefore [ + # ( + # "+" + pkgs.writeShellApplication { + # name = "ensure-sabnzbd-config-edits"; + # runtimeInputs = with pkgs; [initool coreutils systemd]; + # text = '' + # until [ -f "${cfg.stateDir}/sabnzbd.ini" ] + # do + # sleep 1 + # done + # + # if ! initool get "${cfg.stateDir}/sabnzbd.ini" "" __comment__; then + # # force sabnzbd.service restart for ExecStartPre to run now + # # that sabnzbd.ini has been created by the instance + # systemctl restart -f sabnzbd.service + # fi + # + # exit + # ''; + # } + "/bin/ensure-sabnzbd-config-edits" + # ) + # ]; Restart = "on-failure"; StartLimitInterval = 15; StartLimitBurst = 5; From bc85cdc98c6cf818142fef1480a1c799db98638a Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Thu, 9 May 2024 08:20:59 -0400 Subject: [PATCH 11/24] make sabnzbd gui port a user option --- nixarr/sabnzbd/default.nix | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index 53e0f81..edcb43b 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -6,7 +6,6 @@ }: with lib; let cfg = config.nixarr.sabnzbd; - defaultPort = 8080; nixarr = config.nixarr; edited-flag = "edited by nixarr"; @@ -22,6 +21,7 @@ with lib; let mkINIInitScript = ( { sabnzbd-state-dir, + guiPort, access-externally ? true, whitelist-hosts ? [], whitelist-ranges ? [] @@ -48,6 +48,7 @@ with lib; let | initool set - misc download_dir "${nixarr.mediaDir}/usenet/.incomplete" \ | initool set - misc complete_dir "${nixarr.mediaDir}/usenet/manual" \ | initool set - misc dirscan_dir "${nixarr.mediaDir}/usenet/.watch" \ + | initool set - misc port "${builtins.toString guiPort}" \ '' + # set host to 0.0.0.0 if remote access needed @@ -95,6 +96,15 @@ in { ''; }; + guiPort = mkOption { + type = types.port; + default = 8080; + example = 9999; + description = '' + The port that SABnzbd's GUI will listen on for incomming connections. + ''; + }; + openFirewall = mkOption { type = types.bool; defaultText = literalExpression ''!nixarr.SABnzbd.vpn.enable''; @@ -163,13 +173,14 @@ in { configFile = "${cfg.stateDir}/sabnzbd.ini"; }; - networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ defaultPort ]; + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.guiPort ]; systemd.services.sabnzbd.serviceConfig = { ExecStartPre = mkBefore [ ( "+" + mkINIInitScript { sabnzbd-state-dir = cfg.stateDir; + guiPort = cfg.guiPort; access-externally = cfg.openFirewall; whitelist-hosts = cfg.whitelistHostnames; whitelist-ranges = cfg.whitelistRanges; @@ -214,8 +225,8 @@ in { vpnnamespaces.wg = mkIf cfg.vpn.enable { portMappings = [ { - from = defaultPort; - to = defaultPort; + from = cfg.guiPort; + to = cfg.guiPort; } ]; }; @@ -227,17 +238,17 @@ in { recommendedOptimisation = true; recommendedGzipSettings = true; - virtualHosts."127.0.0.1:${builtins.toString defaultPort}" = { + virtualHosts."127.0.0.1:${builtins.toString cfg.guiPort}" = { listen = [ { addr = "0.0.0.0"; - port = defaultPort; + port = cfg.guiPort; } ]; locations."/" = { recommendedProxySettings = true; proxyWebsockets = true; - proxyPass = "http://192.168.15.1:${builtins.toString defaultPort}"; + proxyPass = "http://192.168.15.1:${builtins.toString cfg.guiPort}"; }; }; }; From 18bf4901d6b1adca89de1328b93653b70b19a3ad Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Thu, 9 May 2024 08:43:24 -0400 Subject: [PATCH 12/24] remove commented-out sabnzbd ExecStartPost script --- nixarr/sabnzbd/default.nix | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index edcb43b..d31c836 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -187,29 +187,6 @@ in { } + "/bin/set-sabnzbd-ini-values" ) ]; - - # ExecStartPost = mkBefore [ - # ( - # "+" + pkgs.writeShellApplication { - # name = "ensure-sabnzbd-config-edits"; - # runtimeInputs = with pkgs; [initool coreutils systemd]; - # text = '' - # until [ -f "${cfg.stateDir}/sabnzbd.ini" ] - # do - # sleep 1 - # done - # - # if ! initool get "${cfg.stateDir}/sabnzbd.ini" "" __comment__; then - # # force sabnzbd.service restart for ExecStartPre to run now - # # that sabnzbd.ini has been created by the instance - # systemctl restart -f sabnzbd.service - # fi - # - # exit - # ''; - # } + "/bin/ensure-sabnzbd-config-edits" - # ) - # ]; Restart = "on-failure"; StartLimitInterval = 15; StartLimitBurst = 5; From 2e2e3ff5cee613ced1ec6f10858ee62c55d57646 Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Thu, 9 May 2024 08:45:57 -0400 Subject: [PATCH 13/24] set sabnzbd state files to user-only access permissions --- nixarr/nixarr.nix | 2 +- nixarr/sabnzbd/default.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nixarr/nixarr.nix b/nixarr/nixarr.nix index 41dad4a..060cb04 100644 --- a/nixarr/nixarr.nix +++ b/nixarr/nixarr.nix @@ -38,7 +38,7 @@ with lib; let find "${cfg.transmission.stateDir}" \( -type d -exec chmod 0750 {} + -true \) -o \( -exec chmod 0640 {} + \) '' + strings.optionalString cfg.sabnzbd.enable '' chown -R usenet:root "${cfg.sabnzbd.stateDir}" - find "${cfg.sabnzbd.stateDir}" \( -type d -exec chmod 0750 {} + -true \) -o \( -exec chmod 0640 {} + \) + find "${cfg.sabnzbd.stateDir}" \( -type d -exec chmod 0700 {} + -true \) -o \( -exec chmod 0600 {} + \) '' + strings.optionalString cfg.transmission.privateTrackers.cross-seed.enable '' chown -R cross-seed:root "${cfg.transmission.privateTrackers.cross-seed.stateDir}" find "${cfg.transmission.privateTrackers.cross-seed.stateDir}" \( -type d -exec chmod 0700 {} + -true \) -o \( -exec chmod 0600 {} + \) diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index d31c836..bfd70b5 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -163,7 +163,7 @@ in { config = mkIf cfg.enable { systemd.tmpfiles.rules = [ - "d '${cfg.stateDir}' 0750 usenet root - -" + "d '${cfg.stateDir}' 0700 usenet root - -" ]; services.sabnzbd = { From f835deedd3cc3892b3084f0646c12aef3a269d05 Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Sat, 11 May 2024 18:22:42 -0400 Subject: [PATCH 14/24] move default config generation to separate module --- nixarr/sabnzbd/base-config.ini | 319 +++++++++++++++++++++++++++++++++ nixarr/sabnzbd/config.nix | 86 +++++++++ nixarr/sabnzbd/default.nix | 79 +------- 3 files changed, 406 insertions(+), 78 deletions(-) create mode 100644 nixarr/sabnzbd/base-config.ini create mode 100644 nixarr/sabnzbd/config.nix diff --git a/nixarr/sabnzbd/base-config.ini b/nixarr/sabnzbd/base-config.ini new file mode 100644 index 0000000..49bbbce --- /dev/null +++ b/nixarr/sabnzbd/base-config.ini @@ -0,0 +1,319 @@ +__version__ = 19 +__encoding__ = utf-8 +[misc] +helpful_warnings = 1 +queue_complete = "" +queue_complete_pers = 0 +bandwidth_perc = 100 +refresh_rate = 0 +interface_settings = "" +queue_limit = 20 +config_lock = 0 +fixed_ports = 1 +notified_new_skin = 0 +direct_unpack_tested = 0 +sorters_converted = 1 +check_new_rel = 1 +auto_browser = 0 +language = en +enable_https_verification = 1 +host = 127.0.0.1 +port = 8080 +https_port = "" +username = "" +password = "" +bandwidth_max = "" +cache_limit = 1G +web_dir = Glitter +web_color = Auto +https_cert = server.cert +https_key = server.key +https_chain = "" +enable_https = 0 +inet_exposure = 0 +api_key = 7e5bba66499740fb99c069230cd750b7 +nzb_key = 17f2984c97be487283c5a8bb00896415 +socks5_proxy_url = "" +permissions = "" +download_dir = Downloads/incomplete +download_free = "" +complete_dir = Downloads/complete +complete_free = "" +fulldisk_autoresume = 0 +script_dir = "" +nzb_backup_dir = "" +admin_dir = admin +backup_dir = "" +dirscan_dir = "" +dirscan_speed = 5 +password_file = "" +log_dir = logs +max_art_tries = 3 +top_only = 0 +sfv_check = 1 +script_can_fail = 0 +enable_recursive = 1 +flat_unpack = 0 +par_option = "" +pre_check = 0 +nice = "" +win_process_prio = 3 +ionice = "" +fail_hopeless_jobs = 1 +fast_fail = 1 +auto_disconnect = 1 +pre_script = None +end_queue_script = None +no_dupes = 0 +no_series_dupes = 0 +no_smart_dupes = 0 +dupes_propercheck = 1 +pause_on_pwrar = 1 +ignore_samples = 0 +deobfuscate_final_filenames = 1 +auto_sort = "" +direct_unpack = 0 +propagation_delay = 0 +folder_rename = 1 +replace_spaces = 0 +replace_underscores = 0 +replace_dots = 0 +safe_postproc = 1 +pause_on_post_processing = 0 +enable_all_par = 0 +sanitize_safe = 0 +cleanup_list = , +unwanted_extensions = , +action_on_unwanted_extensions = 0 +unwanted_extensions_mode = 0 +new_nzb_on_failure = 0 +history_retention = "" +history_retention_option = all +history_retention_number = 0 +quota_size = "" +quota_day = "" +quota_resume = 0 +quota_period = m +enable_tv_sorting = 0 +tv_sort_string = "" +tv_categories = tv, +enable_movie_sorting = 0 +movie_sort_string = "" +movie_sort_extra = -cd%1 +movie_categories = movies, +enable_date_sorting = 0 +date_sort_string = "" +date_categories = tv, +schedlines = , +rss_rate = 60 +ampm = 0 +start_paused = 0 +preserve_paused_state = 0 +enable_par_cleanup = 1 +process_unpacked_par2 = 1 +enable_multipar = 1 +enable_unrar = 1 +enable_7zip = 1 +enable_filejoin = 1 +enable_tsjoin = 1 +overwrite_files = 0 +ignore_unrar_dates = 0 +backup_for_duplicates = 0 +empty_postproc = 0 +wait_for_dfolder = 0 +rss_filenames = 0 +api_logging = 1 +html_login = 1 +warn_dupl_jobs = 0 +keep_awake = 1 +tray_icon = 1 +allow_incomplete_nzb = 0 +enable_broadcast = 1 +ipv6_hosting = 0 +ipv6_staging = 0 +api_warnings = 1 +no_penalties = 0 +x_frame_options = 1 +allow_old_ssl_tls = 0 +enable_season_sorting = 1 +verify_xff_header = 0 +rss_odd_titles = nzbindex.nl/, nzbindex.com/, nzbclub.com/ +quick_check_ext_ignore = nfo, sfv, srr +req_completion_rate = 100.2 +selftest_host = self-test.sabnzbd.org +movie_rename_limit = 100M +episode_rename_limit = 20M +size_limit = 0 +direct_unpack_threads = 3 +history_limit = 10 +wait_ext_drive = 5 +max_foldername_length = 246 +nomedia_marker = "" +ipv6_servers = 1 +url_base = /sabnzbd +host_whitelist = snootflix, +local_ranges = , +max_url_retries = 10 +downloader_sleep_time = 10 +receive_threads = 2 +switchinterval = 0.005 +ssdp_broadcast_interval = 15 +ext_rename_ignore = , +email_server = "" +email_to = , +email_from = "" +email_account = "" +email_pwd = "" +email_endjob = 0 +email_full = 0 +email_dir = "" +email_rss = 0 +email_cats = *, +[logging] +log_level = 1 +max_log_size = 5242880 +log_backups = 5 +[ncenter] +ncenter_enable = 0 +ncenter_cats = *, +ncenter_prio_startup = 0 +ncenter_prio_download = 0 +ncenter_prio_pause_resume = 0 +ncenter_prio_pp = 0 +ncenter_prio_complete = 1 +ncenter_prio_failed = 1 +ncenter_prio_disk_full = 1 +ncenter_prio_new_login = 0 +ncenter_prio_warning = 0 +ncenter_prio_error = 0 +ncenter_prio_queue_done = 0 +ncenter_prio_other = 1 +[acenter] +acenter_enable = 0 +acenter_cats = *, +acenter_prio_startup = 0 +acenter_prio_download = 0 +acenter_prio_pause_resume = 0 +acenter_prio_pp = 0 +acenter_prio_complete = 1 +acenter_prio_failed = 1 +acenter_prio_disk_full = 1 +acenter_prio_new_login = 0 +acenter_prio_warning = 0 +acenter_prio_error = 0 +acenter_prio_queue_done = 0 +acenter_prio_other = 1 +[ntfosd] +ntfosd_enable = 1 +ntfosd_cats = *, +ntfosd_prio_startup = 0 +ntfosd_prio_download = 0 +ntfosd_prio_pause_resume = 0 +ntfosd_prio_pp = 0 +ntfosd_prio_complete = 1 +ntfosd_prio_failed = 1 +ntfosd_prio_disk_full = 1 +ntfosd_prio_new_login = 0 +ntfosd_prio_warning = 0 +ntfosd_prio_error = 0 +ntfosd_prio_queue_done = 0 +ntfosd_prio_other = 1 +[prowl] +prowl_enable = 0 +prowl_cats = *, +prowl_apikey = "" +prowl_prio_startup = -3 +prowl_prio_download = -3 +prowl_prio_pause_resume = -3 +prowl_prio_pp = -3 +prowl_prio_complete = 0 +prowl_prio_failed = 1 +prowl_prio_disk_full = 1 +prowl_prio_new_login = -3 +prowl_prio_warning = -3 +prowl_prio_error = -3 +prowl_prio_queue_done = -3 +prowl_prio_other = 0 +[pushover] +pushover_token = "" +pushover_userkey = "" +pushover_device = "" +pushover_emergency_expire = 3600 +pushover_emergency_retry = 60 +pushover_enable = 0 +pushover_cats = *, +pushover_prio_startup = -3 +pushover_prio_download = -2 +pushover_prio_pause_resume = -2 +pushover_prio_pp = -3 +pushover_prio_complete = -1 +pushover_prio_failed = -1 +pushover_prio_disk_full = 1 +pushover_prio_new_login = -3 +pushover_prio_warning = 1 +pushover_prio_error = 1 +pushover_prio_queue_done = -3 +pushover_prio_other = -1 +[pushbullet] +pushbullet_enable = 0 +pushbullet_cats = *, +pushbullet_apikey = "" +pushbullet_device = "" +pushbullet_prio_startup = 0 +pushbullet_prio_download = 0 +pushbullet_prio_pause_resume = 0 +pushbullet_prio_pp = 0 +pushbullet_prio_complete = 1 +pushbullet_prio_failed = 1 +pushbullet_prio_disk_full = 1 +pushbullet_prio_new_login = 0 +pushbullet_prio_warning = 0 +pushbullet_prio_error = 0 +pushbullet_prio_queue_done = 0 +pushbullet_prio_other = 1 +[apprise] +apprise_enable = 0 +apprise_cats = *, +apprise_urls = "" +apprise_target_startup = "" +apprise_target_startup_enable = 0 +apprise_target_download = "" +apprise_target_download_enable = 0 +apprise_target_pause_resume = "" +apprise_target_pause_resume_enable = 0 +apprise_target_pp = "" +apprise_target_pp_enable = 0 +apprise_target_complete = "" +apprise_target_complete_enable = 1 +apprise_target_failed = "" +apprise_target_failed_enable = 1 +apprise_target_disk_full = "" +apprise_target_disk_full_enable = 0 +apprise_target_new_login = "" +apprise_target_new_login_enable = 1 +apprise_target_warning = "" +apprise_target_warning_enable = 0 +apprise_target_error = "" +apprise_target_error_enable = 0 +apprise_target_queue_done = "" +apprise_target_queue_done_enable = 0 +apprise_target_other = "" +apprise_target_other_enable = 1 +[nscript] +nscript_enable = 0 +nscript_cats = *, +nscript_script = "" +nscript_parameters = "" +nscript_prio_startup = 0 +nscript_prio_download = 0 +nscript_prio_pause_resume = 0 +nscript_prio_pp = 0 +nscript_prio_complete = 1 +nscript_prio_failed = 1 +nscript_prio_disk_full = 1 +nscript_prio_new_login = 0 +nscript_prio_warning = 0 +nscript_prio_error = 0 +nscript_prio_queue_done = 0 +nscript_prio_other = 1 + diff --git a/nixarr/sabnzbd/config.nix b/nixarr/sabnzbd/config.nix new file mode 100644 index 0000000..b45b47c --- /dev/null +++ b/nixarr/sabnzbd/config.nix @@ -0,0 +1,86 @@ +{ config, pkgs, lib, ... }: +let + cfg = config.nixarr.sabnzbd; + nixarr = config.nixarr; + ini-file-target = "${cfg.stateDir}/sabnzbd.ini"; + + concatStringsCommaIfExists = with lib.strings; stringList: ( + optionalString (builtins.length stringList > 0) ( + concatStringsSep "," stringList + ) + ); + + dynamic-configs = { + misc = { + host = if cfg.openFirewall then "0.0.0.0" else "127.0.0.1"; + port = cfg.guiPort; + download_dir = "${nixarr.mediaDir}/usenet/.incomplete"; + complete_dir = "${nixarr.mediaDir}/usenet/manual"; + dirscan_dir = "${nixarr.mediaDir}/usenet/watch"; + host_whitelist = concatStringsCommaIfExists cfg.whitelistHostnames; + local_ranges = concatStringsCommaIfExists cfg.whitelistRanges; + }; + }; + + dynamic-config-set-cmds = with lib.attrsets; mapAttrsToList ( + group-n: group-v: ( + mapAttrsToList ( + n: v: "| initool set - ${group-n} ${n} \"${builtins.toString v}\" \\\n" + ) group-v + ) + ) dynamic-configs; + + apply-dynamic-configs-script = pkgs.writeShellApplication { + name = "sabnzbd-set-dynamic-values"; + runtimeInputs = with pkgs; [initool util-linux]; + text = with lib; '' + if [ ! -f ${ini-file-target} ]; then + echo "FAILURE: Cannot write changes to ${ini-file-target}, file does not exist" + exit 1 + fi + + cp --preserve ${ini-file-target}{,.tmp} + initool set ${ini-file-target} "" __comment__ 'created by nixarr' \ + '' + (strings.concatStrings (lists.flatten dynamic-config-set-cmds)) + + '' + > ${ini-file-target}.tmp && mv -f ${ini-file-target}{.tmp,} + ''; + }; + + bashCheckIfEmptyStr = v: "[[ -z \$${v} || \$${v} == '\"\"' ]]"; + gen-uuids-script = pkgs.writeShellApplication { + name = "sabnzbd-set-random-api-uuids"; + runtimeInputs = with pkgs; [initool util-linux]; + text = '' + if [ ! -f ${ini-file-target} ]; then + echo "FAILURE: ${ini-file-target} does not exist. Cannot generate crypto strings." + exit 1 + fi + + api_key_value=$(initool get ${ini-file-target} misc api_key -v) + nzb_key_value=$(initool get ${ini-file-target} misc nzb_key -v) + + cp --preserve ${ini-file-target}{,.tmp} + if ${bashCheckIfEmptyStr "api_key_value"}; then + api_uuid=$(uuidgen --random | tr -d '-') + initool set ${ini-file-target} misc api_key "$api_uuid" \ + > ${ini-file-target}.tmp + echo "Generated api_key for ${ini-file-target}" + fi + if ${bashCheckIfEmptyStr "nzb_key_value"}; then + nzb_uuid=$(uuidgen --random | tr -d '-') + initool set ${ini-file-target} misc nzb_key "$nzb_uuid" \ + > ${ini-file-target}.tmp + echo "Generated nzb_key for ${ini-file-target}" + fi + mv -f ${ini-file-target}{.tmp,} + ''; + }; +in +{ + systemd.tmpfiles.rules = [ "C ${cfg.stateDir}/sabnzbd.ini - - - - ${./base-config.ini}" ]; + systemd.services.sabnzbd.serviceConfig.ExecStartPre = lib.mkBefore [ + (gen-uuids-script + "/bin/sabnzbd-set-random-api-uuids") + (apply-dynamic-configs-script + "/bin/sabnzbd-set-dynamic-values") + ]; +} diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index bfd70b5..264805c 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -7,72 +7,6 @@ with lib; let cfg = config.nixarr.sabnzbd; nixarr = config.nixarr; - - edited-flag = "edited by nixarr"; - - mkSetHostWhitelistCmd = with lib.strings; (hosts: '' - | initool set - misc host_whitelist ${concatStringsSep "," hosts} \ - ''); - - mkSetRangeWhitelistCmd = with lib.strings; (ranges: '' - | initool set - misc local_ranges ${concatStringsSep "," ranges} \ - ''); - - mkINIInitScript = ( - { - sabnzbd-state-dir, - guiPort, - access-externally ? true, - whitelist-hosts ? [], - whitelist-ranges ? [] - }: - pkgs.writeShellApplication { - name = "set-sabnzbd-ini-values"; - runtimeInputs = with pkgs; [initool sabnzbd sudo coreutils]; - text = with lib.strings; ( - # set download dirs - '' - if [ ! -f ${sabnzbd-state-dir}/sabnzbd.ini ]; then - sudo -u usenet -g media sabnzbd -p -d -f ${sabnzbd-state-dir}/sabnzbd.ini - sab_pid=$! - - until [ -f "${sabnzbd-state-dir}/sabnzbd.ini" ] - do - sleep 1 - done - - kill -INT $sab_pid - fi - - initool set ${sabnzbd-state-dir}/sabnzbd.ini "" __comment__ '${edited-flag}' \ - | initool set - misc download_dir "${nixarr.mediaDir}/usenet/.incomplete" \ - | initool set - misc complete_dir "${nixarr.mediaDir}/usenet/manual" \ - | initool set - misc dirscan_dir "${nixarr.mediaDir}/usenet/.watch" \ - | initool set - misc port "${builtins.toString guiPort}" \ - '' + - - # set host to 0.0.0.0 if remote access needed - optionalString access-externally '' - | initool set - misc host 0.0.0.0 \ - '' + - - # set hostname whitelist - optionalString (builtins.length whitelist-hosts > 0) ( - mkSetHostWhitelistCmd whitelist-hosts - ) + - - # set ip range whitelist - optionalString (builtins.length whitelist-ranges > 0) ( - mkSetRangeWhitelistCmd whitelist-ranges - ) + - - '' - > ${sabnzbd-state-dir}/sabnzbd.ini.tmp \ - && mv ${sabnzbd-state-dir}/sabnzbd.ini{.tmp,} - '' - ); - } - ); in { options.nixarr.sabnzbd = { enable = mkEnableOption "Enable the SABnzbd service."; @@ -159,7 +93,7 @@ in { }; }; - imports = []; + imports = [ ./config.nix ]; config = mkIf cfg.enable { systemd.tmpfiles.rules = [ @@ -176,17 +110,6 @@ in { networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.guiPort ]; systemd.services.sabnzbd.serviceConfig = { - ExecStartPre = mkBefore [ - ( - "+" + mkINIInitScript { - sabnzbd-state-dir = cfg.stateDir; - guiPort = cfg.guiPort; - access-externally = cfg.openFirewall; - whitelist-hosts = cfg.whitelistHostnames; - whitelist-ranges = cfg.whitelistRanges; - } + "/bin/set-sabnzbd-ini-values" - ) - ]; Restart = "on-failure"; StartLimitInterval = 15; StartLimitBurst = 5; From 90629ff83303d97dcb329aca069197e8e255cc8f Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Thu, 16 May 2024 15:02:10 -0400 Subject: [PATCH 15/24] add ExecStartPre script to fix possible sabnzbd permissions issue --- nixarr/sabnzbd/config.nix | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/nixarr/sabnzbd/config.nix b/nixarr/sabnzbd/config.nix index b45b47c..a8721de 100644 --- a/nixarr/sabnzbd/config.nix +++ b/nixarr/sabnzbd/config.nix @@ -30,6 +30,20 @@ let ) ) dynamic-configs; + fix-config-permissions-script = pkgs.writeShellApplication { + name = "sabnzbd-fix-config-permissions"; + runtimeInputs = with pkgs; [util-linux]; + text = '' + if [ ! -f ${ini-file-target} ]; then + echo 'FAILURE: cannot change permissions of ${ini-file-target}, file does not exist' + exit 1 + fi + + chmod 600 ${ini-file-target} + chown usenet:media ${ini-file-target} + ''; + }; + apply-dynamic-configs-script = pkgs.writeShellApplication { name = "sabnzbd-set-dynamic-values"; runtimeInputs = with pkgs; [initool util-linux]; @@ -80,6 +94,7 @@ in { systemd.tmpfiles.rules = [ "C ${cfg.stateDir}/sabnzbd.ini - - - - ${./base-config.ini}" ]; systemd.services.sabnzbd.serviceConfig.ExecStartPre = lib.mkBefore [ + ("+" + fix-config-permissions-script + "/bin/sabnzbd-fix-config-permissions") (gen-uuids-script + "/bin/sabnzbd-set-random-api-uuids") (apply-dynamic-configs-script + "/bin/sabnzbd-set-dynamic-values") ]; From 0344e470b689d5d34b74f79af231bef49c4dd7c7 Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Thu, 16 May 2024 15:09:39 -0400 Subject: [PATCH 16/24] fix language on sabnzbd config edited by nixarr --- nixarr/sabnzbd/config.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixarr/sabnzbd/config.nix b/nixarr/sabnzbd/config.nix index a8721de..713c248 100644 --- a/nixarr/sabnzbd/config.nix +++ b/nixarr/sabnzbd/config.nix @@ -54,7 +54,7 @@ let fi cp --preserve ${ini-file-target}{,.tmp} - initool set ${ini-file-target} "" __comment__ 'created by nixarr' \ + initool set ${ini-file-target} "" __comment__ 'edited by nixarr' \ '' + (strings.concatStrings (lists.flatten dynamic-config-set-cmds)) + '' > ${ini-file-target}.tmp && mv -f ${ini-file-target}{.tmp,} From f20993ed5707ca92513059bf77586c9d26338cbc Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Tue, 21 May 2024 15:36:33 -0400 Subject: [PATCH 17/24] remove dependency on sabnzbd default config and use sed for editing Because initool cannot parse double-nested categories, sed is used instead to edit sabnzbd.ini values. It also appears that SABnzbd will keep any initial values written to sabnzbd.ini and then add any missing keys with their default values. Therefore, we can just generate the bits of config we need and let SABnzbd do the rest on its first run. --- nixarr/sabnzbd/base-config.ini | 319 --------------------------------- nixarr/sabnzbd/config.nix | 60 ++++--- 2 files changed, 35 insertions(+), 344 deletions(-) delete mode 100644 nixarr/sabnzbd/base-config.ini diff --git a/nixarr/sabnzbd/base-config.ini b/nixarr/sabnzbd/base-config.ini deleted file mode 100644 index 49bbbce..0000000 --- a/nixarr/sabnzbd/base-config.ini +++ /dev/null @@ -1,319 +0,0 @@ -__version__ = 19 -__encoding__ = utf-8 -[misc] -helpful_warnings = 1 -queue_complete = "" -queue_complete_pers = 0 -bandwidth_perc = 100 -refresh_rate = 0 -interface_settings = "" -queue_limit = 20 -config_lock = 0 -fixed_ports = 1 -notified_new_skin = 0 -direct_unpack_tested = 0 -sorters_converted = 1 -check_new_rel = 1 -auto_browser = 0 -language = en -enable_https_verification = 1 -host = 127.0.0.1 -port = 8080 -https_port = "" -username = "" -password = "" -bandwidth_max = "" -cache_limit = 1G -web_dir = Glitter -web_color = Auto -https_cert = server.cert -https_key = server.key -https_chain = "" -enable_https = 0 -inet_exposure = 0 -api_key = 7e5bba66499740fb99c069230cd750b7 -nzb_key = 17f2984c97be487283c5a8bb00896415 -socks5_proxy_url = "" -permissions = "" -download_dir = Downloads/incomplete -download_free = "" -complete_dir = Downloads/complete -complete_free = "" -fulldisk_autoresume = 0 -script_dir = "" -nzb_backup_dir = "" -admin_dir = admin -backup_dir = "" -dirscan_dir = "" -dirscan_speed = 5 -password_file = "" -log_dir = logs -max_art_tries = 3 -top_only = 0 -sfv_check = 1 -script_can_fail = 0 -enable_recursive = 1 -flat_unpack = 0 -par_option = "" -pre_check = 0 -nice = "" -win_process_prio = 3 -ionice = "" -fail_hopeless_jobs = 1 -fast_fail = 1 -auto_disconnect = 1 -pre_script = None -end_queue_script = None -no_dupes = 0 -no_series_dupes = 0 -no_smart_dupes = 0 -dupes_propercheck = 1 -pause_on_pwrar = 1 -ignore_samples = 0 -deobfuscate_final_filenames = 1 -auto_sort = "" -direct_unpack = 0 -propagation_delay = 0 -folder_rename = 1 -replace_spaces = 0 -replace_underscores = 0 -replace_dots = 0 -safe_postproc = 1 -pause_on_post_processing = 0 -enable_all_par = 0 -sanitize_safe = 0 -cleanup_list = , -unwanted_extensions = , -action_on_unwanted_extensions = 0 -unwanted_extensions_mode = 0 -new_nzb_on_failure = 0 -history_retention = "" -history_retention_option = all -history_retention_number = 0 -quota_size = "" -quota_day = "" -quota_resume = 0 -quota_period = m -enable_tv_sorting = 0 -tv_sort_string = "" -tv_categories = tv, -enable_movie_sorting = 0 -movie_sort_string = "" -movie_sort_extra = -cd%1 -movie_categories = movies, -enable_date_sorting = 0 -date_sort_string = "" -date_categories = tv, -schedlines = , -rss_rate = 60 -ampm = 0 -start_paused = 0 -preserve_paused_state = 0 -enable_par_cleanup = 1 -process_unpacked_par2 = 1 -enable_multipar = 1 -enable_unrar = 1 -enable_7zip = 1 -enable_filejoin = 1 -enable_tsjoin = 1 -overwrite_files = 0 -ignore_unrar_dates = 0 -backup_for_duplicates = 0 -empty_postproc = 0 -wait_for_dfolder = 0 -rss_filenames = 0 -api_logging = 1 -html_login = 1 -warn_dupl_jobs = 0 -keep_awake = 1 -tray_icon = 1 -allow_incomplete_nzb = 0 -enable_broadcast = 1 -ipv6_hosting = 0 -ipv6_staging = 0 -api_warnings = 1 -no_penalties = 0 -x_frame_options = 1 -allow_old_ssl_tls = 0 -enable_season_sorting = 1 -verify_xff_header = 0 -rss_odd_titles = nzbindex.nl/, nzbindex.com/, nzbclub.com/ -quick_check_ext_ignore = nfo, sfv, srr -req_completion_rate = 100.2 -selftest_host = self-test.sabnzbd.org -movie_rename_limit = 100M -episode_rename_limit = 20M -size_limit = 0 -direct_unpack_threads = 3 -history_limit = 10 -wait_ext_drive = 5 -max_foldername_length = 246 -nomedia_marker = "" -ipv6_servers = 1 -url_base = /sabnzbd -host_whitelist = snootflix, -local_ranges = , -max_url_retries = 10 -downloader_sleep_time = 10 -receive_threads = 2 -switchinterval = 0.005 -ssdp_broadcast_interval = 15 -ext_rename_ignore = , -email_server = "" -email_to = , -email_from = "" -email_account = "" -email_pwd = "" -email_endjob = 0 -email_full = 0 -email_dir = "" -email_rss = 0 -email_cats = *, -[logging] -log_level = 1 -max_log_size = 5242880 -log_backups = 5 -[ncenter] -ncenter_enable = 0 -ncenter_cats = *, -ncenter_prio_startup = 0 -ncenter_prio_download = 0 -ncenter_prio_pause_resume = 0 -ncenter_prio_pp = 0 -ncenter_prio_complete = 1 -ncenter_prio_failed = 1 -ncenter_prio_disk_full = 1 -ncenter_prio_new_login = 0 -ncenter_prio_warning = 0 -ncenter_prio_error = 0 -ncenter_prio_queue_done = 0 -ncenter_prio_other = 1 -[acenter] -acenter_enable = 0 -acenter_cats = *, -acenter_prio_startup = 0 -acenter_prio_download = 0 -acenter_prio_pause_resume = 0 -acenter_prio_pp = 0 -acenter_prio_complete = 1 -acenter_prio_failed = 1 -acenter_prio_disk_full = 1 -acenter_prio_new_login = 0 -acenter_prio_warning = 0 -acenter_prio_error = 0 -acenter_prio_queue_done = 0 -acenter_prio_other = 1 -[ntfosd] -ntfosd_enable = 1 -ntfosd_cats = *, -ntfosd_prio_startup = 0 -ntfosd_prio_download = 0 -ntfosd_prio_pause_resume = 0 -ntfosd_prio_pp = 0 -ntfosd_prio_complete = 1 -ntfosd_prio_failed = 1 -ntfosd_prio_disk_full = 1 -ntfosd_prio_new_login = 0 -ntfosd_prio_warning = 0 -ntfosd_prio_error = 0 -ntfosd_prio_queue_done = 0 -ntfosd_prio_other = 1 -[prowl] -prowl_enable = 0 -prowl_cats = *, -prowl_apikey = "" -prowl_prio_startup = -3 -prowl_prio_download = -3 -prowl_prio_pause_resume = -3 -prowl_prio_pp = -3 -prowl_prio_complete = 0 -prowl_prio_failed = 1 -prowl_prio_disk_full = 1 -prowl_prio_new_login = -3 -prowl_prio_warning = -3 -prowl_prio_error = -3 -prowl_prio_queue_done = -3 -prowl_prio_other = 0 -[pushover] -pushover_token = "" -pushover_userkey = "" -pushover_device = "" -pushover_emergency_expire = 3600 -pushover_emergency_retry = 60 -pushover_enable = 0 -pushover_cats = *, -pushover_prio_startup = -3 -pushover_prio_download = -2 -pushover_prio_pause_resume = -2 -pushover_prio_pp = -3 -pushover_prio_complete = -1 -pushover_prio_failed = -1 -pushover_prio_disk_full = 1 -pushover_prio_new_login = -3 -pushover_prio_warning = 1 -pushover_prio_error = 1 -pushover_prio_queue_done = -3 -pushover_prio_other = -1 -[pushbullet] -pushbullet_enable = 0 -pushbullet_cats = *, -pushbullet_apikey = "" -pushbullet_device = "" -pushbullet_prio_startup = 0 -pushbullet_prio_download = 0 -pushbullet_prio_pause_resume = 0 -pushbullet_prio_pp = 0 -pushbullet_prio_complete = 1 -pushbullet_prio_failed = 1 -pushbullet_prio_disk_full = 1 -pushbullet_prio_new_login = 0 -pushbullet_prio_warning = 0 -pushbullet_prio_error = 0 -pushbullet_prio_queue_done = 0 -pushbullet_prio_other = 1 -[apprise] -apprise_enable = 0 -apprise_cats = *, -apprise_urls = "" -apprise_target_startup = "" -apprise_target_startup_enable = 0 -apprise_target_download = "" -apprise_target_download_enable = 0 -apprise_target_pause_resume = "" -apprise_target_pause_resume_enable = 0 -apprise_target_pp = "" -apprise_target_pp_enable = 0 -apprise_target_complete = "" -apprise_target_complete_enable = 1 -apprise_target_failed = "" -apprise_target_failed_enable = 1 -apprise_target_disk_full = "" -apprise_target_disk_full_enable = 0 -apprise_target_new_login = "" -apprise_target_new_login_enable = 1 -apprise_target_warning = "" -apprise_target_warning_enable = 0 -apprise_target_error = "" -apprise_target_error_enable = 0 -apprise_target_queue_done = "" -apprise_target_queue_done_enable = 0 -apprise_target_other = "" -apprise_target_other_enable = 1 -[nscript] -nscript_enable = 0 -nscript_cats = *, -nscript_script = "" -nscript_parameters = "" -nscript_prio_startup = 0 -nscript_prio_download = 0 -nscript_prio_pause_resume = 0 -nscript_prio_pp = 0 -nscript_prio_complete = 1 -nscript_prio_failed = 1 -nscript_prio_disk_full = 1 -nscript_prio_new_login = 0 -nscript_prio_warning = 0 -nscript_prio_error = 0 -nscript_prio_queue_done = 0 -nscript_prio_other = 1 - diff --git a/nixarr/sabnzbd/config.nix b/nixarr/sabnzbd/config.nix index 713c248..b45b92a 100644 --- a/nixarr/sabnzbd/config.nix +++ b/nixarr/sabnzbd/config.nix @@ -3,14 +3,13 @@ let cfg = config.nixarr.sabnzbd; nixarr = config.nixarr; ini-file-target = "${cfg.stateDir}/sabnzbd.ini"; - concatStringsCommaIfExists = with lib.strings; stringList: ( optionalString (builtins.length stringList > 0) ( concatStringsSep "," stringList ) ); - dynamic-configs = { + user-configs = { misc = { host = if cfg.openFirewall then "0.0.0.0" else "127.0.0.1"; port = cfg.guiPort; @@ -22,13 +21,29 @@ let }; }; - dynamic-config-set-cmds = with lib.attrsets; mapAttrsToList ( + api-key-configs = { + misc = { + api_key = ""; + nzb_key = ""; + }; + }; + + compiled-configs = {misc = (user-configs.misc // api-key-configs.misc);}; + + ini-base-config-file = pkgs.writeTextFile { + name = "base-config.ini"; + text = lib.generators.toINI {} compiled-configs; + }; + + mkSedEditValue = name: value: ''sed -E 's%(\b${name} ?= ?).*%\1${builtins.toString value}%g' ''; + + user-config-set-cmds = with lib.attrsets; mapAttrsToList ( group-n: group-v: ( mapAttrsToList ( - n: v: "| initool set - ${group-n} ${n} \"${builtins.toString v}\" \\\n" + n: v: "${mkSedEditValue n v} \\\n" ) group-v ) - ) dynamic-configs; + ) user-configs; fix-config-permissions-script = pkgs.writeShellApplication { name = "sabnzbd-fix-config-permissions"; @@ -44,9 +59,9 @@ let ''; }; - apply-dynamic-configs-script = pkgs.writeShellApplication { - name = "sabnzbd-set-dynamic-values"; - runtimeInputs = with pkgs; [initool util-linux]; + apply-user-configs-script = pkgs.writeShellApplication { + name = "sabnzbd-set-user-values"; + runtimeInputs = with pkgs; [gnused util-linux]; text = with lib; '' if [ ! -f ${ini-file-target} ]; then echo "FAILURE: Cannot write changes to ${ini-file-target}, file does not exist" @@ -54,8 +69,8 @@ let fi cp --preserve ${ini-file-target}{,.tmp} - initool set ${ini-file-target} "" __comment__ 'edited by nixarr' \ - '' + (strings.concatStrings (lists.flatten dynamic-config-set-cmds)) + < ${ini-file-target} \ + '' + (strings.concatStringsSep "|" (lists.flatten user-config-set-cmds)) + '' > ${ini-file-target}.tmp && mv -f ${ini-file-target}{.tmp,} ''; @@ -64,7 +79,7 @@ let bashCheckIfEmptyStr = v: "[[ -z \$${v} || \$${v} == '\"\"' ]]"; gen-uuids-script = pkgs.writeShellApplication { name = "sabnzbd-set-random-api-uuids"; - runtimeInputs = with pkgs; [initool util-linux]; + runtimeInputs = with pkgs; [initool gnused util-linux]; text = '' if [ ! -f ${ini-file-target} ]; then echo "FAILURE: ${ini-file-target} does not exist. Cannot generate crypto strings." @@ -73,29 +88,24 @@ let api_key_value=$(initool get ${ini-file-target} misc api_key -v) nzb_key_value=$(initool get ${ini-file-target} misc nzb_key -v) - - cp --preserve ${ini-file-target}{,.tmp} - if ${bashCheckIfEmptyStr "api_key_value"}; then + + if ${bashCheckIfEmptyStr "api_key_value"} || ${bashCheckIfEmptyStr "nzb_key_value"}; then + cp --preserve ${ini-file-target}{,.tmp} api_uuid=$(uuidgen --random | tr -d '-') - initool set ${ini-file-target} misc api_key "$api_uuid" \ - > ${ini-file-target}.tmp - echo "Generated api_key for ${ini-file-target}" - fi - if ${bashCheckIfEmptyStr "nzb_key_value"}; then nzb_uuid=$(uuidgen --random | tr -d '-') - initool set ${ini-file-target} misc nzb_key "$nzb_uuid" \ - > ${ini-file-target}.tmp - echo "Generated nzb_key for ${ini-file-target}" + < ${ini-file-target} \ + ${mkSedEditValue "api_key" "'\"$api_uuid\"'"} \ + | ${mkSedEditValue "nzb_key" "'\"$nzb_uuid\"'"} \ + > ${ini-file-target}.tmp && mv -f ${ini-file-target}{.tmp,} fi - mv -f ${ini-file-target}{.tmp,} ''; }; in { - systemd.tmpfiles.rules = [ "C ${cfg.stateDir}/sabnzbd.ini - - - - ${./base-config.ini}" ]; + systemd.tmpfiles.rules = [ "C ${cfg.stateDir}/sabnzbd.ini - - - - ${ini-base-config-file}" ]; systemd.services.sabnzbd.serviceConfig.ExecStartPre = lib.mkBefore [ ("+" + fix-config-permissions-script + "/bin/sabnzbd-fix-config-permissions") (gen-uuids-script + "/bin/sabnzbd-set-random-api-uuids") - (apply-dynamic-configs-script + "/bin/sabnzbd-set-dynamic-values") + (apply-user-configs-script + "/bin/sabnzbd-set-user-values") ]; } From 2af829d35eb13433fbac26b89485d8a783b88d3a Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Tue, 4 Jun 2024 18:51:36 -0400 Subject: [PATCH 18/24] use configobj for post-install config changes The Python configobj library is what SABnzbd uses to create and modify their ini config file. Figured it'd be easiest to do the same, at least for when we need to make changes after the initial config file has been copied. --- nixarr/sabnzbd/config.nix | 41 +++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/nixarr/sabnzbd/config.nix b/nixarr/sabnzbd/config.nix index b45b92a..6a16a08 100644 --- a/nixarr/sabnzbd/config.nix +++ b/nixarr/sabnzbd/config.nix @@ -59,22 +59,33 @@ let ''; }; - apply-user-configs-script = pkgs.writeShellApplication { - name = "sabnzbd-set-user-values"; - runtimeInputs = with pkgs; [gnused util-linux]; - text = with lib; '' - if [ ! -f ${ini-file-target} ]; then - echo "FAILURE: Cannot write changes to ${ini-file-target}, file does not exist" - exit 1 - fi + user-configs-to-python = with lib; + attrsets.collect (f: !builtins.isAttrs f) ( + attrsets.mapAttrsRecursive ( + path: value: + "sab_config_map['" + + (lib.strings.concatStringsSep "']['" path) + + "'] = '" + + (builtins.toString value) + + "'" + ) + user-configs + ); + apply-user-configs-script = with lib; (pkgs.writers.writePython3Bin + "sabnzbd-set-user-values" {libraries = [pkgs.python3Packages.configobj];} '' + from pathlib import Path + from configobj import ConfigObj - cp --preserve ${ini-file-target}{,.tmp} - < ${ini-file-target} \ - '' + (strings.concatStringsSep "|" (lists.flatten user-config-set-cmds)) - + '' - > ${ini-file-target}.tmp && mv -f ${ini-file-target}{.tmp,} - ''; - }; + sab_config_path = Path("${ini-file-target}") + if not sab_config_path.is_file() or sab_config_path.suffix != ".ini": + raise Exception(f"{sab_config_path} is not a valid config file path.") + + sab_config_map = ConfigObj(str(sab_config_path)) + + ${lib.strings.concatStringsSep "\n" user-configs-to-python} + + sab_config_map.write() + ''); bashCheckIfEmptyStr = v: "[[ -z \$${v} || \$${v} == '\"\"' ]]"; gen-uuids-script = pkgs.writeShellApplication { From 41619cd4cd53ea8009f28bb6ed2925d45ad72970 Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Tue, 4 Jun 2024 18:52:10 -0400 Subject: [PATCH 19/24] treefmt-nix formatting --- nixarr/sabnzbd/config.nix | 50 +++++++++++++++++++++++--------------- nixarr/sabnzbd/default.nix | 8 +++--- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/nixarr/sabnzbd/config.nix b/nixarr/sabnzbd/config.nix index 6a16a08..db33eee 100644 --- a/nixarr/sabnzbd/config.nix +++ b/nixarr/sabnzbd/config.nix @@ -1,17 +1,25 @@ -{ config, pkgs, lib, ... }: -let +{ + config, + pkgs, + lib, + ... +}: let cfg = config.nixarr.sabnzbd; nixarr = config.nixarr; ini-file-target = "${cfg.stateDir}/sabnzbd.ini"; - concatStringsCommaIfExists = with lib.strings; stringList: ( - optionalString (builtins.length stringList > 0) ( - concatStringsSep "," stringList - ) - ); + concatStringsCommaIfExists = with lib.strings; + stringList: ( + optionalString (builtins.length stringList > 0) ( + concatStringsSep "," stringList + ) + ); user-configs = { misc = { - host = if cfg.openFirewall then "0.0.0.0" else "127.0.0.1"; + host = + if cfg.openFirewall + then "0.0.0.0" + else "127.0.0.1"; port = cfg.guiPort; download_dir = "${nixarr.mediaDir}/usenet/.incomplete"; complete_dir = "${nixarr.mediaDir}/usenet/manual"; @@ -28,22 +36,25 @@ let }; }; - compiled-configs = {misc = (user-configs.misc // api-key-configs.misc);}; + compiled-configs = {misc = user-configs.misc // api-key-configs.misc;}; ini-base-config-file = pkgs.writeTextFile { - name = "base-config.ini"; + name = "base-config.ini"; text = lib.generators.toINI {} compiled-configs; }; mkSedEditValue = name: value: ''sed -E 's%(\b${name} ?= ?).*%\1${builtins.toString value}%g' ''; - user-config-set-cmds = with lib.attrsets; mapAttrsToList ( - group-n: group-v: ( - mapAttrsToList ( - n: v: "${mkSedEditValue n v} \\\n" - ) group-v + user-config-set-cmds = with lib.attrsets; + mapAttrsToList ( + group-n: group-v: ( + mapAttrsToList ( + n: v: "${mkSedEditValue n v} \\\n" + ) + group-v + ) ) - ) user-configs; + user-configs; fix-config-permissions-script = pkgs.writeShellApplication { name = "sabnzbd-fix-config-permissions"; @@ -99,7 +110,7 @@ let api_key_value=$(initool get ${ini-file-target} misc api_key -v) nzb_key_value=$(initool get ${ini-file-target} misc nzb_key -v) - + if ${bashCheckIfEmptyStr "api_key_value"} || ${bashCheckIfEmptyStr "nzb_key_value"}; then cp --preserve ${ini-file-target}{,.tmp} api_uuid=$(uuidgen --random | tr -d '-') @@ -111,9 +122,8 @@ let fi ''; }; -in -{ - systemd.tmpfiles.rules = [ "C ${cfg.stateDir}/sabnzbd.ini - - - - ${ini-base-config-file}" ]; +in { + systemd.tmpfiles.rules = ["C ${cfg.stateDir}/sabnzbd.ini - - - - ${ini-base-config-file}"]; systemd.services.sabnzbd.serviceConfig.ExecStartPre = lib.mkBefore [ ("+" + fix-config-permissions-script + "/bin/sabnzbd-fix-config-permissions") (gen-uuids-script + "/bin/sabnzbd-set-random-api-uuids") diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index 264805c..7fc60ac 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -49,7 +49,7 @@ in { whitelistHostnames = mkOption { type = types.listOf types.str; - default = [ config.networking.hostName ]; + default = [config.networking.hostName]; defaultText = "[ config.networking.hostName ]"; example = ''[ "mediaserv" "media.example.com" ]''; description = '' @@ -71,7 +71,7 @@ in { whitelistRanges = mkOption { type = types.listOf types.str; - default = [ ]; + default = []; defaultText = "[ ]"; example = ''[ "192.168.1.0/24" "10.0.0.0/23" ]''; description = '' @@ -93,7 +93,7 @@ in { }; }; - imports = [ ./config.nix ]; + imports = [./config.nix]; config = mkIf cfg.enable { systemd.tmpfiles.rules = [ @@ -107,7 +107,7 @@ in { configFile = "${cfg.stateDir}/sabnzbd.ini"; }; - networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.guiPort ]; + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [cfg.guiPort]; systemd.services.sabnzbd.serviceConfig = { Restart = "on-failure"; From 2e791cbcb5723910cba2bd3533defeae3a713343 Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Fri, 7 Jun 2024 19:52:04 -0400 Subject: [PATCH 20/24] media group needs write permissions for usenet downloads (for arrs to delete etc.) --- nixarr/sabnzbd/config.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/nixarr/sabnzbd/config.nix b/nixarr/sabnzbd/config.nix index db33eee..d8a67ae 100644 --- a/nixarr/sabnzbd/config.nix +++ b/nixarr/sabnzbd/config.nix @@ -26,6 +26,7 @@ dirscan_dir = "${nixarr.mediaDir}/usenet/watch"; host_whitelist = concatStringsCommaIfExists cfg.whitelistHostnames; local_ranges = concatStringsCommaIfExists cfg.whitelistRanges; + permissions = "775"; }; }; From e695de950c07fd4b37f9181dd3dbff5d4e2f55ec Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Sun, 9 Jun 2024 13:23:42 -0400 Subject: [PATCH 21/24] set usenet arr dirs to 775 so that arrs can remove subdirs on import --- nixarr/nixarr.nix | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nixarr/nixarr.nix b/nixarr/nixarr.nix index 060cb04..c4e8418 100644 --- a/nixarr/nixarr.nix +++ b/nixarr/nixarr.nix @@ -275,11 +275,11 @@ in { "d '${cfg.mediaDir}/usenet' 0755 usenet media - -" "d '${cfg.mediaDir}/usenet/.incomplete' 0755 usenet media - -" "d '${cfg.mediaDir}/usenet/.watch' 0755 usenet media - -" - "d '${cfg.mediaDir}/usenet/manual' 0755 usenet media - -" - "d '${cfg.mediaDir}/usenet/liadarr' 0755 usenet media - -" - "d '${cfg.mediaDir}/usenet/radarr' 0755 usenet media - -" - "d '${cfg.mediaDir}/usenet/sonarr' 0755 usenet media - -" - "d '${cfg.mediaDir}/usenet/readarr' 0755 usenet media - -" + "d '${cfg.mediaDir}/usenet/manual' 0775 usenet media - -" + "d '${cfg.mediaDir}/usenet/liadarr' 0775 usenet media - -" + "d '${cfg.mediaDir}/usenet/radarr' 0775 usenet media - -" + "d '${cfg.mediaDir}/usenet/sonarr' 0775 usenet media - -" + "d '${cfg.mediaDir}/usenet/readarr' 0775 usenet media - -" ]; environment.systemPackages = with pkgs; [ From 88c99d2f37aabb1e288c3ddc496ff7aed80696ce Mon Sep 17 00:00:00 2001 From: jsecchiero Date: Sun, 23 Jun 2024 21:24:22 +0200 Subject: [PATCH 22/24] Passthrough the credentialsFile transmission option --- nixarr/transmission/default.nix | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/nixarr/transmission/default.nix b/nixarr/transmission/default.nix index d98eef3..b3a78f5 100644 --- a/nixarr/transmission/default.nix +++ b/nixarr/transmission/default.nix @@ -234,6 +234,17 @@ in { description = "Transmission web-UI port."; }; + credentialsFile = mkOption { + type = types.path; + description = '' + Path to a JSON file to be merged with the settings. + Useful to merge a file which is better kept out of the Nix store + to set secret config parameters like `rpc-password`. + ''; + default = "/dev/null"; + example = "/var/lib/secrets/transmission/settings.json"; + }; + extraSettings = mkOption { type = types.attrs; default = {}; @@ -339,6 +350,7 @@ in { package = pkgs.transmission_4; openRPCPort = cfg.openFirewall; openPeerPorts = cfg.openFirewall; + credentialsFile = cfg.credentialsFile; settings = { download-dir = downloadDir; From d524d09d0d27aa160f428fb3ab109b82a8e1d759 Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Sun, 14 Jul 2024 16:06:30 -0400 Subject: [PATCH 23/24] remove unneeded pkgs import and depricated StartLimitInterval --- nixarr/sabnzbd/default.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/nixarr/sabnzbd/default.nix b/nixarr/sabnzbd/default.nix index 7fc60ac..90ba825 100644 --- a/nixarr/sabnzbd/default.nix +++ b/nixarr/sabnzbd/default.nix @@ -1,7 +1,6 @@ { config, lib, - pkgs, ... }: with lib; let @@ -111,7 +110,6 @@ in { systemd.services.sabnzbd.serviceConfig = { Restart = "on-failure"; - StartLimitInterval = 15; StartLimitBurst = 5; }; From f9d626bb6ef73090292d1f099d5aa3e1d56ebb6e Mon Sep 17 00:00:00 2001 From: Richard Carter Date: Sun, 14 Jul 2024 16:10:57 -0400 Subject: [PATCH 24/24] simplify sabnzbd config file generation Let api keys be generated by SABnzbd on first run; there's no point in trying to do this ourselves. That effort was originally made when we had confidence in generating the whole config file from scratch. --- nixarr/sabnzbd/config.nix | 54 +++------------------------------------ 1 file changed, 3 insertions(+), 51 deletions(-) diff --git a/nixarr/sabnzbd/config.nix b/nixarr/sabnzbd/config.nix index d8a67ae..a2f6cba 100644 --- a/nixarr/sabnzbd/config.nix +++ b/nixarr/sabnzbd/config.nix @@ -30,33 +30,11 @@ }; }; - api-key-configs = { - misc = { - api_key = ""; - nzb_key = ""; - }; - }; - - compiled-configs = {misc = user-configs.misc // api-key-configs.misc;}; - ini-base-config-file = pkgs.writeTextFile { name = "base-config.ini"; - text = lib.generators.toINI {} compiled-configs; + text = lib.generators.toINI {} user-configs; }; - mkSedEditValue = name: value: ''sed -E 's%(\b${name} ?= ?).*%\1${builtins.toString value}%g' ''; - - user-config-set-cmds = with lib.attrsets; - mapAttrsToList ( - group-n: group-v: ( - mapAttrsToList ( - n: v: "${mkSedEditValue n v} \\\n" - ) - group-v - ) - ) - user-configs; - fix-config-permissions-script = pkgs.writeShellApplication { name = "sabnzbd-fix-config-permissions"; runtimeInputs = with pkgs; [util-linux]; @@ -71,7 +49,7 @@ ''; }; - user-configs-to-python = with lib; + user-configs-to-python-list = with lib; attrsets.collect (f: !builtins.isAttrs f) ( attrsets.mapAttrsRecursive ( path: value: @@ -94,40 +72,14 @@ sab_config_map = ConfigObj(str(sab_config_path)) - ${lib.strings.concatStringsSep "\n" user-configs-to-python} + ${lib.strings.concatStringsSep "\n" user-configs-to-python-list} sab_config_map.write() ''); - - bashCheckIfEmptyStr = v: "[[ -z \$${v} || \$${v} == '\"\"' ]]"; - gen-uuids-script = pkgs.writeShellApplication { - name = "sabnzbd-set-random-api-uuids"; - runtimeInputs = with pkgs; [initool gnused util-linux]; - text = '' - if [ ! -f ${ini-file-target} ]; then - echo "FAILURE: ${ini-file-target} does not exist. Cannot generate crypto strings." - exit 1 - fi - - api_key_value=$(initool get ${ini-file-target} misc api_key -v) - nzb_key_value=$(initool get ${ini-file-target} misc nzb_key -v) - - if ${bashCheckIfEmptyStr "api_key_value"} || ${bashCheckIfEmptyStr "nzb_key_value"}; then - cp --preserve ${ini-file-target}{,.tmp} - api_uuid=$(uuidgen --random | tr -d '-') - nzb_uuid=$(uuidgen --random | tr -d '-') - < ${ini-file-target} \ - ${mkSedEditValue "api_key" "'\"$api_uuid\"'"} \ - | ${mkSedEditValue "nzb_key" "'\"$nzb_uuid\"'"} \ - > ${ini-file-target}.tmp && mv -f ${ini-file-target}{.tmp,} - fi - ''; - }; in { systemd.tmpfiles.rules = ["C ${cfg.stateDir}/sabnzbd.ini - - - - ${ini-base-config-file}"]; systemd.services.sabnzbd.serviceConfig.ExecStartPre = lib.mkBefore [ ("+" + fix-config-permissions-script + "/bin/sabnzbd-fix-config-permissions") - (gen-uuids-script + "/bin/sabnzbd-set-random-api-uuids") (apply-user-configs-script + "/bin/sabnzbd-set-user-values") ]; }