fix: XSS escaping, null guards, JS bug fixes, and documentation updates

- Escape $serverObject and $systemUrl in AdminHTML.php heredocs to prevent XSS
- Add null guard in Database::getSystemUrl() to prevent fatal error
- Guard primaryNetwork access in module.js to prevent null dereference
- Reset badge/traffic-bar CSS classes on refresh to prevent accumulation
- Add VNC popup-blocked check with user-facing message
- Add BS3 input-group-btn dual class for theme compatibility
- Escape billing template variables with |escape:'htmlall'
- Add cache-busting to admin CSS/JS includes
- Switch cache-busting format from version to date-based (20260207)
- Create .releaserc.json for automated CHANGELOG.md management
- Add changelog/git plugins to semantic-release workflow
- Remove manual [Unreleased] section from CHANGELOG.md
- Update README: install/upgrade with rsync, accuracy fixes, add keygen.js
- Update CLAUDE.md: add keygen.js, document removed features
- Fix SECURITY.md grammar and version operator

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
EZSCALE
2026-02-07 15:48:49 -06:00
parent e73e85c5a9
commit 6c7cdc6421
11 changed files with 91 additions and 115 deletions

View File

@@ -26,6 +26,9 @@ jobs:
with: with:
# You can specify the branches to release from # You can specify the branches to release from
branch: main branch: main
extra_plugins: |
@semantic-release/changelog
@semantic-release/git
env: env:
# GITHUB_TOKEN is required for authentication # GITHUB_TOKEN is required for authentication
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

13
.releaserc.json Normal file
View File

