{ stdenv , fetchgit , fetchurl , symlinkJoin , tor , tor-browser-unwrapped # Wrapper runtime , coreutils , hicolor_icon_theme , shared_mime_info , noto-fonts , noto-fonts-emoji # Audio support , audioSupport ? mediaSupport , apulse # Media support (implies audio support) , mediaSupport ? false , gstreamer , gst-plugins-base , gst-plugins-good , gst-ffmpeg , gmp , ffmpeg # Extensions, common , zip # HTTPS Everywhere , git , libxml2 # xmllint , python27 , python27Packages , rsync # Pluggable transports , obfsproxy # Customization , extraPrefs ? "" , extraExtensions ? [ ] }: with stdenv.lib; let tor-browser-build_src = fetchgit { url = "https://git.torproject.org/builders/tor-browser-build.git"; rev = "refs/tags/tbb-7.5a5-build5"; sha256 = "0j37mqldj33fnzghxifvy6v8vdwkcz0i4z81prww64md5s8qcsa9"; }; firefoxExtensions = import ./extensions.nix { inherit stdenv fetchurl fetchgit zip git libxml2 python27 python27Packages rsync; }; bundledExtensions = with firefoxExtensions; [ https-everywhere noscript torbutton tor-launcher ] ++ extraExtensions; fontsEnv = symlinkJoin { name = "tor-browser-fonts"; paths = [ noto-fonts noto-fonts-emoji ]; }; fontsDir = "${fontsEnv}/share/fonts"; gstPluginsPath = concatMapStringsSep ":" (x: "${x}/lib/gstreamer-0.10") [ gstreamer gst-plugins-base gst-plugins-good gst-ffmpeg ]; gstLibPath = makeLibraryPath [ gstreamer gst-plugins-base gmp ffmpeg ]; in stdenv.mkDerivation rec { name = "tor-browser-bundle-${version}"; version = tor-browser-unwrapped.version; buildInputs = [ tor-browser-unwrapped tor ]; unpackPhase = ":"; buildPhase = ":"; # The following creates a customized firefox distribution. For # simplicity, we copy the entire base firefox runtime, to work around # firefox's annoying insistence on resolving the installation directory # relative to the real firefox executable. A little tacky and # inefficient but it works. installPhase = '' TBBUILD=${tor-browser-build_src}/projects/tor-browser TBDATA_PATH=TorBrowser-Data self=$out/lib/tor-browser mkdir -p $self && cd $self TBDATA_IN_STORE=$self/$TBDATA_PATH cp -dR ${tor-browser-unwrapped}/lib"/"*"/"* . chmod -R +w . # Prepare for autoconfig cat >defaults/pref/autoconfig.js <<EOF pref("general.config.filename", "mozilla.cfg"); pref("general.config.obscure_value", 0); EOF # Hardcoded configuration cat >mozilla.cfg <<EOF // First line must be a comment // Always update via Nixpkgs lockPref("app.update.auto", false); lockPref("app.update.enabled", false); lockPref("extensions.update.autoUpdateDefault", false); lockPref("extensions.update.enabled", false); lockPref("extensions.torbutton.updateNeeded", false); lockPref("extensions.torbutton.versioncheck_enabled", false); // Where to find the Nixpkgs tor executable & config lockPref("extensions.torlauncher.tor_path", "${tor}/bin/tor"); lockPref("extensions.torlauncher.torrc-defaults_path", "$TBDATA_IN_STORE/torrc-defaults"); // Captures store paths clearPref("extensions.xpiState"); clearPref("extensions.bootstrappedAddons"); // Insist on using IPC for communicating with Tor lockPref("extensions.torlauncher.control_port_use_ipc", true); lockPref("extensions.torlauncher.socks_port_use_ipc", true); // Allow sandbox access to sound devices if using ALSA directly ${if audioSupport then '' pref("security.sandbox.content.write_path_whitelist", "/dev/snd/"); '' else '' clearPref("security.sandbox.content.write_path_whitelist"); ''} // User customization ${extraPrefs} EOF # Preload extensions find ${toString bundledExtensions} -name '*.xpi' -exec ln -s -t browser/extensions '{}' '+' # Copy bundle data bundlePlatform=linux bundleData=$TBBUILD/Bundle-Data mkdir -p $TBDATA_PATH cat \ $bundleData/$bundlePlatform/Data/Tor/torrc-defaults \ >> $TBDATA_PATH/torrc-defaults cat \ $bundleData/$bundlePlatform/Data/Browser/profile.default/preferences/extension-overrides.js \ $bundleData/PTConfigs/bridge_prefs.js \ >> defaults/pref/extension-overrides.js # Configure geoip # # tor-launcher insists on resolving geoip data relative to torrc-defaults # (and passes them directly on the tor command-line). # # Write the paths into torrc-defaults anyway, otherwise they'll be # captured in the runtime torrc. ln -s -t $TBDATA_PATH ${tor.geoip}/share/tor/geoip{,6} cat >>$TBDATA_PATH/torrc-defaults <<EOF GeoIPFile $TBDATA_IN_STORE/geoip GeoIPv6File $TBDATA_IN_STORE/geoip6 EOF # Configure pluggable transports cat >>$TBDATA_PATH/torrc-defaults <<EOF ClientTransportPlugin obfs2,obfs3 exec ${obfsproxy}/bin/obfsproxy managed EOF # Hard-code path to TBB fonts; xref: FONTCONFIG_FILE in the wrapper below sed $bundleData/$bundlePlatform/Data/fontconfig/fonts.conf \ -e "s,<dir>fonts</dir>,<dir>${fontsDir}</dir>," \ > $TBDATA_PATH/fonts.conf # Generate a suitable wrapper wrapper_PATH=${makeBinPath [ coreutils ]} wrapper_XDG_DATA_DIRS=${concatMapStringsSep ":" (x: "${x}/share") [ hicolor_icon_theme shared_mime_info ]} ${optionalString audioSupport '' # apulse uses a non-standard library path ... wrapper_LD_LIBRARY_PATH=${apulse}/lib/apulse''${wrapper_LD_LIBRARY_PATH:+:$wrapper_LD_LIBRARY_PATH} ''} ${optionalString mediaSupport '' wrapper_LD_LIBRARY_PATH=${gstLibPath}''${wrapper_LD_LIBRARY_PATH:+:$wrapper_LD_LIBRARY_PATH} ''} mkdir -p $out/bin cat >$out/bin/tor-browser <<EOF #! ${stdenv.shell} -eu umask 077 PATH=$wrapper_PATH readonly THE_HOME=\$HOME TBB_HOME=\''${TBB_HOME:-\''${XDG_DATA_HOME:-\$HOME/.local/share}/tor-browser} if [[ \''${TBB_HOME:0:1} != / ]] ; then TBB_HOME=\$PWD/\$TBB_HOME fi readonly TBB_HOME # Basic sanity check: never want to vomit directly onto user's homedir if [[ "\$TBB_HOME" = "\$THE_HOME" ]] ; then echo 'TBB_HOME=\$HOME; refusing to run' >&2 exit 1 fi mkdir -p "\$TBB_HOME" HOME=\$TBB_HOME cd "\$HOME" # Re-init XDG basedir envvars XDG_CACHE_HOME=\$HOME/.cache XDG_CONFIG_HOME=\$HOME/.config XDG_DATA_HOME=\$HOME/.local/share # Initialize empty TBB runtime state directory hierarchy. Mirror the # layout used by the official TBB, to avoid the hassle of working # against the assumptions made by tor-launcher & co. mkdir -p "\$HOME/TorBrowser" "\$HOME/TorBrowser/Data" # Initialize the Tor data directory. mkdir -p "\$HOME/TorBrowser/Data/Tor" # TBB fails if ownership is too permissive chmod 0700 "\$HOME/TorBrowser/Data/Tor" # Initialize the browser profile state. Expect TBB to generate all data. mkdir -p "\$HOME/TorBrowser/Data/Browser/profile.default" # Files that capture store paths; re-generated by firefox at startup rm -rf "\$HOME/TorBrowser/Data/Browser/profile.default"/{compatibility.ini,extensions.ini,extensions.json,startupCache} # Clear out fontconfig caches rm -f "\$HOME/.cache/fontconfig/"*.cache-* # Lift-off! # # TZ is set to avoid stat()ing /etc/localtime over and over ... # # DBUS_SESSION_BUS_ADDRESS is inherited to avoid auto-launching a new # dbus instance; to prevent using the session bus, set the envvar to # an empty/invalid value prior to running tor-browser. # # 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. # # HOME, TMPDIR, XDG_*_HOME are set as a form of soft confinement; # ideally, tor-browser should not write to any path outside TBB_HOME # and should run even under strict confinement to TBB_HOME. # # XDG_DATA_DIRS is set to prevent searching system directories for # mime and icon data. # # PULSE_{SERVER,COOKIE} is necessary for audio playback w/pulseaudio # # APULSE_PLAYBACK_DEVICE is for audio playback w/o pulseaudio (no capture yet) # # GST_PLUGIN_SYSTEM_PATH is for HD video playback # # GST_REGISTRY is set to devnull to minimize disk writes # # TOR_* is for using an external tor instance # # Parameters lacking a default value below are *required* (enforced by # -o nounset). exec env -i \ LD_LIBRARY_PATH=$wrapper_LD_LIBRARY_PATH \ \ TZ=":" \ \ DISPLAY="\$DISPLAY" \ XAUTHORITY="\$XAUTHORITY" \ DBUS_SESSION_BUS_ADDRESS="\$DBUS_SESSION_BUS_ADDRESS" \ \ HOME="\$HOME" \ TMPDIR="\$XDG_CACHE_HOME/tmp" \ XDG_CONFIG_HOME="\$XDG_CONFIG_HOME" \ XDG_DATA_HOME="\$XDG_DATA_HOME" \ XDG_CACHE_HOME="\$XDG_CACHE_HOME" \ XDG_RUNTIME_DIR="\$HOME/run" \ \ XDG_DATA_DIRS="$wrapper_XDG_DATA_DIRS" \ \ FONTCONFIG_FILE="$TBDATA_IN_STORE/fonts.conf" \ \ APULSE_PLAYBACK_DEVICE="\''${APULSE_PLAYBACK_DEVICE:-plug:dmix}" \ \ GST_PLUGIN_SYSTEM_PATH="${optionalString mediaSupport gstPluginsPath}" \ GST_REGISTRY="/dev/null" \ GST_REGISTRY_UPDATE="no" \ \ TOR_SKIP_LAUNCH="\''${TOR_SKIP_LAUNCH:-}" \ TOR_CONTROL_PORT="\''${TOR_CONTROL_PORT:-}" \ TOR_SOCKS_PORT="\''${TOR_SOCKS_PORT:-}" \ \ $self/firefox \ -no-remote \ -profile "\$HOME/TorBrowser/Data/Browser/profile.default" \ "\$@" EOF chmod +x $out/bin/tor-browser echo "Syntax checking wrapper ..." bash -n $out/bin/tor-browser echo "Checking wrapper ..." DISPLAY="" XAUTHORITY="" DBUS_SESSION_BUS_ADDRESS="" TBB_HOME=$(mktemp -d) \ $out/bin/tor-browser -version >/dev/null ''; meta = with stdenv.lib; { description = "An unofficial version of the tor browser bundle, built from source"; homepage = https://torproject.org/; license = licenses.unfreeRedistributable; # TODO: check this platforms = [ "x86_64-linux" ]; hydraPlatforms = [ ]; maintainers = with maintainers; [ joachifm ]; }; }