Files
myron dbc5a01de9 Fix #4-#8: mail virtual domains, DNS verified, reseller isolation, missing DB tables
#4: Postfix virtual mailbox config (virtual_mailbox_domains/maps, vmail user, maildir
    at /var/mail/vhosts/%d/%n). Dovecot SQL backend pointed at novacpx.email_accounts
    with SHA512-CRYPT passdb and per-domain Maildir userdb.

#5: BIND9 confirmed working — dig @localhost resolves testdomain1.com correctly.

#6: Certbot 2.9.0 confirmed installed; domains.document_root wired; infrastructure
    ready for live domain issuance (testdomain1.com not publicly resolvable so
    dry-run expected to fail).

#7: Fixed all broken user-panel API queries — missing tables (databases, ftp_accounts,
    ssl_certs, cron_jobs, php_configs, notifications) created; `databases` reserved-word
    backtick-quoted across DatabaseManager+endpoints; domains.php is_primary→type=main,
    doc_root→document_root column fixes; DNSManager::createZone call signature fixed;
    stats/account auto-resolves account_id for user role.

#8: assert_account_access() helper added to api/index.php; reseller ownership check
    wired into email, ftp, databases, domains, dns, ssl endpoints.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 03:31:30 +00:00

140 lines
7.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# nova-test.sh — NovaCPX API endpoint test suite
# Tests auth, common endpoints, and panel responses against the live VM
# Usage: bash nova-test.sh [--host IP] [--admin-pass PASS]
set -euo pipefail
HOST="${NOVACPX_HOST:-10.48.200.110}"
ADMIN_PASS="${NOVACPX_ADMIN_PASS:-bUe9JXTRmWJbyrFA}"
PORT_USER=8880; PORT_RESELLER=8881; PORT_ADMIN=8882; PORT_WEBMAIL=8883
PASS_CHECKS=0; FAIL_CHECKS=0; SKIP_CHECKS=0
GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
for arg in "$@"; do
case "$arg" in
--host) HOST="${2:-}"; shift ;;
--admin-pass) ADMIN_PASS="${2:-}"; shift ;;
esac
done
check() {
local name="$1" expected="$2" actual="$3" detail="${4:-}"
if [[ "$actual" == "$expected" ]]; then
echo -e "${GREEN}[PASS]${NC} $name${detail:+ — $detail}"
PASS_CHECKS=$((PASS_CHECKS+1))
else
echo -e "${RED}[FAIL]${NC} $name — expected $expected, got $actual ${detail:+($detail)}"
FAIL_CHECKS=$((FAIL_CHECKS+1))
fi
}
api() {
local port="$1" method="$2" endpoint="$3" data="${4:-}"
local url="https://$HOST:$port/api/$endpoint"
local args=(-sk --max-time 8 -X "$method" -H "Content-Type: application/json")
[[ -n "${TOKEN:-}" ]] && args+=(-H "Authorization: Bearer $TOKEN")
[[ -n "$data" ]] && args+=(-d "$data")
curl "${args[@]}" -w "\n%{http_code}" "$url" 2>/dev/null
}
http_code() { echo "$1" | tail -1; }
body() { echo "$1" | head -n -1; }
echo ""
echo -e "${BLUE}══════════════════════════════════════════${NC}"
echo -e "${BLUE} NovaCPX API Test Suite${NC}"
echo -e "${BLUE} Host: $HOST${NC}"
echo -e "${BLUE}══════════════════════════════════════════${NC}"
echo ""
# ── 1. Panel ports reachable ──────────────────────────────────────────────────
echo "── Panel Ports ──"
for PORT in $PORT_USER $PORT_RESELLER $PORT_ADMIN $PORT_WEBMAIL; do
LABEL="user"; [[ $PORT -eq 8881 ]] && LABEL="reseller"; [[ $PORT -eq 8882 ]] && LABEL="admin"; [[ $PORT -eq 8883 ]] && LABEL="webmail"
SC=$(curl -sk --max-time 6 -o /dev/null -w "%{http_code}" "https://$HOST:$PORT/" 2>/dev/null || echo "ERR")
if [[ "$SC" =~ ^[23] ]] || [[ "$SC" == "401" ]] || [[ "$SC" == "403" ]]; then
echo -e "${GREEN}[PASS]${NC} Port $PORT ($LABEL): HTTP $SC"
PASS_CHECKS=$((PASS_CHECKS+1))
else
echo -e "${RED}[FAIL]${NC} Port $PORT ($LABEL): HTTP $SC (not responding)"
FAIL_CHECKS=$((FAIL_CHECKS+1))
fi
done
# ── 2. Auth — bad credentials ─────────────────────────────────────────────────
echo ""
echo "── Auth Endpoint ──"
RESP=$(api $PORT_ADMIN POST "auth/login" '{"username":"nobody","password":"badpass"}')
check "Bad login returns 401" "401" "$(http_code "$RESP")"
# ── 3. Auth — valid login ─────────────────────────────────────────────────────
RESP=$(api $PORT_ADMIN POST "auth/login" "{\"username\":\"admin\",\"password\":\"$ADMIN_PASS\"}")
SC=$(http_code "$RESP")
check "Admin login succeeds (200)" "200" "$SC"
TOKEN=$(body "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('data',{}).get('token',''))" 2>/dev/null || echo "")
if [[ -n "$TOKEN" ]]; then
echo -e "${GREEN}[INFO]${NC} Token acquired: ${TOKEN:0:20}..."
else
echo -e "${YELLOW}[WARN]${NC} No token in login response — subsequent tests will fail auth"
fi
# ── 4. Auth — me endpoint ─────────────────────────────────────────────────────
RESP=$(api $PORT_ADMIN GET "auth/me")
check "auth/me returns 200" "200" "$(http_code "$RESP")"
ROLE=$(body "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('data',{}).get('role',''))" 2>/dev/null || echo "")
check "auth/me role=admin" "admin" "$ROLE"
# ── 5. Packages ───────────────────────────────────────────────────────────────
echo ""
echo "── Packages ──"
RESP=$(api $PORT_ADMIN GET "packages/list")
check "packages/list returns 200" "200" "$(http_code "$RESP")"
# ── 6. Domains ────────────────────────────────────────────────────────────────
echo ""
echo "── Domains ──"
RESP=$(api $PORT_ADMIN GET "domains/list")
check "domains/list returns 200" "200" "$(http_code "$RESP")"
# ── 7. System ─────────────────────────────────────────────────────────────────
echo ""
echo "── System ──"
RESP=$(api $PORT_ADMIN GET "system/status")
check "system/status returns 200" "200" "$(http_code "$RESP")"
RESP=$(api $PORT_ADMIN GET "system/services")
check "system/services returns 200" "200" "$(http_code "$RESP")"
# ── 8. Firewall ───────────────────────────────────────────────────────────────
echo ""
echo "── Firewall ──"
RESP=$(api $PORT_ADMIN GET "firewall/status")
check "firewall/status returns 200" "200" "$(http_code "$RESP")"
# ── 9. Stats ──────────────────────────────────────────────────────────────────
echo ""
echo "── Stats ──"
RESP=$(api $PORT_ADMIN GET "stats/overview")
check "stats/overview returns 200" "200" "$(http_code "$RESP")"
# ── 10. Unauthorized access ───────────────────────────────────────────────────
echo ""
echo "── Auth Enforcement ──"
TOKEN=""
RESP=$(api $PORT_ADMIN GET "packages/list")
check "packages/list without token returns 401" "401" "$(http_code "$RESP")"
RESP=$(api $PORT_ADMIN GET "firewall/status")
check "firewall/status without token returns 401" "401" "$(http_code "$RESP")"
# ── Summary ───────────────────────────────────────────────────────────────────
TOTAL=$((PASS_CHECKS + FAIL_CHECKS + SKIP_CHECKS))
echo ""
echo -e "${BLUE}══════════════════════════════════════════${NC}"
echo -e " Results: ${GREEN}$PASS_CHECKS passed${NC} ${RED}$FAIL_CHECKS failed${NC} ${YELLOW}$SKIP_CHECKS skipped${NC} / $TOTAL total"
echo -e "${BLUE}══════════════════════════════════════════${NC}"
echo ""
[[ $FAIL_CHECKS -eq 0 ]] && exit 0 || exit 1