32 , libnotifySupport ? stdenv.hostPlatform.isLinux
35 , waylandSupport ? stdenv.hostPlatform.isLinux
43 , audioSupport ? mediaSupport
45 , pipewireSupport ? audioSupport
48 , pulseaudioSupport ? audioSupport
53 , libvaSupport ? mediaSupport
57 , graphene-hardened-malloc
58 # Whether to use graphene-hardened-malloc
59 , useHardenedMalloc ? null
61 # Whether to disable multiprocess support
62 , disableContentSandbox ? false
68 lib.warnIf (useHardenedMalloc != null)
69 "tor-browser: useHardenedMalloc is deprecated and enabling it can cause issues"
72 libPath = lib.makeLibraryPath (
96 ] ++ lib.optionals libnotifySupport [ libnotify ]
97 ++ lib.optionals waylandSupport [ libxkbcommon libdrm libGL ]
98 ++ lib.optionals pipewireSupport [ pipewire ]
99 ++ lib.optionals pulseaudioSupport [ libpulseaudio ]
100 ++ lib.optionals libvaSupport [ libva ]
101 ++ lib.optionals mediaSupport [ ffmpeg ]
107 x86_64-linux = fetchurl {
109 "https://archive.torproject.org/tor-package-archive/torbrowser/${version}/tor-browser-linux-x86_64-${version}.tar.xz"
110 "https://dist.torproject.org/torbrowser/${version}/tor-browser-linux-x86_64-${version}.tar.xz"
111 "https://tor.eff.org/dist/torbrowser/${version}/tor-browser-linux-x86_64-${version}.tar.xz"
112 "https://tor.calyxinstitute.org/dist/torbrowser/${version}/tor-browser-linux-x86_64-${version}.tar.xz"
114 hash = "sha256-dEairGoBMsXF4gtnnqa2KsA8PpW9VwF8woUrInVWuKM=";
117 i686-linux = fetchurl {
119 "https://archive.torproject.org/tor-package-archive/torbrowser/${version}/tor-browser-linux-i686-${version}.tar.xz"
120 "https://dist.torproject.org/torbrowser/${version}/tor-browser-linux-i686-${version}.tar.xz"
121 "https://tor.eff.org/dist/torbrowser/${version}/tor-browser-linux-i686-${version}.tar.xz"
122 "https://tor.calyxinstitute.org/dist/torbrowser/${version}/tor-browser-linux-i686-${version}.tar.xz"
124 hash = "sha256-9WRN+iU7vvt9KvVudsS7qe0hoJwDP/J+yOTHW7nmrxs=";
128 distributionIni = writeText "distribution.ini" (lib.generators.toINI {} {
129 # Some light branding indicating this build uses our distro preferences
133 about = "Tor Browser for NixOS";
137 policiesJson = writeText "policies.json" (builtins.toJSON {
138 policies.DisableAppUpdate = true;
141 stdenv.mkDerivation rec {
142 pname = "tor-browser";
145 src = sources.${stdenv.hostPlatform.system} or (throw "unsupported system: ${stdenv.hostPlatform.system}");
147 nativeBuildInputs = [ autoPatchelfHook copyDesktopItems makeWrapper wrapGAppsHook3 ];
155 preferLocalBuild = true;
156 allowSubstitutes = false;
158 desktopItems = [(makeDesktopItem {
160 exec = "tor-browser %U";
161 icon = "tor-browser";
162 desktopName = "Tor Browser";
163 genericName = "Web Browser";
164 comment = meta.description;
165 categories = [ "Network" "WebBrowser" "Security" ];
169 "application/xhtml+xml"
170 "application/vnd.mozilla.xul+xml"
171 "x-scheme-handler/http"
172 "x-scheme-handler/https"
179 # For convenience ...
180 TBB_IN_STORE=$out/share/tor-browser
181 interp=$(< $NIX_CC/nix-support/dynamic-linker)
184 mkdir -p "$TBB_IN_STORE"
185 tar xf "$src" -C "$TBB_IN_STORE" --strip-components=2
186 pushd "$TBB_IN_STORE"
188 # Set ELF interpreter
189 for exe in firefox.real TorBrowser/Tor/tor ; do
190 echo "Setting ELF interpreter on $exe ..." >&2
191 patchelf --set-interpreter "$interp" "$exe"
194 # firefox is a wrapper that checks for a more recent libstdc++ & appends it to the ld path
195 mv firefox.real firefox
197 # store state at `~/.tor browser` instead of relative to executable
198 touch "$TBB_IN_STORE/system-install"
200 # The final libPath. Note, we could split this into firefoxLibPath
201 # and torLibPath for accuracy, but this is more convenient ...
202 libPath=${libPath}:$TBB_IN_STORE:$TBB_IN_STORE/TorBrowser/Tor
204 # apulse uses a non-standard library path. For now special-case it.
205 ${lib.optionalString (audioSupport && !pulseaudioSupport) ''
206 libPath=${apulse}/lib/apulse:$libPath
209 # Fixup paths to pluggable transports.
210 substituteInPlace TorBrowser/Data/Tor/torrc-defaults \
211 --replace-fail './TorBrowser' "$TBB_IN_STORE/TorBrowser"
213 # Fixup obfs transport. Work around patchelf failing to set
214 # interpreter for pre-compiled Go binaries by invoking the interpreter
216 sed -i TorBrowser/Data/Tor/torrc-defaults \
217 -e "s|\(ClientTransportPlugin meek_lite,obfs2,obfs3,obfs4,scramblesuit\) exec|\1 exec $interp|"
219 # Similarly fixup snowflake
220 sed -i TorBrowser/Data/Tor/torrc-defaults \
221 -e "s|\(ClientTransportPlugin snowflake\) exec|\1 exec $interp|"
223 # Prepare for autoconfig.
225 # See https://developer.mozilla.org/en-US/Firefox/Enterprise_deployment
226 cat >defaults/pref/autoconfig.js <<EOF
228 pref("general.config.filename", "mozilla.cfg");
229 pref("general.config.obscure_value", 0);
232 # Hard-coded Firefox preferences.
233 cat >mozilla.cfg <<EOF
234 // First line must be a comment
236 // Reset pref that captures store paths.
237 clearPref("extensions.xpiState");
239 // Stop obnoxious first-run redirection.
240 lockPref("noscript.firstRunRedirection", false);
242 // User should never change these. Locking prevents these
243 // values from being written to prefs.js, avoiding Store
245 lockPref("extensions.torlauncher.torrc-defaults_path", "$TBB_IN_STORE/TorBrowser/Data/Tor/torrc-defaults");
246 lockPref("extensions.torlauncher.tor_path", "$TBB_IN_STORE/TorBrowser/Tor/tor");
248 // Insist on using IPC for communicating with Tor
250 // Defaults to creating \$XDG_RUNTIME_DIR/Tor/{socks,control}.socket
251 lockPref("extensions.torlauncher.control_port_use_ipc", true);
252 lockPref("extensions.torlauncher.socks_port_use_ipc", true);
254 // Optionally disable multiprocess support. We always set this to ensure that
255 // toggling the pref takes effect.
256 lockPref("browser.tabs.remote.autostart.2", ${if disableContentSandbox then "false" else "true"});
258 // Allow sandbox access to sound devices if using ALSA directly
259 ${if (audioSupport && !pulseaudioSupport) then ''
260 pref("security.sandbox.content.write_path_whitelist", "/dev/snd/");
262 clearPref("security.sandbox.content.write_path_whitelist");
265 ${lib.optionalString (extraPrefs != "") ''
270 # FONTCONFIG_FILE is required to make fontconfig read the TBB
271 # fonts.conf; upstream uses FONTCONFIG_PATH, but FC_DEBUG=1024
272 # indicates the system fonts.conf being used instead.
273 FONTCONFIG_FILE=$TBB_IN_STORE/fontconfig/fonts.conf
274 substituteInPlace "$FONTCONFIG_FILE" \
275 --replace-fail '<dir prefix="cwd">fonts</dir>' "<dir>$TBB_IN_STORE/fonts</dir>"
277 # Hard-code paths to geoip data files. TBB resolves the geoip files
278 # relative to torrc-defaults_path but if we do not hard-code them
279 # here, these paths end up being written to the torrc in the user's
281 cat >>TorBrowser/Data/Tor/torrc-defaults <<EOF
282 GeoIPFile $TBB_IN_STORE/TorBrowser/Data/Tor/geoip
283 GeoIPv6File $TBB_IN_STORE/TorBrowser/Data/Tor/geoip6
288 makeWrapper "$TBB_IN_STORE/firefox" "$out/bin/tor-browser" \
289 --prefix LD_PRELOAD : "${lib.optionalString (useHardenedMalloc == true)
290 "${graphene-hardened-malloc}/lib/libhardened_malloc.so"}" \
291 --prefix LD_LIBRARY_PATH : "$libPath" \
292 --set FONTCONFIG_FILE "$FONTCONFIG_FILE" \
293 --set-default MOZ_ENABLE_WAYLAND 1
295 # Easier access to docs
296 mkdir -p $out/share/doc
297 ln -s $TBB_IN_STORE/TorBrowser/Docs $out/share/doc/tor-browser
300 for i in 16 32 48 64 128; do
301 mkdir -p $out/share/icons/hicolor/''${i}x''${i}/apps/
302 ln -s $out/share/tor-browser/browser/chrome/icons/default/default$i.png $out/share/icons/hicolor/''${i}x''${i}/apps/tor-browser.png
305 # Check installed apps
306 echo "Checking bundled Tor ..."
307 LD_LIBRARY_PATH=$libPath $TBB_IN_STORE/TorBrowser/Tor/tor --version >/dev/null
309 echo "Checking tor-browser wrapper ..."
310 $out/bin/tor-browser --version >/dev/null
318 # Install distribution customizations
319 install -Dvm644 ${distributionIni} $out/share/tor-browser/distribution/distribution.ini
320 install -Dvm644 ${policiesJson} $out/share/tor-browser/distribution/policies.json
327 updateScript = callPackage ./update.nix {
328 inherit pname version meta;
333 description = "Privacy-focused browser routing traffic through the Tor network";
334 mainProgram = "tor-browser";
335 homepage = "https://www.torproject.org/";
336 changelog = "https://gitweb.torproject.org/builders/tor-browser-build.git/plain/projects/tor-browser/Bundle-Data/Docs/ChangeLog.txt?h=maint-${version}";
337 platforms = attrNames sources;
338 maintainers = with maintainers; [ felschr panicgh joachifm hax404 ];
339 # MPL2.0+, GPL+, &c. While it's not entirely clear whether
340 # the compound is "libre" in a strict sense (some components place certain
341 # restrictions on redistribution), it's free enough for our purposes.
342 license = with licenses; [ mpl20 lgpl21Plus lgpl3Plus free ];
343 sourceProvenance = with sourceTypes; [ binaryNativeCode ];