[Guide] Automatically install extensions and configure new (dispvm) hardened Firefox profiles with arkenfox user.js and policies

Here’s an addition of caching Firefox addons to install addons using policies.json.

The new DispVMs on boot will request caching VM to get the Firefox addons before Firefox will start.
Caching VM on receiving request will get the latest addon version info and check the addon on disk if it’s the latest version. It’ll download the addon if the version on disk is not the latest. Then it’ll send the latest addon to the requester.

Example for uBlock Origins.
Change sys-whonix in /usr/local/bin/firefox-get-addons in disposable template and in /etc/qubes/policy.d/30-user.policy in dom0 to your desired VM that will be processing the requests to get the Firefox addons.
Change debian-11-dvm in dom0 qvm-tags to your desired disposable template.

To make disposable VMs based on other disposable templates use the caching VM you need to repeat step 1 in new disposable template and add firefox tag to it in dom0:
qvm-tags debian-11-firefox-dvm add tag firefox

1. In disposable template (debian-11-dvm in this example):

Run as user:

mkdir -p /home/user/.config/systemd/user
cat << 'EOF' | sudo tee /usr/local/bin/firefox-get-addons
#!/bin/sh
qubes_vm_name="$(qubesdb-read /name)"
# Check that we're not running inside Disposable Template
if echo "$qubes_vm_name" | grep -q --invert-match "\-dvm" ; then
    /usr/lib/qubes/qrexec-client-vm --filter-escape-chars-stderr -- sys-whonix user.FirefoxGetAddon+uBlockOrigin /usr/lib/qubes/qfile-unpacker
fi
EOF
sudo chmod +x /usr/local/bin/firefox-get-addons 
mkdir -p /home/user/.config/systemd/user
cat << 'EOF' > /home/user/.config/systemd/user/firefox-get-addons.service
[Unit]
Description=Get Firefox Add-ons
Before=basic.target
DefaultDependencies=no

[Service]
Type=oneshot
Environment=QREXEC_REMOTE_DOMAIN=dom0
ExecStart=/usr/local/bin/firefox-get-addons

[Install]
WantedBy=basic.target
EOF
systemctl --user daemon-reload
systemctl --user enable firefox-get-addons.service

Add extension to install in ExtensionSettings in policies.json file:

        "ExtensionSettings": {
            "*": {
                "installation_mode": "blocked"
            },
            "uBlock0@raymondhill.net": {
                "installation_mode": "normal_installed",
                "install_url": "file:///home/user/QubesIncoming/dom0/ublock_origin-latest.xpi"
            }
        },

2. In your caching VM (sys-whonix in this example):

Run as user:

sudo mkdir -p /usr/local/etc/qubes-rpc
cat << 'EOF' | sudo tee /usr/local/etc/qubes-rpc/user.FirefoxGetAddon+uBlockOrigin 
#!/usr/bin/env python3
import os
import sys
import json
import requests
import shutil
import hashlib
import subprocess as s

def download_file(url,proxies,filename):
    with requests.get(url, proxies=proxies, stream=True) as r:
        with open(filename, 'wb') as f:
            shutil.copyfileobj(r.raw, f)

def sha256sum(filename):
    h  = hashlib.sha256()
    b  = bytearray(128*1024)
    mv = memoryview(b)
    with open(filename, 'rb', buffering=0) as f:
        while n := f.readinto(mv):
            h.update(mv[:n])
    return h.hexdigest()

def main():
    # Set Tor proxy if we're running in Whonix VM
    if os.path.exists('/usr/share/whonix/marker'):
        proxy = 'socks5h://127.0.0.1:9050'
    else:
        proxy = ''
    proxies = {
       'http': proxy,
       'https': proxy
    }
    url = 'https://addons.mozilla.org/api/v5/addons/addon/ublock-origin/versions/?page_size=1'
    response = requests.get(url, proxies=proxies)
    addon_latest_json = response.json()['results'][0]
    addon_dest_file = '/home/user/Downloads/firefox-extensions/ublock_origin-latest.xpi'
    os.makedirs(os.path.dirname(addon_dest_file), exist_ok=True)
    if not os.path.exists(addon_dest_file) or sha256sum(addon_dest_file) != addon_latest_json['file']['hash'].split(':')[1]:
        download_file(addon_latest_json['file']['url'], proxies, addon_dest_file)
        if not os.path.exists(addon_dest_file) or sha256sum(addon_dest_file) != addon_latest_json['file']['hash'].split(':')[1]:
            s.call(['notify-send','Failed to get latest uBlock Origin Firefox addon','--icon=dialog-error'])
            sys.exit(1)
    s.call(['/usr/lib/qubes/qfile-agent',addon_dest_file])
    sys.exit(0)
if __name__ == '__main__':
    main()
EOF

3. In dom0:

Run as user:

cat << 'EOF' | sudo tee -a /etc/qubes/policy.d/30-user.policy
user.FirefoxGetAddon +uBlockOrigin @tag:firefox sys-whonix allow
EOF
qvm-tags debian-11-dvm add tag firefox
1 Like