{ config, lib, pkgs, ... }: let inherit (lib.modules) mkIf; inherit (lib.trivial) boolToString; inherit (lib.attrsets) mapAttrsToList optionalAttrs; inherit (lib.strings) coptionalString oncatStringsSep; inherit (pkgs) writeText writeShellScript; cfg = config.services.piped; sedEscapeSlashes = "sed 's#/#\\\/#'"; sedEscapeSingleQuotes = "sed \"s#'#\\\'#\""; backendConfig = { PORT = cfg.internalBackendPort; HTTP_WORKERS = cfg.httpWorkers; PROXY_PART = "https://${cfg.proxyDomain}"; API_URL = "https://${cfg.backendDomain}"; FRONTEND_URL = "https://${cfg.frontendDomain}"; DISABLE_REGISTRATION = cfg.disableRegistrations; COMPROMISED_PASSWORD_CHECK = cfg.enableCompromisedPasswordCheck; FEED_RETENTION = cfg.feedRetentionDays; SUBSCRIPTIONS_EXPIRY = cfg.subscriptionRetentionDays; SPONSORBLOCK_SERVERS = concatStringsSep "," cfg.sponsorblockServers; DISABLE_RYD = cfg.disableRYD; DISABLE_LBRY = cfg.disableLBRYStreams; RYD_PROXY_URL = cfg.rydAPIURL; SENTRY_DSN = cfg.sentryDSN; "hibernate.connection.url" = "jdbc:postgresql://${cfg.postgresDBHost}:${toString cfg.postgresDBPort}/${cfg.postgresDBName}"; "hibernate.connection.driver_class" = "org.postgresql.Driver"; "hibernate.dialect" = "org.hibernate.dialect.PostgreSQLDialect"; "hibernate.connection.username" = "${cfg.postgresDBUsername}"; "hibernate.connection.password" = if cfg.postgresDBPasswordFile == null then cfg.postgresDBPassword else "POSTGRES_PASSWORD_PLACEHOLDER"; } // (optionalAttrs cfg.enableCaptcha { CAPTCHA_API_URL = cfg.captchaAPIURL; # This is substituted in the PreStart of piped-backend.service CAPTCHA_API_KEY = if cfg.captchaAPIKeyFile != "" then "CAPTCHA_API_KEY_FILE_PLACEHOLDER" else cfg.captchaAPIKey; }) // (optionalAttrs cfg.enableFederation { MATRIX_SERVER = cfg.matrixServerAddr; # also substituted MATRIX_TOKEN = if cfg.matrixTokenFile != "" then "MATRIX_TOKEN_FILE_PLACEHOLDER" else cfg.matrixToken; }); cfgValueToString = value: if builtins.isBool value then boolToString value else toString value; cfgToLine = key: value: "${key}:${cfgValueToString value}"; cfgToString = config: (concatStringsSep "\n" (mapAttrsToList cfgToLine config)); backendConfigFile = writeText "config.properties" (cfgToString backendConfig); in { config = mkIf (cfg.enable && !cfg.disableBackend) { systemd.tmpfiles.rules = ["d /run/piped-backend - piped piped"]; systemd.services.piped-backend = { wantedBy = ["multi-user.target"]; serviceConfig = { WorkingDirectory = "/run/piped-backend"; ExecStartPre = let confFile = "/run/piped-backend/config.properties"; in writeShellScript "piped-backend-init" '' [ -f "${confFile}" ] && rm ${confFile} cp ${backendConfigFile} ${confFile} chmod 660 ${confFile} ${optionalString (cfg.enableCaptcha && cfg.captchaAPIKeyFile != "") '' sed -i "s/CAPTCHA_API_KEY_FILE_PLACEHOLDER/$(cat ${cfg.captchaAPIKeyFile} | ${sedEscapeSlashes})/" ${confFile} ''} ${optionalString (cfg.enableFederation && cfg.matrixTokenFile != "") '' sed -i "s/MATRIX_TOKEN_FILE_PLACEHOLDER/$(cat ${cfg.matrixTokenFile} | ${sedEscapeSlashes})/" ${confFile} ''} ${optionalString (cfg.postgresDBPasswordFile != null) '' sed -i "s/POSTGRES_PASSWORD_PLACEHOLDER/$(cat ${cfg.postgresDBPasswordFile} | ${sedEscapeSlashes})/" ${confFile} ''} ''; ExecStart = "${pkgs.piped-backend}/bin/piped-backend"; RestartSec = "5s"; User = "piped"; CapabilityBoundingSet = ""; PrivateDevices = true; PrivateUsers = true; ProtectHome = true; ProtectKernelLogs = true; ProtectProc = "invisible"; RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6"]; RestrictNamespaces = true; SystemCallArchitectures = "native"; SystemCallFilter = ["@system-service" "~@privileged" "~@resources"]; }; }; # Set password for piped when running postgres as piped won't run with # passwordless authentication systemd.services.piped-password = mkIf (!cfg.disablePostgresDB) { serviceConfig = { Type = "oneshot"; User = "postgres"; }; wantedBy = ["piped-backend.service"]; wants = ["postgresql.service"]; after = ["postgresql.service"]; script = '' ${config.services.postgresql.package}/bin/psql -c "ALTER USER ${cfg.postgresDBUsername} WITH PASSWORD '${ if cfg.postgresDBPasswordFile != null then "$(cat ${cfg.postgresDBPasswordFile} | ${sedEscapeSingleQuotes})" else cfg.postgresDBPassword }';" ''; }; services.postgresql = mkIf (!cfg.disablePostgresDB) { enable = true; ensureUsers = [ { name = cfg.postgresDBUsername; ensurePermissions."DATABASE ${cfg.postgresDBName}" = "ALL PRIVILEGES"; } ]; ensureDatabases = [cfg.postgresDBName]; }; services.nginx.virtualHosts."${cfg.backendDomain}" = mkIf (!cfg.disableNginx) { forceSSL = cfg.nginxForceSSL; enableACME = cfg.nginxEnableACME; locations."/" = { proxyPass = "http://127.0.0.1:${toString cfg.internalBackendPort}"; }; }; }; }