Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands - CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround - CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check - NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere - MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates - LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference Co-authored-by: Cursor <cursoragent@cursor.com>
201 lines
8.0 KiB
Bash
Executable File
201 lines
8.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# List all NPMplus TLS certificates with status: which should be RENEWED (expiring soon or in use with unknown expiry),
|
||
# which should be KEPT (in use, not expiring soon), and which should be REMOVED (not assigned to any proxy host).
|
||
# Uses NPM API only. Optional: set PROXMOX_HOST and NPMPLUS_VMID to fetch expiry from container cert files.
|
||
# Uses .env for NPM_URL, NPM_EMAIL, NPM_PASSWORD. See docs/04-configuration/NPMPLUS_TLS_CLEANUP.md
|
||
|
||
set -euo pipefail
|
||
|
||
# Load IP configuration
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||
source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true
|
||
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||
|
||
# Preserve NPM credentials from environment
|
||
_orig_npm_url="${NPM_URL:-}"
|
||
_orig_npm_email="${NPM_EMAIL:-}"
|
||
_orig_npm_password="${NPM_PASSWORD:-}"
|
||
if [ -f "$PROJECT_ROOT/.env" ]; then
|
||
set +u
|
||
set -a
|
||
# shellcheck source=/dev/null
|
||
source "$PROJECT_ROOT/.env" 2>/dev/null || true
|
||
set +a
|
||
set -u
|
||
[ -n "$_orig_npm_url" ] && NPM_URL="$_orig_npm_url"
|
||
[ -n "$_orig_npm_email" ] && NPM_EMAIL="$_orig_npm_email"
|
||
[ -n "$_orig_npm_password" ] && NPM_PASSWORD="$_orig_npm_password"
|
||
fi
|
||
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
CYAN='\033[0;36m'
|
||
NC='\033[0m'
|
||
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
|
||
log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; }
|
||
log_error() { echo -e "${RED}[✗]${NC} $1"; }
|
||
|
||
RENEW_DAYS="${RENEW_DAYS:-30}"
|
||
NPM_URL="${NPM_URL:-https://${IP_NPMPLUS}:81}"
|
||
NPM_EMAIL="${NPM_EMAIL:-admin@example.org}"
|
||
NPM_PASSWORD="${NPM_PASSWORD:-}"
|
||
PROXMOX_HOST="${PROXMOX_HOST:-}"
|
||
NPMPLUS_VMID="${NPMPLUS_VMID:-${NPM_VMID:-10233}}"
|
||
|
||
if [ -z "$NPM_PASSWORD" ]; then
|
||
log_error "NPM_PASSWORD is required. Set it in .env or export NPM_PASSWORD=..."
|
||
exit 1
|
||
fi
|
||
|
||
echo ""
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo "🔒 NPMplus TLS Certificates – Renew vs Remove"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo ""
|
||
|
||
# Authenticate
|
||
log_info "Authenticating to NPMplus..."
|
||
AUTH_JSON=$(jq -n --arg identity "$NPM_EMAIL" --arg secret "$NPM_PASSWORD" '{identity:$identity,secret:$secret}')
|
||
TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" -H "Content-Type: application/json" -d "$AUTH_JSON")
|
||
TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || echo "")
|
||
|
||
if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then
|
||
log_error "Authentication failed. Check NPM_URL, NPM_EMAIL, NPM_PASSWORD."
|
||
exit 1
|
||
fi
|
||
log_success "Authenticated"
|
||
echo ""
|
||
|
||
# Get proxy hosts – certificate_id in use
|
||
log_info "Fetching proxy hosts..."
|
||
PROXY_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" -H "Authorization: Bearer $TOKEN")
|
||
IN_USE_IDS=$(echo "$PROXY_JSON" | jq -r '[.[] | select(.certificate_id != null and .certificate_id > 0) | .certificate_id] | unique[]' 2>/dev/null || true)
|
||
echo "$IN_USE_IDS" | grep -q . || IN_USE_IDS=""
|
||
log_info "Certificate IDs in use: $(echo $IN_USE_IDS | tr '\n' ' ')"
|
||
echo ""
|
||
|
||
# Get all certificates
|
||
log_info "Fetching certificates..."
|
||
CERTS_JSON=$(curl -s -k -X GET "$NPM_URL/api/nginx/certificates" -H "Authorization: Bearer $TOKEN")
|
||
CERT_COUNT=$(echo "$CERTS_JSON" | jq 'length' 2>/dev/null || echo "0")
|
||
log_info "Total certificates: $CERT_COUNT"
|
||
echo ""
|
||
|
||
# Optional: fetch expiry from container cert files (openssl x509 -enddate)
|
||
get_expiry_from_container() {
|
||
local cert_id="$1"
|
||
if [ -z "$PROXMOX_HOST" ] || [ -z "$NPMPLUS_VMID" ]; then
|
||
echo ""
|
||
return
|
||
fi
|
||
ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=accept-new root@"$PROXMOX_HOST" \
|
||
"pct exec $NPMPLUS_VMID -- openssl x509 -in /data/tls/certbot/live/npm-${cert_id}/fullchain.pem -noout -enddate 2>/dev/null | cut -d= -f2" 2>/dev/null || echo ""
|
||
}
|
||
|
||
# Table header
|
||
printf "${CYAN}%-6s %-45s %-8s %-12s %-22s %-6s${NC}\n" "ID" "Domains" "In use" "Expires" "Days left" "Action"
|
||
printf "%.0s─" $(seq 1 100)
|
||
echo ""
|
||
|
||
TO_RENEW=0
|
||
TO_KEEP=0
|
||
TO_REMOVE=0
|
||
|
||
while IFS= read -r cert; do
|
||
[ -z "$cert" ] && continue
|
||
cid=$(echo "$cert" | jq -r '.id' 2>/dev/null)
|
||
[ -z "$cid" ] || [ "$cid" = "null" ] && continue
|
||
|
||
domains=$(echo "$cert" | jq -r '.domain_names // [] | if type == "array" then join(", ") else . end' 2>/dev/null || echo "")
|
||
[ -z "$domains" ] || [ "$domains" = "null" ] && domains="(no domains)"
|
||
if [ "${#domains}" -gt 44 ]; then
|
||
domains="${domains:0:42}.."
|
||
fi
|
||
|
||
in_use="no"
|
||
echo "$IN_USE_IDS" | grep -q "^${cid}$" && in_use="yes"
|
||
|
||
# Expiry: try API first (expires_on, expiry_date, valid_to often in ms or ISO)
|
||
expiry_raw=$(echo "$cert" | jq -r '.expires_on // .expiry_date // .valid_to // empty' 2>/dev/null || echo "")
|
||
expiry_str=""
|
||
days_left=""
|
||
|
||
if [ -n "$expiry_raw" ] && [ "$expiry_raw" != "null" ]; then
|
||
if echo "$expiry_raw" | grep -qE '^[0-9]+$'; then
|
||
expiry_str=$(date -d "@$((expiry_raw / 1000))" +%Y-%m-%d 2>/dev/null) || expiry_str="$expiry_raw"
|
||
else
|
||
expiry_str=$(echo "$expiry_raw" | cut -d'T' -f1 2>/dev/null) || expiry_str="$expiry_raw"
|
||
fi
|
||
fi
|
||
|
||
if [ -z "$expiry_str" ] && [ -n "$PROXMOX_HOST" ]; then
|
||
expiry_from_file=$(get_expiry_from_container "$cid")
|
||
if [ -n "$expiry_from_file" ]; then
|
||
expiry_str=$(date -d "$expiry_from_file" +%Y-%m-%d 2>/dev/null) || expiry_str="$expiry_from_file"
|
||
fi
|
||
fi
|
||
|
||
if [ -n "$expiry_str" ]; then
|
||
expiry_ts=$(date -d "$expiry_str" +%s 2>/dev/null || echo "")
|
||
if [ -n "$expiry_ts" ]; then
|
||
now_ts=$(date +%s)
|
||
days_left=$(( (expiry_ts - now_ts) / 86400 ))
|
||
fi
|
||
fi
|
||
|
||
days_display="—"
|
||
[ -n "$days_left" ] && days_display="${days_left}"
|
||
|
||
# Action: REMOVE if not in use; RENEW if in use and (expired or < RENEW_DAYS or unknown expiry); KEEP otherwise
|
||
action="KEEP"
|
||
if [ "$in_use" = "no" ]; then
|
||
action="REMOVE"
|
||
TO_REMOVE=$((TO_REMOVE + 1))
|
||
elif [ -n "$days_left" ]; then
|
||
if [ "$days_left" -lt 0 ]; then
|
||
action="RENEW"
|
||
TO_RENEW=$((TO_RENEW + 1))
|
||
elif [ "$days_left" -lt "$RENEW_DAYS" ]; then
|
||
action="RENEW"
|
||
TO_RENEW=$((TO_RENEW + 1))
|
||
else
|
||
TO_KEEP=$((TO_KEEP + 1))
|
||
fi
|
||
else
|
||
action="RENEW?"
|
||
TO_RENEW=$((TO_RENEW + 1))
|
||
fi
|
||
|
||
printf "%-6s %-45s %-8s %-12s %-22s " "$cid" "$domains" "$in_use" "${expiry_str:---}" "$days_display"
|
||
case "$action" in
|
||
RENEW|RENEW?) echo -e "${YELLOW}$action${NC}"; ;;
|
||
REMOVE) echo -e "${RED}$action${NC}"; ;;
|
||
*) echo -e "${GREEN}$action${NC}"; ;;
|
||
esac
|
||
done < <(echo "$CERTS_JSON" | jq -c '.[]' 2>/dev/null || true)
|
||
|
||
echo ""
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo "Summary (RENEW_DAYS=$RENEW_DAYS):"
|
||
echo " RENEW: In use and (expired / expiring within ${RENEW_DAYS} days / unknown expiry)"
|
||
echo " KEEP: In use and not expiring soon"
|
||
echo " REMOVE: Not assigned to any proxy host (inactive)"
|
||
echo ""
|
||
printf " ${YELLOW}RENEW:${NC} %s\n" "$TO_RENEW"
|
||
printf " ${GREEN}KEEP:${NC} %s\n" "$TO_KEEP"
|
||
printf " ${RED}REMOVE:${NC} %s\n" "$TO_REMOVE"
|
||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
echo ""
|
||
log_info "To remove inactive certs: ./scripts/cleanup-npmplus-inactive-certificates.sh true (dry run)"
|
||
log_info " ./scripts/cleanup-npmplus-inactive-certificates.sh false (delete)"
|
||
log_info "To request/renew certs: ./scripts/request-npmplus-certificates.sh (only for hosts without a cert)"
|
||
log_info " Or request renewal in NPMplus UI per proxy host (SSL tab)."
|
||
echo ""
|