diff --git a/nixos/doc/manual/release-notes/rl-2511.section.md b/nixos/doc/manual/release-notes/rl-2511.section.md index a030c95c8f8e..e0dd13567a43 100644 --- a/nixos/doc/manual/release-notes/rl-2511.section.md +++ b/nixos/doc/manual/release-notes/rl-2511.section.md @@ -112,6 +112,8 @@ - [ente](https://github.com/ente-io/ente), a service that provides a fully open source, end-to-end encrypted platform for photos and videos. Available as [services.ente.api](#opt-services.ente.api.enable) and [services.ente.web](#opt-services.ente.web.enable). +- [PairDrop](https://github.com/schlagmichdoch/pairdrop), a peer-to-peer file transfer web app. Available as [services.pairdrop](#opt-services.pairdrop.enable). + - [SuiteNumérique Docs](https://github.com/suitenumerique/docs), a collaborative note taking, wiki and documentation web platform and alternative to Notion or Outline. Available as [services.lasuite-docs](#opt-services.lasuite-docs.enable). - [dwl](https://codeberg.org/dwl/dwl), a compact, hackable compositor for Wayland based on wlroots. Available as [programs.dwl](#opt-programs.dwl.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 871244a929c0..01e55d267bf2 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1671,6 +1671,7 @@ ./services/web-apps/openvscode-server.nix ./services/web-apps/openwebrx.nix ./services/web-apps/outline.nix + ./services/web-apps/pairdrop.nix ./services/web-apps/part-db.nix ./services/web-apps/peering-manager.nix ./services/web-apps/peertube-runner.nix diff --git a/nixos/modules/services/web-apps/pairdrop.nix b/nixos/modules/services/web-apps/pairdrop.nix new file mode 100644 index 000000000000..56de9b252e45 --- /dev/null +++ b/nixos/modules/services/web-apps/pairdrop.nix @@ -0,0 +1,152 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (lib) + boolToString + getExe + isBool + maintainers + mapAttrs + mkEnableOption + mkIf + mkOption + mkPackageOption + optionalAttrs + optionals + types + ; + + cfg = config.services.pairdrop; + + json = pkgs.formats.json { }; +in +{ + options.services.pairdrop = { + enable = mkEnableOption "pairdrop"; + + package = mkPackageOption pkgs "pairdrop" { }; + + port = mkOption { + type = types.port; + default = 3000; + example = 3010; + description = "The port to listen on."; + }; + + rtcConfig = mkOption { + type = json.type; + default = null; + example = { + sdpSemantics = "unified-plan"; + iceServers = [ + { + urls = "stun:stun.example.com:19302"; + } + ]; + }; + description = '' + Configuration for STUN/TURN servers. + This is converted to JSON and written into a file automatically. + If you want to provide a file path instead, set `RTC_CONFIG` in {option}`services.pairdrop.environment`. + ''; + }; + + environment = mkOption { + description = '' + Additional configuration (environment variables) for PairDrop, see + + for supported values. + ''; + + type = types.submodule { + freeformType = + with types; + attrsOf (oneOf [ + bool + int + str + ]); + + options = { }; + }; + + default = { }; + + example = { + DEBUG_MODE = true; + RATE_LIMIT = 1; + IPV6_LOCALIZE = 4; + WS_FALLBACK = true; + SIGNALING_SERVER = "pairdrop.net"; + RTC_CONFIG = "/etc/pairdrop/rtc-config.json"; + + DONATION_BUTTON_ACTIVE = false; + TWITTER_BUTTON_ACTIVE = false; + MASTODON_BUTTON_ACTIVE = false; + BLUESKY_BUTTON_ACTIVE = false; + CUSTOM_BUTTON_ACTIVE = false; + PRIVACYPOLICY_BUTTON_ACTIVE = false; + }; + }; + }; + + config = mkIf cfg.enable { + warnings = optionals (cfg.rtcConfig != null && cfg.environment ? RTC_CONFIG) [ + "Both services.pairdrop.rtcConfig and services.pairdrop.environment.RTC_CONFIG are set. The environment variable will take precedence." + ]; + + systemd.services.pairdrop = + let + environment = { + PORT = toString cfg.port; + } + // (optionalAttrs (cfg.rtcConfig != null) { + RTC_CONFIG = json.generate "rtc-config.json" cfg.rtcConfig; + }) + // (mapAttrs (_: v: if isBool v then boolToString v else toString v) cfg.environment); + in + { + inherit environment; + + description = "PairDrop: Transfer Files Cross-Platform"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = getExe cfg.package; + + Type = "simple"; + Restart = "on-failure"; + RestartSec = 3; + DynamicUser = true; + + # Hardening + CapabilityBoundingSet = ""; + NoNewPrivileges = true; + PrivateUsers = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateMounts = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + }; + }; + }; + + meta.maintainers = with maintainers; [ diogotcorreia ]; +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 86b223ad06f2..5ddcd2484b4a 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -1149,6 +1149,7 @@ in oxidized = handleTest ./oxidized.nix { }; pacemaker = runTest ./pacemaker.nix; packagekit = runTest ./packagekit.nix; + pairdrop = runTest ./web-apps/pairdrop.nix; paisa = runTest ./paisa.nix; pam-file-contents = runTest ./pam/pam-file-contents.nix; pam-lastlog = runTest ./pam/pam-lastlog.nix; diff --git a/nixos/tests/web-apps/pairdrop.nix b/nixos/tests/web-apps/pairdrop.nix new file mode 100644 index 000000000000..bf404edfa7eb --- /dev/null +++ b/nixos/tests/web-apps/pairdrop.nix @@ -0,0 +1,32 @@ +{ ... }: +{ + name = "pairdrop-nixos"; + + nodes.machine = + { pkgs, ... }: + { + services.pairdrop = { + enable = true; + port = 1337; + environment = { + SIGNALING_SERVER = "pairdrop.net"; + CUSTOM_BUTTON_ACTIVE = false; + }; + }; + }; + + testScript = '' + import json + + machine.wait_for_unit("pairdrop.service") + + machine.wait_for_open_port(1337) + machine.succeed("curl --fail http://localhost:1337/") + + res = machine.succeed("curl --fail http://localhost:1337/config") + print(res) + cfg = json.loads(res) + assert cfg["signalingServer"] == "pairdrop.net/" + assert cfg["buttons"]["custom_button"]["active"] == "false" + ''; +} diff --git a/pkgs/by-name/pa/pairdrop/package.nix b/pkgs/by-name/pa/pairdrop/package.nix index d4b2aa08b70c..1fa983f47b26 100644 --- a/pkgs/by-name/pa/pairdrop/package.nix +++ b/pkgs/by-name/pa/pairdrop/package.nix @@ -2,6 +2,7 @@ lib, buildNpmPackage, fetchFromGitHub, + nixosTests, nodejs, }: @@ -36,6 +37,12 @@ buildNpmPackage rec { runHook postInstall ''; + passthru = { + tests = { + inherit (nixosTests) pairdrop; + }; + }; + meta = with lib; { description = "Local file sharing in your browser"; mainProgram = "pairdrop";