#!/bin/sh
set -e
# This isn't very useful without I2P...
grep -qw "i2p" /proc/cmdline || exit 0
CMD=$(basename ${0})
LOCK=/var/lock/${CMD}
. gettext.sh
TEXTDOMAIN="tails"
export TEXTDOMAIN
. /usr/local/lib/tails-shell-library/i2p.sh
ROFS=/lib/live/mount/rootfs/filesystem.squashfs
CONF_DIR=/var/lib/i2p-browser
COW=${CONF_DIR}/cow
CHROOT=${CONF_DIR}/chroot
BROWSER_USER=i2pbrowser
TBB_PREFS="/etc/tor-browser/profile/preferences"
START_PAGE="http://127.0.0.1:7657"
# Import the TBB_INSTALL, TBB_EXT and TBB_PROFILE variables
. /usr/local/lib/tails-shell-library/tor-browser.sh
NOSCRIPT="${TBB_INSTALL}/extensions/{73a6fe31-595d-460b-a920-fcc0f8843232}.xpi"
TORBUTTON="${TBB_INSTALL}/extensions/torbutton@torproject.org"
NAME="`gettext \"I2P Browser\"`"
if [ -e /var/lib/gdm3/tails.camouflage ]; then
CAMOUFLAGE=yes
fi
cleanup () {
# Break down the chroot and kill all of its processes
local counter=0
local ret=0
while [ "${counter}" -le 10 ] && \
pgrep -u ${BROWSER_USER} 1>/dev/null 2>&1; do
pkill -u ${BROWSER_USER} 1>/dev/null 2>&1
ret=${?}
sleep 1
counter=$((${counter}+1))
done
[ ${ret} -eq 0 ] || pkill -9 -u ${BROWSER_USER} 1>/dev/null 2>&1
for mnt in ${CHROOT}/dev ${CHROOT}/proc ${CHROOT} ${COW}; do
counter=0
while [ "${counter}" -le 10 ] && mountpoint -q ${mnt} 2>/dev/null; do
umount ${mnt} 2>/dev/null
sleep 1
counter=$((${counter}+1))
done
done
rmdir ${COW} ${CHROOT} 2>/dev/null
}
error () {
local cli_text="${CMD}: `gettext \"error:\"` ${@}"
local dialog_text="`gettext \"Error\"`
${@}"
echo "${cli_text}" >&2
sudo -u ${SUDO_USER} zenity --error --title "" --text "${dialog_text}"
exit 1
}
verify_start () {
# Make sure the user really wants to start the browser in case the router console isn't available
local dialog_msg="`gettext \"Do you still want to launch I2P Browser?\"`
`gettext \"The I2P router console is not ready.\"`"
local launch="`gettext \"_Launch\"`"
local exit="`gettext \"_Exit\"`"
# Since zenity can't set the default button to cancel, we switch the
# labels and interpret the return value as its negation.
if sudo -u ${SUDO_USER} zenity --question --title "" --ok-label "${exit}" \
--cancel-label "${launch}" --text "${dialog_msg}"; then
exit 0
fi
}
show_start_notification () {
local title="`gettext \"Starting the I2P Browser...\"`"
local body="`gettext \"This may take a while, so please be patient.\"`"
tails-notify-user "${title}" "${body}" 10000
}
setup_chroot () {
# Setup a chroot on an aufs "fork" of the filesystem.
# FIXME: When LXC matures to the point where it becomes a viable option
# for creating isolated jails, the chroot can be used as its rootfs.
echo "* Setting up chroot"
trap cleanup INT
trap cleanup EXIT
mkdir -p ${COW} ${CHROOT} && \
mount -t tmpfs tmpfs ${COW} && \
mount -t aufs -o noatime,noxino,dirs=${COW}=rw:${ROFS}=rr+wh aufs ${CHROOT} && \
mount -t proc proc ${CHROOT}/proc && \
mount --bind /dev ${CHROOT}/dev || \
error "`gettext \"Failed to setup chroot.\"`"
# Workaround for todo/buggy_aufs_vs_unsafe-browser
chmod -t ${COW}
}
set_chroot_browser_name () {
NAME="${1}"
LONG=$(echo ${LANG} | grep -o "^[a-zA-Z_]*")
SHORT=${LONG%%_*}
EXT_DIR="${CHROOT}/${TBB_EXT}"
BRANDING=branding/brand.dtd
if [ -e "${EXT_DIR}/langpack-${LONG}@firefox.mozilla.org.xpi" ]; then
PACK="${EXT_DIR}/langpack-${LONG}@firefox.mozilla.org.xpi"
TOP=browser/chrome
REST=${LONG}/locale
elif [ -e "${EXT_DIR}/langpack-${SHORT}@firefox.mozilla.org.xpi" ]; then
PACK="${EXT_DIR}/langpack-${SHORT}@firefox.mozilla.org.xpi"
TOP=browser/chrome
REST=${SHORT}/locale
else
PACK="${CHROOT}/${TBB_INSTALL}/Browser/browser/omni.ja"
TOP=chrome
REST=en-US/locale
fi
TMP=$(mktemp -d)
# Non-zero exit code due to non-standard ZIP archive.
# The following steps will fail soon if the extraction failed anyway.
unzip -d "${TMP}" "${PACK}" || true
sed -i "s/<"'!'"ENTITY\s\+brand\(Full\|Short\)Name.*$/<"'!'"ENTITY brand\1Name \"${NAME}\">/" "${TMP}/${TOP}/${REST}/${BRANDING}"
rm "${PACK}"
(cd $TMP ; 7z a -tzip "${PACK}" .)
chmod a+r "${PACK}"
rm -Rf "${TMP}"
}
configure_chroot () {
echo "* Configuring chroot"
# Prevent sudo from complaining about failing to resolve the 'amnesia' host
echo "127.0.0.1 localhost amnesia" > ${CHROOT}/etc/hosts
# Keep the NoScript and TorButton addons
chroot ${CHROOT} dpkg -l 'xul-ext*' |grep -v 'noscript\|torbutton' \
| awk '/^ii/{print $2}' | xargs -r chroot ${CHROOT} dpkg --remove
# Create a fresh Tor Browser profile for the i2pbrowser user
BROWSER_PROFILE="${CHROOT}/home/${BROWSER_USER}/.tor-browser/profile.default"
BROWSER_EXT="${BROWSER_PROFILE}/extensions"
mkdir -p "${BROWSER_EXT}"
ln -s "${NOSCRIPT}" "${BROWSER_EXT}"
# TorButton forces the Browser name to Tor Browser. This hack is to undo that and set it to I2P Browser
# to try to prevent user confusion.
#ln -s "${TORBUTTON}" "${BROWSER_EXT}"
TMP=$(mktemp -d)
cp -a /usr/share/xul-ext/torbutton/ $TMP
for LANGPACK in $(ls ${TBB_PROFILE}/extensions/langpack-*.xpi); do
ln -s "${LANGPACK}" "${BROWSER_EXT}"
done
find $TMP/torbutton -name 'brand.dtd' -print0 | \
xargs -0 -r sed -i "s/<"'!'"ENTITY\s\+brand\(Full\|Short\)Name.*$/<"'!'"ENTITY brand\1Name \"${NAME}\">/"
cd $TMP/torbutton && 7z a -tzip "${BROWSER_EXT}/torbutton@torproject.org.xpi" .
rm -r $TMP
BROWSER_PREF_DIR="${BROWSER_PROFILE}/preferences"
BROWSER_PREFS="${BROWSER_PREF_DIR}/prefs.js"
mkdir -p "${BROWSER_PREF_DIR}"
# Selectively copy the TBB prefs we want
sed '/\(security\|update\|download\|spell\|noscript\|torbrowser\|torbutton\)/!d' $TBB_PREFS/0000tails.js > \
${BROWSER_PREF_DIR}/0000tails.js
sed '/\(capability\|noscript\|torbutton\)/!d' ${TBB_PREFS}/extension-overrides.js > \
${BROWSER_PREF_DIR}/extension-overrides.js
# Localization
cat /var/lib/tails-user-session/browser-locale.js >> "${BROWSER_PREFS}"
# Prevent File -> Print or CTRL+P from causing the browser to hang
# for several minutes while trying to communicate with CUPS, since
# access to port 631 isn't allowed through.
echo 'user_pref("print.postscript.cups.enabled", false);' >> \
${BROWSER_PREFS}
# Set the name (e.g. window title) of the browser
set_chroot_browser_name "`gettext \"I2P Browser\"`"
# Set start page to the router console
echo 'user_pref("browser.startup.homepage", "'${START_PAGE}'");' >> \
${BROWSER_PREFS}
# Disable searching from the URL bar
echo 'user_pref("keyword.enabled", false);' >> \
${BROWSER_PREFS}
# Hide "Get Addons" in Add-ons manager
echo 'user_pref("extensions.getAddons.showPane", false);' >> \
${BROWSER_PREFS}
# add the I2P proxy to all protocols
cat > "${BROWSER_PREF_DIR}/i2p.js" << EOF
user_pref("extensions.torbutton.http_port", 4444);
user_pref("extensions.torbutton.http_proxy", "127.0.0.1");
user_pref("extensions.torbutton.https_port", 4444);
user_pref("extensions.torbutton.https_proxy", "127.0.0.1");
user_pref("extensions.torbutton.custom.ftp_port", 4444);
user_pref("extensions.torbutton.custom.ftp_proxy", "127.0.0.1");
user_pref("extensions.torbutton.custom.http_port", 4444);
user_pref("extensions.torbutton.custom.http_proxy", "127.0.0.1");
user_pref("extensions.torbutton.custom.https_port", 4444);
user_pref("extensions.torbutton.custom.https_proxy", "127.0.0.1");
user_pref("extensions.torbutton.ftp_port", 4444);
user_pref("extensions.torbutton.ftp_proxy", "127.0.0.1");
user_pref("extensions.torbutton.gopher_port", 4444);
user_pref("extensions.torbutton.gopher_proxy", "127.0.0.1");
user_pref("extensions.torbutton.inserted_button", true);
user_pref("extensions.torbutton.settings_method", "custom");
user_pref("network.proxy.ftp", "127.0.0.1");
user_pref("network.proxy.ftp_port", 4444);
user_pref("network.proxy.http", "127.0.0.1");
user_pref("network.proxy.http_port", 4444);
user_pref("network.proxy.no_proxies_on", "127.0.0.1");
user_pref("network.proxy.ssl", "127.0.0.1");
user_pref("network.proxy.ssl_port", 4444);
EOF
# Hide options in the I2P Browser.
# It would be good to implement the ability to persist the browser profile in the
# future. At that point, the Bookmark functionality could be restored.
BROWSER_CHROME="${BROWSER_PROFILE}/chrome/userChrome.css"
mkdir -p "$(dirname "${BROWSER_CHROME}")"
cat > ${BROWSER_CHROME} << EOF
/* Required, do not remove */
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
/* Hide access to the bookmarks to try to prevent "data loss" due to users
* adding bookmarks even though the profile is destroyed at browser close.
* Keyboard shortcuts still work, but this makes it harder to 'accidentally'
* lose bookmarks.
*
* Note that any of the selectors that start with 'app' apply to the menu that
* is used if the main menu is hidden. Any that start with 'wrapper' are
* buttons that are normally visible within the 'customize toolbar' option. The
* others are probably self-explanatory.
*/
/* Remove the History and Bookmarks menus and buttons */
#appmenu_bookmarks,
#appmenu_history,
#bookmarks,
#bookmarks-menu-button,
#bookmarksMenu,
#history,
#history-menu,
#history-menu-button,
#wrapper-history-button,
#wrapper-bookmarks-button,
/* Hide the sidebar menu (underneath View) since the default sidebars consist
* of history and bookmarks. Also disable the bookmark toolbar.
*/
#toggle_PersonalToolbar,
#viewSidebarMenuMenu,
/* Remove the "Star button" and "History Dropdown arrow" from the URL bar
* since neither history nor bookmarks are saved.
*/
#star-button,
[anonid="historydropmarker"],
/* Remove bookmark options from the context menus */
#context-bookmarkframe,
#context-bookmarklink,
#context-bookmarkpage,
/* Hide the option for emailing links since it's doomed to failure
* without a configured email client.
*/
menuitem[command="Browser:SendLink"],
/* Hide Print options */
/*
#menu_printSetup,
#menu_printPreview,
#menu_print,
#menu_print + menuseparator,
[command="cmd_print"],
*/
/* Hide the sync functionality which won't work with I2P */
#BrowserPreferences radio[pane="paneSync"],
#sync-button,
#sync-menu-button,
#sync-setup,
#sync-setup-appmenu,
#sync-status-button,
#sync-syncnowitem-appmenu,
#wrapper-sync-button,
/* Without I2P search engines defined, the search bar is useless.
* Since there are no I2P search engines added to Tails (yet),
* let's hide it and the Update Pane in Firefox's Preferences.
*/
#search-container,
#updateTab,
/* Hide options in the Help menu that lead to disallowed resources on the
* Internet.
*/
#appmenu_feedbackPage,
#appmenu_gettingStarted,
#appmenu_openHelp,
#feedbackPage,
#gettingStarted,
#menu_HelpPopup_reportPhishingtoolmenu,
#menu_openHelp,
/* Hide TorBrowser Health Report and its configuration option */
#appmenu_healthReport,
#dataChoicesTab,
#healthReport
/* Now the actual hiding */
{display: none !important}
EOF
rm -rf ${BROWSER_EXT}/branding@amnesia.boum.org
# Remove all bookmarks
rm -f "${CHROOT}/${TBB_PROFILE}/bookmarks.html"
rm -f ${BROWSER_PROFILE}/bookmarks.html
rm -f ${BROWSER_PROFILE}/places.sqlite
chown -R ${BROWSER_USER}:${BROWSER_USER} "${CHROOT}/home/${BROWSER_USER}/.tor-browser"
# Change the theme when not using Windows camouflage
if [ -z "${CAMOUFLAGE}" ]; then
cat >> ${BROWSER_PREFS} </dev/null
chroot ${CHROOT} sudo -u ${BROWSER_USER} LD_LIBRARY_PATH="${TBB_INSTALL}" "${TBB_INSTALL}/Browser/firefox" -DISPLAY=:0.0 -profile /home/${BROWSER_USER}/.tor-browser/profile.default
sudo -u ${SUDO_USER} xhost -SI:localuser:${BROWSER_USER} 2>/dev/null
}
show_shutdown_notification () {
local title="`gettext \"Shutting down the I2P Browser...\"`"
local body="`gettext \"This may take a while, and you may not restart the I2P Browser until it is properly shut down.\"`"
tails-notify-user "${title}" "${body}" 10000
}
# Prevent multiple instances of the script.
exec 9>${LOCK}
if ! flock -x -n 9; then
error "`gettext \"Another I2P Browser is currently running, or being cleaned up. Please retry in a while.\"`"
fi
if ! i2p_router_console_is_ready; then
verify_start
fi
show_start_notification
setup_chroot
configure_chroot
run_browser_in_chroot
show_shutdown_notification
exit 0