chore: full project audit cleanup, dead code removal, and documentation update

Dead code removed:
- Module.php: remove assignBackupPlan(), getSelfServiceCurrencies() (no callers)
- Cache.php: remove forgetPattern() (no callers, no-op on filesystem)
- module.js: remove vfLoadSelfServiceReport() (no UI trigger)

Stale files removed:
- .releaserc.json (orphaned, conflicts with tag-based workflow)
- .github/workflows/api-sync-check.yml (baseline never populated)
- docs/openapi-baseline.yaml (placeholder stub)
- scripts/generate-endpoint-doc.sh (broken grep patterns)

Security fixes:
- AdminHTML: cast $serverId to (int), cast $serviceId to (int)
- admin.php: add explicit break after every output() call, sanitize error msgs

File hygiene:
- Move modify.sql into modules/servers/VirtFusionDirect/ (matches README docs)
- Fix CHANGELOG.md: remove duplicate 1.0.0 entry, clean up mixed git host URLs

Documentation:
- CLAUDE.md: full rewrite with current architecture, Cache class, development
  rules (try/catch, ownership validation, HTTP methods, caching policy)
- README.md: remove stale IPv4 removal references, add new features (traffic,
  backups, VNC toggle, password reset, OS gallery, copy buttons), add Cache.php
  to file structure, remove "Primary IPv4 Protection" known issue

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Prophet731
2026-03-19 14:28:58 -05:00
parent 3ca9eb60c3
commit 1ab2ef42a5
13 changed files with 125 additions and 346 deletions

View File

