SimpleX setup with dispvm

Im using SimpleX. I’m having trouble placing the icons and getting appimage to open directly. The “disposable template appvm” has also caused me some doubts and I don’t know if I’ve implemented it correctly. Could an experienced user check this?

#!/bin/bash

#######################################################################
# File Name    : whonix-simplex-dvm.sh
# Description  : This script creates a SimpleX qube and template based
#                in Whonix DisposableVM template just with persistent
#                identity across disposables. It downloads and verify
#                the hash of the last SimpleX AppImage and uses sys-
#                whonix NetVM. For ease of use the script aggregates
#                shortcuts to application menu.
# Dependencies : curl
# Usage        : • Transfer this script from appvm to dom0 with:
#                [user@dom0 ~]$ qvm-run --pass-io appvm 'cat ~/whonix-simplex-dvm.sh' > ~/whonix-simplex-dvm.sh
#                • Make the script executable with:
#                [user@dom0 ~]$ chmod +x ~/whonix-simplex-dvm.sh
#                • Run the script with:
#                [user@dom0 ~]$ bash ~/whonix-simplex-dvm.sh
#                • To update, run the script in whonix-simplex-template:
#                bash ~/update-whonix-simplex-dvm.sh
# Author       : Me and the bois
# License      : Free of charge, no warranty
#######################################################################

# Safety check
set -eu

# Define Variables
APP_NAME="simplex-chat.AppImage"
APP_NAME_MENU="SimpleX Chat"
APP_DESKTOP="/usr/share/applications/simplex-chat.desktop"
BASE_TEMPLATE="whonix-workstation-17"
DISP_TEMPLATE_APPVM="whonix-simplex-template"
DISPVM_INSTANCE="whonix-simplex-dvm"
NET_VM="sys-whonix"
DOWNLOAD_URL="https://api.github.com/repos/simplex-chat/simplex-chat/releases/latest"
SIMPLEX_PERSISTENT_DIR="/rw/config/simplex-persistent"
SIMPLEX_CONFIG_DIR="$HOME/.config/simplex"

# Verify base template exists
if ! qvm-check "$BASE_TEMPLATE" >/dev/null 2>&1; then
    echo -e "\nError: Base template $BASE_TEMPLATE not found!" >&2
    exit 1
fi

# Update base template using qubesctl
echo -e "\nUpdating base template..."
sudo qubesctl --show-output --skip-dom0 --targets="$BASE_TEMPLATE" state.sls update.qubes-vm

# Create new AppVM based on Whonix template
echo -e "\nCreating $DISP_TEMPLATE_APPVM based on $BASE_TEMPLATE..."
qvm-create --class AppVM --property template="$BASE_TEMPLATE" --property label=gray "$DISP_TEMPLATE_APPVM"
echo -e "\nShutting down $DISP_TEMPLATE_APPVM to save changes..."
qvm-shutdown --wait "$DISP_TEMPLATE_APPVM"

# Configure it as DisposableVM template
echo -e "\nConfiguring $DISP_TEMPLATE_APPVM as DisposableVM template..."
qvm-prefs "$DISP_TEMPLATE_APPVM" template_for_dispvms True
qvm-prefs "$DISP_TEMPLATE_APPVM" netvm "$NET_VM"
qvm-features "$DISP_TEMPLATE_APPVM" appmenus-dispvm 1

# Install dependencies for new template
echo -e "\nInstalling dependencies..."
qvm-run -u root "$DISP_TEMPLATE_APPVM" 'apt update -y && apt install -y curl'

# Setup persistent storage
echo -e "\nConfiguring persistent storage..."
qvm-run -u root "$DISP_TEMPLATE_APPVM" "mkdir -p '$SIMPLEX_PERSISTENT_DIR' && \
    chown user:user '$SIMPLEX_PERSISTENT_DIR' && \
    ln -s '$SIMPLEX_PERSISTENT_DIR' '$SIMPLEX_CONFIG_DIR'"

