From 2989cefb799ad7ab08cc436c0780e2e680e6a277 Mon Sep 17 00:00:00 2001 From: Gmer4Lfe Date: Sat, 30 May 2026 21:29:20 -0400 Subject: [PATCH] Redesign Cancel/Delete Keys in Partnership Actions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit onboard_cancel.sh: - --direction=h1 (default): remove HOST1's key from HOST2 + delete local pair - --direction=h2: remove HOST2's key from HOST1's authorized_keys (by hostname match) - --direction=both: both directions (used by Cancel button at phase 1) pages/partnership.php: - Cancel button: phase 1 only, runs --direction=both (full undo) - Delete Keys (πŸ—‘): available at all phases, expands inline panel showing HOST1β†’HOST2 and HOST2β†’HOST1 as separate removal buttons with descriptions - _vvDeleteKeys toggle state persists across polls alongside _vvOnboarding - vvPtShowDeleteKeys / vvPtHideDeleteKeys top-level toggle fns - vvPtDeleteH1 / vvPtDeleteH2 targeted removal fns --- Partnership/onboard_cancel.sh | 185 +++++++++++++++------------- Plugin/unraid/pages/partnership.php | 121 ++++++++++++------ 2 files changed, 180 insertions(+), 126 deletions(-) diff --git a/Partnership/onboard_cancel.sh b/Partnership/onboard_cancel.sh index e8d3d7d..eecf7e4 100755 --- a/Partnership/onboard_cancel.sh +++ b/Partnership/onboard_cancel.sh @@ -1,36 +1,48 @@ #!/bin/bash # ============================================================================================== -# ============================= Onboard Cancel ================================================= +# ============================= Delete Keys ==================================================== # ============================================================================================== # # PURPOSE # ───────────────────────────────────────────────────────────────────────────── -# Undoes Phase 1 of the onboard process: -# 1. Remove HOST1's public key from HOST2's authorized_keys (while key still works) -# 2. Remove phase flags from HOST2's varaverk_setup.db -# 3. Delete local SSH key pair -# 4. Clear phase flags from local varaverk_setup.db -# -# Run on the OWNER. If HOST2 is unreachable the local side is still cleaned up. +# Removes SSH keys between HOST1 and HOST2 in the specified direction. +# Safe to run at any phase. Clears related setup.db flags. # # ============================================================================================== # RUNTIME MODES # ============================================================================================== # -# Partnership/onboard_cancel.sh -# Cancel Phase 1 β€” remove keys and reset state +# Partnership/onboard_cancel.sh --direction=h1 (default) +# HOST1 β†’ HOST2: remove HOST1's public key from HOST2's authorized_keys, +# delete local HOST1 key pair, clear HOST2 phase flags from setup.db. +# +# Partnership/onboard_cancel.sh --direction=h2 +# HOST2 β†’ HOST1: remove HOST2's public key from HOST1's authorized_keys. +# Identifies the key by HOST2's hostname in the key comment. +# +# Partnership/onboard_cancel.sh --direction=both +# Both directions. # # Partnership/onboard_cancel.sh --dry-run -# Preview all steps without making changes +# Preview without making changes. # # ============================================================================================== SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SCRIPTS_ROOT="$SCRIPT_DIR/.." SSH_TIMEOUT=15 +DIRECTION="h1" +FILTERED_ARGS=() + +for arg in "$@"; do + case "$arg" in + --direction=*) DIRECTION="${arg#--direction=}" ;; + *) FILTERED_ARGS+=("$arg") ;; + esac +done source "$SCRIPTS_ROOT/load_config.sh" -parse_args "$@" +parse_args "${FILTERED_ARGS[@]}" [[ "$EUID" -ne 0 ]] && { error "Must be run as root"; exit 1; } @@ -43,99 +55,98 @@ MIRROR_ID=$( [[ "$OWNER_ID" == "HOST1" ]] && echo "HOST2" || echo "HOST1" ) MIRROR="${!MIRROR_ID}" SSH_KEY_PUB="${SSH_KEY}.pub" STATE_FILE="/boot/config/varaverk_setup.db" +AUTH_KEYS="/root/.ssh/authorized_keys" +MIRROR_SHORT="${MIRROR%%.*}" START=$(date +%s) echo "" -echo "━━━ Cancel Phase 1 β€” $MY_ID β†’ $MIRROR_ID ($MIRROR) β€” $(date '+%Y-%m-%d %H:%M:%S') ━━━" -echo "" +echo "━━━ Delete Keys β€” direction:${DIRECTION} β€” $(date '+%Y-%m-%d %H:%M:%S') ━━━" [[ "$DRY_RUN" == true ]] && warn "DRY RUN β€” no changes will be made" echo "" -REMOTE_CLEANED=false -LOCAL_KEY_GONE=false -STATE_CLEARED=false +H1_DONE=false +H2_DONE=false -# ── Step 1: Remove HOST1's public key from HOST2 ────────────────────────────── -echo "━━━ Step 1 β€” Remove Public Key from $MIRROR_ID ━━━" +# ── HOST1 β†’ HOST2: remove HOST1's key from HOST2 + delete local pair ────────── +if [[ "$DIRECTION" == "h1" || "$DIRECTION" == "both" ]]; then + echo "━━━ HOST1 β†’ HOST2: Remove HOST1 key from $MIRROR ━━━" -if [[ ! -f "$SSH_KEY_PUB" ]]; then - log "No local public key at $SSH_KEY_PUB β€” nothing to remove from $MIRROR_ID" - REMOTE_CLEANED=true -else - # Extract the key blob (middle field of pub key) β€” used as a unique identifier. - # Use | as sed delimiter to avoid clashing with base64 / characters in the blob. - KEY_BLOB=$(awk '{print $2}' "$SSH_KEY_PUB") - MIRROR_IP=$(resolve_tailscale_ip "$MIRROR" 2>/dev/null || true) - - if [[ -z "$MIRROR_IP" ]]; then - warn "Cannot resolve $MIRROR Tailscale IP β€” skipping remote cleanup" - warn "Remove HOST1's public key from $MIRROR:/root/.ssh/authorized_keys manually" - elif [[ "$DRY_RUN" == true ]]; then - warn "DRY RUN β€” would remove key blob from $MIRROR:/root/.ssh/authorized_keys" - warn "DRY RUN β€” would clear ${MIRROR_ID}_PHASE* from $MIRROR:/boot/config/varaverk_setup.db" - REMOTE_CLEANED=true + if [[ ! -f "$SSH_KEY_PUB" ]]; then + log "No local public key β€” nothing to remove from $MIRROR" + H1_DONE=true else - timeout "$SSH_TIMEOUT" ssh -i "$SSH_KEY" \ - -o ConnectTimeout="$SSH_TIMEOUT" -o BatchMode=yes root@"$MIRROR_IP" \ - "sed -i \"|${KEY_BLOB}|d\" /root/.ssh/authorized_keys 2>/dev/null - sed -i \"/^${MIRROR_ID}_PHASE/d\" /boot/config/varaverk_setup.db 2>/dev/null - echo ok" 2>/dev/null | grep -q ok && { - log "HOST1 key removed from $MIRROR authorized_keys βœ…" - log "Phase flags cleared on $MIRROR βœ…" - REMOTE_CLEANED=true - } || warn "Could not SSH to $MIRROR β€” remove HOST1 key and phase flags there manually" + KEY_BLOB=$(awk '{print $2}' "$SSH_KEY_PUB") + MIRROR_IP=$(resolve_tailscale_ip "$MIRROR" 2>/dev/null || true) + + if [[ -z "$MIRROR_IP" ]]; then + warn "Cannot resolve $MIRROR Tailscale IP β€” remove HOST1 key from $MIRROR manually" + elif [[ "$DRY_RUN" == true ]]; then + warn "DRY RUN β€” would remove HOST1 key from $MIRROR:/root/.ssh/authorized_keys" + H1_DONE=true + else + timeout "$SSH_TIMEOUT" ssh -i "$SSH_KEY" \ + -o ConnectTimeout="$SSH_TIMEOUT" -o BatchMode=yes root@"$MIRROR_IP" \ + "sed -i \"|${KEY_BLOB}|d\" /root/.ssh/authorized_keys 2>/dev/null + sed -i \"/^${MIRROR_ID}_PHASE\|^${MIRROR_ID}_KEY_READY/d\" /boot/config/varaverk_setup.db 2>/dev/null + echo ok" 2>/dev/null | grep -q ok && { + log "HOST1 key removed from $MIRROR authorized_keys βœ…" + H1_DONE=true + } || warn "Could not SSH to $MIRROR β€” remove HOST1 key there manually" + fi fi + + # Delete local key pair + if [[ ! -f "$SSH_KEY" && ! -f "$SSH_KEY_PUB" ]]; then + log "Local key already gone" + elif [[ "$DRY_RUN" == true ]]; then + warn "DRY RUN β€” would delete: $SSH_KEY and ${SSH_KEY}.pub" + else + rm -f "$SSH_KEY" "$SSH_KEY_PUB" && log "Local key pair deleted βœ…" || \ + warn "Failed to delete local key β€” check permissions" + fi + + # Clear HOST2 phase flags from local setup.db + if [[ -f "$STATE_FILE" ]]; then + if [[ "$DRY_RUN" == false ]]; then + sed -i "/^${MIRROR_ID}_PHASE/d; /^${MIRROR_ID}_KEY_READY/d" "$STATE_FILE" + log "Phase flags cleared from local setup.db βœ…" + else + warn "DRY RUN β€” would clear ${MIRROR_ID}_PHASE* from setup.db" + fi + fi + echo "" fi -# ── Step 2: Delete local SSH key pair ───────────────────────────────────────── -echo "" -echo "━━━ Step 2 β€” Delete Local SSH Key ━━━" +# ── HOST2 β†’ HOST1: remove HOST2's key from HOST1's authorized_keys ──────────── +if [[ "$DIRECTION" == "h2" || "$DIRECTION" == "both" ]]; then + echo "━━━ HOST2 β†’ HOST1: Remove $MIRROR key from HOST1 ━━━" -if [[ ! -f "$SSH_KEY" && ! -f "$SSH_KEY_PUB" ]]; then - log "Local key already gone" - LOCAL_KEY_GONE=true -elif [[ "$DRY_RUN" == true ]]; then - warn "DRY RUN β€” would delete: $SSH_KEY" - warn "DRY RUN β€” would delete: $SSH_KEY_PUB" - LOCAL_KEY_GONE=true -else - rm -f "$SSH_KEY" "$SSH_KEY_PUB" && { - log "Local key pair deleted βœ…" - LOCAL_KEY_GONE=true - } || warn "Failed to delete $SSH_KEY β€” check permissions" -fi - -# ── Step 3: Clear phase flags from local setup.db ───────────────────────────── -echo "" -echo "━━━ Step 3 β€” Clear Phase State ━━━" - -if [[ ! -f "$STATE_FILE" ]]; then - log "No varaverk_setup.db β€” nothing to clear" - STATE_CLEARED=true -elif [[ "$DRY_RUN" == true ]]; then - warn "DRY RUN β€” would remove ${MIRROR_ID}_PHASE* from $STATE_FILE" - STATE_CLEARED=true -else - sed -i "/^${MIRROR_ID}_PHASE/d" "$STATE_FILE" && { - log "Phase flags cleared from local setup.db βœ…" - STATE_CLEARED=true - } + if [[ ! -f "$AUTH_KEYS" ]]; then + log "No authorized_keys on HOST1 β€” nothing to remove" + H2_DONE=true + elif ! grep -qi "$MIRROR_SHORT" "$AUTH_KEYS" 2>/dev/null; then + log "$MIRROR key not found in HOST1 authorized_keys (already removed or never added)" + H2_DONE=true + elif [[ "$DRY_RUN" == true ]]; then + warn "DRY RUN β€” would remove $MIRROR_SHORT key from $AUTH_KEYS" + H2_DONE=true + else + sed -i "/${MIRROR_SHORT}/Id" "$AUTH_KEYS" && { + log "$MIRROR key removed from HOST1 authorized_keys βœ…" + H2_DONE=true + } || warn "Failed to remove $MIRROR key from HOST1 authorized_keys" + fi + echo "" fi # ── Summary ─────────────────────────────────────────────────────────────────── END=$(date +%s) -echo "" -echo "━━━━━ CANCEL SUMMARY ━━━━━" -echo " $MIRROR_ID key removed: $( [[ "$REMOTE_CLEANED" == true ]] && echo "βœ…" || echo "⚠ manual cleanup needed" )" -echo " Local key deleted: $( [[ "$LOCAL_KEY_GONE" == true ]] && echo "βœ…" || echo "⚠ still present" )" -echo " Phase state cleared: $( [[ "$STATE_CLEARED" == true ]] && echo "βœ…" || echo "⚠" )" +echo "━━━━━ DONE ━━━━━" +[[ "$DIRECTION" == "h1" || "$DIRECTION" == "both" ]] && \ + echo " HOST1 β†’ HOST2: $( [[ "$H1_DONE" == true ]] && echo "βœ…" || echo "⚠ manual step may be needed" )" +[[ "$DIRECTION" == "h2" || "$DIRECTION" == "both" ]] && \ + echo " HOST2 β†’ HOST1: $( [[ "$H2_DONE" == true ]] && echo "βœ…" || echo "⚠" )" echo " Duration: $(format_duration $(( END - START )))" -echo "" -if [[ "$REMOTE_CLEANED" == false ]]; then - echo " Manual cleanup on $MIRROR:" - echo " sed -i '/$(awk "{print \$3}" "$SSH_KEY_PUB" 2>/dev/null || echo "HOST1_key_comment")//d' /root/.ssh/authorized_keys" -fi -echo " Run Phase 1 again to restart the onboard process." echo "━━━━━━━━━━━━━━━━━━━━━━━" exit 0 diff --git a/Plugin/unraid/pages/partnership.php b/Plugin/unraid/pages/partnership.php index f5697ef..643ef9f 100644 --- a/Plugin/unraid/pages/partnership.php +++ b/Plugin/unraid/pages/partnership.php @@ -56,9 +56,10 @@