#!/bin/bash set -euo pipefail EXTENSION_ID="bastionguard-mail@codelinsoft.it" SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" EXTENSION_SRC="$SCRIPT_DIR" TB_DIR="$HOME/.thunderbird" PROFILES_INI="$TB_DIR/profiles.ini" NATIVE_HOST_NAME="it.codelinsoft.bastionguard.mail" NATIVE_HOST_JSON="$EXTENSION_SRC/it.codelinsoft.bastionguard.mail.json" NATIVE_HOST_SCRIPT="$EXTENSION_SRC/bastionguard-native-mail.py" NATIVE_HOST_DEST="/usr/bin/bastionguard-native-mail" XPI_NAME="${EXTENSION_ID}.xpi" WORK_DIR="${XDG_RUNTIME_DIR:-/tmp}/bastionguard-thunderbird" mkdir -p "$WORK_DIR" XPI_PATH="$WORK_DIR/$XPI_NAME" log() { echo "[BastionGuard] $*" } fail() { echo "[BastionGuard] ERRORE: $*" >&2 exit 1 } require_file() { local path="$1" [ -f "$path" ] || fail "File non trovato: $path" } require_dir() { local path="$1" [ -d "$path" ] || fail "Cartella non trovata: $path" } run_sudo() { if [ -n "${BASTIONGUARD_SUDO_PASSWORD:-}" ]; then printf '%s\n' "$BASTIONGUARD_SUDO_PASSWORD" | sudo -S -p '' "$@" else sudo "$@" fi } check_extension_layout() { require_dir "$EXTENSION_SRC" require_file "$EXTENSION_SRC/manifest.json" require_file "$EXTENSION_SRC/background.js" require_file "$NATIVE_HOST_SCRIPT" require_file "$NATIVE_HOST_JSON" if ! command -v zip >/dev/null 2>&1; then fail "Il comando 'zip' non è installato. Installa il pacchetto zip." fi if ! command -v python3 >/dev/null 2>&1; then fail "python3 non trovato." fi } find_tb_profile() { [ -f "$PROFILES_INI" ] || fail "profiles.ini non trovato in $TB_DIR" local profile_path="" local is_relative="1" profile_path=$(awk ' /^\[Install/ { in_install=1; next } /^\[/ { in_install=0 } in_install && /^Default=/ { print substr($0, 9); exit } ' "$PROFILES_INI") if [ -z "$profile_path" ]; then local result result=$(awk ' /^\[Profile/ { in_profile=1; path=""; def=0; rel=1; next } /^\[/ && !/^\[Profile/ { in_profile=0 } in_profile && /^Path=/ { path=substr($0, 6) } in_profile && /^Default=1/ { def=1 } in_profile && /^IsRelative=0/ { rel=0 } in_profile && def && path != "" { print path "|" rel; exit } ' "$PROFILES_INI") if [ -n "$result" ]; then profile_path="${result%|*}" is_relative="${result#*|}" fi fi if [ -z "$profile_path" ]; then profile_path=$(awk ' /^\[Profile/ { in_profile=1; path=""; rel=1; next } /^\[/ && !/^\[Profile/ { in_profile=0 } in_profile && /^Path=/ { path=substr($0, 6) } in_profile && /^IsRelative=0/ { rel=0 } in_profile && path ~ /default-release/ { print path "|" rel; exit } ' "$PROFILES_INI") if [ -n "$profile_path" ] && [[ "$profile_path" == *"|"* ]]; then is_relative="${profile_path#*|}" profile_path="${profile_path%|*}" fi fi if [ -z "$profile_path" ]; then local result result=$(awk ' /^\[Profile/ { in_profile=1; path=""; rel=1; next } /^\[/ && !/^\[Profile/ { in_profile=0 } in_profile && /^Path=/ { path=substr($0, 6) } in_profile && /^IsRelative=0/ { rel=0 } in_profile && path != "" { print path "|" rel; exit } ' "$PROFILES_INI") [ -n "$result" ] || fail "Nessun profilo trovato in $PROFILES_INI" is_relative="${result#*|}" profile_path="${result%|*}" fi [ -n "$profile_path" ] || fail "Nessun profilo Thunderbird trovato" if [[ "$profile_path" = /* ]] || [ "$is_relative" = "0" ]; then echo "$profile_path" else echo "$TB_DIR/$profile_path" fi } build_xpi() { log "Creo pacchetto XPI..." rm -f "$XPI_PATH" ( cd "$EXTENSION_SRC" zip -qr "$XPI_PATH" \ manifest.json \ background.js \ bastionguard-native-mail.py \ it.codelinsoft.bastionguard.mail.json \ _locales \ icons ) require_file "$XPI_PATH" log "✔ XPI creato: $XPI_PATH" } install_native_host_script() { require_file "$NATIVE_HOST_SCRIPT" log "Installo native host in $NATIVE_HOST_DEST (richiede password root)..." run_sudo cp "$NATIVE_HOST_SCRIPT" "$NATIVE_HOST_DEST" run_sudo chmod 755 "$NATIVE_HOST_DEST" log "✔ Native host installato in $NATIVE_HOST_DEST" } install_native_host_manifest() { require_file "$NATIVE_HOST_JSON" local tmp_manifest tmp_manifest="$(mktemp)" python3 - "$NATIVE_HOST_JSON" "$NATIVE_HOST_DEST" "$tmp_manifest" <<'PYEOF' import json import sys src, real_path, dst = sys.argv[1], sys.argv[2], sys.argv[3] with open(src, "r", encoding="utf-8") as f: data = json.load(f) data["path"] = real_path with open(dst, "w", encoding="utf-8") as f: json.dump(data, f, indent=2, ensure_ascii=False) f.write("\n") PYEOF local system_dir="/usr/lib/thunderbird/native-messaging-hosts" local home_dir="$HOME/.mozilla/native-messaging-hosts" log "Installo manifest native host system-wide in $system_dir (richiede root)..." run_sudo mkdir -p "$system_dir" run_sudo cp "$tmp_manifest" "$system_dir/${NATIVE_HOST_NAME}.json" run_sudo chmod 644 "$system_dir/${NATIVE_HOST_NAME}.json" log "✔ Manifest installato in $system_dir" log "Installo manifest native host utente in $home_dir..." mkdir -p "$home_dir" cp "$tmp_manifest" "$home_dir/${NATIVE_HOST_NAME}.json" chmod 644 "$home_dir/${NATIVE_HOST_NAME}.json" log "✔ Manifest installato in $home_dir" rm -f "$tmp_manifest" } install_extension() { local extensions_dir="$TB_PROFILE/extensions" local dest="$extensions_dir/$XPI_NAME" mkdir -p "$extensions_dir" if [ -e "$dest" ]; then log "Rimuovo installazione precedente..." rm -f "$dest" fi log "Installo estensione XPI in: $dest" cp -f "$XPI_PATH" "$dest" chmod 644 "$dest" log "✔ Estensione installata correttamente" } enable_unsigned_extensions() { local user_js="$TB_PROFILE/user.js" touch "$user_js" if ! grep -q 'xpinstall.signatures.required' "$user_js" 2>/dev/null; then echo 'user_pref("xpinstall.signatures.required", false);' >> "$user_js" log "✔ xpinstall.signatures.required=false impostato" fi if ! grep -q 'extensions.langpacks.signatures.required' "$user_js" 2>/dev/null; then echo 'user_pref("extensions.langpacks.signatures.required", false);' >> "$user_js" log "✔ extensions.langpacks.signatures.required=false impostato" fi } disable_thunderbird_signatures() { local prefs="$TB_PROFILE/prefs.js" if [ ! -f "$prefs" ]; then log "prefs.js non trovato, salto disabilitazione firme native" return fi log "Disabilito firme native Thunderbird..." cp "$prefs" "$prefs.bg_backup" python3 - "$prefs" <<'PYEOF' import re import sys path = sys.argv[1] with open(path, "r", encoding="utf-8") as f: content = f.read() content = re.sub(r'user_pref\("mail\.identity\.id\d+\.htmlSigText"[^)]*\);\n?', '', content) content = re.sub(r'user_pref\("mail\.identity\.id\d+\.htmlSigFormat"[^)]*\);\n?', '', content) content = re.sub(r'user_pref\("mail\.identity\.id\d+\.reply_on_top"[^)]*\);\n?', '', content) ids = set(re.findall(r'mail\.identity\.(id\d+)\.', content)) lines = [] for id_ in sorted(ids): lines.append(f'user_pref("mail.identity.{id_}.htmlSigText", "");') lines.append(f'user_pref("mail.identity.{id_}.htmlSigFormat", false);') if lines: content = content.rstrip("\n") + "\n" + "\n".join(lines) + "\n" with open(path, "w", encoding="utf-8") as f: f.write(content) print(f"[BastionGuard] Disabilitate firme per {len(ids)} identità") PYEOF log "✔ Firme native disabilitate (backup: $prefs.bg_backup)" } main() { check_extension_layout if [ -n "${1:-}" ]; then TB_PROFILE="$1" else TB_PROFILE="$(find_tb_profile)" fi log "SCRIPT_DIR: $SCRIPT_DIR" log "EXTENSION_SRC: $EXTENSION_SRC" log "Profilo Thunderbird: $TB_PROFILE" require_dir "$TB_PROFILE" build_xpi install_native_host_script install_native_host_manifest install_extension enable_unsigned_extensions disable_thunderbird_signatures echo log "✔ Installazione completata." log "Riavvia Thunderbird per attivare BastionGuard Mail Security." } main "$@"