# Download function
download_appimage() {
    echo -e "\nFetching release info from GitHub..."

    # Get release JSON with --pass-io for reliable transfer
    RELEASE_JSON=$(qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "curl -sL '$DOWNLOAD_URL'")

    # Extract download URL (more robust parsing)
    DOWNLOAD_URL=$(echo -e "\n$RELEASE_JSON" | grep -o '"browser_download_url": *"[^"]*"' | \
        grep -i 'simplex-desktop.*x86_64.*\.AppImage' | \
        cut -d '"' -f 4 | head -n 1)

    # Fallback to any AppImage if specific one not found
    if [[ -z "$DOWNLOAD_URL" ]]; then
        DOWNLOAD_URL=$(echo -e "\n$RELEASE_JSON" | grep -o '"browser_download_url": *"[^"]*"' | \
            grep -i '\.AppImage"' | cut -d '"' -f 4 | head -n 1)
    fi

    if [[ -z "$DOWNLOAD_URL" ]]; then
        echo -e "\nError: Could not find AppImage download URL in:" >&2
        echo -e "\n$RELEASE_JSON" >&2
        exit 1
    fi

    echo -e "\nDownloading AppImage from: $DOWNLOAD_URL"
    if ! qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "curl -L -o '$HOME/$APP_NAME' '$DOWNLOAD_URL'"; then
        echo -e "\nDownload failed!" >&2
        exit 1
    fi

    qvm-run "$DISP_TEMPLATE_APPVM" "chmod +x '$HOME/$APP_NAME'"
}

# Hash verification function
verify_hash() {
    echo -e "\nExtracting expected hash from release info..."

    # Get the release body text that contains the hashes
    local release_body=$(echo "$RELEASE_JSON" | grep -zoP '"body":\s*".*?"' | cut -d'"' -f4 | tr -d '\0')

    # Extract ONLY the AppImage hash from the release body
    local expected_hash=$(echo "$release_body" | grep -o "SHA2-256(simplex-desktop-x86_64.AppImage)= [a-f0-9]*" | cut -d' ' -f2)

    if [[ -z "$expected_hash" ]]; then
        echo "Error: Could not extract AppImage hash from release info!" >&2
        exit 1
    fi

    echo -e "\nCalculating actual hash of downloaded file..."
    local actual_hash=$(qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "sha256sum '$HOME/$APP_NAME' | cut -d' ' -f1")

    echo -e "\nVerifying hashes..."
    echo "Expected: $expected_hash"
    echo "Actual:   $actual_hash"

    if [[ "$expected_hash" != "$actual_hash" ]]; then
        echo "ERROR: Hash verification failed!" >&2
        exit 1
    fi
    echo "Hash verification passed"
}

# Download and verify
download_appimage
verify_hash

