#!/usr/bin/env bash # --- CONFIGURATION --- # 1. Give your profile a distinct, single-word name (NO spaces) PROFILE_NAME="SharedProfile" # 2. Define exactly where the folder should live PROFILE_DIR="$HOME/network_drives/home/.mozilla/shared_profile" # Detect OS to set the correct Firefox binary path if [[ "$OSTYPE" == "darwin"* ]]; then FIREFOX_BIN="/Applications/Firefox.app/Contents/MacOS/firefox" LOCK_FILE="$PROFILE_DIR/.parentlock" else FIREFOX_BIN="firefox" # Assumes 'firefox' is in your system PATH on Linux LOCK_FILE="$PROFILE_DIR/lock" fi # --------------------- # --- MAKE SURE THE SHARED HOME IS REALLY MOUNTED --- # ~/network_drives/home is a symlink that mount-user-cifs-shares.service # (/opt/pli/bin/create-network-drive-links) creates asynchronously at the # start of a session. firefox_as ssh's to localhost, which often IS the # start of a new session, so we can get here before that link exists. # Never mkdir under it in that case: a plain directory there makes the # mount script's "ln -sf" put its link INSIDE it, leaving the whole # session with a local, empty "home" (new firefox profile, broken gopass). fail() { echo "[ERROR] $1" >&2 zenity --error --title="Firefox shared profile" --width=480 --text="$1" 2>/dev/null exit 1 } if [[ "$OSTYPE" != "darwin"* ]]; then NET_HOME="$HOME/network_drives/home" if [ -e "$NET_HOME" ] && [ ! -L "$NET_HOME" ]; then fail "$NET_HOME is a local directory, not the link to your network home.\n\nSomething created it before the network drives were mounted, so this session cannot see the shared profile (or gopass).\n\nFix: close everything that uses it, then run:\n mv $NET_HOME ${NET_HOME}.broken\n setup-network-drives" fi for i in $(seq 1 20); do [ -L "$NET_HOME" ] && [ -d "$NET_HOME/" ] && break if [ "$i" -eq 3 ]; then echo "[INFO] Waiting for network drives to be mounted..." systemctl --user start mount-user-cifs-shares.service 2>/dev/null fi sleep 1 done if ! [ -L "$NET_HOME" ] || ! [ -d "$NET_HOME/" ]; then fail "Network home $NET_HOME is not available (no Kerberos ticket?).\n\nRun 'setup-network-drives' in a terminal as $USER, then try again." fi fi # Ensure the parent directory folder physically exists first mkdir -p "$PROFILE_DIR" # Check if the folder is empty/doesn't exist if [ ! -d "$PROFILE_DIR" ] || [ -z "$(ls -A "$PROFILE_DIR")" ]; then echo "[INFO] Profile not found or empty. Forcing registration via Firefox CLI..." # Modern Firefox fix: We use -CreateProfile paired with a dummy screenshot # to force Firefox to write the directory structure and exit cleanly. $FIREFOX_BIN -CreateProfile "$PROFILE_NAME $PROFILE_DIR" --headless --screenshot /dev/null > /dev/null 2>&1 echo "[SUCCESS] Profile '$PROFILE_NAME' registered at: $PROFILE_DIR" else echo "[INFO] Profile folder already exists. Skipping creation step." fi SIGNAL_FILE="$PROFILE_DIR/remote_shutdown.signal" # --- NEW NETWORK-SAFE LOCK DETECTION LOGIC --- echo "[INFO] Scanning for active network locks..." # Force network share to drop local metadata cache ls -la "$PROFILE_DIR" > /dev/null 2>&1 ACTIVE_LOCK_FOUND=false # Check all 3 potential lock names for POSSIBLE_LOCK in "lock" ".parentlock" "parent.lock"; do TARGET_LOCK_PATH="$PROFILE_DIR/$POSSIBLE_LOCK" if [ -e "$TARGET_LOCK_PATH" ] || [ -L "$TARGET_LOCK_PATH" ]; then # FIXED: We use -newermt to see if the lock was touched within the last 25 seconds. # This operates natively across Linux/Mac and accepts precise time strings safely. IS_ACTIVE=$(find "$TARGET_LOCK_PATH" -newermt '25 seconds ago' 2>/dev/null) if [ -n "$IS_ACTIVE" ]; then echo "[WARN] Active remote lock verified: $POSSIBLE_LOCK (Modified within last 25s)" ACTIVE_LOCK_FOUND=true break else echo "[INFO] Stale lock ignored: $POSSIBLE_LOCK (Not modified recently)" fi fi done # Act on our findings if [ "$ACTIVE_LOCK_FOUND" = true ]; then zenity --question \ --title="Firefox Profile Warning" \ --text="This profile is actively running on another computer.\n\nDo you want to send a SHUTDOWN SIGNAL to close the other session remotely?" \ --ok-label="Close Other & Open Here" \ --cancel-label="Cancel Launch" \ --width=420 2>/dev/null if [ $? -eq 0 ]; then echo "[INFO] Creating shutdown signal file..." touch "$SIGNAL_FILE" ( for i in {1..12}; do ls -la "$PROFILE_DIR" > /dev/null 2>&1 # Update the progress tracker loop to use the same -newermt logic STILL_ACTIVE=$(find "$PROFILE_DIR" \( -name "lock" -o -name ".parentlock" -o -name "parent.lock" \) -newermt '25 seconds ago' 2>/dev/null) if [ -z "$STILL_ACTIVE" ]; then echo 100; break fi echo $((i * 8)) sleep 1 done ) | zenity --progress --title="Waiting" --text="Signaling remote session to close cleanly..." --auto-close --width=300 2>/dev/null rm -f "$PROFILE_DIR/lock" "$PROFILE_DIR/.parentlock" "$PROFILE_DIR/parent.lock" "$SIGNAL_FILE" else echo "[INFO] Aborted by user." exit 0 fi fi echo "[INFO] Launching Firefox instance..." # FIX: Added the '&' back to the end of the line so the script can continue # executing the background heartbeat loop while Firefox runs. $FIREFOX_BIN --profile "$PROFILE_DIR" -no-remote > /dev/null 2>&1 & FF_PID=$! # This will now successfully capture Firefox's background PID echo "[INFO] Monitoring session (PID: $FF_PID). Close the window to exit." # --- STEP 3: BACKGROUND MONITORING LOOP WITH HEARTBEAT --- while kill -0 $FF_PID 2>/dev/null; do # 1. Update our local lock file timestamp so other machines know we are alive touch "$PROFILE_DIR/lock" "$PROFILE_DIR/.parentlock" 2>/dev/null # 2. Check for the remote shutdown signal if [ -f "$SIGNAL_FILE" ]; then echo "[SIGNAL] Remote shutdown request received! Closing Firefox..." kill -15 $FF_PID rm -f "$SIGNAL_FILE" wait $FF_PID 2>/dev/null break fi sleep 3 # Heartbeat/check interval every 3 seconds done # Safety wait to ensure the process is fully reaped if closed manually wait $FF_PID 2>/dev/null # Final local cleanup rm -f "$PROFILE_DIR/lock" "$PROFILE_DIR/.parentlock" "$PROFILE_DIR/parent.lock" echo "[INFO] Session closed cleanly." exit 0