From 3ff425cdd3dc7a221ee0837a5085daa4afbc7bc3 Mon Sep 17 00:00:00 2001 From: Brian Zalewski Date: Mon, 27 Mar 2023 09:56:38 +0000 Subject: [PATCH] Update 6 files - /home/dot_local/share/firefox/prefs.js - /home/.chezmoiscripts/universal/run_onchange_after_40-firefox.tmpl - /home/dot_local/share/firefox/profiles.ini.tmpl - /home/dot_config/firefox/user.js - /home/dot_config/firefoxprofileswitcher/profile-options.json - /home/dot_config/firefoxprofileswitcher/avatars.json --- .../run_onchange_after_40-firefox.tmpl | 176 ++++++++++++------ .../prefs.js => dot_config/firefox/user.js} | 0 .../firefoxprofileswitcher/avatars.json | 11 ++ .../profile-options.json | 11 ++ .../dot_local/share/firefox/profiles.ini.tmpl | 17 +- 5 files changed, 149 insertions(+), 66 deletions(-) rename home/{dot_local/share/firefox/prefs.js => dot_config/firefox/user.js} (100%) create mode 100644 home/dot_config/firefoxprofileswitcher/avatars.json create mode 100644 home/dot_config/firefoxprofileswitcher/profile-options.json diff --git a/home/.chezmoiscripts/universal/run_onchange_after_40-firefox.tmpl b/home/.chezmoiscripts/universal/run_onchange_after_40-firefox.tmpl index 86af6ad7..03a97791 100644 --- a/home/.chezmoiscripts/universal/run_onchange_after_40-firefox.tmpl +++ b/home/.chezmoiscripts/universal/run_onchange_after_40-firefox.tmpl @@ -1,5 +1,44 @@ {{- if ne .host.distro.family "windows" -}} #!/usr/bin/env bash +# @file run_onchange_after_40-firefox.tmpl +# @brief Configures system-wide settings, sets up Firefox Profile Switcher, creates various profiles from different sources, and more. +# @description +# The Firefox setup script performs a handful of tasks that automate the setup of Firefox as well as +# useful utilities that will benefit Firefox power-users. The script also performs the same logic on +# [LibreWolf](https://librewolf.net/) installations. The features that are included are: +# +# * Installs and sets up [Firefox Profile Switcher](https://github.com/null-dev/firefox-profile-switcher) +# * Sets up system-wide enterprise settings (with configurations found in `~/.local/share/firefox`) +# * Sets up a handful of default profiles to use with the Firefox Profile Switcher +# * Automatically installs the plugins defined in the firefoxAddOns key of [`home/.chezmoidata.yaml`](https://github.com/megabyte-labs/install.doctor/blob/master/home/.chezmoidata.yaml) to the Standard and Private profiles +# * Configures the default profile to clone its settings from the profile stored in firefoxPublicProfile of `home/.chezmoidata.yaml` +# * Optionally, if the Chezmoi encryption key is present, then the default profile will be set to the contents of an encrypted `.tar.gz` that must be stored in the cloud somewhere (with the firefoxPrivateProfile key in `home/.chezmoidata.yaml` defining the URL of the encrypted `.tar.gz`) +# +# ## Profiles +# +# The script sets up numerous profiles for user flexibility. They can be switched by using the Firefox Profile Switcher +# that this script sets up. The map of the profiles is generated by using the template file stored in `~/.local/share/firefox/profiles.ini`. +# The following details the features of each profile: +# +# | Name | Description | +# |------------------|---------------------------------------------------------------------------------------------| +# | Factory | Default browser settings (system-wide configurations still apply) | +# | default-release | Same as Factory (unmodified and generated by headlessly opening Firefox / LibreWolf) | +# | Git (Public) | Pre-configured profile with address stored in `firefoxPublicProfile` | +# | Standard | Cloned from the profile above with `firefoxAddOns` also installed | +# | Miscellaneous | Cloned from the Factory profile (with the user.js found in `~/.config/firefox` applied) | +# | Development | Same as Miscellaneous | +# | Automation | Same as Miscellaneous | +# | Private | Populated from an encrypted profile stored in the cloud (also installs `firefoxAddOns`) | +# +# ## Notes +# +# * The Firefox Profile Switcher is only compatible with Firefox and not LibreWolf +# * This script is only designed to properly provision profiles on a fresh installation (so it does not mess around with pre-existing / already configured profiles) +# +# @see [Script on GitHub](https://github.com/megabyte-labs/install.doctor/blob/master/home/.chezmoiscripts/universal/run_onchange_after_40-firefox.tmpl) +# @see [System-wide configurations](https://github.com/megabyte-labs/install.doctor/tree/master/home/dot_local/share/firefox) as well as the location of the `profile.ini` and some other configurations +# @see [User-specific configurations](https://github.com/megabyte-labs/install.doctor/blob/master/home/dot_config/firefox/user.js) added to all profiles except Factory {{ includeTemplate "universal/profile" }} {{ includeTemplate "universal/logg" }} @@ -23,7 +62,7 @@ function installFirefoxProfileConnector() { ### Add Firefox enterprise profile # TODO - figure out how to do this for other installations like Flatpak and macOS and Librewolf -for FIREFOX_DIR in '/usr/lib/firefox' '/usr/lib/firefox-esr' '/Applications/Firefox.app/Contents/Resources'; do +for FIREFOX_DIR in '/usr/lib/firefox' '/usr/lib/firefox-esr' '/etc/firefox' '/etc/firefox-esr' '/Applications/Firefox.app/Contents/Resources' '/Applications/LibreWolf.app/Contents/Resources/'; do if [ -d "$FIREFOX_DIR" ] && [ -d "${XDG_DATA_HOME:-$HOME/.local/share}/firefox" ] && command -v rsync > /dev/null; then sudo rsync -artvu "${XDG_DATA_HOME:-$HOME/.local/share}/firefox/" "$FIREFOX_DIR" fi @@ -127,9 +166,14 @@ for SETTINGS_DIR in "$HOME/snap/firefox/common/.mozilla/firefox" "$HOME/.var/app FIREFOX_EXE="$(which firefox)" installFirefoxProfileConnector else - logg warn 'Unable to register Firefox executable' - logg info "Settings directory: $SETTINGS_DIR" - continue + if [ -d /Applications ] && [ -d /System ]; then + # Continue on macOS without logging because profiles are not stored here on macOS + continue + else + logg warn 'Unable to register Firefox executable' + logg info "Settings directory: $SETTINGS_DIR" + continue + fi fi fi ### Initiatize Firefox default profiles @@ -142,19 +186,29 @@ for SETTINGS_DIR in "$HOME/snap/firefox/common/.mozilla/firefox" "$HOME/.var/app logg info 'Finished running Firefox headlessly' fi - ### Default profile (created by launching Firefox headlessly) - DEFAULT_RELEASE_PROFILE="$(find "$SETTINGS_DIR" -mindepth 1 -maxdepth 1 -name "*.default-*")" - # DEFAULT_PROFILE="$(find "$SETTINGS_DIR" -mindepth 1 -maxdepth 1 -name "*.default" -not -name "profile.default")" - if [ -n "$DEFAULT_RELEASE_PROFILE" ]; then - logg info "Renaming $DEFAULT_RELEASE_PROFILE to $SETTINGS_DIR/profile.default" - rsync -a "$DEFAULT_RELEASE_PROFILE/" "$SETTINGS_DIR/profile.default" + ### Add the populated profiles.ini + logg info "Copying "${XDG_DATA_HOME:-$HOME/.local/share}/firefox/profiles.ini" to profile directory" + if [ -d /Applications ] && [ -d /System ]; then + # macOS + logg info "Copying ~/.local/share/profiles.ini to $SETTINGS_DIR/../profiles.ini" + cp -f "${XDG_DATA_HOME:-$HOME/.local/share}/firefox/profiles.ini" "$SETTINGS_DIR/../profiles.ini" + SETTINGS_INI="$SETTINGS_DIR/../installs.ini" + else + # Linux + logg info "Copying ~/.local/share/profiles.ini to $SETTINGS_DIR/profiles.ini" + cp -f "${XDG_DATA_HOME:-$HOME/.local/share}/firefox/profiles.ini" "$SETTINGS_DIR/profiles.ini" + SETTINGS_INI="$SETTINGS_DIR/installs.ini" fi - ### Default profile w/ plugins installed (installation happens below) + ### Default profile (created by launching Firefox headlessly) + # DEFAULT_RELEASE_PROFILE="$(find "$SETTINGS_DIR" -mindepth 1 -maxdepth 1 -name "*.default-*")" + DEFAULT_PROFILE_PROFILE="$SETTINGS_DIR/$(cat "$SETTINGS_INI" | grep 'Default=' | sed 's/.*Profiles\///')" + logg info 'Removing previous installs.ini file' + rm -f "$SETTINGS_INI" + # DEFAULT_PROFILE="$(find "$SETTINGS_DIR" -mindepth 1 -maxdepth 1 -name "*.default" -not -name "profile.default")" if [ -n "$DEFAULT_RELEASE_PROFILE" ]; then - logg info "Renaming $DEFAULT_RELEASE_PROFILE to $SETTINGS_DIR/profile.plugins" - rsync -a "$DEFAULT_RELEASE_PROFILE/" "$SETTINGS_DIR/profile.plugins" - rsync -a "${XDG_DATA_HOME:-$HOME/.local/share}/firefox/" "$SETTINGS_DIR/profile.plugins" + logg info "Syncing $DEFAULT_RELEASE_PROFILE to $SETTINGS_DIR/profile.default" + rsync -a "$DEFAULT_RELEASE_PROFILE/" "$SETTINGS_DIR/profile.default" fi ### Miscellaneous default profiles @@ -163,6 +217,7 @@ for SETTINGS_DIR in "$HOME/snap/firefox/common/.mozilla/firefox" "$HOME/.var/app logg info "Cloning $NEW_PROFILE from profile.default" rsync -a "$SETTINGS_DIR/profile.default/" "$SETTINGS_DIR/profile.${NEW_PROFILE}" rsync -a "${XDG_DATA_HOME:-$HOME/.local/share}/firefox/" "$SETTINGS_DIR/profile.${NEW_PROFILE}" + cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/firefox/user.js" "$SETTINGS_DIR/profile.${NEW_PROFILE}" fi done @@ -180,7 +235,18 @@ for SETTINGS_DIR in "$HOME/snap/firefox/common/.mozilla/firefox" "$HOME/.var/app git clone {{ .firefoxPublicProfile }} profile.git fi - {{- if and (stat (joinPath .host.home ".config" "age" "chezmoi.txt")) }} + ### Copy user.js to profile.git profile + cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/firefox/user.js" "$SETTINGS_DIR/profile.git" + + ### Git profile w/ plugins installed (installation happens below) + if [ ! -d "$SETTINGS_DIR/profile.plugins" ]; then + logg info "Syncing $SETTINGS_DIR/profile.git to $SETTINGS_DIR/profile.plugins" + rsync -a "$SETTINGS_DIR/profile.git/" "$SETTINGS_DIR/profile.plugins" + rsync -a "${XDG_DATA_HOME:-$HOME/.local/share}/firefox/" "$SETTINGS_DIR/profile.plugins" + cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/firefox/user.js" "$SETTINGS_DIR/profile.plugins" + fi + + {{- if and (stat (joinPath .host.home ".config" "age" "chezmoi.txt") (ne .firefoxPrivateProfile false)) }} ### Private hosted profile if [ ! -d "$SETTINGS_DIR/profile.private" ]; then logg info 'Downloading the encrypted Firefox private profile' @@ -193,57 +259,53 @@ for SETTINGS_DIR in "$HOME/snap/firefox/common/.mozilla/firefox" "$HOME/.var/app logg info 'Decompressing the Firefox private profile' tar -xzf profile.private.tar.gz logg success 'The Firefox private profile was successfully installed' + cp -f "${XDG_CONFIG_HOME:-$HOME/.config}/firefox/user.js" "$SETTINGS_DIR/profile.private" + logg info 'Copied ~/.config/firefox/user.js to profile.private profile' else logg error 'Failed to decrypt the private Firefox profile' fi fi {{- end }} - - ### Add the populated profiles.ini - logg info "Copying "${XDG_DATA_HOME:-$HOME/.local/share}/firefox/profiles.ini" to profile directory" - if [ -d /Applications ] && [ -d /System ]; then - # macOS - cp -f "${XDG_DATA_HOME:-$HOME/.local/share}/firefox/profiles.ini" "$SETTINGS_DIR/../profiles.ini" - else - # Linux - cp -f "${XDG_DATA_HOME:-$HOME/.local/share}/firefox/profiles.ini" "$SETTINGS_DIR/profiles.ini" - fi ### Install Firefox addons (using list declared in .chezmoidata.yaml) - for FIREFOX_PLUGIN in {{ list (.firefoxAddOns | toString | replace "[" "" | replace "]" "") | uniq | join " " }}; do - logg info "Processing the $FIREFOX_PLUGIN Firefox add-on" - PLUGIN_HTML="$(mktemp)" - curl --silent "https://addons.mozilla.org/en-US/firefox/addon/$FIREFOX_PLUGIN/" > "$PLUGIN_HTML" - PLUGIN_TMP="$(mktemp)" - cat "$PLUGIN_HTML" | htmlq '#redux-store-state' | sed 's/^//' | sed 's/<\/script>$//' > "$PLUGIN_TMP" - PLUGIN_ID="$(jq '.addons.bySlug["'"$FIREFOX_PLUGIN"'"]' "$PLUGIN_TMP")" - if [ "$PLUGIN_ID" != 'null' ]; then - PLUGIN_FILE_ID="$(jq -r '.addons.byID["'"$PLUGIN_ID"'"].guid' "$PLUGIN_TMP")" - if [ "$PLUGIN_FILE_ID" != 'null' ]; then - PLUGIN_URL="$(cat "$PLUGIN_HTML" | htmlq '.InstallButtonWrapper-download-link' --attribute href)" - PLUGIN_FILENAME="${PLUGIN_FILE_ID}.xpi" - PLUGIN_FOLDER="$(echo "$PLUGIN_FILENAME" | sed 's/.xpi$//')" - if [ ! -d "$SETTINGS_DIR/profile.plugins/extensions/$PLUGIN_FOLDER" ]; then - logg info 'Downloading add-on XPI file for '"$PLUGIN_FILENAME"' ('"$FIREFOX_PLUGIN"')' - if [ ! -d "$SETTINGS_DIR/profile.plugins/extensions" ]; then - mkdir -p "$SETTINGS_DIR/profile.plugins/extensions" + for SETTINGS_PROFILE in "profile.plugins" "profile.private"; do + if [ -d "$SETTINGS_DIR/$SETTINGS_PROFILE" ]; then + for FIREFOX_PLUGIN in {{ list (.firefoxAddOns | toString | replace "[" "" | replace "]" "") | uniq | join " " }}; do + logg info "Processing the $FIREFOX_PLUGIN Firefox add-on" + PLUGIN_HTML="$(mktemp)" + curl --silent "https://addons.mozilla.org/en-US/firefox/addon/$FIREFOX_PLUGIN/" > "$PLUGIN_HTML" + PLUGIN_TMP="$(mktemp)" + cat "$PLUGIN_HTML" | htmlq '#redux-store-state' | sed 's/^//' | sed 's/<\/script>$//' > "$PLUGIN_TMP" + PLUGIN_ID="$(jq '.addons.bySlug["'"$FIREFOX_PLUGIN"'"]' "$PLUGIN_TMP")" + if [ "$PLUGIN_ID" != 'null' ]; then + PLUGIN_FILE_ID="$(jq -r '.addons.byID["'"$PLUGIN_ID"'"].guid' "$PLUGIN_TMP")" + if [ "$PLUGIN_FILE_ID" != 'null' ]; then + PLUGIN_URL="$(cat "$PLUGIN_HTML" | htmlq '.InstallButtonWrapper-download-link' --attribute href)" + PLUGIN_FILENAME="${PLUGIN_FILE_ID}.xpi" + PLUGIN_FOLDER="$(echo "$PLUGIN_FILENAME" | sed 's/.xpi$//')" + if [ ! -d "$SETTINGS_DIR/$SETTINGS_PROFILE/extensions/$PLUGIN_FOLDER" ]; then + logg info 'Downloading add-on XPI file for '"$PLUGIN_FILENAME"' ('"$FIREFOX_PLUGIN"')' + if [ ! -d "$SETTINGS_DIR/$SETTINGS_PROFILE/extensions" ]; then + mkdir -p "$SETTINGS_DIR/$SETTINGS_PROFILE/extensions" + fi + curl -sSL "$PLUGIN_URL" -o "$SETTINGS_DIR/$SETTINGS_PROFILE/extensions/$PLUGIN_FILENAME" + # Unzipping like this causes Firefox to complain about unsigned plugins + # TODO - figure out how to headlessly enable the extensions in such a way that is compatible with Flatpak / Snap + # using the /usr/lib/firefox/distribution/policies.json works but this is not compatible with Flatpak / Snap out of the box + # it seems since they do not have access to the file system by default. Also, using the policies.json approach forces + # all Firefox profiles to use the same extensions. Ideally, we should find a way to enable the extensions scoped + # to the user profile. + # logg info 'Unzipping '"$PLUGIN_FILENAME"' ('"$FIREFOX_PLUGIN"')' + # unzip "$SETTINGS_DIR/$SETTINGS_PROFILE/extensions/$PLUGIN_FILENAME" -d "$SETTINGS_DIR/$SETTINGS_PROFILE/extensions/$PLUGIN_FOLDER" + logg success 'Installed `'"$FIREFOX_PLUGIN"'`' + fi + else + logg warn 'A null Firefox add-on filename was detected for `'"$FIREFOX_PLUGIN"'`' fi - curl -sSL "$PLUGIN_URL" -o "$SETTINGS_DIR/profile.plugins/extensions/$PLUGIN_FILENAME" - # Unzipping like this causes Firefox to complain about unsigned plugins - # TODO - figure out how to headlessly enable the extensions in such a way that is compatible with Flatpak / Snap - # using the /usr/lib/firefox/distribution/policies.json works but this is not compatible with Flatpak / Snap out of the box - # it seems since they do not have access to the file system by default. Also, using the policies.json approach forces - # all Firefox profiles to use the same extensions. Ideally, we should find a way to enable the extensions scoped - # to the user profile. - # logg info 'Unzipping '"$PLUGIN_FILENAME"' ('"$FIREFOX_PLUGIN"')' - # unzip "$SETTINGS_DIR/profile.plugins/extensions/$PLUGIN_FILENAME" -d "$SETTINGS_DIR/profile.primary/extensions/$PLUGIN_FOLDER" - logg success 'Installed `'"$FIREFOX_PLUGIN"'`' + else + logg warn 'A null Firefox add-on ID was detected for `'"$FIREFOX_PLUGIN"'`' fi - else - logg warn 'A null Firefox add-on filename was detected for `'"$FIREFOX_PLUGIN"'`' - fi - else - logg warn 'A null Firefox add-on ID was detected for `'"$FIREFOX_PLUGIN"'`' + done fi done fi diff --git a/home/dot_local/share/firefox/prefs.js b/home/dot_config/firefox/user.js similarity index 100% rename from home/dot_local/share/firefox/prefs.js rename to home/dot_config/firefox/user.js diff --git a/home/dot_config/firefoxprofileswitcher/avatars.json b/home/dot_config/firefoxprofileswitcher/avatars.json new file mode 100644 index 00000000..81292b4f --- /dev/null +++ b/home/dot_config/firefoxprofileswitcher/avatars.json @@ -0,0 +1,11 @@ +{ + "avatars": { + "0B803C3C78AB69A7FA2B43EDF4F139C60B16081EE3C8B4F98FAF07D2EA236505": "res:/img/avatars/modern_cros_200/abstract/avatar_melon.png", + "43D07063950E4B54FE593B7C6DF3BC64ADAA374A1BBFA885CDFC04C7A3C8072A": "res:/img/avatars/modern_cros_200/abstract/avatar_pizza.png", + "A9D6FA4B7A2043B7FB3EDCB95FEDCC8B137DF5821357CF76ADB6B29B5B3E558A": "res:/img/avatars/modern_cros_200/abstract/avatar_sandwich.png", + "E098B8A5E8AD32E45AFFE798EBA7067D889111E9D57D92FA01046EF0AFCB1CCA": "res:/img/avatars/modern_cros_200/abstract/avatar_icewater.png", + "2E72B43D0149045B0A028448C9D10BD55F961857D1AD7F758BE71CB87539E787": "res:/img/avatars/modern_cros_200/illustration/avatar_cheese.png", + "1D24BBDF1FB63F9785102F65138E17B1EE8C8531856791F6646A3C75F9B3F852": "res:/img/avatars/modern_cros_200/illustration/avatar_basketball.png", + "4C1004A5D052D0ED7B120AC39DFD6F33EAD3EA7EAC047B9DD4F8AEF91232BE51": "res:/img/avatars/modern_cros_200/abstract/avatar_avocado.png" + } +} \ No newline at end of file diff --git a/home/dot_config/firefoxprofileswitcher/profile-options.json b/home/dot_config/firefoxprofileswitcher/profile-options.json new file mode 100644 index 00000000..316c94e2 --- /dev/null +++ b/home/dot_config/firefoxprofileswitcher/profile-options.json @@ -0,0 +1,11 @@ +{ + "options": { + "E098B8A5E8AD32E45AFFE798EBA7067D889111E9D57D92FA01046EF0AFCB1CCA": {}, + "2E72B43D0149045B0A028448C9D10BD55F961857D1AD7F758BE71CB87539E787": {}, + "0B803C3C78AB69A7FA2B43EDF4F139C60B16081EE3C8B4F98FAF07D2EA236505": {}, + "43D07063950E4B54FE593B7C6DF3BC64ADAA374A1BBFA885CDFC04C7A3C8072A": {}, + "1D24BBDF1FB63F9785102F65138E17B1EE8C8531856791F6646A3C75F9B3F852": {}, + "A9D6FA4B7A2043B7FB3EDCB95FEDCC8B137DF5821357CF76ADB6B29B5B3E558A": {}, + "4C1004A5D052D0ED7B120AC39DFD6F33EAD3EA7EAC047B9DD4F8AEF91232BE51": {} + } +} \ No newline at end of file diff --git a/home/dot_local/share/firefox/profiles.ini.tmpl b/home/dot_local/share/firefox/profiles.ini.tmpl index c8af14ee..7ff5d797 100644 --- a/home/dot_local/share/firefox/profiles.ini.tmpl +++ b/home/dot_local/share/firefox/profiles.ini.tmpl @@ -1,7 +1,10 @@ +{{- if and (stat (joinPath .host.home ".config" "age" "chezmoi.txt") (ne .firefoxPrivateProfile false)) -}} [Profile6] -Name=Factory (w/ plugins) +Name=Private IsRelative=1 -Path={{ if eq .host.distro.family "darwin" }}Profiles/{{ end }}profile.plugins +Path={{ if eq .host.distro.family "darwin" }}Profiles/{{ end }}profile.private +Default=1 +{{- end }} [Profile5] Name=Automation @@ -18,11 +21,11 @@ Name=Miscellaneous IsRelative=1 Path={{ if eq .host.distro.family "darwin" }}Profiles/{{ end }}profile.miscellaneous -{{- if (stat (joinPath .host.home ".config" "age" "chezmoi.txt")) }} [Profile2] -Name=Private +Name=Standard IsRelative=1 -Path={{ if eq .host.distro.family "darwin" }}Profiles/{{ end }}profile.private +Path={{ if eq .host.distro.family "darwin" }}Profiles/{{ end }}profile.plugins +{{- if not (and (stat (joinPath .host.home ".config" "age" "chezmoi.txt") (ne .firefoxPrivateProfile false))) }} Default=1 {{- end }} @@ -30,10 +33,6 @@ Default=1 Name=Git (Public) IsRelative=1 Path={{ if eq .host.distro.family "darwin" }}Profiles/{{ end }}profile.git -{{- if not (stat (joinPath .host.home ".config" "age" "chezmoi.txt")) }} -Default=1 -{{- end }} - [Profile0] Name=Factory