# Create desktop entry and menu entry
setup_desktop_entry() {
    echo -e "\nSetting up desktop entry and app menu integration..."

    # Define the desktop filename using Qubes naming convention
    local QUBES_DESKTOP_FILENAME="org.qubes-os.vm._whonix_dsimplex_dtemplate.simplex-chat.desktop"
    local DESKTOP_FILE_PATH="/usr/share/applications/$QUBES_DESKTOP_FILENAME"

    # Create the desktop entry file with proper contents
    qvm-run "$DISP_TEMPLATE_APPVM" "cat > '/tmp/$QUBES_DESKTOP_FILENAME'" <<"EOF"
[Desktop Entry]
Version=1.0
Type=Application
Name=SimpleX Chat
GenericName=Secure Messenger
Comment=Private and secure messaging with SimpleX
Terminal=false
TryExec=$HOME/$APP_NAME
Exec=$HOME/$APP_NAME
Icon=internet
Categories=Network;InstantMessaging;
StartupNotify=true
EOF

    # Move it to the correct system location
    qvm-run -u root "$DISP_TEMPLATE_APPVM" "mkdir -p /usr/share/applications && \
        mv '/tmp/$QUBES_DESKTOP_FILENAME' '$DESKTOP_FILE_PATH' && \
        chmod 644 '$DESKTOP_FILE_PATH'"

    # Create applications-merged directory in template
    qvm-run "$DISP_TEMPLATE_APPVM" "mkdir -p /home/user/.config/menus/applications-merged"

    # Create proper menu file in template
    qvm-run "$DISP_TEMPLATE_APPVM" "cat > /home/user/.config/menus/applications-merged/user-qubes-vm-directory_whonix_dsimplex_dtemplate.menu" <<EOF
<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
    "http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">
<Menu>
    <Name>Applications</Name>
    <Menu>
        <Name>qubes-vm-directory_whonix_dsimplex_dtemplate</Name>
        <Directory>qubes-vm-directory_whonix_dsimplex_dtemplate.directory</Directory>
        <Include>
            <Filename>$QUBES_DESKTOP_FILENAME</Filename>
            <Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.xfce4-terminal.desktop</Filename>
            <Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.janondisttorbrowser.desktop</Filename>
            <Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.systemcheck.desktop</Filename>
            <Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.thunar.desktop</Filename>
            <Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.anondist-torbrowser_update.desktop</Filename>
            <Filename>org.qubes-os.qubes-vm-settings._whonix_dsimplex_dtemplate.desktop</Filename>
            <Filename>org.qubes-os.vm._whonix_dsimplex_dtemplate.qubes-start.desktop</Filename>
        </Include>
    </Menu>
</Menu>
EOF

    # Force menu refresh
    echo -e "\nForce refreshing application menus..."
    qvm-run "$DISP_TEMPLATE_APPVM" "/etc/qubes-rpc/qubes.GetAppmenus > /dev/null"

    # Sync menus to dom0
    echo -e "\nSyncing application menus to dom0..."
    qvm-sync-appmenus "$DISP_TEMPLATE_APPVM"

    echo -e "\nDesktop entry and app menu setup complete!"
}

# Call the function
setup_desktop_entry

# Create updater script in the template with proper variable handling
create_updater_script() {
    echo -e "\nCreating updater in template...update only in the template!"

    # Define the script content
    local UPDATER_SCRIPT=$(cat <<EOF
#!/bin/bash

# Update only in the template!

# Variables
APP_NAME="simplex-chat.AppImage"
DOWNLOAD_URL="https://api.github.com/repos/simplex-chat/simplex-chat/releases/latest"
SIMPLEX_PERSISTENT_DIR="/rw/config/simplex-persistent"
SIMPLEX_CONFIG_DIR="\$HOME/.config/simplex"

$(declare -f download_appimage)
$(declare -f verify_hash)

# Ensure persistent directory link exists
if [[ ! -L "\$SIMPLEX_CONFIG_DIR" ]]; then
    ln -s "\$SIMPLEX_PERSISTENT_DIR" "\$SIMPLEX_CONFIG_DIR"
fi

# Main execution
download_appimage
verify_hash

echo -e "\\nSimpleX Chat update completed successfully!"
EOF
)
    # Transfer to template
    echo "$UPDATER_SCRIPT" | qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "cat > \$HOME/update-simplex.sh"

    # Make executable
    qvm-run "$DISP_TEMPLATE_APPVM" "chmod +x \$HOME/update-simplex.sh"

    echo "Updater script created in $DISP_TEMPLATE_APPVM"
}
create_updater_script

echo -e "\nShutting down $BASE_TEMPLATE..."
qvm-shutdown --wait "$BASE_TEMPLATE"

echo -e "\nSyncing DISP_TEMPLATE_APPVM application menus..."
qvm-sync-appmenus "$DISP_TEMPLATE_APPVM"


# Finalize

echo -e "\nShutting down $DISP_TEMPLATE_APPVM to create $DISPVM_INSTANCE..."
qvm-shutdown --wait "$DISP_TEMPLATE_APPVM"

echo -e "\nCreating disposable VM..."
qvm-create --property template="$DISP_TEMPLATE_APPVM" --class DispVM --property label=red "$DISPVM_INSTANCE"
qvm-features "$DISPVM_INSTANCE" appmenus-dispvm ''

echo -e "\nInstallation complete!"
echo -e "\nUse '$DISPVM_INSTANCE' from Qubes application menu."
SimpleX References:

