mirror of
https://github.com/myronblair/novacpx
synced 2026-06-30 17:50:41 -05:00
dbc5a01de9
#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>
140 lines
7.2 KiB
Bash
Executable File
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
|