@@ -0,0 +1,13 @@
{
"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

@@ -2,68 +2,6 @@
All notable changes to the VirtFusion Direct Provisioning Module for WHMCS. All notable changes to the VirtFusion Direct Provisioning Module for WHMCS.
## [Unreleased]
### Added
- **Power management** — Start, restart, graceful shutdown, and force power off controls in client area
- **Server rebuild** — Reinstall with any available OS template from client area with confirmation dialog
- **Server rename** — Change server display name via client area
- **Network management** — View and remove IPv4 addresses; view IPv6 subnets from client area
- **VNC console** — Browser-based console access (VirtFusion v6.1.0+)
- **VNC runtime check** — VNC panel auto-hides when VNC is disabled on the server
- **Backup management** — Assign and remove backup plans via API
- **Resource modification** — In-place memory, CPU, and traffic changes (VirtFusion v6.2.0+)
- **Resources panel** — Client area panel showing current memory, CPU, storage, traffic allocation with progress bars and upgrade/downgrade link
- **UsageUpdate cron** — Automated bandwidth and disk usage sync from VirtFusion to WHMCS
- **Dry run validation** — Test server creation parameters before provisioning
- **Admin "Validate Server Config" button** — Dry run from admin services tab
- **TestConnection** — Validate API credentials from WHMCS server settings
- **ServiceSingleSignOn** — Native WHMCS SSO integration for VirtFusion panel
- **Server status badge** — Visual indicator of server state in overview
- **Traffic usage display** — Bandwidth used vs allocated
- **Checkout validation** — `ShoppingCartValidateCheckout` hook ensures OS selection before order placement
- **SSH key paste at checkout** — Users can paste a raw SSH public key during checkout; key is created via `POST /ssh_keys` during provisioning
- **SSH Ed25519 key generator** — Client-side keypair generation on checkout page using Web Crypto API; auto-fills public key and presents private key for download/copy
- **Order form sliders** — Configurable option dropdowns replaced with styled range sliders for resource selection
- **Self-service billing** — Credit balance display, usage breakdown, and credit top-up from client area
- **Self-service config options** — Product config options 4-6: Self-Service Mode, Auto Top-Off Threshold, Auto Top-Off Amount
- **Auto top-off** — During WHMCS daily cron, automatically adds credit when balance falls below threshold
- **Self-service user creation** — New VirtFusion users created with self-service billing settings when enabled
- **CLAUDE.md** — Project architecture and development guidance for Claude Code
### Changed
- Enable SSL/TLS certificate verification by default (was disabled)
- Remove `error_reporting(0)` that silenced all errors
- Add input sanitization on all user parameters (type casting, regex filtering)
- Return proper HTTP status codes (401, 403, 400, 500) instead of always 200
- Add XSS protection with `htmlspecialchars()` and `encodeURIComponent()`
- Readable, unminified JavaScript with JSDoc header
- Dual panel/card CSS classes for Bootstrap 3/4/5 theme compatibility
- `changePackage()` now applies individual resource modifications from configurable options after updating the package
- `initServerBuild()` accepts optional VF user ID parameter for SSH key creation
- `ServerResource::process()` returns raw numeric resource values and `vncEnabled` boolean
- Network panel now populated from server data response instead of separate API call
- Self-service billing panel conditionally rendered based on `selfServiceMode` config option
- Comprehensive README rewrite with installation, configuration, troubleshooting, and API reference
### Fixed
- Add `isset()` guards before `count()` on ipv4/ipv6 arrays in ServerResource to prevent PHP 8.0+ TypeError
- Add null checks after `getWhmcsService()` and `getCP()` in all Module/ModuleFunctions methods to prevent fatal null dereference
- Fix HTTP status codes throughout admin.php (404, 400, 500, 502 instead of always 200)
- Guard ConfigureService methods against `$this->cp === false`
- Replace `exit()` with `RuntimeException` in Curl.php
- Change `catch(Exception)` to `catch(Throwable)` in hooks.php for PHP 8.0+ compatibility
- Open VNC window before AJAX call to avoid popup blocker
- Memory conversion checks key name instead of display name
- Fix TestConnection failing for new/unsaved servers — use `$params` directly instead of database lookup (serverid=0 is falsy)
- Fix traffic "Used" showing `-` instead of `0 GB` when traffic is allocated but no usage reported yet
- Bump cache-busting version to `?v=0.0.20` for JS/CSS includes in overview.tpl
### Removed
- Firewall feature (non-functional — rulesets must be created in VirtFusion admin panel)
- IP add endpoints (`addIPv4`, `addIPv6`, `serverIPs`) and add buttons — IPs are managed by VirtFusion during provisioning
- Upgrade/Downgrade link from resources panel
## [0.0.18] - 2025-10-01 ## [0.0.18] - 2025-10-01
### Changed ### Changed

View File

@@ -56,8 +56,15 @@ Releases are automated via GitHub Actions using semantic-release on pushes to `m
- **`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, resources, VNC, self-service billing, billing overview)
- **`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 (1000+ lines) handling AJAX calls to `client.php`, DOM updates, status badges, power actions, all management UIs
- **`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
- **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
- **Upgrade/Downgrade link** — Removed from resources panel
### Data Flow: Server Creation ### Data Flow: Server Creation
1. WHMCS calls `VirtFusionDirect_CreateAccount()``ModuleFunctions::createAccount()` 1. WHMCS calls `VirtFusionDirect_CreateAccount()``ModuleFunctions::createAccount()`

View File