I am also using SimpleX chat on qubeOS
my simplex qube is runing on a copy of whonix workstation as a template and sys-whonix as netvm
after that i just download simplex appimage and provide autorisation (like for every appimage) on it to make is working on my “simplex qube”
as you internet is working on Tor (sys-whonix) you have to set Simplex to use sockproxy for than you can go on settings, network and server and then use socks proxy
I hope this will help you !

1 Like

Interresting

In the context of Whonix (sys-whonix) everything is through Tor. You can enforce .onion-only mode (incognito mode via SOCKS). Its not clear to me if its important for Qubes setup, Simplex could use separate Tor circuits for connections from different profiles (transport isolation) only if SOCKS is enabled in the AppVM or Its just for Android?

Relevant point is here:

Simplex Documentation:

https://simplex.chat/blog/20220901-simplex-chat-v3.2-incognito-mode.html#incognito-mode :

“We have released support for using SOCKS proxy to access messaging servers via Tor, (…) It means that while your IP address was protected from the server, the whole Tor circuit could have been observed by some actors, and for some communication scenarios it is not desirable.
(…) all servers provided by SimpleX Chat now have dual addresses (one public and one .onion), and you can have your own servers available via two addresses as well (…) you should use the same format for the addresses of your servers.”

https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation :

“Even when you create different chat profiles you are still connecting to your contacts via the same device. Transport isolation, by default, makes connections belonging to the same profile use different TCP sessions, so while the server sees the same IP address, it doesn’t see it as the same client connection. If you are connecting via Tor using SOCKS proxy (e.g. Orbot app on Android) not only the app will use different TCP sessions, it will also use separate Tor circuits for connections from different profiles, preventing the servers and network observers seeing this as traffic coming from the same device.”

Simplex 6.3.3 Default Configuration:

About the script, Im almost there… Entries is commig, work-in-progress

#!/bin/bash

#######################################################################
# File Name    : whonix-simplex-dvm.sh
# Description  : This script creates a SimpleX qube and template based
#                in Whonix DisposableVM template just with persistent
#                identity across disposables. It downloads and verify
#                the hash of the last SimpleX AppImage and uses sys-
#                whonix NetVM. For ease of use the script aggregates
#                shortcuts to application menu.
# Dependencies : curl
# Usage        : • Transfer this script from appvm to dom0 with:
#                [user@dom0 ~]$ qvm-run --pass-io appvm 'cat ~/whonix-simplex-dvm.sh' > ~/whonix-simplex-dvm.sh
#                • Make the script executable with:
#                [user@dom0 ~]$ chmod +x ~/whonix-simplex-dvm.sh
#                • Run the script with:
#                [user@dom0 ~]$ bash ~/whonix-simplex-dvm.sh
#                • To update, run the script in whonix-simplex-template:
#                bash ~/update-whonix-simplex-dvm.sh
# Author       : Me and the bois
# License      : Free of charge, no warranty
#######################################################################

# Safety check
set -eu

# Define Variables
APP_NAME="simplex-chat.AppImage"
APP_NAME_MENU="SimpleX Chat"
BASE_TEMPLATE="whonix-workstation-17"
DISP_TEMPLATE_APPVM="whonix-simplex-template"
DISPVM_INSTANCE="whonix-simplex-dvm"
NET_VM="sys-whonix"
DOWNLOAD_URL="https://api.github.com/repos/simplex-chat/simplex-chat/releases/latest"
SIMPLEX_PERSISTENT_DIR="/rw/bind-dirs/home/user/.config/simplex"
SIMPLEX_CONFIG_DIR="$HOME/.config/simplex"

# Verify base template exists
if ! qvm-check "$BASE_TEMPLATE" >/dev/null 2>&1; then
    echo -e "\nError: Base template $BASE_TEMPLATE not found!" >&2
    exit 1
fi

# Update base template using qubesctl
echo -e "\nUpdating base template..."
sudo qubesctl --show-output --skip-dom0 --targets="$BASE_TEMPLATE" state.sls update.qubes-vm

