For Fox Sake! - Scripting your Firefox Configuration

Image by Gerd Altmann from Pixabay.
Do you often rebuild VMs? Do you find yourself needing to duplicate Firefox settings across a large number of hosts? Don't want to manually configure your Firefox settings every time? Then look no further than this guide.

I recently undertook the task of writing a script to apply my preferences and configurations to a clean install of Kali Linux. The result cut hours of configuration work down to a few keystrokes and a matter of minutes, but getting to that point was no easy feat. When it came to automating Firefox configuration, I hit what seemed to be a brick wall, however, after hours of research, trial and error, and repeated failure, I finally made some headway. As I'm sure I'm not the only one to have faced these issues, I thought I'd document my solutions here to save some of you the headache I went through trying to get this to work.

Disclaimer: All of the techniques in this guide work for Mozilla Firefox 68.9.0esr on Kali Linux 2020.2. Mozilla is constantly making changes to the way Firefox works and so results may differ with other operating systems and versions of the software.

Extensions


Unfortunately, since Mozilla removed support for extension sideloading, I have not been able to find a way to completely automate the installation of extensions. The closest I was able to get was to make a script that downloads extensions and opens a new Firefox instance for each that prompts a user to accept their installation. This script can be seen below:

#!/bin/bash

# Install Firefox addons
mkdir ffaddons
cd ffaddons
addons=( "extension_1_url" "extension_2_url" )
count=1
for addon in "${addons[@]}"; do
    wget -O addon$count.xpi $addon
    firefox --new-window addon$count.xpi &>/dev/null &
    count=$((count + 1))
done

# Pause for user to confirm Firefox extensions have been installed
echo "Ensure any user prompts have been acknowledged and press any key to continue..."
while [ true ] ; do
read -n 1
if [ $? = 0 ] ; then
break
fi
done

# Remove unnecessary files
cd ..
rm -rf ffaddons

Note: The rest of the steps in this guide all require the existence of a user profile directory. It is therefore recommended that you place extension installation before any other Firefox configuration in any build scripts you may write; this will ensure that a profile is created before you attempt to modify it.

Whilst I couldn't find a way to install extensions automatically, I was able to find a way to automate their configuration. Data used by extensions is saved in files in the storage/default directory within Firefox profile directories. When Firefox cannot find these files in a profile, it reverts to a backup stored in the storage-sync.sqlite file in the root of the profile directory (e.g. ~/.mozilla/firefox/j329msd4.default-esr/storage-sync.sqlite). This means that if you have a storage-sync.sqlite file containing your extension configurations, you can force Firefox to load them.

You can easily create such a file by adding your extensions to a local install of Firefox and configuring them manually. The storage-sync.sqlite file created by Firefox in your profile directory can then be used in the following steps.

Note: The rest of the steps in this guide require that no Firefox processes are running. In order to ensure that this is the case, place the following commands in any build scripts you may write:

for proc in `ps -ef | grep firefox | awk '{ print $2 }'`; do 
    kill $proc
done

Once you have a storage-sync.sqlite file, you'll notice that it's not a simple text file and thus can't be easily included in a script. In order to overcome this, you can use the base64 command as shown below:

base64 storage-sync.sqlite

This will encode the file using base64, producing a string of text that can easily be included as part of a script. If the string is too long to be reasonably included in a script, you can try zipping the file before encoding it using the commands below:

gzip storage-sync.sqlite
base64 storage-sync.sqlite.gz

The following commands can then be placed in any build scripts you may write to install your storage-sync.sqlite file:

cd firefoxProfileDirectory
echo "base64 string" | base64 -d > storage-sync.sqlite

Or if you zipped the file before encoding it:

cd firefoxProfileDirectory
echo "base64 string" | base64 -d | gzip -d > storage-sync.sqlite

Note: If you don't know the exact name of your Firefox profile directory, in Kali Linux you can place the following command in your script to ensure that you enter the correct directory:

cd $HOME/.mozilla/firefox/*.default-esr

Now that your storage-sync.sqlite file has been installed, you'll need to force Firefox to use it. To do this, you'll need to remove any existing configuration files from the storage/default directory within your Firefox profile directory. This can be easily done using the following command:

rm -rf storage/default/moz-extension*

The next time you open Firefox, you should notice that your extensions are using your specified configurations instead of their defaults.

Bookmarks


Adding bookmarks can be scripted in much the same way as extension configuration. Firstly, you'll need to manually add your bookmarks to a local install of Firefox. This will cause firefox to generate a file in the bookmarkbackups dirctory within your Firefox profile directory (e.g. ~/.mozilla/firefox/j329msd4.default-esr/bookmarkbackups/bookmarks-2020-06-13_8_ECSfHD7bcckJHB7MxFYBzQ==.jsonlz4). Don't worry if the file doesn't immediately appear, it can take a few minutes before one is generated.

Once you have your bookmarks file, you'll need to base64 encode it using the following command:

base64 filepath

Before installing your bookmarks file, you'll need to remove any existing bookmark files as well as the places.sqlite file in the root of the Firefox profile directory; this will prevent your bookmarks from being ignored or overwritten. This can be achieved with the following commands:

cd firefoxProfileDirectory
rm -f places.sqlite
rm -f bookmarkbackups/*

The following commands can then be used to install your file:

cd bookmarkbackups
echo "base64 string" | base64 -d > filename

Be sure to use the same filename as the original file as Firefox will not load your bookmarks if the filename is not in the correct format!

The next time you open Firefox, you should notice that your bookmarks have been loaded.

Default Search Engine


Again, the default search engine can be scripted in the same way as extension configuration and adding bookmarks. This time, however, the file you're interested in is the search.json.mozlz4 file in the root of the Firefox profile directory. Simply set your default search engine for a local install of Firefox and base64 encode the search.json.mozlz4 file in your Firefox profile directory using the command below:

base64 search.json.mozlz4

The following commands can then be added to any build scripts you may write to change the default search engine:

cd firefoxProfileDirectory
echo "base64 string" | base64 -d > search.json.mozlz4

The next time you open Firefox, you should notice that your default search engine has changed.

User Preferences


So this was the only part of Firefox's configuration I could find that was widely documented, however, I've included it here for completeness.

Firefox stores user preferences in a file called prefs.js. Whilst you shouldn't modify the default prefs.js file for fear of breaking your installation, Firefox does allow you to override the preferences that are stored in it. This can be achieved by placing a file called user.js in a user's Firefox profile directory (e.g. ~/.mozilla/firefox/j329msd4.default-esr). This file should contain user preferences in the following format:

user_pref("preference_name", value);

A list of valid preferences can be found here, however, it should be noted that not all preferences work in every version of Firefox, so make sure to do your research and find out what works for your version.

When it comes to scripting, this process can be automated using the cat command with a heredoc as shown below:

cat <<'EOF' > user.js
// Custom preferences
user_pref("preference_1", value_1);
user_pref("preference_2", value_2);
EOF

You can read more about user.js files here.

Conclusion


If past releases are anything to go by, I'm sure that Mozilla will change how these settings work in future releases of Firefox, however, I hope that this guide is useful to you while it remains relevant.

Happy browsing!

No comments:

Post a Comment

Popular Posts