nixpkgs/pkgs/applications/networking/browsers/tor-browser-bundle/default.nix
2019-07-01 04:23:51 -04:00

346 lines
11 KiB
Nix

{ 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
, ffmpeg
# Extensions, common
, zip
# HTTPS Everywhere
, git
, libxml2 # xmllint
, python27
, python27Packages
, rsync
# Pluggable transports
, obfs4
# 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";
mediaLibPath = makeLibraryPath [
ffmpeg
];
in
stdenv.mkDerivation rec {
name = "tor-browser-bundle-${version}";
version = tor-browser-unwrapped.version;
buildInputs = [ tor-browser-unwrapped tor ];
dontUnpack = true;
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
substituteInPlace $TBDATA_PATH/torrc-defaults \
--replace "./TorBrowser/Tor/PluggableTransports/obfs4proxy" \
"${obfs4}/bin/obfs4proxy"
# 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=${mediaLibPath}''${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)
#
# 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}" \
\
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
'';
passthru.execdir = "/bin";
meta = with stdenv.lib; {
description = "An unofficial version of the Tor Browser Bundle, built from source";
longDescription = ''
Tor Browser Bundle is a bundle of the Tor daemon, Tor Browser (heavily patched version of
Firefox), several essential extensions for Tor Browser, and some tools that glue those
together with a convenient UI.
`tor-browser-bundle-bin` package is the official version built by torproject.org patched with
`patchelf` to work under nix and with bundled scripts adapted to the read-only nature of
the `/nix/store`.
`tor-browser-bundle` package is the version built completely from source. It reuses the `tor`
package for the tor daemon, `firefoxPackages.tor-browser` package for the tor-browser, and
builds all the extensions from source.
Note that `tor-browser-bundle` package is not only built from source, but also bundles Tor
Browser differently from the official `tor-browser-bundle-bin` implementation. The official
Tor Browser is not a normal UNIX program and is heavily patched for its use in the Tor Browser
Bundle (which `tor-browser-bundle-bin` package then has to work around for the read-only
/nix/store). Meanwhile, `firefoxPackages.tor-browser` reverts all those patches, allowing
`firefoxPackages.tor-browser` to be used independently of the bundle, and then implements what
`tor-browser-bundle` needs for the bundling using a much simpler patch. See the
longDescription and expression of the `firefoxPackages.tor-browser` package for more info.
'';
inherit (tor-browser-unwrapped.meta) homepage platforms license;
hydraPlatforms = [ ];
maintainers = with maintainers; [ joachifm ];
};
}