# Create new AppVM based on Whonix template
echo -e "\nCreating $DISP_TEMPLATE_APPVM based on $BASE_TEMPLATE..."
qvm-create --class AppVM --property template="$BASE_TEMPLATE" --property label=gray "$DISP_TEMPLATE_APPVM"
echo -e "\nShutting down $DISP_TEMPLATE_APPVM to save changes..."
qvm-shutdown --wait "$DISP_TEMPLATE_APPVM"

# Configure it as DisposableVM template
echo -e "\nConfiguring $DISP_TEMPLATE_APPVM as DisposableVM template..."
qvm-prefs "$DISP_TEMPLATE_APPVM" template_for_dispvms True
qvm-prefs "$DISP_TEMPLATE_APPVM" netvm "$NET_VM"
qvm-features "$DISP_TEMPLATE_APPVM" appmenus-dispvm 1

# Install dependencies for new template
echo -e "\nInstalling dependencies..."
qvm-run -u root "$DISP_TEMPLATE_APPVM" 'apt update -y && apt install -y curl'

# Setup persistent storage using bind-dirs
echo -e "\nConfiguring persistent storage with bind-dirs..."
qvm-run -u root "$DISP_TEMPLATE_APPVM" "mkdir -p '$SIMPLEX_PERSISTENT_DIR' && \
    chown -R user:user '/rw/bind-dirs/home/user' && \
    mkdir -p /rw/config/qubes-bind-dirs.d && \
    echo '/home/user/.config/simplex' > /rw/config/qubes-bind-dirs.d/50_simplex.conf"

# Download function
download_appimage() {
    echo -e "\nFetching release info from GitHub..."

    # Get release JSON with --pass-io for reliable transfer
    RELEASE_JSON=$(qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "curl -sL '$DOWNLOAD_URL'")

    # Extract download URL (more robust parsing)
    DOWNLOAD_URL=$(echo -e "\n$RELEASE_JSON" | grep -o '"browser_download_url": *"[^"]*"' | \
        grep -i 'simplex-desktop.*x86_64.*\.AppImage' | \
        cut -d '"' -f 4 | head -n 1)

    # Fallback to any AppImage if specific one not found
    if [[ -z "$DOWNLOAD_URL" ]]; then
        DOWNLOAD_URL=$(echo -e "\n$RELEASE_JSON" | grep -o '"browser_download_url": *"[^"]*"' | \
            grep -i '\.AppImage"' | cut -d '"' -f 4 | head -n 1)
    fi

    if [[ -z "$DOWNLOAD_URL" ]]; then
        echo -e "\nError: Could not find AppImage download URL in:" >&2
        echo -e "\n$RELEASE_JSON" >&2
        exit 1
    fi

    echo -e "\nDownloading AppImage from: $DOWNLOAD_URL"
    if ! qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "curl -L -o '$HOME/$APP_NAME' '$DOWNLOAD_URL'"; then
        echo -e "\nDownload failed!" >&2
        exit 1
    fi

    qvm-run "$DISP_TEMPLATE_APPVM" "chmod +x '$HOME/$APP_NAME'"
}
download_appimage

# Hash verification function
verify_hash() {
    echo -e "\nExtracting expected hash from release info..."

    # Get the release body text that contains the hashes
    local release_body=$(echo "$RELEASE_JSON" | grep -zoP '"body":\s*".*?"' | cut -d'"' -f4 | tr -d '\0')

    # Extract ONLY the AppImage hash from the release body
    local expected_hash=$(echo "$release_body" | grep -o "SHA2-256(simplex-desktop-x86_64.AppImage)= [a-f0-9]*" | cut -d' ' -f2)

    if [[ -z "$expected_hash" ]]; then
        echo "Error: Could not extract AppImage hash from release info!" >&2
        exit 1
    fi

    echo -e "\nCalculating actual hash of downloaded file..."
    local actual_hash=$(qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "sha256sum '$HOME/$APP_NAME' | cut -d' ' -f1")

    echo -e "\nVerifying hashes..."
    echo "Expected: $expected_hash"
    echo "Actual:   $actual_hash"

    if [[ "$expected_hash" != "$actual_hash" ]]; then
        echo "ERROR: Hash verification failed!" >&2
        exit 1
    fi
    echo "Hash verification passed"
}
verify_hash

