diff --git a/nixos/modules/services/web-apps/invidious.nix b/nixos/modules/services/web-apps/invidious.nix index f0e860383a62c2d..a2e3246fc5cf8b1 100644 --- a/nixos/modules/services/web-apps/invidious.nix +++ b/nixos/modules/services/web-apps/invidious.nix @@ -199,6 +199,41 @@ let }; }; + sigHelperConfig = lib.mkIf cfg.sig-helper.enable { + services.invidious.settings.signature_server = "tcp://${cfg.sig-helper.listenAddress}"; + systemd.services.invidious-sig-helper = { + script = '' + exec ${lib.getExe cfg.sig-helper.package} --tcp "${cfg.sig-helper.listenAddress}" + ''; + wantedBy = [ "multi-user.target" ]; + before = [ "invidious.service" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + serviceConfig = { + User = "invidious-sig-helper"; + DynamicUser = true; + Restart = "always"; + + PrivateTmp = true; + PrivateUsers = true; + ProtectSystem = true; + ProtectProc = "invisible"; + ProtectHome = true; + PrivateDevices = true; + NoNewPrivileges = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + ProtectKernelLogs = true; + CapabilityBoundingSet = ""; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" "@network-io" ]; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + }; + }; + }; + nginxConfig = lib.mkIf cfg.nginx.enable { services.invidious.settings = { https_only = config.services.nginx.virtualHosts.${cfg.domain}.forceSSL; @@ -392,6 +427,30 @@ in package = lib.mkPackageOptionMD pkgs "http3-ytproxy" { }; }; + + sig-helper = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to enable and configure inv-sig-helper to emulate the youtube client's javascript. This is required + to make certain videos playable. + + This will download and run completely untrusted javascript from youtube! While this service is sandboxed, + this may still be an issue! + ''; + }; + + package = lib.mkPackageOption pkgs "inv-sig-helper" { }; + + listenAddress = lib.mkOption { + type = lib.types.str; + default = "127.0.0.1:2999"; + description = '' + The IP address/port where inv-sig-helper should listen. + ''; + }; + }; }; config = lib.mkIf cfg.enable (lib.mkMerge [ @@ -399,5 +458,6 @@ in localDatabaseConfig nginxConfig ytproxyConfig + sigHelperConfig ]); } diff --git a/nixos/tests/invidious.nix b/nixos/tests/invidious.nix index c042b1065c2612f..05b43c555606024 100644 --- a/nixos/tests/invidious.nix +++ b/nixos/tests/invidious.nix @@ -37,6 +37,19 @@ import ./make-test-python.nix ({ pkgs, ... }: { }; networking.hosts."127.0.0.1" = [ "invidious.example.com" ]; }; + nginx-sig-helper.configuration = { + services.invidious = { + nginx.enable = true; + domain = "invidious.example.com"; + sig-helper.enable = true; + settings.log_level = "Trace"; + }; + services.nginx.virtualHosts."invidious.example.com" = { + forceSSL = false; + enableACME = false; + }; + networking.hosts."127.0.0.1" = [ "invidious.example.com" ]; + }; nginx-scale.configuration = { services.invidious = { nginx.enable = true; @@ -116,6 +129,14 @@ import ./make-test-python.nix ({ pkgs, ... }: { curl_assert_status_code("http://invidious.example.com/vi/dQw4w9WgXcQ/mqdefault.jpg", 502) machine.succeed("journalctl -eu http3-ytproxy.service | grep -o 'dQw4w9WgXcQ'") + activate_specialisation("nginx-sig-helper") + machine.wait_for_unit("invidious-sig-helper.service") + # we can't really test the sig helper that well without internet connection... + # invidious does connect to the sig helper though and crashes when the sig helper is not available + machine.wait_for_open_port(80) + curl_assert_status_code("http://invidious.example.com/search", 200) + machine.succeed("journalctl -eu invidious.service | grep -o \"SigHelper: Using helper at 'tcp://127.0.0.1:2999'\"") + postgres_tcp.wait_for_unit("postgresql.service") activate_specialisation("postgres-tcp") machine.wait_for_open_port(port) diff --git a/pkgs/by-name/in/inv-sig-helper/package.nix b/pkgs/by-name/in/inv-sig-helper/package.nix new file mode 100644 index 000000000000000..5070b60abcddbee --- /dev/null +++ b/pkgs/by-name/in/inv-sig-helper/package.nix @@ -0,0 +1,46 @@ +{ + lib, + stdenv, + rustPlatform, + fetchFromGitHub, + + # nativeBuildInputs + pkg-config, + + # buildInputs + openssl, + darwin, +}: + +rustPlatform.buildRustPackage { + pname = "inv-sig-helper"; + version = "0-unstable-2024-08-17"; + + src = fetchFromGitHub { + owner = "iv-org"; + repo = "inv_sig_helper"; + rev = "215d32c76e5e9e598de6e4f8542316f80dd92f57"; + hash = "sha256-Ge0XoWrscyZSrkmtDPkAnv96IVylKZTcgGgonbFV43I="; + }; + + cargoHash = "sha256-JVpLUhNJ7/4WZwLn/zOurpP8kF5WblF3nphJh6keHG8="; + + nativeBuildInputs = [ + pkg-config + ]; + + buildInputs = + [ openssl ] + ++ lib.optionals stdenv.isDarwin [ + darwin.apple_sdk.frameworks.Security + darwin.apple_sdk.frameworks.SystemConfiguration + ]; + + meta = { + description = "Rust service that decrypts YouTube signatures and manages player information"; + homepage = "https://github.com/iv-org/inv_sig_helper"; + license = lib.licenses.agpl3Only; + maintainers = with lib.maintainers; [ GaetanLepage ]; + mainProgram = "inv_sig_helper_rust"; + }; +}