@@ -1,6 +1,6 @@
# VirtFusion Direct Provisioning Module for WHMCS # VirtFusion Direct Provisioning Module for WHMCS
[![GitHub Super-Linter](https://github.com/EZSCALE/virtfusion-whmcs-module/actions/workflows/publish-release.yml/badge.svg)](https://github.com/EZSCALE/virtfusion-whmcs-module/actions) [![Automated Release](https://github.com/EZSCALE/virtfusion-whmcs-module/actions/workflows/publish-release.yml/badge.svg)](https://github.com/EZSCALE/virtfusion-whmcs-module/actions)
![GitHub](https://img.shields.io/github/license/EZSCALE/virtfusion-whmcs-module) ![GitHub](https://img.shields.io/github/license/EZSCALE/virtfusion-whmcs-module)
![GitHub issues](https://img.shields.io/github/issues/EZSCALE/virtfusion-whmcs-module) ![GitHub issues](https://img.shields.io/github/issues/EZSCALE/virtfusion-whmcs-module)
![GitHub pull requests](https://img.shields.io/github/issues-pr/EZSCALE/virtfusion-whmcs-module) ![GitHub pull requests](https://img.shields.io/github/issues-pr/EZSCALE/virtfusion-whmcs-module)
@@ -62,8 +62,8 @@ 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, add, and remove IPv4 addresses and IPv6 subnets - **Network Management** - View and remove IPv4 addresses; view IPv6 subnets
- **Resources Panel** - Current memory, CPU, storage, traffic allocation with usage bars and upgrade/downgrade link - **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)
- **Bandwidth Usage** - Traffic usage display with allocation limits - **Bandwidth Usage** - Traffic usage display with allocation limits
@@ -81,6 +81,7 @@ You also need a VirtFusion API token with the following permissions:
### Ordering Process ### Ordering Process
- Dynamic OS template dropdown populated from VirtFusion API - Dynamic OS template dropdown populated from VirtFusion API
- 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
- Checkout validation ensuring OS selection before order placement - Checkout validation ensuring OS selection before order placement
- **Resource sliders** - Configurable option dropdowns are replaced with interactive range sliders - **Resource sliders** - Configurable option dropdowns are replaced with interactive range sliders
- Compatible with all WHMCS order form templates - Compatible with all WHMCS order form templates
@@ -107,26 +108,20 @@ You also need a VirtFusion API token with the following permissions:
## Installation ## Installation
### Step 1: Download ### Step 1: Download & Install
Download the latest release from the [releases](https://github.com/EZSCALE/virtfusion-whmcs-module/releases) page, or clone the repository: Download the latest release from the [releases](https://github.com/EZSCALE/virtfusion-whmcs-module/releases) page, or install directly via the command line:
```bash ```bash
cd /tmp
git clone https://github.com/EZSCALE/virtfusion-whmcs-module.git git clone https://github.com/EZSCALE/virtfusion-whmcs-module.git
rsync -ahP --delete /tmp/virtfusion-whmcs-module/modules/servers/VirtFusionDirect/ /path/to/whmcs/modules/servers/VirtFusionDirect/
rm -rf /tmp/virtfusion-whmcs-module
``` ```
### Step 2: Upload Files Replace `/path/to/whmcs` with your actual WHMCS installation root.
Upload the `modules/` folder to your WHMCS installation root directory: The resulting file structure should be:
```
your-whmcs-root/
modules/
servers/
VirtFusionDirect/ <-- This folder
```
The file structure should be:
``` ```
modules/servers/VirtFusionDirect/ modules/servers/VirtFusionDirect/
@@ -149,11 +144,12 @@ modules/servers/VirtFusionDirect/
error.tpl # Error template error.tpl # Error template
css/module.css # Styles css/module.css # Styles
js/module.js # Client JavaScript js/module.js # Client JavaScript
js/keygen.js # SSH Ed25519 key generator
config/ config/
ConfigOptionMapping-example.php # Config mapping example ConfigOptionMapping-example.php # Config mapping example
``` ```
### Step 3: Set Up Server in WHMCS ### Step 2: Set Up Server in WHMCS
1. Go to **Configuration > System Settings > Servers** 1. Go to **Configuration > System Settings > Servers**
2. Click **Add New Server** 2. Click **Add New Server**
@@ -165,7 +161,7 @@ modules/servers/VirtFusionDirect/
4. Click **Test Connection** to verify 4. Click **Test Connection** to verify
5. Click **Save Changes** 5. Click **Save Changes**
### Step 4: Create Product ### Step 3: Create Product
1. Go to **Configuration > System Settings > Products/Services** 1. Go to **Configuration > System Settings > Products/Services**
2. Create a new product or edit an existing one 2. Create a new product or edit an existing one
@@ -175,21 +171,30 @@ modules/servers/VirtFusionDirect/
- Set **Hypervisor Group ID**, **Package ID**, and **Default IPv4** count - Set **Hypervisor Group ID**, **Package ID**, and **Default IPv4** count
4. Save the product 4. Save the product
### Step 5: Set Up Custom Fields ### Step 4: Set Up Custom Fields
See [Custom Fields](#custom-fields) section below. See [Custom Fields](#custom-fields) section below.
### Step 6: Activate Hooks ### Step 5: Activate Hooks
The hooks file (`hooks.php`) is automatically detected by WHMCS when the module is active. If you add the module files to an existing installation, you may need to re-save the product settings or clear the WHMCS template cache for hooks to take effect. The hooks file (`hooks.php`) is automatically detected by WHMCS when the module is active. If you add the module files to an existing installation, you may need to re-save the product settings or clear the WHMCS template cache for hooks to take effect.
## Upgrading ## Upgrading
1. Back up your existing `modules/servers/VirtFusionDirect/` directory 1. Back up your existing `modules/servers/VirtFusionDirect/` directory
2. Download the new version and overwrite all files 2. Back up `config/ConfigOptionMapping.php` if you have a custom mapping
3. If you have a custom `config/ConfigOptionMapping.php`, preserve it 3. Download and deploy the new version:
4. If you have theme-overridden templates, review them for any new template variables
5. Clear the WHMCS template cache: **Configuration > System Settings > General Settings > clear template cache** ```bash
cd /tmp
git clone https://github.com/EZSCALE/virtfusion-whmcs-module.git
rsync -ahP --delete /tmp/virtfusion-whmcs-module/modules/servers/VirtFusionDirect/ /path/to/whmcs/modules/servers/VirtFusionDirect/
rm -rf /tmp/virtfusion-whmcs-module
```
4. Restore your custom `config/ConfigOptionMapping.php` if applicable
5. If you have theme-overridden templates, review them for any new template variables
6. Clear the WHMCS template cache: **Configuration > System Settings > General Settings > clear template cache**
The module database table (`mod_virtfusion_direct`) is automatically migrated on first load. The module database table (`mod_virtfusion_direct`) is automatically migrated on first load.
@@ -300,10 +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
- Add new IPv4 addresses (subject to pool availability)
- Add new IPv6 subnets (subject to pool availability)
- Remove secondary IPv4 addresses (primary cannot be removed) - Remove secondary IPv4 addresses (primary cannot be removed)
- Remove IPv6 subnets
### VNC Console ### VNC Console
- Opens a browser-based VNC console to the server - Opens a browser-based VNC console to the server
@@ -409,10 +411,7 @@ WHMCS automatically loads theme-specific templates when they exist. Copy the ori
| Method | Endpoint | Purpose | | Method | Endpoint | Purpose |
|---|---|---| |---|---|---|
| `POST` | `/servers/{id}/ipv4` | Add IPv4 address |
| `DELETE` | `/servers/{id}/ipv4` | Remove IPv4 address | | `DELETE` | `/servers/{id}/ipv4` | Remove IPv4 address |
| `POST` | `/servers/{id}/ipv6` | Add IPv6 subnet |
| `DELETE` | `/servers/{id}/ipv6` | Remove IPv6 subnet |
### SSH Keys ### SSH Keys
@@ -524,7 +523,7 @@ This data appears in the WHMCS client area and admin product details.
2. **Resource Modification** - Memory and CPU modification requires VirtFusion v6.2.0+. Traffic modification requires v6.0.0+. Backup management requires v4.3.0+. 2. **Resource Modification** - Memory and CPU modification requires VirtFusion v6.2.0+. Traffic modification requires v6.0.0+. Backup management requires v4.3.0+.
3. **IPv6 Management** - IPv6 subnet assignment depends on the VirtFusion installation having IPv6 pools configured. If no pools are available, the add operation will fail with an appropriate error message. 3. **IPv6 Display** - IPv6 subnet display depends on the VirtFusion installation having IPv6 pools configured. If no IPv6 is assigned, the network panel shows "No IPv6 subnets".
4. **Order Form Custom Fields** - The custom fields ("Initial Operating System" and "Initial SSH Key") must be named exactly as specified. The module matches by field name with spaces removed and converted to lowercase. 4. **Order Form Custom Fields** - The custom fields ("Initial Operating System" and "Initial SSH Key") must be named exactly as specified. The module matches by field name with spaces removed and converted to lowercase.
@@ -580,6 +579,7 @@ modules/servers/VirtFusionDirect/
error.tpl # Error display template error.tpl # Error display template
css/module.css # Module styles (responsive, BS3/4/5 compatible) css/module.css # Module styles (responsive, BS3/4/5 compatible)
js/module.js # Client JavaScript (all AJAX interactions) js/module.js # Client JavaScript (all AJAX interactions)
js/keygen.js # SSH Ed25519 key generator (Web Crypto API)
config/ config/
ConfigOptionMapping-example.php # Example custom option name mapping ConfigOptionMapping-example.php # Example custom option name mapping
``` ```

View File

@@ -2,11 +2,11 @@
## Supported Versions ## Supported Versions
The support version of this module with VirtFusion Supported VirtFusion versions:
| Version | Supported | | Version | Supported |
|---------|--------------------| |----------|--------------------|
| > 1.7.3 | :white_check_mark: | | >= 1.7.3 | :white_check_mark: |
| < 1.7.3 | :x: | | < 1.7.3 | :x: |
## Reporting a Vulnerability ## Reporting a Vulnerability

View File

@@ -139,7 +139,7 @@ add_hook('ClientAreaFooterOutput', 1, function ($vars) {
$systemUrl = Database::getSystemUrl(); $systemUrl = Database::getSystemUrl();
return " return "
<script src=\"" . htmlspecialchars($systemUrl, ENT_QUOTES, 'UTF-8') . "modules/servers/VirtFusionDirect/templates/js/keygen.js?v=0.0.20\"></script> <script src=\"" . htmlspecialchars($systemUrl, ENT_QUOTES, 'UTF-8') . "modules/servers/VirtFusionDirect/templates/js/keygen.js?v=20260207\"></script>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
var osTemplates = " . json_encode($dropdownOptions, JSON_THROW_ON_ERROR | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) . "; var osTemplates = " . json_encode($dropdownOptions, JSON_THROW_ON_ERROR | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) . ";

View File

@@ -7,6 +7,7 @@ class AdminHTML
public static function options($systemUrl, $serviceId) public static function options($systemUrl, $serviceId)
{ {
$systemUrl = htmlspecialchars($systemUrl, ENT_QUOTES, 'UTF-8');
return <<<EOT return <<<EOT
<button onclick="impersonateServerOwner('${serviceId}', '${systemUrl}')" type="button" class="btn btn-primary">Impersonate Server Owner</button> <button onclick="impersonateServerOwner('${serviceId}', '${systemUrl}')" type="button" class="btn btn-primary">Impersonate Server Owner</button>
<span class="text-info">&nbsp;&nbsp;A valid VirtFusion admin session in the same browser is required for this functionality to work.</span> <span class="text-info">&nbsp;&nbsp;A valid VirtFusion admin session in the same browser is required for this functionality to work.</span>
@@ -15,6 +16,7 @@ EOT;
public static function serverObject($serverObject) public static function serverObject($serverObject)
{ {
$serverObject = htmlspecialchars($serverObject, ENT_QUOTES, 'UTF-8');
return <<<EOT return <<<EOT
<textarea class="form-control" name="modulefields[1]" rows="10" style="width: 100%" disabled>${serverObject}</textarea> <textarea class="form-control" name="modulefields[1]" rows="10" style="width: 100%" disabled>${serverObject}</textarea>
EOT; EOT;
@@ -31,9 +33,10 @@ EOT;
public static function serverInfo($systemUrl, $serviceId) public static function serverInfo($systemUrl, $serviceId)
{ {
$systemUrl = htmlspecialchars($systemUrl, ENT_QUOTES, 'UTF-8');
return <<<EOT return <<<EOT
<link href="${systemUrl}modules/servers/VirtFusionDirect/templates/css/module.css" rel="stylesheet"> <link href="${systemUrl}modules/servers/VirtFusionDirect/templates/css/module.css?v=20260207" rel="stylesheet">
<script src="${systemUrl}modules/servers/VirtFusionDirect/templates/js/module.js"></script> <script src="${systemUrl}modules/servers/VirtFusionDirect/templates/js/module.js?v=20260207"></script>
<div id="vf-loader" class="vf-loader"> <div id="vf-loader" class="vf-loader">
<div id="vf-loading"></div> <div id="vf-loading"></div>
</div> </div>

View File

@@ -54,6 +54,7 @@ class Database
public static function getSystemUrl() public static function getSystemUrl()
{ {
$url = DB::table('tblconfiguration')->where('setting', '=', 'SystemURL')->first(); $url = DB::table('tblconfiguration')->where('setting', '=', 'SystemURL')->first();
if (!$url) return '';
return $url->value; return $url->value;
} }

View File

@@ -25,13 +25,15 @@ function vfServerData(serviceId, systemUrl) {
$("#vf-data-server-traffic-used").text(response.data.trafficUsed || "-"); $("#vf-data-server-traffic-used").text(response.data.trafficUsed || "-");
$("#vf-data-server-storage").text(response.data.storage); $("#vf-data-server-storage").text(response.data.storage);
$("#vf-data-server-cpu").text(response.data.cpu); $("#vf-data-server-cpu").text(response.data.cpu);
$("#vf-data-server-ipv4").text(response.data.primaryNetwork.ipv4); var pn = response.data.primaryNetwork || {};
$("#vf-data-server-ipv6").text(response.data.primaryNetwork.ipv6); $("#vf-data-server-ipv4").text(pn.ipv4 || "-");
$("#vf-data-server-ipv6").text(pn.ipv6 || "-");
// Update status badge // Update status badge
var statusBadge = $("#vf-status-badge"); var statusBadge = $("#vf-status-badge");
var status = (response.data.status || "unknown").toLowerCase(); var status = (response.data.status || "unknown").toLowerCase();
statusBadge.text(status.charAt(0).toUpperCase() + status.slice(1)); statusBadge.text(status.charAt(0).toUpperCase() + status.slice(1));
statusBadge.removeClass("vf-badge-active vf-badge-suspended vf-badge-awaiting");
if (status === "active" || status === "running") { if (status === "active" || status === "running") {
statusBadge.addClass("vf-badge-active"); statusBadge.addClass("vf-badge-active");
} else if (status === "suspended") { } else if (status === "suspended") {
@@ -56,7 +58,7 @@ function vfServerData(serviceId, systemUrl) {
if (trafficTotal > 0) { if (trafficTotal > 0) {
$("#vf-res-traffic").text(trafficUsed + " / " + trafficTotal + " GB"); $("#vf-res-traffic").text(trafficUsed + " / " + trafficTotal + " GB");
var pct = Math.min(100, Math.round((trafficUsed / trafficTotal) * 100)); var pct = Math.min(100, Math.round((trafficUsed / trafficTotal) * 100));
$("#vf-res-traffic-bar").css("width", pct + "%"); $("#vf-res-traffic-bar").css("width", pct + "%").removeClass("bg-danger bg-warning");
if (pct > 90) { if (pct > 90) {
$("#vf-res-traffic-bar").addClass("bg-danger"); $("#vf-res-traffic-bar").addClass("bg-danger");
} else if (pct > 70) { } else if (pct > 70) {
@@ -140,8 +142,9 @@ function vfServerDataAdmin(serviceId, systemUrl) {
$("#vf-data-server-traffic").text(response.data.traffic); $("#vf-data-server-traffic").text(response.data.traffic);
$("#vf-data-server-storage").text(response.data.storage); $("#vf-data-server-storage").text(response.data.storage);
$("#vf-data-server-cpu").text(response.data.cpu); $("#vf-data-server-cpu").text(response.data.cpu);
$("#vf-data-server-ipv4").text(response.data.primaryNetwork.ipv4); var pnAdmin = response.data.primaryNetwork || {};
$("#vf-data-server-ipv6").text(response.data.primaryNetwork.ipv6); $("#vf-data-server-ipv4").text(pnAdmin.ipv4 || "-");
$("#vf-data-server-ipv6").text(pnAdmin.ipv6 || "-");
$("#vf-server-info").show(); $("#vf-server-info").show();
} else { } else {
$("#vf-server-info-error").show(); $("#vf-server-info-error").show();
@@ -383,6 +386,14 @@ function vfOpenVnc(serviceId, systemUrl) {
// Open window immediately in click context to avoid popup blockers // Open window immediately in click context to avoid popup blockers
var vncWindow = window.open("", "_blank"); var vncWindow = window.open("", "_blank");
if (!vncWindow) {
alertDiv.removeClass("alert-success").addClass("alert-danger");
alertDiv.text("Popup blocked. Please allow popups for this site and try again.");
alertDiv.show();
spinner.hide();
btn.prop("disabled", false);
return;
}
$.ajax({ $.ajax({
type: "GET", type: "GET",

View File

@@ -1,5 +1,5 @@
<link href="{$systemURL}modules/servers/VirtFusionDirect/templates/css/module.css?v=0.0.20" rel="stylesheet"> <link href="{$systemURL}modules/servers/VirtFusionDirect/templates/css/module.css?v=20260207" rel="stylesheet">
<script src="{$systemURL}modules/servers/VirtFusionDirect/templates/js/module.js?v=0.0.20"></script> <script src="{$systemURL}modules/servers/VirtFusionDirect/templates/js/module.js?v=20260207"></script>
{if $serviceStatus eq 'Active'} {if $serviceStatus eq 'Active'}
@@ -274,7 +274,7 @@
<h5 class="vf-bold">Add Credit</h5> <h5 class="vf-bold">Add Credit</h5>
<div class="input-group mb-2"> <div class="input-group mb-2">
<input type="number" id="vf-ss-credit-amount" class="form-control" placeholder="Amount" min="1" step="1"> <input type="number" id="vf-ss-credit-amount" class="form-control" placeholder="Amount" min="1" step="1">
<div class="input-group-append"> <div class="input-group-append input-group-btn">
<button id="vf-ss-add-credit-btn" onclick="vfAddCredit('{$serviceid}','{$systemURL}')" type="button" class="btn btn-primary"> <button id="vf-ss-add-credit-btn" onclick="vfAddCredit('{$serviceid}','{$systemURL}')" type="button" class="btn btn-primary">
<span id="vf-ss-add-credit-spinner" class="spinner-border spinner-border-sm" style="display:none;"></span> <span id="vf-ss-add-credit-spinner" class="spinner-border spinner-border-sm" style="display:none;"></span>
Add Credit Add Credit
@@ -328,29 +328,29 @@
<div class="col-lg-6"> <div class="col-lg-6">
<div class="row p-2"> <div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">Product:</div> <div class="col-xs-6 col-6 text-right vf-bold">Product:</div>
<div class="col-xs-6 col-6">{$groupname} - {$product}</div> <div class="col-xs-6 col-6">{$groupname|escape:'htmlall'} - {$product|escape:'htmlall'}</div>
</div> </div>
<div class="row p-2"> <div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">{$LANG.recurringamount}:</div> <div class="col-xs-6 col-6 text-right vf-bold">{$LANG.recurringamount}:</div>
<div class="col-xs-6 col-6">{$recurringamount}</div> <div class="col-xs-6 col-6">{$recurringamount|escape:'htmlall'}</div>
</div> </div>
<div class="row p-2"> <div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">{$LANG.orderbillingcycle}:</div> <div class="col-xs-6 col-6 text-right vf-bold">{$LANG.orderbillingcycle}:</div>
<div class="col-xs-6 col-6">{$billingcycle}</div> <div class="col-xs-6 col-6">{$billingcycle|escape:'htmlall'}</div>
</div> </div>
</div> </div>
<div class="col-lg-6"> <div class="col-lg-6">
<div class="row p-2"> <div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">{$LANG.clientareahostingregdate}:</div> <div class="col-xs-6 col-6 text-right vf-bold">{$LANG.clientareahostingregdate}:</div>
<div class="col-xs-6 col-6">{$regdate}</div> <div class="col-xs-6 col-6">{$regdate|escape:'htmlall'}</div>
</div> </div>
<div class="row p-2"> <div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">{$LANG.clientareahostingnextduedate}:</div> <div class="col-xs-6 col-6 text-right vf-bold">{$LANG.clientareahostingnextduedate}:</div>
<div class="col-xs-6 col-6">{$nextduedate}</div> <div class="col-xs-6 col-6">{$nextduedate|escape:'htmlall'}</div>
</div> </div>
<div class="row p-2"> <div class="row p-2">
<div class="col-xs-6 col-6 text-right vf-bold">{$LANG.orderpaymentmethod}:</div> <div class="col-xs-6 col-6 text-right vf-bold">{$LANG.orderpaymentmethod}:</div>
<div class="col-xs-6 col-6">{$paymentmethod}</div> <div class="col-xs-6 col-6">{$paymentmethod|escape:'htmlall'}</div>
</div> </div>
</div> </div>
</div> </div>