# Setting up entries with correct variable expansion, heredoc parsing and permissions
setup_desktop_entry() {
    echo -e "\nSetting up desktop entry and app menu integration..."

    # Define paths
    local DESKTOP_FILENAME="qubes-dispvm-simplex-chat.desktop"
    local DESKTOP_FILE_PATH="/usr/local/share/applications/$DESKTOP_FILENAME"
    local MENU_FILE_PATH="/rw/config/xdg/menus/applications-merged/qubes-dispvm.menu"
    local MENU_DIR="/rw/config/xdg/menus/applications-merged"
    local APPS_DIR="/usr/local/share/applications"

    # Create applications directory
    if ! qvm-run -u root "$DISP_TEMPLATE_APPVM" "mkdir -p '$APPS_DIR' && chmod 755 '$APPS_DIR'"; then
        echo "ERROR: Failed to create applications directory" >&2
        exit 1
    fi

    # Create menu directory in persistent storage
    if ! qvm-run -u root "$DISP_TEMPLATE_APPVM" "mkdir -p '$MENU_DIR' && chmod 755 '$MENU_DIR'"; then
        echo "ERROR: Failed to create menu directory" >&2
        exit 1
    fi

    # Configure bind-dirs using a different approach
    if ! qvm-run -u root "$DISP_TEMPLATE_APPVM" "mkdir -p /rw/config/qubes-bind-dirs.d"; then
        echo "ERROR: Failed to create qubes-bind-dirs.d" >&2
        exit 1
    fi

    # Create the bind-dirs config file using cat with a here-document
    if ! qvm-run -u root "$DISP_TEMPLATE_APPVM" "cat > /rw/config/qubes-bind-dirs.d/50_menus.conf" <<'BIND_EOF'
binds+=( '/etc/xdg/menus' )
BIND_EOF
    then
        echo "ERROR: Failed to configure bind-dirs" >&2
        exit 1
    fi

    # Create desktop file
    local DESKTOP_CONTENT="[Desktop Entry]
Version=1.0
Type=Application
Name=SimpleX Chat (DispVM)
GenericName=Secure Messenger
Comment=Private and secure messaging with SimpleX
Exec=qvm-run --dispvm=$DISP_TEMPLATE_APPVM \\\"\\\$HOME/$APP_NAME\\\"
Icon=internet
Terminal=false
Categories=Network;InstantMessaging;X-Qubes-VM;
StartupNotify=true
X-Qubes-VMName=$DISPVM_INSTANCE"

    if ! qvm-run -u root "$DISP_TEMPLATE_APPVM" "echo '$DESKTOP_CONTENT' > '$DESKTOP_FILE_PATH'"; then
        echo "ERROR: Failed to create desktop file" >&2
        exit 1
    fi

    # Set desktop file permissions
    if ! qvm-run -u root "$DISP_TEMPLATE_APPVM" "chown root:root '$DESKTOP_FILE_PATH' && chmod 644 '$DESKTOP_FILE_PATH'"; then
        echo "ERROR: Failed to set desktop file permissions" >&2
        exit 1
    fi

    # Create menu file
    local MENU_CONTENT='<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"
    "http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">
<Menu>
    <Name>Applications</Name>
    <Menu>
        <Name>DisposableVMs</Name>
        <Directory>qubes-dispvm.directory</Directory>
        <Include>
            <Filename>qubes-dispvm-simplex-chat.desktop</Filename>
        </Include>
    </Menu>
</Menu>'

    if ! qvm-run -u root "$DISP_TEMPLATE_APPVM" "echo '$MENU_CONTENT' > '$MENU_FILE_PATH'"; then
        echo "ERROR: Failed to create menu file" >&2
        exit 1
    fi

    # Create symlink - simplified approach
    if ! qvm-run -u root "$DISP_TEMPLATE_APPVM" "mkdir -p /etc/xdg/menus/applications-merged"; then
        echo "ERROR: Failed to create applications-merged directory" >&2
        exit 1
    fi

    if ! qvm-run -u root "$DISP_TEMPLATE_APPVM" "ln -sf '$MENU_FILE_PATH' '/etc/xdg/menus/applications-merged/qubes-dispvm.menu'"; then
        echo "ERROR: Failed to create menu symlink" >&2
        exit 1
    fi

    # Update desktop database
    if ! qvm-run -u root "$DISP_TEMPLATE_APPVM" "update-desktop-database '$APPS_DIR'"; then
        echo "ERROR: Failed to update desktop database" >&2
        exit 1
    fi

    # Verification
    echo -e "\nVerification:"
    qvm-run -p "$DISP_TEMPLATE_APPVM" "ls -l '$DESKTOP_FILE_PATH' '$MENU_FILE_PATH'"
    qvm-run -p "$DISP_TEMPLATE_APPVM" "ls -l /etc/xdg/menus/applications-merged/"
    qvm-run -p "$DISP_TEMPLATE_APPVM" "cat /rw/config/qubes-bind-dirs.d/50_menus.conf"

    echo -e "\nDesktop entry and app menu setup complete in template!"
}
setup_desktop_entry

