Skip to content

Releases: EZSCALE/virtfusion-whmcs-module

v1.5.1

02 Jun 17:11

Choose a tag to compare

Tested against: WHMCS 9.0.3 and VirtFusion v7.0.0 Build 9.

Bug Fixes

  • Critical: package upgrades/downgrades reported "Update package request failed. VirtFusion API returned HTTP 200" even though the change succeeded. ChangePackage issues PUT /servers/{id}/package/{packageId}, and VirtFusion v7 answers a successful change with HTTP 200 (carrying an info[] body describing what was/wasn't synced from the new package) — but the success whitelist only accepted 204, so every real package change fell through to the default branch and surfaced a failure to WHMCS. Because that branch returns early, the follow-up Memory/CPU/Bandwidth tuning never ran either, and WHMCS recorded a failure for an operation VirtFusion had actually applied (state drift). Fixed by accepting 200 (and keeping 204 for older builds); the returned info[] array is now logged so an operator can see when the panel skipped part of a change.

  • Per-resource tuning during a package change silently failed on VirtFusion v7. modifyResource() sent the CPU value under the field name cpuCores, but the /servers/{id}/modify/cpuCores endpoint requires the field cores — the request omitted the required property and was rejected by the API. It also only accepted HTTP 200/204 as success, while v7 returns 201 Created on every /modify/* call (the same version shift already handled for the rename endpoint in 1.5.0). Both are fixed: CPU is now sent as cores, and 201 is added to the success whitelist for memory, CPU, and traffic. These failures had been masked by the HTTP 200 bug above (which returned before the tuning loop) and were swallowed silently — the loop now logs any modifyResource() failure instead of discarding it.

Disk-downgrade safety (unchanged, confirmed): the module cannot shrink a primary disk and never could. It sends no disk flag on the package change, modifyResource() excludes storage entirely, no disk-modify endpoint exists, and VirtFusion itself refuses to lower a primary disk ("primary disk not updated. It either matches or is lower than the current value"). A downgrade leaves the disk at its larger size — there is no data-loss path.

Documentation

  • Vendored the VirtFusion v7 OpenAPI spec at docs/openapi.yaml for offline API reference when auditing endpoint behavior.

Full Changelog: v1.5.0...v1.5.1

v1.4.0

08 May 19:13

Choose a tag to compare

Features

  • Dynamic VPS stock control driven by live hypervisor capacity. Opt-in per product via WHMCS's native tblproducts.stockcontrol toggle; when enabled, the module overwrites tblproducts.qty with the real number of VPSes the panel can still provision and WHMCS handles the "Out of Stock" badge, Add-to-Cart gating, and checkout refusal natively — no template work required. qty is derived by combining two authoritative sources:

    • GET /packages/{packageId} for the per-VPS resource footprint (memory, cpuCores, primaryStorage, primaryStorageProfile, enabled)
    • GET /compute/hypervisors/groups/{id}/resources for live per-hypervisor free/allocated data

    Algorithm sums min(memory, cpu, storage) across eligible hypervisors (enabled AND commissioned AND !prohibit) for every group the product can be placed in (default configoption1 plus every numeric value of a Location configurable option), capped by the group-level IPv4 pool taken as max() within a group to avoid double-counting. Storage matching is strict against package.primaryStorageProfile; hypervisors without the named pool contribute 0. Confirmed-missing conditions (HTTP 404 on /packages/{id}, package.enabled=false) force qty=0; transient failures leave qty UNTOUCHED to avoid false out-of-stock during API blips.

  • Event-driven stock recalculation hooks:

    • AfterModuleCreate — refreshes qty after every VirtFusion provision (capacity just decreased). Bursts of parallel provisions coalesce via a 30 s shared rate-limit.
    • AfterModuleTerminate — refreshes qty after every VirtFusion termination (capacity just increased). Shares the 30 s rate-limit with create.
    • AfterCronJob — every-2-hour safety net that catches capacity changes made directly in the VirtFusion panel without going through WHMCS. Interval tunable via STOCK_CRON_INTERVAL_SECONDS in hooks.php.
    • ClientAreaPageCart — opportunistic per-product refresh during the order flow, rate-limited to once per product per 60 s.
  • Order auto-accept after successful provision. AfterModuleCreate calls WHMCS AcceptOrder (with autosetup=false so there's no double-provision) when the parent order is still in Pending status. Closes the gap for installs that rely on pending-order workflows for non-VF products but want VirtFusion provisions to auto-advance. Idempotent — already-accepted orders are skipped.

  • Admin-triggered full recalculation. New admin.php?action=stockRecalculate action (POST + same-origin required) runs StockControl::recalculateAll() on demand and returns a JSON {productId: qty} map; the module log gets a compact summary ({total, updated, zeroed, skipped}) so it stays readable on stores with hundreds of products.

  • Per-product safety buffer. New stockSafetyBufferPct config option (configoption7, default 10) reserves X% of each resource's max during stock calculation. Applied only to capped resources (unlimited resources with max=0 skip the buffer). Admins can override per product in the module settings; blank falls back to 10% so existing products get sensible headroom without any config change.

  • Test Connection now probes /compute/hypervisors/groups. A VirtFusion API token scoped only to /servers would pass the existing /connect check but silently break nightly stock updates. The admin's Test Connection button now surfaces missing /compute read scope at config time with a specific error rather than as unexplained nightly silence.

Caching

  • New cache keys: pkg:{packageId} (10 min TTL, package definitions rarely change) and grpres:{groupId} (120 s TTL, resources change minute-to-minute under load). Confirmed 404 responses are cached for 60 s so an admin re-creating a deleted package/group takes effect quickly.

Safety Properties

  • Module::fetchPackage() and Module::fetchGroupResources() return a tri-state array | false | null: false means "VirtFusion confirmed this doesn't exist → OOS is correct", null means "we can't tell right now → don't touch existing qty". Without this distinction the module would either zero out inventory during transient API blips, or show inventory for deleted packages.
  • \Throwable catches on every stock-path entry point (not just \Exception) so a TypeError from a malformed API response can't escape the tri-state contract.
  • Stock-control is gated by tblproducts.stockcontrol=1 — products that opt out are never touched, even by the safety-net cron.

Full Changelog: v1.3.0...v1.4.0

v1.3.0

18 Apr 02:05

Choose a tag to compare

Bug Fixes

  • Critical: decrypt() corruption of plaintext addon API keys. Config::get() was calling WHMCS's decrypt() on the raw tbladdonmodules.value for the PowerDNS API key and accepting whatever non-empty result came back. WHMCS addon password-type fields are actually stored plaintext (unlike tblservers.password which is encrypted), and decrypt() on plaintext input returns ~4 bytes of binary garbage instead of empty. That garbage was ending up in the X-API-Key: header, producing a baffling 401 from PowerDNS and an empty zone list — which then surfaced as "no zone" for every IP in the client-area rDNS panel. Fix: only use decrypt()'s output when it's printable ASCII; fall back to raw otherwise. Also trim() the chosen value so a stray paste-newline can't corrupt the header.

Features

  • IPv6 subnet visibility + custom-host PTR flow. VirtFusion allocates v6 as whole subnets (e.g. a /64 routed to the VPS) rather than discrete host addresses. The module previously filtered these silently; now subnets appear as first-class rows in the client rDNS panel with a collapsible "Add host PTR" form. Ownership verification uses subnet containment (IpUtil::ipv6InSubnet() via inet_pton + bit masking) so any address inside one of the VPS's allocated subnets is writeable, while addresses outside them are rejected. FCrDNS / rate-limit / CSRF guards all still apply.
  • Diagnose-an-IP tool on the VirtFusion DNS addon admin page. Takes an IP input and runs the full PtrManager pipeline inline: config snapshot, fresh zone list (cache-bypassed), computed PTR name, matched zone, current PTR content. Every common failure mode (wrong key, wrong serverId, forgotten zone, mis-aligned RFC 2317 label, stale cache) produces a distinctive shape in that output, turning "support ticket" into "screenshot the diagnosis".
  • Actionable auth-error messages. Client::ping() now returns structured guidance on 401/403 (check API key, api-allow-from, whitespace) and 404 (check serverId, it should be the literal localhost), replacing the previous "authentication failed (check API key)" / "unexpected HTTP 404" which gave no clue which of several causes was actually biting.

Full Changelog: v1.2.0...v1.3.0

v1.2.0 — PowerDNS Reverse DNS Integration

18 Apr 01:32

Choose a tag to compare

This release adds an opt-in reverse DNS management subsystem for operators running PowerDNS, plus a round of security hardening and code-level documentation improvements.

Highlights

PowerDNS Reverse DNS (PTR) Integration

A new companion addon module (VirtFusionDns) lets the provisioning module automatically manage PTR records through the PowerDNS HTTP API — fully optional, with zero impact on existing deployments that don't activate it.

  • Automatic PTR lifecycle — PTRs are created on server provisioning, updated on rename, and deleted on termination
  • Client-area Reverse DNS panel — one editable PTR input per assigned IP on the service overview, with per-row status badges
  • Admin services-tab widget — live PTR state plus Reconcile (additive) and Reconcile (force reset) buttons
  • Daily additive reconciliation via WHMCS DailyCronJob — creates any missing PTRs, never overwrites existing values
  • Forward-confirmed reverse DNS (FCrDNS) enforcement — PTR writes are rejected if the hostname's forward A/AAAA doesn't already resolve to the target IP, so rDNS is never left in a deliverability-harming mismatched state
  • IPv4 + IPv6 support including full nibble-reversal for ip6.arpa zones
  • RFC 2317 classless delegation support — both CIDR-prefix (0/26) and block-size (64/64) naming conventions are parsed and matched by IP range
  • Automatic NOTIFY after every successful PATCH so slaves pick up the SOA-bumped serial immediately (no waiting for the next scheduled refresh)

Security Hardening

New reusable guards on the Module base class, applied to the rDNS endpoints:

  • requirePost() — enforces POST for mutating endpoints (405 otherwise)
  • requireSameOrigin() — validates Origin/Referer against the WHMCS host as a CSRF defense against cross-site form POSTs
  • requireServiceStatus() — filters by tblhosting.domainstatus (writes require Active, reads allow Active+Suspended)

Every successful PTR edit is written to the WHMCS Module Log with {clientId, serviceId, ip} for audit traceability.

Merged Test Connection

The admin Test Connection button now validates both VirtFusion and PowerDNS in a single check when the DNS addon is active.

Fixed

  • IpUtil::parseClasslessZone now rejects misaligned RFC 2317 zone names (e.g., 3/26.x.y.z.in-addr.arpa. — a /26 delegation must begin at a multiple of 64). Prevents silent writes into the wrong zone on misconfigured labels.

Documentation

  • Extensive design-rationale commentary added across the module's support classes (Cache, Curl, Log, Database, ServerResource, ConfigureService) and throughout the new PowerDNS subsystem
  • README.md gains a full Reverse DNS Addon (PowerDNS) section covering prerequisites, activation, settings, behaviour-by-event, RFC 2317 handling, and security posture
  • CLAUDE.md updated with architecture notes and a PowerDNS API compatibility matrix

Installation / Upgrade

Existing installs can pull the latest module files as usual. The DNS addon is opt-in — deploying it is a no-op until an operator activates it. Set WHMCS once and it's reused for every rsync destination:

WHMCS=/path/to/whmcs
git clone https://github.com/EZSCALE/virtfusion-whmcs-module.git /tmp/vf \
  && rsync -ahP --delete /tmp/vf/modules/servers/VirtFusionDirect/ "$WHMCS/modules/servers/VirtFusionDirect/" \
  && rsync -ahP --delete /tmp/vf/modules/addons/VirtFusionDns/ "$WHMCS/modules/addons/VirtFusionDns/" \
  && rm -rf /tmp/vf

The second rsync line is only needed if you want to use the Reverse DNS addon. To activate it: WHMCS Admin → System Settings → Addon Modules → VirtFusion DNS → Activate, then Configure and enter the PowerDNS endpoint + API key. The README's Reverse DNS Addon (PowerDNS) section walks through the full setup.

No database migration is required — addon settings live in tbladdonmodules and are created on activation. The existing mod_virtfusion_direct table is unchanged.

Requirements for the DNS Addon

  • PowerDNS Authoritative 4.x with HTTP API enabled (webserver=yes, api=yes, api-key=...)
  • api-allow-from must include your WHMCS host's IP
  • All reverse zones you want to manage must already exist in PowerDNS — the addon never creates zones
  • Recommended: set soa_edit_api=INCREASE on each zone so PowerDNS auto-bumps the SOA serial on API writes

Full Changelog

See CHANGELOG.md · Compare: v1.1.0...v1.2.0

v1.1.0

19 Mar 20:15

Choose a tag to compare

Features

  • Auto-create custom fieldsInitial Operating System and Initial SSH Key fields are now created automatically on module load via Database::ensureCustomFields(). No more manual SQL import. modify.sql has been removed. (d253bd4)
  • OS gallery, server rename, traffic chart, backups, VNC toggle, password reset, Redis caching, UX improvements (90a97c4)
  • Laravel Pint code formatting with pre-commit hook, auto-installed via Composer (d253bd4)

Bug Fixes

  • Restore OS template icons using correct VirtFusion path /img/logo/ (6528c8a)
  • Constrain OS icon sizing and remove background when image loads (6694a5e)
  • Constrain category header icon images with overflow:hidden and max dimensions (64dcce3)
  • Use unix timestamp for cache busting, generic server icon for Other category (504d292)
  • Force generic icon on 'Other' category even when API provides linux_logo.png (3ca9eb6)
  • OS gallery accordion auto-collapses other sections when one opens (a9565ff)
  • OS gallery accordion layout and remove broken remote icon fetching (9cd737c)
  • Remove dead code, update stale versions, tag-based release workflow (d3d75b4)

Code Quality

  • Comprehensive try/catch — every DB operation and API call is now wrapped per project error handling rules (d253bd4)
  • Full PHPDoc — class-level and method-level documentation on all PHP files (d253bd4)
  • Dead code removal and project audit cleanup (1ab2ef4)
  • Consolidate duplicate logic across codebase (0ade74d)
  • Simplified README installation to a single copy-paste command

1.0.0

07 Feb 22:03

Choose a tag to compare

1.0.0 (2026-02-07)

Bug Fixes

  • add null/false guards, proper error handling, and VNC popup fix (49fdd9e)
  • TestConnection for unsaved servers, traffic display, and cache-busting (e8d2eb0)
  • XSS escaping, null guards, JS bug fixes, and documentation updates (6c7cdc6)

Features

  • add client-side SSH Ed25519 key generator on order page (209e01d)
  • add VNC check, SSH key paste, resources panel, sliders, and self-service billing (1e471af)
  • streamline network panel, conditional self-service, remove IP add endpoints (e73e85c)

0.0.18

01 Oct 17:09

Choose a tag to compare

Full Changelog: 0.0.17...0.0.18

0.0.17

16 Jan 17:13
9aa8378

Choose a tag to compare

Release 0.0.17

0.0.16

11 Sep 04:31
a46223e

Choose a tag to compare

Release 0.0.16

0.0.15

11 Sep 03:58

Choose a tag to compare

Release 0.0.15