#!/usr/bin/env bash # Export NPMplus configuration (proxy hosts and certificates) # Verifies configuration matches documentation 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)" EVIDENCE_DIR="$PROJECT_ROOT/docs/04-configuration/verification-evidence" # Colors 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"; } cd "$PROJECT_ROOT" # Source .env if [ -f .env ]; then set +euo pipefail source .env 2>/dev/null || true set -euo pipefail fi NPM_URL="${NPM_URL:-https://${IP_NPMPLUS}:81}" NPM_EMAIL="${NPM_EMAIL:-nsatoshi2007@hotmail.com}" NPM_PASSWORD="${NPM_PASSWORD:-}" NPMPLUS_VMID="${NPMPLUS_VMID:-${NPM_VMID:-10233}}" NPMPLUS_HOST="${NPMPLUS_HOST:-${NPM_PROXMOX_HOST:-${PROXMOX_HOST:-192.168.11.11}}}" TIMESTAMP=$(date +%Y%m%d_%H%M%S) OUTPUT_DIR="$EVIDENCE_DIR/npmplus-verification-$TIMESTAMP" mkdir -p "$OUTPUT_DIR" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "🔍 NPMplus Configuration Verification & Export" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" # Authenticate to NPMplus log_info "Authenticating to NPMplus..." if [ -z "$NPM_PASSWORD" ]; then log_warn "NPM_PASSWORD not found in .env - skipping NPMplus verification" log_info "To enable: add NPM_PASSWORD and NPM_EMAIL to .env (see config/ip-addresses.conf)" log_success "Skipped (optional)" exit 0 fi TOKEN_RESPONSE=$(curl -s -k -X POST "$NPM_URL/api/tokens" \ -H "Content-Type: application/json" \ -d "{\"identity\":\"$NPM_EMAIL\",\"secret\":\"$NPM_PASSWORD\"}") TOKEN=$(echo "$TOKEN_RESPONSE" | jq -r '.token // empty' 2>/dev/null || echo "") if [ -z "$TOKEN" ] || [ "$TOKEN" = "null" ]; then ERROR_MSG=$(echo "$TOKEN_RESPONSE" | jq -r '.error.message // "Unknown error"' 2>/dev/null || echo "$TOKEN_RESPONSE") log_error "Authentication failed: $ERROR_MSG" exit 1 fi log_success "Authentication successful" echo "" # Verify container status log_info "Verifying NPMplus container status..." CONTAINER_STATUS=$(ssh -o StrictHostKeyChecking=no root@"$NPMPLUS_HOST" "pct status $NPMPLUS_VMID 2>/dev/null || echo 'not-found'" 2>/dev/null || echo "unknown") if echo "$CONTAINER_STATUS" | grep -q "running"; then log_success "Container VMID $NPMPLUS_VMID is running" elif echo "$CONTAINER_STATUS" | grep -q "stopped"; then log_warn "Container VMID $NPMPLUS_VMID is stopped" else log_warn "Could not determine container status" fi # Get container IP CONTAINER_IP=$(ssh -o StrictHostKeyChecking=no root@"$NPMPLUS_HOST" "pct config $NPMPLUS_VMID 2>/dev/null | grep -E '^ip[0-9]+' | head -1 | awk -F'=' '{print \$2}' | awk '{print \$1}'" 2>/dev/null || echo "") if [ -n "$CONTAINER_IP" ]; then log_info "Container IP: $CONTAINER_IP" fi echo "" # Export proxy hosts log_info "Exporting proxy hosts..." PROXY_HOSTS_RESPONSE=$(curl -s -k -X GET "$NPM_URL/api/nginx/proxy-hosts" \ -H "Authorization: Bearer $TOKEN") if [ $? -ne 0 ]; then log_error "Failed to fetch proxy hosts" exit 1 fi PROXY_HOSTS=$(echo "$PROXY_HOSTS_RESPONSE" | jq '.' 2>/dev/null || echo "[]") echo "$PROXY_HOSTS" > "$OUTPUT_DIR/proxy_hosts.json" PROXY_HOST_COUNT=$(echo "$PROXY_HOSTS" | jq '. | length' 2>/dev/null || echo "0") log_success "Exported $PROXY_HOST_COUNT proxy hosts" # Export certificates log_info "Exporting SSL certificates..." CERTIFICATES_RESPONSE=$(curl -s -k -X GET "$NPM_URL/api/nginx/certificates" \ -H "Authorization: Bearer $TOKEN") if [ $? -ne 0 ]; then log_error "Failed to fetch certificates" exit 1 fi CERTIFICATES=$(echo "$CERTIFICATES_RESPONSE" | jq '.' 2>/dev/null || echo "[]") echo "$CERTIFICATES" > "$OUTPUT_DIR/certificates.json" CERT_COUNT=$(echo "$CERTIFICATES" | jq '. | length' 2>/dev/null || echo "0") log_success "Exported $CERT_COUNT certificates" # Verify certificate files on disk log_info "" log_info "Verifying certificate files on disk..." VERIFIED_CERTS=0 MISSING_CERTS=0 CERT_VERIFICATION=() while IFS= read -r cert; do cert_id=$(echo "$cert" | jq -r '.id' 2>/dev/null || echo "") cert_name=$(echo "$cert" | jq -r '.nice_name // "cert-'$cert_id'"' 2>/dev/null || echo "") domains=$(echo "$cert" | jq -r '.domain_names | join(", ")' 2>/dev/null || echo "") if [ -z "$cert_id" ] || [ "$cert_id" = "null" ]; then continue fi # Check certificate files in container CERT_DIR="/data/tls/certbot/live/npm-$cert_id" fullchain_exists=$(ssh -o StrictHostKeyChecking=no root@"$NPMPLUS_HOST" \ "pct exec $NPMPLUS_VMID -- test -f $CERT_DIR/fullchain.pem && echo 'yes' || echo 'no'" 2>/dev/null || echo "unknown") privkey_exists=$(ssh -o StrictHostKeyChecking=no root@"$NPMPLUS_HOST" \ "pct exec $NPMPLUS_VMID -- test -f $CERT_DIR/privkey.pem && echo 'yes' || echo 'no'" 2>/dev/null || echo "unknown") # Get certificate expiration from file if it exists expires_from_file="" if [ "$fullchain_exists" = "yes" ]; then expires_from_file=$(ssh -o StrictHostKeyChecking=no root@"$NPMPLUS_HOST" \ "pct exec $NPMPLUS_VMID -- openssl x509 -in $CERT_DIR/fullchain.pem -noout -enddate 2>/dev/null | cut -d= -f2" 2>/dev/null || echo "") fi if [ "$fullchain_exists" = "yes" ] && [ "$privkey_exists" = "yes" ]; then VERIFIED_CERTS=$((VERIFIED_CERTS + 1)) log_success "Cert ID $cert_id ($cert_name): Files exist" if [ -n "$expires_from_file" ]; then log_info " Expires: $expires_from_file" fi else MISSING_CERTS=$((MISSING_CERTS + 1)) log_warn "Cert ID $cert_id ($cert_name): Files missing" fi CERT_VERIFICATION+=("{\"cert_id\":$cert_id,\"cert_name\":\"$cert_name\",\"domains\":\"$domains\",\"fullchain_exists\":\"$fullchain_exists\",\"privkey_exists\":\"$privkey_exists\",\"expires_from_file\":\"$expires_from_file\"}") done < <(echo "$CERTIFICATES" | jq -c '.[]' 2>/dev/null || true) # Write certificate verification results echo "${CERT_VERIFICATION[@]}" | jq -s '.' > "$OUTPUT_DIR/certificate_verification.json" # Generate report REPORT_FILE="$OUTPUT_DIR/verification_report.md" cat > "$REPORT_FILE" </dev/null || echo "") cert_name=$(echo "$cert_ver" | jq -r '.cert_name' 2>/dev/null || echo "") domains=$(echo "$cert_ver" | jq -r '.domains' 2>/dev/null || echo "") fullchain_exists=$(echo "$cert_ver" | jq -r '.fullchain_exists' 2>/dev/null || echo "") privkey_exists=$(echo "$cert_ver" | jq -r '.privkey_exists' 2>/dev/null || echo "") expires=$(echo "$cert_ver" | jq -r '.expires_from_file' 2>/dev/null || echo "") status_icon="❌" if [ "$fullchain_exists" = "yes" ] && [ "$privkey_exists" = "yes" ]; then status_icon="✅" fi echo "" >> "$REPORT_FILE" echo "### Cert ID $cert_id: $cert_name" >> "$REPORT_FILE" echo "- Domains: $domains" >> "$REPORT_FILE" echo "- Fullchain: $fullchain_exists $status_icon" >> "$REPORT_FILE" echo "- Privkey: $privkey_exists $status_icon" >> "$REPORT_FILE" if [ -n "$expires" ]; then echo "- Expires: $expires" >> "$REPORT_FILE" fi done cat >> "$REPORT_FILE" <