@@ -1,65 +0,0 @@
name: VirtFusion API Change Detection
on:
schedule:
- cron: '0 9 * * 1' # Monday 9am UTC
workflow_dispatch:
jobs:
check-api:
runs-on: ubuntu-latest
permissions:
contents: write
issues: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Download current API spec
run: curl -sSL -o /tmp/openapi-current.yaml https://docs.virtfusion.com/api/openapi.yaml
- name: Compare with baseline
id: diff
run: |
if [ ! -f docs/openapi-baseline.yaml ]; then
echo "No baseline found — creating initial baseline"
cp /tmp/openapi-current.yaml docs/openapi-baseline.yaml
echo "changed=initial" >> "$GITHUB_OUTPUT"
elif ! diff -q docs/openapi-baseline.yaml /tmp/openapi-current.yaml > /dev/null 2>&1; then
echo "API spec has changed"
diff docs/openapi-baseline.yaml /tmp/openapi-current.yaml > /tmp/api-diff.txt || true
echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "No changes detected"
echo "changed=false" >> "$GITHUB_OUTPUT"
fi
- name: Create issue on change
if: steps.diff.outputs.changed == 'true'
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const diff = fs.readFileSync('/tmp/api-diff.txt', 'utf8').substring(0, 60000);
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `VirtFusion API spec changed (${new Date().toISOString().split('T')[0]})`,
body: `The VirtFusion OpenAPI spec has been updated.\n\n<details><summary>Diff</summary>\n\n\`\`\`diff\n${diff}\n\`\`\`\n</details>\n\nReview the changes and update the module if needed.`,
labels: ['api-sync']
});
- name: Update baseline and create PR
if: steps.diff.outputs.changed == 'true' || steps.diff.outputs.changed == 'initial'
run: |
cp /tmp/openapi-current.yaml docs/openapi-baseline.yaml
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
BRANCH="api-sync/$(date +%Y-%m-%d)"
git checkout -b "$BRANCH"
git add docs/openapi-baseline.yaml
git commit -m "chore: update VirtFusion API baseline spec"
git push origin "$BRANCH"
gh pr create --title "chore: update VirtFusion API baseline" --body "Automated update of the VirtFusion OpenAPI baseline spec." --base main
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,13 +0,0 @@
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/changelog", { "changelogFile": "CHANGELOG.md" }],
"@semantic-release/github",
["@semantic-release/git", {
"assets": ["CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}]
]
}

View File

@@ -1,42 +1,39 @@
# 1.0.0 (2026-03-19)
### Bug Fixes
* add null/false guards, proper error handling, and VNC popup fix ([49fdd9e](https://git.ezscale.cloud/EZSCALE/virtfusion-whmcs-module/commit/49fdd9e49ba87bfb4b72dd741e15f790c1050033))
* OS gallery accordion auto-collapses other sections when one opens ([a9565ff](https://git.ezscale.cloud/EZSCALE/virtfusion-whmcs-module/commit/a9565ff6f920ab480a9298c055b8f4581786f3a4))
* OS gallery accordion layout and remove broken remote icon fetching ([9cd737c](https://git.ezscale.cloud/EZSCALE/virtfusion-whmcs-module/commit/9cd737c5d5d26587bea8fa40bf75f5e25544ff18))
* TestConnection for unsaved servers, traffic display, and cache-busting ([e8d2eb0](https://git.ezscale.cloud/EZSCALE/virtfusion-whmcs-module/commit/e8d2eb0aa1f173f13bb0b8d7dfca0acebb821ac7))
* XSS escaping, null guards, JS bug fixes, and documentation updates ([6c7cdc6](https://git.ezscale.cloud/EZSCALE/virtfusion-whmcs-module/commit/6c7cdc6421678390746adcee4877a7ade8f2a061))
### Features
* add client-side SSH Ed25519 key generator on order page ([209e01d](https://git.ezscale.cloud/EZSCALE/virtfusion-whmcs-module/commit/209e01deb6832dce76a307410fbab28b1e420093))
* add VNC check, SSH key paste, resources panel, sliders, and self-service billing ([1e471af](https://git.ezscale.cloud/EZSCALE/virtfusion-whmcs-module/commit/1e471affd0ae9a68358afa5704523bce9bb413d0))
* major enhancement — OS gallery, server rename, traffic chart, backups, VNC toggle, password reset, Redis caching, UX improvements ([90a97c4](https://git.ezscale.cloud/EZSCALE/virtfusion-whmcs-module/commit/90a97c4afb61a179eda40e23b97637dd90507b55))
* streamline network panel, conditional self-service, remove IP add endpoints ([e73e85c](https://git.ezscale.cloud/EZSCALE/virtfusion-whmcs-module/commit/e73e85c5a9faa79b50e4949328c1d2a3cbc49ddf))
# 1.0.0 (2026-02-07)
### Bug Fixes
* add null/false guards, proper error handling, and VNC popup fix ([49fdd9e](https://github.com/EZSCALE/virtfusion-whmcs-module/commit/49fdd9e49ba87bfb4b72dd741e15f790c1050033))
* TestConnection for unsaved servers, traffic display, and cache-busting ([e8d2eb0](https://github.com/EZSCALE/virtfusion-whmcs-module/commit/e8d2eb0aa1f173f13bb0b8d7dfca0acebb821ac7))
* XSS escaping, null guards, JS bug fixes, and documentation updates ([6c7cdc6](https://github.com/EZSCALE/virtfusion-whmcs-module/commit/6c7cdc6421678390746adcee4877a7ade8f2a061))
### Features
* add client-side SSH Ed25519 key generator on order page ([209e01d](https://github.com/EZSCALE/virtfusion-whmcs-module/commit/209e01deb6832dce76a307410fbab28b1e420093))
* add VNC check, SSH key paste, resources panel, sliders, and self-service billing ([1e471af](https://github.com/EZSCALE/virtfusion-whmcs-module/commit/1e471affd0ae9a68358afa5704523bce9bb413d0))
* streamline network panel, conditional self-service, remove IP add endpoints ([e73e85c](https://github.com/EZSCALE/virtfusion-whmcs-module/commit/e73e85c5a9faa79b50e4949328c1d2a3cbc49ddf))
# Changelog # Changelog
All notable changes to the VirtFusion Direct Provisioning Module for WHMCS. All notable changes to the VirtFusion Direct Provisioning Module for WHMCS.
## [1.0.0] - 2026-03-19
### Features
- OS template tile gallery with accordion categories, brand icons, and search
- Inline server rename with friendly name generator
- Traffic statistics canvas chart in resources panel
- Backup listing timeline in manage panel
- VNC enable/disable toggle with connection details and password copy
- Server root password reset with auto-clipboard copy
- Redis-backed API response caching with filesystem fallback
- Skeleton loading, action cooldowns, progress indicators
- Copy-to-clipboard buttons for IP addresses
- Client-side SSH Ed25519 key generator on checkout page
- VNC console support, resources panel, self-service billing
- Configurable option sliders on checkout page
### Bug Fixes
- XSS escaping, null guards, and proper error handling
- All state-mutating operations use POST instead of GET
- Explicit break after all output() calls in client.php
- Server-side regex validation on rename endpoint
- Error messages sanitized (no raw API errors exposed to clients)
### Removed
- Client IP removal capability (IPs managed by VirtFusion)
- IP add buttons (managed by VirtFusion during provisioning)
- Firewall panel (non-functional; managed in VirtFusion admin)
### Infrastructure
- Tag-based release workflow (compatible with Gitea and GitHub)
- Codebase consolidation: resolveServiceContext(), groupOsTemplates(), vfUrl(), vfShowAlert()
## [0.0.18] - 2025-10-01 ## [0.0.18] - 2025-10-01
### Changed ### Changed
@@ -93,6 +90,6 @@ All notable changes to the VirtFusion Direct Provisioning Module for WHMCS.
- Admin services tab with server ID management - Admin services tab with server ID management
- Package change (upgrade/downgrade) support - Package change (upgrade/downgrade) support
- Configurable option mapping for dynamic resource allocation - Configurable option mapping for dynamic resource allocation
- GitHub Actions CI/CD with semantic-release - GitHub Actions CI/CD
- Security policy (SECURITY.md) - Security policy (SECURITY.md)
- License (GPL v3) - License (GPL v3)

View File

@@ -15,12 +15,27 @@ There is no automated test suite, linter, or build step. Testing is manual:
- **Module logging:** WHMCS Admin → Utilities → Logs → Module Log captures all API calls and responses - **Module logging:** WHMCS Admin → Utilities → Logs → Module Log captures all API calls and responses
- **Server object viewer:** Admin services tab shows full JSON response from VirtFusion API - **Server object viewer:** Admin services tab shows full JSON response from VirtFusion API
## Development Rules
- **Error handling:** Always use try...catch blocks around API calls, database operations, and any code that may throw exceptions. Never let exceptions bubble up unhandled to the user. Log caught exceptions via `Log::insert()`.
- **Ownership validation:** Every client-facing action MUST verify service ownership via `validateUserOwnsService()` before performing any operation. Server IDs must be cross-referenced against the authenticated client to prevent cross-customer data access.
- **Security:** All input must be validated server-side. Never trust client-side validation alone. Cast IDs to `(int)`, validate strings with regex, escape output with `htmlspecialchars()`.
- **Control flow:** Every `$vf->output()` call in switch cases must be followed by `break`. Do not rely on `exit()` inside `output()` for flow control.
- **HTTP methods:** Read-only operations use GET. State-mutating operations (power, rebuild, rename, password reset, credit, VNC toggle) use POST with data in the request body.
- **Caching:** Use the `Cache` class for slow-changing API responses. Never cache real-time data (server status, VNC sessions, login tokens) or mutation responses.
## Release Process ## Release Process
Releases are automated via GitHub Actions using semantic-release on pushes to `main`. Use **conventional commits**: Releases are triggered by pushing a git tag:
- `fix:` → patch release ```bash
- `feat:` → minor release git tag v1.1.0
- `BREAKING CHANGE:` in commit body → major release git push origin v1.1.0
```
The `publish-release.yml` workflow creates a GitHub/Gitea release with auto-generated notes from the commit log. Use **conventional commits** for clear changelogs:
- `fix:` → patch-level change
- `feat:` → feature addition
- `refactor:` → code improvement without behavior change
## Architecture ## Architecture
@@ -31,38 +46,39 @@ Releases are automated via GitHub Actions using semantic-release on pushes to `m
| File | Purpose | | File | Purpose |
|------|---------| |------|---------|
| `VirtFusionDirect.php` | WHMCS module interface — non-namespaced functions (`VirtFusionDirect_CreateAccount()`, etc.) that delegate to library classes | | `VirtFusionDirect.php` | WHMCS module interface — non-namespaced functions (`VirtFusionDirect_CreateAccount()`, etc.) that delegate to library classes |
| `client.php` | Client-facing AJAX API — authenticated by WHMCS session + service ownership validation | | `client.php` | Client-facing AJAX API — authenticated by WHMCS session + service ownership validation. POST for mutations, GET for reads. |
| `admin.php` | Admin-facing AJAX API — requires WHMCS admin authentication | | `admin.php` | Admin-facing AJAX API — requires WHMCS admin authentication |
| `hooks.php` | WHMCS hooks — checkout validation (OS selection), dynamic dropdown/slider injection, SSH key paste | | `hooks.php` | WHMCS hooks — checkout validation (OS selection), OS gallery + SSH key UI injection, slider UI for configurable options |
### Core Classes (in `lib/`) ### Core Classes (in `lib/`)
| Class | Role | | Class | Role |
|-------|------| |-------|------|
| `Module` | Base class with API integration, auth checks, power/network/VNC/backup/resource/self-service methods. All client/admin actions route through here. | | `Module` | Base class with API integration, auth checks, and all feature methods (power, network, VNC, backup, resource, self-service, traffic, rename, password reset). Contains `resolveServiceContext()` for DRY service lookups and `groupOsTemplates()` for shared OS category logic. |
| `ModuleFunctions` | Extends `Module`. Service lifecycle: create, suspend, unsuspend, terminate, change package, usage updates, client area rendering. | | `ModuleFunctions` | Extends `Module`. Service lifecycle: create, suspend, unsuspend, terminate, change package, usage updates, client area rendering. |
| `ConfigureService` | Extends `Module`. Order-time operations: package discovery, OS template fetching, server build initialization, SSH key retrieval and creation. | | `ConfigureService` | Extends `Module`. Order-time operations: package discovery, OS template fetching, server build initialization, SSH key retrieval and creation. |
| `Database` | Static methods for `mod_virtfusion_direct` table operations and WHMCS DB queries. Auto-creates/migrates schema on first use. | | `Database` | Static methods for `mod_virtfusion_direct` table operations and WHMCS DB queries. Auto-creates/migrates schema on first use. |
| `Curl` | HTTP client wrapper with Bearer token auth, SSL verification, 30s timeout. Methods: `get`, `post`, `put`, `patch`, `delete`. | | `Curl` | HTTP client wrapper with Bearer token auth, SSL verification, 30s timeout. Methods: `get`, `post`, `put`, `patch`, `delete`. Single-use — each instance makes one request. |
| `Cache` | Two-tier caching: Redis (if `ext-redis` available) with atomic filesystem fallback. TTLs: OS templates 10min, traffic/backups 2min, packages 10min. |
| `ServerResource` | Transforms VirtFusion API response into flat key-value format for Smarty templates. | | `ServerResource` | Transforms VirtFusion API response into flat key-value format for Smarty templates. |
| `AdminHTML` | Static methods generating admin services tab HTML (server ID editor, JSON viewer, action buttons). | | `AdminHTML` | Static methods generating admin services tab HTML (server ID editor, JSON viewer, action buttons). |
| `Log` | Thin wrapper around WHMCS module logging. | | `Log` | Thin wrapper around WHMCS module logging. |
### Class Hierarchy ### Class Hierarchy
`ModuleFunctions` and `ConfigureService` both extend `Module`. Most business logic lives in `Module` — it handles API calls, auth, validation, and all feature-specific operations (power, network, VNC, backup, resource modification). `ModuleFunctions` orchestrates the WHMCS service lifecycle (provisioning flow, suspension, termination). `ModuleFunctions` and `ConfigureService` both extend `Module`. Most business logic lives in `Module` — it handles API calls, auth, validation, and all feature-specific operations. The `resolveServiceContext()` method provides a standardized way to look up service → WHMCS service → control panel → curl client in a single call, eliminating boilerplate across all API methods.
### Client-Side ### Client-Side
- **`templates/overview.tpl`** — Smarty template for client area (server info, power, network, rebuild, resources, VNC, self-service billing, billing overview) - **`templates/overview.tpl`** — Smarty template for client area (server info, power, network, rebuild with OS gallery, resources with traffic chart, VNC toggle, self-service billing, billing overview, backups timeline, server rename, password reset)
- **`templates/js/module.js`** — Vanilla JS (1000+ lines) handling AJAX calls to `client.php`, DOM updates, status badges, power actions, all management UIs - **`templates/js/module.js`** — Vanilla JS + jQuery handling AJAX calls, DOM updates, status badges, power actions, all management UIs. Key helpers: `vfUrl()` (URL builder), `vfShowAlert()` (alert display), `vfRenderOsGallery()` (accordion gallery), `vfDrawTrafficChart()` (canvas chart)
- **`templates/js/keygen.js`** — Client-side SSH Ed25519 key generator using Web Crypto API (loaded on checkout page) - **`templates/js/keygen.js`** — Client-side SSH Ed25519 key generator using Web Crypto API (loaded on checkout page)
- **`templates/css/module.css`** — Cross-theme styles with Bootstrap 3/4/5 dual class support (`panel card`, `panel-body card-body`) - **`templates/css/module.css`** — Cross-theme styles with Bootstrap 3/4/5 dual class support (`panel card`, `panel-body card-body`)
### Removed Features ### Removed Features
- **Firewall** — Removed (non-functional; rulesets must be created in VirtFusion admin panel) - **Firewall** — Removed (non-functional; rulesets must be created in VirtFusion admin panel)
- **IP add buttons** — Removed (`addIPv4`, `addIPv6` endpoints and UI); IPs are managed by VirtFusion during provisioning - **IP add/remove buttons** — Removed; IPs are managed by VirtFusion during provisioning
- **Upgrade/Downgrade link** — Removed from resources panel - **Upgrade/Downgrade link** — Removed from resources panel
### Data Flow: Server Creation ### Data Flow: Server Creation
@@ -81,12 +97,13 @@ Custom option names can be mapped in `config/ConfigOptionMapping.php` (copy from
## Security Patterns ## Security Patterns
- All PHP files start with `if (!defined("WHMCS")) die()` to prevent direct access - All PHP files start with `if (!defined("WHMCS")) die()` to prevent direct access (except entry points using `init.php`)
- Client endpoints validate WHMCS session AND service ownership before any operation - Client endpoints validate WHMCS session AND service ownership before any operation
- API tokens stored encrypted in WHMCS server password field (decrypted via `localAPI('DecryptPassword')`) - API tokens stored encrypted in WHMCS server password field (decrypted via `localAPI('DecryptPassword')`)
- Input validation: type casting, regex filtering, `filter_var()` for IP addresses - Input validation: type casting (`(int)`), regex filtering, `filter_var()` for IP addresses
- Output escaping: `htmlspecialchars()` in Smarty, `encodeURIComponent()` / `.text()` in JS - Output escaping: `htmlspecialchars()` in PHP, `$('<span>').text()` in jQuery, `{escape:'htmlall'}` in Smarty
- SSL verification enabled on all API calls (`CURLOPT_SSL_VERIFYPEER` + `CURLOPT_SSL_VERIFYHOST = 2`) - SSL verification enabled on all API calls (`CURLOPT_SSL_VERIFYPEER` + `CURLOPT_SSL_VERIFYHOST = 2`)
- Server rename validated both client-side and server-side with RFC 1123 regex
## VirtFusion API Compatibility ## VirtFusion API Compatibility
@@ -95,6 +112,7 @@ Custom option names can be mapped in `config/ConfigOptionMapping.php` (copy from
- **VNC console:** v6.1.0+ - **VNC console:** v6.1.0+
- **Resource modification:** v6.2.0+ - **Resource modification:** v6.2.0+
- **Self-service billing:** Requires self-service feature enabled in VirtFusion - **Self-service billing:** Requires self-service feature enabled in VirtFusion
- **OS icon path:** `{baseUrl}/img/logo/{icon_filename}` (public, no auth required)
## Product Config Options ## Product Config Options
@@ -111,4 +129,5 @@ Custom option names can be mapped in `config/ConfigOptionMapping.php` (copy from
- WHMCS 8.x+ (tested 8.08.10) - WHMCS 8.x+ (tested 8.08.10)
- PHP 8.0+ with cURL extension - PHP 8.0+ with cURL extension
- Redis extension optional (improves caching performance, falls back to filesystem)
- All WHMCS themes supported (Six, Twenty-One, Lagom, custom) via Bootstrap 3/4/5 dual classes - All WHMCS themes supported (Six, Twenty-One, Lagom, custom) via Bootstrap 3/4/5 dual classes

View File

@@ -62,7 +62,7 @@ You also need a VirtFusion API token with the following permissions:
- **Control Panel SSO** - One-click login to VirtFusion panel - **Control Panel SSO** - One-click login to VirtFusion panel
- **Server Rebuild** - Reinstall with any available OS template - **Server Rebuild** - Reinstall with any available OS template
- **Password Reset** - Reset VirtFusion panel login credentials - **Password Reset** - Reset VirtFusion panel login credentials
- **Network Management** - View and remove IPv4 addresses; view IPv6 subnets - **Network Management** - View IPv4 addresses and IPv6 subnets with copy-to-clipboard
- **Resources Panel** - Current memory, CPU, storage, traffic allocation with usage bars - **Resources Panel** - Current memory, CPU, storage, traffic allocation with usage bars
- **VNC Console** - Browser-based console access (panel auto-hides when VNC is disabled on the server) - **VNC Console** - Browser-based console access (panel auto-hides when VNC is disabled on the server)
- **Self-Service Billing** - Credit balance display, usage breakdown, and credit top-up (when enabled) - **Self-Service Billing** - Credit balance display, usage breakdown, and credit top-up (when enabled)
@@ -79,7 +79,7 @@ You also need a VirtFusion API token with the following permissions:
- **Update Server Object** - Refresh cached server data from VirtFusion - **Update Server Object** - Refresh cached server data from VirtFusion
### Ordering Process ### Ordering Process
- Dynamic OS template dropdown populated from VirtFusion API - OS template tile gallery with accordion categories, search, and brand icons
- SSH key selection dropdown for users with saved keys, with option to paste a new public key - SSH key selection dropdown for users with saved keys, with option to paste a new public key
- **SSH Ed25519 key generator** — Client-side keypair generation using Web Crypto API - **SSH Ed25519 key generator** — Client-side keypair generation using Web Crypto API
- Checkout validation ensuring OS selection before order placement - Checkout validation ensuring OS selection before order placement
@@ -305,7 +305,7 @@ Four power control buttons:
### Network Management ### Network Management
- View all IPv4 addresses and IPv6 subnets assigned to the server - View all IPv4 addresses and IPv6 subnets assigned to the server
- Remove secondary IPv4 addresses (primary cannot be removed) - Copy IP addresses to clipboard with one click
### VNC Console ### VNC Console
- Opens a browser-based VNC console to the server - Opens a browser-based VNC console to the server
@@ -407,12 +407,6 @@ WHMCS automatically loads theme-specific templates when they exist. Copy the ori
| `GET` | `/media/templates/fromServerPackageSpec/{id}` | OS templates | | `GET` | `/media/templates/fromServerPackageSpec/{id}` | OS templates |
| `GET` | `/ssh_keys/user/{id}` | SSH key listing | | `GET` | `/ssh_keys/user/{id}` | SSH key listing |
### Network
| Method | Endpoint | Purpose |
|---|---|---|
| `DELETE` | `/servers/{id}/ipv4` | Remove IPv4 address |
### SSH Keys ### SSH Keys
| Method | Endpoint | Purpose | | Method | Endpoint | Purpose |
@@ -426,7 +420,10 @@ WHMCS automatically loads theme-specific templates when they exist. Copy the ori
| `GET` | `/selfService/usage/byUserExtRelationId/{id}` | Usage data by WHMCS client ID | | `GET` | `/selfService/usage/byUserExtRelationId/{id}` | Usage data by WHMCS client ID |
| `GET` | `/selfService/report/byUserExtRelationId/{id}` | Billing report by WHMCS client ID | | `GET` | `/selfService/report/byUserExtRelationId/{id}` | Billing report by WHMCS client ID |
| `POST` | `/selfService/credit/byUserExtRelationId/{id}` | Add credit by WHMCS client ID | | `POST` | `/selfService/credit/byUserExtRelationId/{id}` | Add credit by WHMCS client ID |
| `GET` | `/selfService/currencies` | Available self-service currencies | | `GET` | `/servers/{id}/traffic` | Traffic statistics |
| `GET` | `/backups/server/{id}` | Backup listing |
| `POST` | `/servers/{id}/vnc` | Toggle VNC on/off |
| `POST` | `/servers/{id}/resetPassword` | Reset server root password |
### Advanced ### Advanced
@@ -533,9 +530,7 @@ This data appears in the WHMCS client area and admin product details.
7. **Concurrent API Calls** - The module makes individual API calls for each feature panel on the client area page. If the VirtFusion API is slow, the page may take longer to fully load. All panels load asynchronously to minimize perceived delay. 7. **Concurrent API Calls** - The module makes individual API calls for each feature panel on the client area page. If the VirtFusion API is slow, the page may take longer to fully load. All panels load asynchronously to minimize perceived delay.
8. **Primary IPv4 Protection** - The first IPv4 address cannot be removed through the client area interface. This is by design to prevent users from accidentally removing their primary IP address. 8. **Self-Signed SSL Certificates** - SSL verification is enforced by default. VirtFusion panels using self-signed certificates will cause connection failures. Use a valid SSL certificate (e.g., Let's Encrypt) on your VirtFusion panel.
9. **Self-Signed SSL Certificates** - SSL verification is enforced by default. VirtFusion panels using self-signed certificates will cause connection failures. Use a valid SSL certificate (e.g., Let's Encrypt) on your VirtFusion panel.
## Security ## Security
@@ -570,6 +565,7 @@ modules/servers/VirtFusionDirect/
ModuleFunctions.php # Provisioning: create, suspend, unsuspend, terminate, change package ModuleFunctions.php # Provisioning: create, suspend, unsuspend, terminate, change package
ConfigureService.php # Order configuration: OS templates, SSH keys, server build init ConfigureService.php # Order configuration: OS templates, SSH keys, server build init
Database.php # Database operations: custom table, WHMCS table queries Database.php # Database operations: custom table, WHMCS table queries
Cache.php # Two-tier cache: Redis with filesystem fallback
Curl.php # HTTP client: GET, POST, PUT, PATCH, DELETE with SSL verification Curl.php # HTTP client: GET, POST, PUT, PATCH, DELETE with SSL verification
ServerResource.php # Data transformer: VirtFusion API response -> display format ServerResource.php # Data transformer: VirtFusion API response -> display format
AdminHTML.php # Admin interface: HTML generation for admin services tab AdminHTML.php # Admin interface: HTML generation for admin services tab

View File

@@ -1,7 +0,0 @@
# VirtFusion OpenAPI Baseline
# This file will be auto-populated by the api-sync-check workflow
# on first run. Do not edit manually.
openapi: "3.0.0"
info:
title: VirtFusion API Baseline Placeholder
version: "0.0.0"

View File

@@ -13,81 +13,71 @@ $vf->adminOnly();
switch ($vf->validateAction(true)) { switch ($vf->validateAction(true)) {
/** /**
*
* Get server information. * Get server information.
*
*/ */
case 'serverData': case 'serverData':
if ($vf->validateServiceID(true)) { $serviceID = $vf->validateServiceID(true);
/** No need to validate ownership **/ $whmcsService = Database::getWhmcsService($serviceID);
$whmcsService = Database::getWhmcsService((int)$_GET['serviceID']);
if (!$whmcsService) {
$vf->output(['success' => false, 'errors' => 'Service not found.'], true, true, 404);
}
if ($whmcsService->domainstatus == 'Pending' || $whmcsService->domainstatus == 'Terminated' || $whmcsService->domainstatus == 'Cancelled' || $whmcsService->domainstatus == 'Fraud') {
$vf->output(['success' => false, 'errors' => 'Server is not Active, Suspended or Completed. Not fetching remote data.'], true, true, 400);
}
$data = $vf->fetchServerData((int)$_GET['serviceID']);
if (!$data) {
$vf->output(['success' => false, 'errors' => 'No data returned from VirtFusion.'], true, true, 502);
}
$vf->updateWhmcsServiceParamsOnServerObject((int)$_GET['serviceID'], $data);
$vf->output(['success' => true, 'data' => (new ServerResource())->process($data)], true, true, 200);
if (!$whmcsService) {
$vf->output(['success' => false, 'errors' => 'Service not found.'], true, true, 404);
break;
} }
if (in_array($whmcsService->domainstatus, ['Pending', 'Terminated', 'Cancelled', 'Fraud'], true)) {
$vf->output(['success' => false, 'errors' => 'Server is not Active, Suspended or Completed. Not fetching remote data.'], true, true, 400);
break;
}
$data = $vf->fetchServerData($serviceID);
if (!$data) {
$vf->output(['success' => false, 'errors' => 'No data returned from VirtFusion.'], true, true, 502);
break;
}
$vf->updateWhmcsServiceParamsOnServerObject($serviceID, $data);
$vf->output(['success' => true, 'data' => (new ServerResource())->process($data)], true, true, 200);
break; break;
/** /**
*
* Impersonate server owner. * Impersonate server owner.
*
*/ */
case 'impersonateServerOwner': case 'impersonateServerOwner':
if ($vf->validateServiceID(true)) { $serviceID = $vf->validateServiceID(true);
$service = Database::getSystemService((int)$_GET['serviceID']);
if (!$service) {
$vf->output(['success' => false, 'errors' => 'Service not found'], true, true, 404);
}
$whmcsService = Database::getWhmcsService((int)$_GET['serviceID']);
if (!$whmcsService) {
$vf->output(['success' => false, 'errors' => 'WHMCS service not found'], true, true, 404);
}
$cp = $vf->getCP($whmcsService->server);
if (!$cp) {
$vf->output(['success' => false, 'errors' => 'Control server not found'], true, true, 500);
}
$request = $vf->initCurl($cp['token']);
$data = $request->get($cp['url'] . '/users/' . $whmcsService->userid . '/byExtRelation');
if ($request->getRequestInfo('http_code') === 200) {
$vf->output(['success' => true, 'url' => $cp['base_url'], 'user' => json_decode($data, true)['data']], true, true, 200);
}
$vf->output(['success' => false, 'errors' => 'Received HTTP code ' . $request->getRequestInfo('http_code')], true, true, 502);
$service = Database::getSystemService($serviceID);
if (!$service) {
$vf->output(['success' => false, 'errors' => 'Service not found'], true, true, 404);
break;
} }
$whmcsService = Database::getWhmcsService($serviceID);
if (!$whmcsService) {
$vf->output(['success' => false, 'errors' => 'WHMCS service not found'], true, true, 404);
break;
}
$cp = $vf->getCP($whmcsService->server);
if (!$cp) {
$vf->output(['success' => false, 'errors' => 'Control server not found'], true, true, 500);
break;
}
$request = $vf->initCurl($cp['token']);
$data = $request->get($cp['url'] . '/users/' . (int) $whmcsService->userid . '/byExtRelation');
if ($request->getRequestInfo('http_code') === 200) {
$vf->output(['success' => true, 'url' => $cp['base_url'], 'user' => json_decode($data, true)['data']], true, true, 200);
break;
}
$vf->output(['success' => false, 'errors' => 'Unable to fetch user data'], true, true, 502);
break; break;
default: default:
/** No valid action was specified **/
$vf->output(['success' => false, 'errors' => 'invalid action'], true, true, 400); $vf->output(['success' => false, 'errors' => 'invalid action'], true, true, 400);
} }

View File

@@ -25,6 +25,7 @@ EOT;
public static function serverId($serverId) public static function serverId($serverId)
{ {
$serverId = (int) $serverId;
return <<<EOT return <<<EOT
<input type="text" class="form-control input-200 input-inline" name="modulefields[0]" size="20" value="${serverId}" /> <input type="text" class="form-control input-200 input-inline" name="modulefields[0]" size="20" value="${serverId}" />
<span class="text-info">&nbsp;&nbsp;Changing the Sever ID manually is not recommended. Alterations to this field are usually handled automatically.</span> <span class="text-info">&nbsp;&nbsp;Changing the Sever ID manually is not recommended. Alterations to this field are usually handled automatically.</span>
@@ -34,6 +35,7 @@ EOT;
public static function serverInfo($systemUrl, $serviceId) public static function serverInfo($systemUrl, $serviceId)
{ {
$systemUrl = htmlspecialchars($systemUrl, ENT_QUOTES, 'UTF-8'); $systemUrl = htmlspecialchars($systemUrl, ENT_QUOTES, 'UTF-8');
$serviceId = (int) $serviceId;
$cacheV = time(); $cacheV = time();
return <<<EOT return <<<EOT
<link href="${systemUrl}modules/servers/VirtFusionDirect/templates/css/module.css?v=${cacheV}" rel="stylesheet"> <link href="${systemUrl}modules/servers/VirtFusionDirect/templates/css/module.css?v=${cacheV}" rel="stylesheet">

View File

@@ -170,27 +170,4 @@ class Cache
} }
} }
/**
* Delete all cache keys matching a pattern.
*
* @param string $pattern Glob pattern (e.g., "os:*")
*/
public static function forgetPattern($pattern)
{
$redis = self::redis();
if ($redis) {
try {
$keys = $redis->keys(self::PREFIX . $pattern);
if (!empty($keys)) {
$redis->del($keys);
}
} catch (\Exception $e) {
// Continue to file cleanup
}
}
// File cache: can only clear all files for pattern matches
// Since file names are md5 hashed, we can't match patterns.
// For non-Redis, TTL expiry handles cleanup naturally.
}
} }

View File

@@ -379,31 +379,6 @@ class Module
return false; return false;
} }
/**
* Assign a backup plan to a server.
*
* @param int $serviceID
* @param int $planId Backup plan ID (0 to remove)
* @return object|false
*/
public function assignBackupPlan($serviceID, $planId)
{
$planId = (int) $planId;
$ctx = $this->resolveServiceContext($serviceID);
if (!$ctx) return false;
$ctx['request']->addOption(CURLOPT_POSTFIELDS, json_encode(['planId' => $planId]));
$endpoint = $ctx['cp']['url'] . '/servers/' . $ctx['serverId'] . '/backup/plan';
$data = $planId > 0 ? $ctx['request']->post($endpoint) : $ctx['request']->delete($endpoint);
Log::insert(__FUNCTION__, $ctx['request']->getRequestInfo(), $data);
$httpCode = $ctx['request']->getRequestInfo('http_code');
if ($httpCode == 200 || $httpCode == 204) {
return json_decode($data) ?: (object) ['success' => true];
}
return false;
}
// ========================================================================= // =========================================================================
// VNC Console // VNC Console
// ========================================================================= // =========================================================================
@@ -740,40 +715,6 @@ class Module
return false; return false;
} }
/**
* Get available self-service currencies.
*
* @param int $serviceID
* @return array|false
*/
public function getSelfServiceCurrencies($serviceID)
{
$cacheKey = 'ss_currencies';
$cached = Cache::get($cacheKey);
if ($cached !== null) {
return $cached;
}
$serviceID = (int) $serviceID;
$whmcsService = Database::getWhmcsService($serviceID);
if (!$whmcsService) return false;
$cp = $this->getCP($whmcsService->server);
if (!$cp) return false;
$request = $this->initCurl($cp['token']);
$data = $request->get($cp['url'] . '/selfService/currencies');
Log::insert(__FUNCTION__, $request->getRequestInfo(), $data);
if ($request->getRequestInfo('http_code') == 200) {
$result = json_decode($data, true);
Cache::set($cacheKey, $result, 1800);
return $result;
}
return false;
}
/** /**
* Decodes a response from JSON into an associative array. * Decodes a response from JSON into an associative array.
* *

View File

@@ -663,31 +663,6 @@ function vfLoadSelfServiceUsage(serviceId, systemUrl) {
}); });
} }
function vfLoadSelfServiceReport(serviceId, systemUrl) {
$.ajax({
type: "GET",
dataType: "json",
url: vfUrl(systemUrl, serviceId, "selfServiceReport")
}).done(function (response) {
if (response.success && response.data) {
var data = response.data.data || response.data;
var tbody = $("#vf-ss-usage-table");
tbody.empty();
var items = data.items || data.report || [];
if (Array.isArray(items) && items.length > 0) {
$.each(items, function (i, item) {
var desc = item.description || item.name || "Item";
var cost = item.cost !== undefined ? parseFloat(item.cost).toFixed(2) : "-";
tbody.append('<tr><td>' + $('<span>').text(desc).html() + '</td><td class="text-right">' + $('<span>').text(cost).html() + '</td></tr>');
});
} else {
tbody.append('<tr><td colspan="2" class="text-muted">No report data available</td></tr>');
}
}
});
}
function vfAddCredit(serviceId, systemUrl) { function vfAddCredit(serviceId, systemUrl) {
var amount = $("#vf-ss-credit-amount").val(); var amount = $("#vf-ss-credit-amount").val();
var alertDiv = $("#vf-selfservice-alert"); var alertDiv = $("#vf-selfservice-alert");

View File

@@ -1,33 +0,0 @@
#!/bin/bash
# Generate API endpoint documentation from PHP source files
# Usage: bash scripts/generate-endpoint-doc.sh > docs/API-ENDPOINTS.md
MODULE_DIR="modules/servers/VirtFusionDirect"
echo "# VirtFusion WHMCS Module — API Endpoints"
echo ""
echo "Auto-generated from source code. Do not edit manually."
echo ""
echo "| Endpoint Pattern | HTTP Method | PHP File | Function |"
echo "|---|---|---|---|"
# Extract API URL patterns from PHP files
grep -rn "->get\|->post\|->put\|->patch\|->delete" "$MODULE_DIR/lib/" 2>/dev/null | \
grep -oP "(?<=>)(get|post|put|patch|delete)\(.*?'[^']*'" | \
while IFS= read -r line; do
method=$(echo "$line" | grep -oP "^(get|post|put|patch|delete)" | tr '[:lower:]' '[:upper:]')
url=$(echo "$line" | grep -oP "'[^']*'" | tr -d "'")
echo "| \`$url\` | $method | - | - |"
done
echo ""
echo "## Client Endpoints (client.php)"
echo ""
echo "| Action | Description |"
echo "|---|---|"
grep -n "case '" "$MODULE_DIR/client.php" 2>/dev/null | \
while IFS= read -r line; do
action=$(echo "$line" | grep -oP "case '\K[^']+")
echo "| \`$action\` | - |"
done