create_updater_script() {
    echo -e "\nCreating updater in template...update only in the template!"

    # Generate updater script content
    local UPDATER_CONTENT=$(cat <<'UP_EOF'
#!/bin/bash

# Update only in the template!

# Variables
APP_NAME="simplex-chat.AppImage"
DOWNLOAD_URL="https://api.github.com/repos/simplex-chat/simplex-chat/releases/latest"
UP_EOF
    )
    # Add functions
    UPDATER_CONTENT+="\n\n$(declare -f download_appimage | sed 's/^/    /')"
    UPDATER_CONTENT+="\n\n$(declare -f verify_hash | sed 's/^/    /')"
    UPDATER_CONTENT+="\n\n# Main execution\ndownload_appimage\nverify_hash\n"
    UPDATER_CONTENT+='echo -e "\nSimpleX Chat update completed successfully!"'

    # Transfer to template with proper permissions
    echo "$UPDATER_CONTENT" | qvm-run --pass-io "$DISP_TEMPLATE_APPVM" "
        cat > \$HOME/update-simplex.sh &&
        chown user:user \$HOME/update-simplex.sh &&
        chmod 700 \$HOME/update-simplex.sh
    "

    echo "Updater script created in $DISP_TEMPLATE_APPVM"
}
create_updater_script

# Finalize
echo -e "\nShutting down $BASE_TEMPLATE..."
qvm-shutdown --wait "$BASE_TEMPLATE"

# Start template to sync menus
echo -e "\nStarting $DISP_TEMPLATE_APPVM to sync menus..."
qvm-start "$DISP_TEMPLATE_APPVM" && sleep 5

# Sync menus while template is running
echo -e "\nSyncing application menus to dom0..."
qvm-sync-appmenus "$DISP_TEMPLATE_APPVM"

# Shutdown template to create disposable
echo -e "\nShutting down $DISP_TEMPLATE_APPVM to create $DISPVM_INSTANCE..."
qvm-shutdown --wait "$DISP_TEMPLATE_APPVM"

# Create disposable VM
echo -e "\nCreating disposable VM..."
qvm-create --property template="$DISP_TEMPLATE_APPVM" --class DispVM --property label=red "$DISPVM_INSTANCE"
qvm-features "$DISPVM_INSTANCE" appmenus-dispvm ''

# Final menu update targeting the disposable VM
echo -e "\nUpdating application menus in dom0..."
qvm-appmenus --update --force "$DISPVM_INSTANCE"

echo -e "\nInstallation complete!"

regarding the script I am not the good one to help you.
I can just confirm than I had information than socks proxy is the best option regarding privacy and having onion address is always better.
It’s working well for me with the settings I previously explained

1 Like