#!/bin/bash
# Copyright (c) 2016-2019 Xavier G. <xavier.prooties@kindwolf.org>
# This program is free software. It comes without any warranty, to the extent
# permitted by applicable law. You can redistribute it and/or modify it under
# the terms of the Do What The Fuck You Want To Public License, Version 2, as
# published by Sam Hocevar. See http://www.wtfpl.net/ for more details.
function exit_with_message {
echo "${2}"
exit "${1}"
}
function mk_dir {
local path="${1}"
local mode="${2}"
mkdir -p "${path}" || \
exit_with_message 126 \
"Unable to create the following directory, aborting: ${path}"
chmod "${mode}" "${path}" || \
exit_with_message 125 \
"Unable to chmod the following directory, aborting: ${path}"
}
# This script may rely on its invoked name to fetch extra configuration
# directives.
invoked_name="$(basename "${0}")"
# By default, invoke "proot" and "firefox":
proot_path="$(which 'proot')"
browser_path='firefox'
# Base directory for our crap
work_dir_base="/run/user/$(id -u)/browser-wrapper"
mk_dir "${work_dir_base}" 0700
work_dir="$(mktemp --directory "${work_dir_base}/$$.XXXXXXXX")" || \
exit_with_message 110 "Unable to create working directory, aborting."
# Directory to replace /home
slash_home_dir="${work_dir}/slash_home"
# Directory to replace $HOME
home_dir="${work_dir}/home"
# Directory to replace /tmp
tmp_dir="${work_dir}/tmp"
# Empty dir to replace /dev
dev_dir="${work_dir}/dev"
# Directory for uploads
upload_dir="${HOME}/Uploads"
# Directory for downloads
download_dir="${HOME}/Downloads"
for directory in {{slash_,}home,tmp,{up,down}load,dev}_dir; do
mk_dir "${!directory}" 0700
done
# Leverage proot to make the browser believe that:
# - some directories located right under the root, such as /boot, /root and
# /srv, are absent as they are not expected to be of any use to any web
# browser.
root_dir_options="
--bind=/dev/null:/boot \
--bind=/dev/null:/root \
--bind=/dev/null:/srv"
# - /home is either empty or contains only our home
slash_home_options="--bind=${slash_home_dir}:/home"
# - the home directory is almost empty
home_options="--bind=${home_dir}:${HOME}"
# - the X11 stuff is still there (e.g. cursors and fonts)
# Note that, as per man 5 fonts-conf, ~/.fonts.conf and ~/.fonts.conf.d are
# deprecated.
x11_options="
--bind=${HOME}/.icons:${HOME}/.icons
--bind=${HOME}/.fonts:${HOME}/.fonts
--bind=${HOME}/.fontconfig:${HOME}/.fontconfig"
# - the PulseAudio stuff is still there (typically: client.conf)
# Note that it may be necessary to either bind /dev/shm or to set
# enable-shm = no in PulseAudio's client.conf.
pulse_options="
--bind=${HOME}/.pulse:${HOME}/.pulse
--bind=${HOME}/.config/pulse:${HOME}/.config/pulse"
# - its configuration directory is still there
# - its cache directory is still there
browser_conf_options="
--bind=${HOME}/.mozilla/firefox:${HOME}/.mozilla/firefox \
--bind=${HOME}/.cache/mozilla/firefox:${HOME}/.cache/mozilla/firefox"
# - its download directory is still there
# (at least the one for English speakers)
download_options="--bind=${download_dir}:${HOME}/Downloads"
# - a ~/Uploads directory is present
upload_options="--bind=${upload_dir}:${HOME}/Uploads"
# - ~/.adobe and ~/.macromedia are still there
# (for the sake of Flash Player and other plugins)
adobe_options="
--bind=${HOME}/.adobe:${HOME}/.adobe \
--bind=${HOME}/.macromedia:${HOME}/.macromedia"
# - various directories related to Java applets are still there
# (assuming IcedTea-Web >= 1.5 / OpenJDK)
java_options="
--bind=${HOME}/.config/icedtea-web:${HOME}/.config/icedtea-web
--bind=${HOME}/.cache/icedtea-web:${HOME}/.cache/icedtea-web
--bind=${HOME}/.java:${HOME}/.java
--bind=${HOME}/.local/share/applications/javaws:${HOME}/.local/share/application/javaws"
# - /tmp is empty
# (as in: do not even try to mess with the Unix sockets to ssh-agent)
tmp_options="--bind=${tmp_dir}:/tmp"
# - /sys is simply absent
# (Firefox tries to reach various things under /sys/devices/system/ but
# seems to cope without it)
sys_options="--bind=/dev/null:/sys"
# - /proc is still there, unless you want to hit that very detailed error:
# too much recursion
# - /proc/sys is still there, unless you want to hit that charming error:
# FATAL: error reading `/proc/sys/crypto/fips_enabled' in libgcrypt: Not a directory
proc_options=""
# - /dev is present yet minimalist
# /dev/dri is included for the sake of webGL performance and to avoid the
# following error message:
# libGL error: failed to open drm device: No such file or directory
dev_options="
--bind=${dev_dir}:/dev
--bind=/dev/dri:/dev/dri
--bind=/dev/null:/dev/null
--bind=/dev/random:/dev/random
--bind=/dev/urandom:/dev/urandom"
# Let users override this through "configuration files":
generic_config_path="${HOME}/.config/browser-wrapper/main.conf"
[ -f "${generic_config_path}" ] && source "${generic_config_path}"
specific_config_path="${HOME}/.config/browser-wrapper/${invoked_name}.conf"
[ -f "${specific_config_path}" ] && source "${specific_config_path}"
# Let users override some things through environment variables:
[ -n "${BW_PROOT_PATH}" ] && proot_path="${BW_PROOT_PATH}"
[ -n "${BW_BROWSER_PATH}" ] && browser_path="${BW_BROWSER_PATH}"
if [ -x "${proot_path}" ]; then
echo "proot is present and will be used to mask some directories"
echo 'Tips:'
echo " Your fake home is ${home_dir}"
echo " Your fake /tmp is ${tmp_dir}"
echo ' Do you need to upload files?'
echo " Put them in ${upload_dir}"
echo ' Do you need to download files?'
echo " They should end up in ${download_dir}"
"${proot_path}" \
${pre_options} \
${root_dir_options} \
${slash_home_options} \
${home_options} \
${x11_options} \
${pulse_options} \
${browser_conf_options} \
${download_options} \
${upload_options} \
${adobe_options} \
${java_options} \
${tmp_options} \
${sys_options} \
${proc_options} \
${dev_options} \
${post_options} \
--cwd="${HOME}" \
"${browser_path}" "$@"
else
echo "proot is missing; the browser will NOT be launched"
exit 127
fi