wren-linux / lib / firefox-profiles.sh
# shellcheck shell=bash
# lib/firefox-profiles.sh: helpers for new-profile.sh, sourced after lib.sh and
# lib/firefox-sandbox.sh.
# Files written by the scripts here
OURS='Wren Linux (extras/)?firefox-profiles/[a-z-]+\.sh'
# fx_cmd_taken NAME: a command, builtin or keyword is called NAME already.
# ~/.local/bin comes first in PATH, so a profile's command must never take
# such a name: it would stand in for that program (git, sudo, ls...).
fx_cmd_taken() {
local d
[ -z "$(type -t "$1")" ] || return 0
for d in /usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/local/games /usr/games "$HOME/bin"; do
[ ! -e "$d/$1" ] || return 0
done
return 1
}
# fx_profile_cmd NAME: the command that opens the profile NAME: NAME itself
# (github), or firefox-NAME when NAME is taken or one of yours (not ours) is there
fx_profile_cmd() {
local short=$BIN/$1
if [ -e "$short" ]; then
if grep -qsE "$OURS" "$short"; then echo "$short"; return; fi
elif ! fx_cmd_taken "$1"; then
echo "$short"
return
fi
echo "$BIN/firefox-$1"
}
# make_profile NAME URL FAST [TOOLBARS [SOUND [COOKIES]]]: a Firefox profile with a
# locked-down user of its own (fx-NAME), its settings, and a command that opens
# it: NAME, or firefox-NAME when NAME is a command already (fx_profile_cmd).
# FAST=yes turns the JavaScript JIT back on for this profile only. TOOLBARS is
# hidden (the default: the window shows only the page) or shown. SOUND is yes
# (the default) or no. COOKIES is keep (the default: you stay logged in) or
# delete (cookies, site data and the cache go when it closes). The user is like the sandboxed
# Firefox's (extras/firefox-sandbox.sh): no password, no login, none of your
# files; only the clipboard and ~/Downloads/NAME are shared with you.
make_profile() {
local name=$1 url=$2 fast=$3 toolbars=${4:-shown} sound=${5:-yes} cookies=${6:-delete} cmd user=fx-$1 conf
case $toolbars in hidden | shown) ;; *) die "TOOLBARS is hidden or shown, not \"$toolbars\"." ;; esac
case $sound in yes | no) ;; *) die "SOUND is yes or no, not \"$sound\"." ;; esac
case $cookies in keep | delete) ;; *) die "COOKIES is keep or delete, not \"$cookies\"." ;; esac
fx_profile_name_ok "$name" || die "\"$name\" can't be a profile name: lowercase letters, digits and dashes, starting with a letter, at most 28 long (and not esr, restart-check or session)."
cmd=$(fx_profile_cmd "$name")
# A firefox-NAME command that isn't ours: stop before any user or rule is made
if [ -e "$cmd" ] && ! grep -qsE "$OURS" "$cmd"; then
die "$cmd already exists and isn't Wren Linux's; pick another name. Nothing was changed."
fi
# The sandbox itself (the group, the firewall, the session script) comes first
if [ ! -x "$FX_CLIENT" ] || [ ! -x "$FX_SESSION" ]; then
note "A profile with its own user needs the sandboxed Firefox (extras/firefox-sandbox.sh)."
ask "Set that up now?" y || die "Nothing was changed."
bash "$WREN_DIR/extras/firefox-sandbox.sh" || die "The sandboxed Firefox didn't finish; the profile was not made."
fi
say "Firefox profile: $name (user $user)"
watch_before
fx_create_user "$user" "$FX_HOME_ROOT/$name" "Wren Linux Firefox profile $name"
# Its address and its choices, in a file only root can write: the session
# reads it as the profile's user, who has no way to change it (and the
# firefox command, for sound)
conf="$FX_PROFILE_DIR/$name.conf"
sudo install -d -o root -g root -m 0750 "$FX_PROFILE_DIR"
printf '# Written by Wren Linux extras/firefox-profiles/new-profile.sh\nurl=%s\nfast_js=%s\ntoolbars=%s\nsound=%s\ncookies=%s\n' "$url" "$fast" "$toolbars" "$sound" "$cookies" |
sudo tee "$conf" >/dev/null
fx_conf_private "$user" "$conf"
fx_allow_session "$user"
note "$name: opens $url$([ "$fast" = yes ] && echo ', fast JavaScript')$([ "$sound" = no ] && echo ', no sound')$([ "$cookies" = delete ] && echo ', cookies deleted when it closes'); runs as $user"
if [ "$toolbars" = hidden ]; then
note "Its window shows only the page: no tabs or address bar. Keys still work:"
note " Alt+Left back, Alt+Right forward, F5 reload, Ctrl+W close."
fi
mkdir -p "$BIN"
cat >"$cmd" <<EOF
#!/bin/sh
# ${cmd##*/}: $url in its own Firefox profile, as its own locked-down user.
# Written by Wren Linux extras/firefox-profiles/new-profile.sh
exec $FX_CLIENT --profile $name "\$@"
EOF
chmod +x "$cmd"
# the other name, from an older version: one command per profile
local took=("$cmd") c
for c in "$BIN/$name" "$BIN/firefox-$name"; do
if [ "$c" != "$cmd" ] && grep -qsE "$OURS" "$c"; then took+=("$c"); fi
done
fx_remove_cmd "$name" "$cmd"
# What this wrote, and the old command of ours it took away: not "startup changed". Only
# those: the other name may be a command of yours, which isn't this to accept.
watch_take "${took[@]}"
if [ "$cmd" != "$BIN/$name" ]; then
note "\"$name\" is a command already, so this one is called ${cmd##*/}."
fi
note "Start it with: ${cmd##*/} (Super+d finds it too)"
note "Its downloads go to ~/Downloads/$name; it cannot read your files or the other profiles'."
# Debian's standard ~/.profile adds ~/.local/bin to PATH at login
grep -qs '\.local/bin' "$HOME/.profile" ||
warn "$BIN isn't added to your PATH by ~/.profile; start it as $cmd"
}
# fx_remove_cmd NAME [KEEP]: removes the profile's commands that are ours (NAME,
# firefox-NAME), but KEEP
fx_remove_cmd() {
local c
for c in "$BIN/$1" "$BIN/firefox-$1"; do
if [ "$c" != "${2:-}" ] && grep -qsE "$OURS" "$c"; then rm -f "$c"; fi
done
}
# remove_profile NAME: removes its command (NAME or firefox-NAME). A profile with
# a user of its own (made by this version) loses its sudo rule and its settings
# file, and you are asked whether to delete the logins and the user too; the
# older kind (a profile in your own Firefox) keeps its profile, as before. A
# profile whose command is gone (deleted by hand, or a run that stopped
# part-way) is still removed from its settings file or its user.
remove_profile() {
local name=$1 c cmd='' user=fx-$1 sandboxed=false
for c in "$BIN/$name" "$BIN/firefox-$name"; do
if grep -qsE "$OURS" "$c"; then cmd=$c; fi
done
# (decided from the launcher, before it is removed; your user can't look
# into /etc/sudoers.d, so the rule itself can't tell)
if grep -qs -e 'firefox --profile' "$cmd"; then sandboxed=true; fi
if [ -e "$FX_PROFILE_DIR/$name.conf" ] || id "$user" >/dev/null 2>&1; then sandboxed=true; fi
if [ -z "$cmd" ] && ! $sandboxed; then
note "The profile $name isn't set up."
return 0
fi
watch_before
local took=()
for c in "$BIN/$name" "$BIN/firefox-$name"; do
if grep -qsE "$OURS" "$c"; then took+=("$c"); fi
done
fx_remove_cmd "$name"
# What this took away (only commands of ours, never one of yours): not "startup changed".
# Only for a profile of its own user, which needs sudo anyway: the older kind is removed
# without sudo, as it always was.
if $sandboxed && [ ${#took[@]} -gt 0 ]; then watch_take "${took[@]}"; fi
if ! $sandboxed; then
note "Removed ${cmd##*/}. The profile and its logins are kept;"
note "delete it in Firefox at about:profiles if you want it gone."
return 0
fi
fx_disallow_session "$user"
sudo rm -f "$FX_PROFILE_DIR/$name.conf"
sudo setfacl -x "u:$user" "$FX_PROFILE_DIR" 2>/dev/null || true
note "Removed ${cmd:+${cmd##*/}, }the permission to run it and its settings."
if id "$user" >/dev/null 2>&1; then
note "Its logins and history are kept in $FX_HOME_ROOT/$name (user $user, locked)."
if ask "Delete them and the user too?" n; then
sudo pkill -KILL -u "$user" 2>/dev/null || true
sudo userdel "$user" 2>/dev/null || true
sudo rm -rf "${FX_HOME_ROOT:?}/$name"
# (its folders' two names exactly: NAME-run* would also match a profile called NAME-run-x)
sudo find /dev/shm -maxdepth 1 \( -name "$user-run" -o -name "$user-run.*" \) -exec rm -rf {} + 2>/dev/null || true
note "Deleted the profile and its user. Files it downloaded are still in ~/Downloads/$name."
fi
fi
}