diff options
Diffstat (limited to 'nixpkgs/pkgs/applications/networking/browsers/tor-browser/default.nix')
-rw-r--r-- | nixpkgs/pkgs/applications/networking/browsers/tor-browser/default.nix | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/applications/networking/browsers/tor-browser/default.nix b/nixpkgs/pkgs/applications/networking/browsers/tor-browser/default.nix new file mode 100644 index 000000000000..c453113394ca --- /dev/null +++ b/nixpkgs/pkgs/applications/networking/browsers/tor-browser/default.nix @@ -0,0 +1,336 @@ +{ lib +, stdenv +, fetchurl +, makeDesktopItem +, copyDesktopItems +, makeWrapper +, writeText +, autoPatchelfHook +, wrapGAppsHook +, callPackage + +, atk +, cairo +, dbus +, dbus-glib +, fontconfig +, freetype +, gdk-pixbuf +, glib +, gtk3 +, libxcb +, libX11 +, libXext +, libXrender +, libXt +, libXtst +, mesa +, pango +, pciutils +, zlib + +, libnotifySupport ? stdenv.isLinux +, libnotify + +, waylandSupport ? stdenv.isLinux +, libxkbcommon +, libdrm +, libGL + +, mediaSupport ? true +, ffmpeg + +, audioSupport ? mediaSupport + +, pipewireSupport ? audioSupport +, pipewire + +, pulseaudioSupport ? audioSupport +, libpulseaudio +, apulse +, alsa-lib + +, libvaSupport ? mediaSupport +, libva + +# Hardening +, graphene-hardened-malloc +# Whether to use graphene-hardened-malloc +, useHardenedMalloc ? null + +# Whether to disable multiprocess support +, disableContentSandbox ? false + +# Extra preferences +, extraPrefs ? "" +}: + +lib.warnIf (useHardenedMalloc != null) + "tor-browser: useHardenedMalloc is deprecated and enabling it can cause issues" + +(let + libPath = lib.makeLibraryPath ( + [ + alsa-lib + atk + cairo + dbus + dbus-glib + fontconfig + freetype + gdk-pixbuf + glib + gtk3 + libxcb + libX11 + libXext + libXrender + libXt + libXtst + mesa # for libgbm + pango + pciutils + stdenv.cc.cc + stdenv.cc.libc + zlib + ] ++ lib.optionals libnotifySupport [ libnotify ] + ++ lib.optionals waylandSupport [ libxkbcommon libdrm libGL ] + ++ lib.optionals pipewireSupport [ pipewire ] + ++ lib.optionals pulseaudioSupport [ libpulseaudio ] + ++ lib.optionals libvaSupport [ libva ] + ++ lib.optionals mediaSupport [ ffmpeg ] + ); + + version = "13.0.10"; + + sources = { + x86_64-linux = fetchurl { + urls = [ + "https://archive.torproject.org/tor-package-archive/torbrowser/${version}/tor-browser-linux-x86_64-${version}.tar.xz" + "https://dist.torproject.org/torbrowser/${version}/tor-browser-linux-x86_64-${version}.tar.xz" + "https://tor.eff.org/dist/torbrowser/${version}/tor-browser-linux-x86_64-${version}.tar.xz" + "https://tor.calyxinstitute.org/dist/torbrowser/${version}/tor-browser-linux-x86_64-${version}.tar.xz" + ]; + hash = "sha256-/Lpz8R2NvMuV+3NzBy7gC/vWheHliNm9thQQw/9bkuw="; + }; + + i686-linux = fetchurl { + urls = [ + "https://archive.torproject.org/tor-package-archive/torbrowser/${version}/tor-browser-linux-i686-${version}.tar.xz" + "https://dist.torproject.org/torbrowser/${version}/tor-browser-linux-i686-${version}.tar.xz" + "https://tor.eff.org/dist/torbrowser/${version}/tor-browser-linux-i686-${version}.tar.xz" + "https://tor.calyxinstitute.org/dist/torbrowser/${version}/tor-browser-linux-i686-${version}.tar.xz" + ]; + hash = "sha256-zDiXXNRik/R3DBQEWBuXD31MI+Kg4UL1KK6em+JtyCs="; + }; + }; + + distributionIni = writeText "distribution.ini" (lib.generators.toINI {} { + # Some light branding indicating this build uses our distro preferences + Global = { + id = "nixos"; + version = "1.0"; + about = "Tor Browser for NixOS"; + }; + }); + + policiesJson = writeText "policies.json" (builtins.toJSON { + policies.DisableAppUpdate = true; + }); +in +stdenv.mkDerivation rec { + pname = "tor-browser"; + inherit version; + + src = sources.${stdenv.hostPlatform.system} or (throw "unsupported system: ${stdenv.hostPlatform.system}"); + + nativeBuildInputs = [ autoPatchelfHook copyDesktopItems makeWrapper wrapGAppsHook ]; + buildInputs = [ + gtk3 + alsa-lib + dbus-glib + libXtst + ]; + + preferLocalBuild = true; + allowSubstitutes = false; + + desktopItems = [(makeDesktopItem { + name = "torbrowser"; + exec = "tor-browser %U"; + icon = "tor-browser"; + desktopName = "Tor Browser"; + genericName = "Web Browser"; + comment = meta.description; + categories = [ "Network" "WebBrowser" "Security" ]; + })]; + + buildPhase = '' + runHook preBuild + + # For convenience ... + TBB_IN_STORE=$out/share/tor-browser + interp=$(< $NIX_CC/nix-support/dynamic-linker) + + # Unpack & enter + mkdir -p "$TBB_IN_STORE" + tar xf "$src" -C "$TBB_IN_STORE" --strip-components=2 + pushd "$TBB_IN_STORE" + + # Set ELF interpreter + for exe in firefox.real TorBrowser/Tor/tor ; do + echo "Setting ELF interpreter on $exe ..." >&2 + patchelf --set-interpreter "$interp" "$exe" + done + + # firefox is a wrapper that checks for a more recent libstdc++ & appends it to the ld path + mv firefox.real firefox + + # store state at `~/.tor browser` instead of relative to executable + touch "$TBB_IN_STORE/system-install" + + # The final libPath. Note, we could split this into firefoxLibPath + # and torLibPath for accuracy, but this is more convenient ... + libPath=${libPath}:$TBB_IN_STORE:$TBB_IN_STORE/TorBrowser/Tor + + # apulse uses a non-standard library path. For now special-case it. + ${lib.optionalString (audioSupport && !pulseaudioSupport) '' + libPath=${apulse}/lib/apulse:$libPath + ''} + + # Fixup paths to pluggable transports. + sed -i TorBrowser/Data/Tor/torrc-defaults \ + -e "s,./TorBrowser,$TBB_IN_STORE/TorBrowser,g" + + # Fixup obfs transport. Work around patchelf failing to set + # interpreter for pre-compiled Go binaries by invoking the interpreter + # directly. + sed -i TorBrowser/Data/Tor/torrc-defaults \ + -e "s|\(ClientTransportPlugin meek_lite,obfs2,obfs3,obfs4,scramblesuit\) exec|\1 exec $interp|" + + # Similarly fixup snowflake + sed -i TorBrowser/Data/Tor/torrc-defaults \ + -e "s|\(ClientTransportPlugin snowflake\) exec|\1 exec $interp|" + + # Prepare for autoconfig. + # + # See https://developer.mozilla.org/en-US/Firefox/Enterprise_deployment + cat >defaults/pref/autoconfig.js <<EOF + // + pref("general.config.filename", "mozilla.cfg"); + pref("general.config.obscure_value", 0); + EOF + + # Hard-coded Firefox preferences. + cat >mozilla.cfg <<EOF + // First line must be a comment + + // Reset pref that captures store paths. + clearPref("extensions.xpiState"); + + // Stop obnoxious first-run redirection. + lockPref("noscript.firstRunRedirection", false); + + // User should never change these. Locking prevents these + // values from being written to prefs.js, avoiding Store + // path capture. + lockPref("extensions.torlauncher.torrc-defaults_path", "$TBB_IN_STORE/TorBrowser/Data/Tor/torrc-defaults"); + lockPref("extensions.torlauncher.tor_path", "$TBB_IN_STORE/TorBrowser/Tor/tor"); + + // Insist on using IPC for communicating with Tor + // + // Defaults to creating \$XDG_RUNTIME_DIR/Tor/{socks,control}.socket + lockPref("extensions.torlauncher.control_port_use_ipc", true); + lockPref("extensions.torlauncher.socks_port_use_ipc", true); + + // Optionally disable multiprocess support. We always set this to ensure that + // toggling the pref takes effect. + lockPref("browser.tabs.remote.autostart.2", ${if disableContentSandbox then "false" else "true"}); + + // Allow sandbox access to sound devices if using ALSA directly + ${if (audioSupport && !pulseaudioSupport) then '' + pref("security.sandbox.content.write_path_whitelist", "/dev/snd/"); + '' else '' + clearPref("security.sandbox.content.write_path_whitelist"); + ''} + + ${lib.optionalString (extraPrefs != "") '' + ${extraPrefs} + ''} + EOF + + # FONTCONFIG_FILE is required to make fontconfig read the TBB + # fonts.conf; upstream uses FONTCONFIG_PATH, but FC_DEBUG=1024 + # indicates the system fonts.conf being used instead. + FONTCONFIG_FILE=$TBB_IN_STORE/fontconfig/fonts.conf + sed -i "$FONTCONFIG_FILE" \ + -e "s,<dir>fonts</dir>,<dir>$TBB_IN_STORE/fonts</dir>," + + # Hard-code paths to geoip data files. TBB resolves the geoip files + # relative to torrc-defaults_path but if we do not hard-code them + # here, these paths end up being written to the torrc in the user's + # state dir. + cat >>TorBrowser/Data/Tor/torrc-defaults <<EOF + GeoIPFile $TBB_IN_STORE/TorBrowser/Data/Tor/geoip + GeoIPv6File $TBB_IN_STORE/TorBrowser/Data/Tor/geoip6 + EOF + + mkdir -p $out/bin + + makeWrapper "$TBB_IN_STORE/firefox" "$out/bin/tor-browser" \ + --prefix LD_PRELOAD : "${lib.optionalString (useHardenedMalloc == true) + "${graphene-hardened-malloc}/lib/libhardened_malloc.so"}" \ + --prefix LD_LIBRARY_PATH : "$libPath" \ + --set FONTCONFIG_FILE "$FONTCONFIG_FILE" \ + --set-default MOZ_ENABLE_WAYLAND 1 + + # Easier access to docs + mkdir -p $out/share/doc + ln -s $TBB_IN_STORE/TorBrowser/Docs $out/share/doc/tor-browser + + # Install icons + for i in 16 32 48 64 128; do + mkdir -p $out/share/icons/hicolor/''${i}x''${i}/apps/ + ln -s $out/share/tor-browser/browser/chrome/icons/default/default$i.png $out/share/icons/hicolor/''${i}x''${i}/apps/tor-browser.png + done + + # Check installed apps + echo "Checking bundled Tor ..." + LD_LIBRARY_PATH=$libPath $TBB_IN_STORE/TorBrowser/Tor/tor --version >/dev/null + + echo "Checking tor-browser wrapper ..." + $out/bin/tor-browser --version >/dev/null + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + # Install distribution customizations + install -Dvm644 ${distributionIni} $out/share/tor-browser/distribution/distribution.ini + install -Dvm644 ${policiesJson} $out/share/tor-browser/distribution/policies.json + + runHook postInstall + ''; + + passthru = { + inherit sources; + updateScript = callPackage ./update.nix { + inherit pname version meta; + }; + }; + + meta = with lib; { + description = "Privacy-focused browser routing traffic through the Tor network"; + homepage = "https://www.torproject.org/"; + changelog = "https://gitweb.torproject.org/builders/tor-browser-build.git/plain/projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt?h=maint-${version}"; + platforms = attrNames sources; + maintainers = with maintainers; [ felschr panicgh joachifm hax404 ]; + # MPL2.0+, GPL+, &c. While it's not entirely clear whether + # the compound is "libre" in a strict sense (some components place certain + # restrictions on redistribution), it's free enough for our purposes. + license = with licenses; [ mpl20 lgpl21Plus lgpl3Plus free ]; + sourceProvenance = with sourceTypes; [ binaryNativeCode ]; + }; +}) |