#!/bin/bash set -euo pipefail usage() { echo "Usage: $0 [extension_name|all] [inet-to-intra|intra-to-inet]" echo " no arguments: list extension names from the source profile" echo " extension_name: copy the first matching extension by name" echo " all: copy every extension from source to target" echo " direction: which way to copy (default: inet-to-intra)" } EXTENSION_NAME="" DIRECTION="inet-to-intra" case $# in 0) ;; 1) case "$1" in inet-to-intra|intra-to-inet) usage exit 1 ;; *) EXTENSION_NAME="$1" ;; esac ;; 2) EXTENSION_NAME="$1" DIRECTION="$2" ;; *) usage exit 1 ;; esac if [[ "$DIRECTION" != "inet-to-intra" && "$DIRECTION" != "intra-to-inet" ]]; then usage exit 1 fi MOZILLA_BASE="${HOME}/.mozilla/firefox" SNAP_BASE="${HOME}/snap/firefox/common/.mozilla/firefox" find_base_path() { if [[ -d "$MOZILLA_BASE" ]] && [[ -f "$MOZILLA_BASE/profiles.ini" ]]; then echo "$MOZILLA_BASE" return 0 elif [[ -d "$SNAP_BASE" ]] && [[ -f "$SNAP_BASE/profiles.ini" ]]; then echo "$SNAP_BASE" return 0 fi return 1 } find_profile() { local base="$1" local name="$2" local pattern case "$name" in internet) pattern="*internet*" ;; intranet) pattern="*intranet*" ;; noproxy) pattern="*noProxy*" ;; *) pattern="*${name}*" ;; esac for prof in "$base"/$pattern; do if [[ -d "$prof" ]]; then echo "$prof" return 0 fi done return 1 } list_profiles() { local base="$1" if [[ ! -d "$base" ]]; then return 1 fi for prof in "$base"/*.default*; do if [[ -d "$prof" ]]; then echo "$prof" fi done for prof in "$base"/*.*; do if [[ -d "$prof" ]]; then echo "$prof" fi done } find_extension() { local ext_dir="$1" local name="$2" if [[ ! -d "$ext_dir" ]]; then return 1 fi for ext in "$ext_dir"/*; do if [[ -d "$ext" ]]; then if [[ -f "$ext/manifest.json" ]]; then if grep -qi "$name" "$ext/manifest.json" 2>/dev/null; then echo "$ext" return 0 fi fi elif [[ -f "$ext" ]] && [[ "$ext" == *.xpi ]]; then if unzip -p "$ext" manifest.json 2>/dev/null | grep -qi "$name"; then echo "$ext" return 0 fi fi done return 1 } list_extensions() { local ext_dir="$1" if [[ ! -d "$ext_dir" ]]; then return 1 fi shopt -s nullglob for ext in "$ext_dir"/*; do if [[ -d "$ext" ]]; then if [[ -f "$ext/manifest.json" ]]; then local manifest_name manifest_name=$(grep -oE '"name"[[:space:]]*:[[:space:]]*"[^"]+"' "$ext/manifest.json" 2>/dev/null | head -n1 | sed -E 's/.*"([^"]+)".*/\1/' || true) if [[ -n "$manifest_name" ]]; then echo "$manifest_name" else echo "$(basename "$ext")" fi fi elif [[ -f "$ext" ]] && [[ "$ext" == *.xpi ]]; then local manifest_name manifest_name=$(unzip -p "$ext" manifest.json 2>/dev/null | grep -oE '"name"[[:space:]]*:[[:space:]]*"[^"]+"' | head -n1 | sed -E 's/.*"([^"]+)".*/\1/' || true) if [[ -n "$manifest_name" ]]; then echo "$manifest_name" else echo "$(basename "$ext")" fi fi done shopt -u nullglob } copy_all_extensions() { local source_ext_dir="$1" local target_ext_dir="$2" if [[ ! -d "$source_ext_dir" ]]; then echo "Error: Source extensions directory not found" exit 1 fi mkdir -p "$target_ext_dir" shopt -s nullglob local copied=0 for ext in "$source_ext_dir"/*; do local ext_name ext_name=$(basename "$ext") local target_ext="$target_ext_dir/$ext_name" if [[ -e "$target_ext" ]]; then echo "Removing existing extension from target: $ext_name" rm -rf "$target_ext" fi cp -r "$ext" "$target_ext" echo "Copied: $ext_name" copied=1 done shopt -u nullglob if [[ $copied -eq 0 ]]; then echo "No extensions found to copy." fi } main() { echo "=== Firefox Extension Sync ($DIRECTION) ===" echo "" local base_path base_path=$(find_base_path) || { echo "Error: Could not find Firefox profile directory" exit 1 } echo "Profile base path: $base_path" echo "Available profiles:" list_profiles "$base_path" | while read -r p; do echo " - $(basename "$p")" done echo "" local source_profile target_profile case "$DIRECTION" in inet-to-intra) source_profile=$(find_profile "$base_path" "internet") target_profile=$(find_profile "$base_path" "intranet") ;; intra-to-inet) source_profile=$(find_profile "$base_path" "intranet") target_profile=$(find_profile "$base_path" "internet") ;; esac if [[ -z "$source_profile" ]]; then echo "Error: Could not find source profile" exit 1 fi if [[ -z "$target_profile" ]]; then echo "Error: Could not find target profile" exit 1 fi echo "Source: $(basename "$source_profile")" echo "Target: $(basename "$target_profile")" echo "" if [[ -z "$EXTENSION_NAME" ]]; then echo "Extensions in source profile:" local found=0 while IFS= read -r ext; do found=1 [[ -n "$ext" ]] && echo " - $ext" done < <(list_extensions "$source_profile/extensions" || true) if [[ $found -eq 0 ]]; then echo " - " fi exit 0 fi if [[ "$EXTENSION_NAME" == "all" ]]; then echo "Copying all extensions..." copy_all_extensions "$source_profile/extensions" "$target_profile/extensions" echo "" echo "Done! Restart Firefox to load the extensions." exit 0 fi local source_ext source_ext=$(find_extension "$source_profile/extensions" "$EXTENSION_NAME") || { echo "Error: $EXTENSION_NAME extension not found in source profile" exit 1 } local ext_name ext_name=$(basename "$source_ext") echo "Found extension: $ext_name" echo "" local target_ext="$target_profile/extensions/$ext_name" if [[ -d "$target_ext" ]]; then echo "Removing existing extension from target..." rm -rf "$target_ext" fi cp -r "$source_ext" "$target_ext" echo "Copied successfully!" echo "" echo "Done! Restart Firefox to load the extension." } main "$@"