Feature

WisPanel 1.0 is Here!

Tr
Trung Đặng
December 20, 2025 328 views

WisPanel 1.0 Official Release

After months of intensive development and community feedback, we're thrilled to announce the official release of WisPanel 1.0!

<?php
require_once '../database/connection.php';
require_once '../helpers/LicenseHelpers.php';

// ============================================
// CONSTANTS
// ============================================
const PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----
MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCSKZMwIYa+f0LE
0KFarJkmWslZuC5kK9F//GmJCfnLc7TGHRIZRFih/GzObOMI+MmcFB8bG4Nm6u5z
a5+EZZMgsigG17/cC3BzumNMci4htTouWzJyGvY181QzS0W54I4+5wHcqgrU0ABD
ISZ+a4ayBZWZOe42rbCBuwolCEjjXYd4aRNryxtGiR9zbJAuCmHHiRzdoJYs2YUd
t/UvQ7aMVWy8ZUbvPKdNiGoYjBlxb0fbu7IXkWoKj8SmMFFIe7+Q6y+QR1p9VxDj
XOYikUPQ5b/Ua3ygASS2lnUAg+nxcsgusTFpkbesrvS7p22GH4v8+3fV+moUhT0D
w+zigXmtqWus5iOJHCx3gYvSA9ZAbTIIJJ3y5Yimt6Lwl77OWRoIZ2ZHaRVIRTeA
VMaAX/8k+tWOHaeQSlsaqgmc+kxq5PhakTkGsUF0gpj3WFr3p+yi506L6dFPdvDl
6OCQvSDNkmFlcY1mwzG347kW9HJipEc7MD+UbwKAUS+Rp6cKMcZpFhxYbi8gZ1c8
OiUuU8hMm9DUBrokFAKhfHmkHDCJf33XsJCkmSWzy9PggMDARYiWgcNflp8OmXmg
ooo3j+z1sLd//TPWcRD50z4is0eCGG6CbcQai0TNBcRUEKmYqzN53c7bUxTN8cs8
rm06Vw/2b1BkkS8f1ZjGXOlOqmE7jwIDAQABAoICABO6bIVZbnRa/VpPELW080JT
4baW9MgM3rey4anKFhR/LHN11rdgsW1CguCFSPWxOEE1ZBIcGhXeTaDNnNfZf/eF
+dTGnT0TBt16rHl+iznTL3m0py/zR1qhL93GjLBEnjPg/rAtUXidD1QARE+vAsds
7TQj4hfbmiXrPDjNuqIvFyB1ClaJMR10V7GULI0nq0ABV/Xq0tUAkoZK31tpp9j0
P3uEWK6Plhi8ehmQcMS4sPnN3AFwsrVJ53tJApz70FpmrDesseBAzA+W6Ucu1U5R
HHM3A44d6WSDFWLO61jtgGtGUSA/N2FQXMnRalKUAn37O+xpYupx0M+ny9sHf91G
Y21RQtdY0jlOxHAcayaX5pMCfbPU69M/ZlRYGgDlmCZOFjzFLUjqZbd7bizbvYPk
uurcIXkiEpz9Ggrr+oTSuOnKO4PfwQm0mD+7WXNHvkcqRwQUzbihAJrv7aWOXssQ
auI9yp4j6tg+IDlZXWAlJRR581FlsnXKtYBCEfSWmTWqF5tPTBU81qTIxaViDzEd
UpVyZNcE45LjQGMfMghQ+02oSavYM3Hf8qfShIIB6fP7bc0i0L6T73S/s7+jbZnw
MwtKEr9n2bccR01PUC3F0gSmcyWttRIDxxdDtRu9BEDVroL7Q+2ZcaphpzKkMvMA
BwsU/px52Tax8jVVgVJZAoIBAQDMTJx67w+aLjUpIMUMnKQSUcqgDfJhu/MYLhZ+
4viUh0m4p7E21D32To4WgMNEAWqM3/0GfL7nYutSR+N/jcgaGdR+ciZb1b7zYuAt
CPRRPEzEI5LlBXrBvHPll1w2I6VnpLxIEKZarCRg3SwRF3Nila6cXiXY2wLXeBXB
5iW1I2lnlJdFZ3AZ7yBQ5wQVbb5jG9Cezyz5vAA6bM1Io/F1f8Hs0ggGB8Ct0W/E
bmzmb0hZhwx8vwJcUREyARu4d8cadb4TJoUaDyfUGlH4IjWJMz47/aaUD5mmGh0z
VqRaeJgVAKsw1YtlQY/gYq2hMAXYn7pppW1/2EZxqjSdd8eJAoIBAQC3JptTgNIO
IkusjMAMAFe2U64xzA7Z4yUK5kLuGWVJ/a1Jm2KWu5bwEbPM8WTTL6Vr57deCDjR
Rcz7vs9/XMLZ6A3o1W4dDD3W9wexagtKpKgtJaCxltpfpqKqRe92CMh5lz8GEZBg
UBcS9nsDMA83M3e9ZrcuuyNwCtA3qtSo68kMZkm9jNU/LSZGLTTW4XqyNOlU23Sx
CrmyvrHX3wyIUVjCLVeyKBdM5YV05HpIqClvfODtvrAMsTrUEhFk2QKah+dq1u4b
IZaNvsNqS/wZ2y+TUu4Ctsdaoso5YHTea960QyjVNMXnCmCGFrwOA6fmtpgfpWXm
ee7AGDtYQgxXAoIBAATAM1NYg9BeCrZuIKbubZJPfJrEOEK1kC2bxMImnQk3LCuz
Gpffz6EOqpczX1cRgVzNSKEB/Z572mULburkbSbOOvbFyMaR7eLTBcuGTcgl0tMs
0JmqyvP+YeOQ5YAMzCfg2NAEMxogrqfh/MhY90HvoSPZvJ+SWDqSfE8J/w57SFQ0
TGA8y4qO2P2Iobut1aOQXgWTY8Ra7tZs+UkbJt5InkXXjIA3Ze+k0yiKONYS+Ge8
kDnGZ1OmPvQeunpLrsGaw1TGrImymIaCJi3S/dO28VeLynfe9P+707oB5ciEzWSP
o2t7S8aLA8GACfGZoEktTbRvOGCkst6pypdu1aECggEAO/j0W7+PCPnJ9dKRAF0M
W7PDEqNTKZ3rf0ovGHBQbo4WtEehXOJIZowlaDKTZWPwswjJTo06raxBlx3ALGBf
naMTCu74g6KCjWWOq1WiJOsN9tqfaAeRskiKc187Lldp7gbMqFwP/rm7FIaJeV2/
XcAIsYh062R0Ejg4PkI+KKIsz1afRuZa3bkXE1uyNbrXxor07Mh/yYlNjW5MJffv
zqN0gQD/+mKOXqu5q7E1KZ2HE+68aJ1MYJuYO+E+uNsmsxtVd/KxPUkeV4Pj0WbY
Qk83oPJC5bicRt2PgoJHQp3n6vci483IEAOh38aKBbzEuhOIdLRgTbwXpedJZ3kZ
OQKCAQB+DGgzBdSqFmuHdDWelmEWaryjFDP27aSbqucR/GiCvxfnQ7bhFdwVqIMw
VclorEc5oienfjChdkiCsrN9QJ5L2f40r7Hv40E7gv/tdOc8QN/lwb2hs9wsx+p1
h7tNtayBz50ziH0zEEBuMTn1OHBt7xVq/r7tiK/Gu5ycanapr1MuxBb04zd8B0EJ
0BZfnuARBnCHMrMB0J1XmRVBv/aYLqyMj2SXiqD7MwqK0K/TUfD/aiyN72l968jm
lgTusCmk9wQqQvFXdwLhVx3NAC2pgHf9mUTlabsvNI8Td5xDvmqKgNniYNh3JXbG
2u2XDXcn+4MZJRoSsUaVPZYG4mTY
-----END PRIVATE KEY-----';

const MASTER_KEY = 'WHMCSNULLED_MASTER001';
const LAGOM_PRODUCT_IDS = ['6', '18', '19'];
const ALL_EXTENSIONS = 'Client Notifications,Promotion Manager,Website Builder,Email Template,Custom Code,Support Hours,Sensitive Data';

const VALID_API_KEYS = [
    'whmcsnulled' => 'prx8fxkifpbPOoVKDiprOI21Bz',
    'whmcspremium' => 'haJG9VhPVECT2jarHFWQgTzr0u',
    'client3' => 'POoG9VVKDiarHFWQgTzr0u',
];

const EXTENSION_PRODUCT_MAP = [
    115 => 'Client Notifications',
    129 => 'Sensitive Data',
    67 => 'Promotion Manager',
    6 => 'Promotion Manager,Email Template',
    19 => 'Promotion Manager',
    122 => 'Website Builder',
    97 => 'Email Template',
    123 => 'Custom Code',
    124 => 'Support Hours',
];

// ============================================
// HELPER FUNCTIONS
// ============================================

function getPrivateKey()
{
    $key = openssl_pkey_get_private(PRIVATE_KEY);
    if (!$key) {
        throw new Exception('Private key loading failed.');
    }
    return $key;
}

function encode($data)
{
    $key = getPrivateKey();
    $dataString = json_encode($data);
    $chunks = str_split($dataString, 117);

    $encryptedData = '';
    foreach ($chunks as $chunk) {
        openssl_private_encrypt($chunk, $encryptedChunk, $key);
        $encryptedData .= $encryptedChunk;
    }

    return base64_encode($encryptedData);
}

function encodeString($string)
{
    try {
        $key = getPrivateKey();
        openssl_private_encrypt($string, $encrypted, $key);
        return base64_encode($encrypted);
    } catch (Exception $e) {
        return '';
    }
}

function sendResponse($data, $httpCode = 200)
{
    http_response_code($httpCode);
    echo encode($data);
    exit;
}

function sendError($message, $status = 'Invalid', $httpCode = 200, $extra = [])
{
    $response = array_merge(['status' => $status, 'message' => $message], $extra);
    sendResponse($response, $httpCode);
}

function isMasterKey($licenseKey)
{
    return $licenseKey === MASTER_KEY;
}

function isLagomProduct($productId)
{
    return in_array($productId, LAGOM_PRODUCT_IDS);
}

// ============================================
// DOMAIN FUNCTIONS
// ============================================

function getMainDomain($domain)
{
    $domain = strtolower($domain);

    if (filter_var($domain, FILTER_VALIDATE_IP)) {
        return $domain;
    }

    $arr = array_values(array_filter(explode('.', $domain, 4), fn($v) => $v !== 'www'));

    if (count($arr) <= 2) {
        if (count($arr) === 2) {
            $first = array_shift($arr);
            if (strpos(join('.', $arr), '.') === false && !in_array($arr[0], ['localhost', 'test', 'invalid'])) {
                array_unshift($arr, $first);
            }
        }
        return join('.', $arr);
    }

    $count = count($arr);
    $lastPart = explode('.', $count === 4 ? $arr[3] : $arr[2]);
    $tlds = ['aero', 'arpa', 'asia', 'biz', 'cat', 'com', 'coop', 'edu', 'gov', 'info', 'jobs', 'mil', 'mobi', 'museum', 'name', 'net', 'org', 'post', 'pro', 'tel', 'travel', 'xxx'];

    if (count($lastPart) === 2) {
        array_shift($arr);
        if ($count === 4) array_shift($arr);
    } elseif (count($lastPart) === 1) {
        $removed = array_shift($arr);
        if (strlen($lastPart[0]) === 2 && $count === 3) {
            array_unshift($arr, $removed);
        } elseif (count($arr) > 2 && in_array($lastPart[0], $tlds)) {
            array_shift($arr);
        }
    } else {
        for ($i = count($lastPart); $i > 1; $i--) {
            array_shift($arr);
        }
    }

    return join('.', $arr);
}

function buildDomainList($domain, $ip)
{
    $clean = str_replace('www.', '', $domain);
    return implode(',', [$clean, 'www.' . $clean, getMainDomain($domain), $ip]);
}

function cleanDomain($domain)
{
    return str_replace('www.', '', $domain);
}

// ============================================
// DATABASE FUNCTIONS
// ============================================

function logAction($license, $domain, $path, $ip, $message, $licenseCode = null)
{
    $db = getDatabaseConnection();
    $finalLicenseCode = $license['license_key'] ?? $licenseCode;

    $check = $db->prepare("
        SELECT id FROM license_logs 
        WHERE license_code = :license_code AND domain = :domain AND path = :path AND ip = :ip AND DATE(created_at) = CURDATE() 
        LIMIT 1
    ");
    $check->execute([
        'license_code' => $finalLicenseCode,
        'domain' => $domain,
        'path' => $path,
        'ip' => $ip
    ]);

    $existing = $check->fetch(PDO::FETCH_ASSOC);

    if ($existing) {
        $db->prepare("UPDATE license_logs SET updated_at = NOW(), message = :message WHERE id = :id")
            ->execute(['message' => $message, 'id' => $existing['id']]);
    } else {
        $db->prepare("
            INSERT INTO license_logs (license_id, license_code, user_id, product_id, domain, ip, path, message, created_at, updated_at)
            VALUES (:license_id, :license_code, :user_id, :product_id, :domain, :ip, :path, :message, NOW(), NOW())
        ")->execute([
            'license_id' => $license['id'] ?? null,
            'license_code' => $finalLicenseCode,
            'user_id' => $license['user_id'] ?? null,
            'product_id' => $license['product_id'] ?? null,
            'domain' => $domain ?? '',
            'ip' => $ip ?? '',
            'path' => $path ?? '',
            'message' => $message ?? ''
        ]);
    }
}

function isBlocked($domain, $ip)
{
    $db = getDatabaseConnection();
    $mainDomain = getMainDomain($domain);

    $query = $db->prepare("SELECT 1 FROM blocked_domains_ips WHERE domain = :domain OR ip = :ip LIMIT 1");
    $query->execute(['domain' => $mainDomain, 'ip' => $ip]);

    return (bool)$query->fetch();
}

function findLicense($licenseKey, $productId)
{
    $db = getDatabaseConnection();

    if (isMasterKey($licenseKey)) {
        $query = $db->prepare("SELECT * FROM licenses WHERE license_key = :license_key");
        $query->execute(['license_key' => $licenseKey]);
    } elseif (isLagomProduct($productId)) {
        $query = $db->prepare("SELECT * FROM licenses WHERE license_key = :license_key AND product_id IN (6, 18, 19)");
        $query->execute(['license_key' => $licenseKey]);
    } else {
        $query = $db->prepare("SELECT * FROM licenses WHERE license_key = :license_key AND product_id = :product_id");
        $query->execute(['license_key' => $licenseKey, 'product_id' => $productId]);
    }

    return $query->fetch(PDO::FETCH_ASSOC);
}

function updateLastAccess($licenseId)
{
    $db = getDatabaseConnection();
    $db->prepare("UPDATE licenses SET last_access = NOW() WHERE id = :id")->execute(['id' => $licenseId]);
}

function reissueLicense($license, $domain, $ip, $directory)
{
    $db = getDatabaseConnection();
    $cleanDomain = cleanDomain($domain);
    $validDomain = $cleanDomain . ',www.' . $cleanDomain;

    $db->prepare("
        UPDATE licenses SET validdomain = :validdomain, validip = :validip, validdirectory = :validdirectory, status = 'Active' WHERE id = :id
    ")->execute([
        'validdomain' => $validDomain,
        'validip' => $ip,
        'validdirectory' => $directory,
        'id' => $license['id']
    ]);

    return ['validdomain' => $validDomain, 'validip' => $ip, 'validdirectory' => $directory];
}

// ============================================
// VALIDATION FUNCTIONS
// ============================================

function validateInput($data)
{
    $errors = [];

    if (empty($data['licensekey'])) {
        $errors[] = "License key is required.";
    }

    if (empty($data['domain'])) {
        $errors[] = "Invalid domain format.";
    } else {
        $domain = $data['domain'];
        if (strpos($domain, '${') !== false || strpos($domain, '$') !== false || preg_match('/[<>"\'\{\}]/', $domain)) {
            $errors[] = "Invalid domain format - special characters not allowed.";
        }
        if (!preg_match('/^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$/', $domain)) {
            $errors[] = "Invalid domain format.";
        }
    }

    if (empty($data['ip']) || !filter_var($data['ip'], FILTER_VALIDATE_IP)) {
        $errors[] = "Invalid IP address.";
    }

    if (empty($data['dir'])) {
        $errors[] = "Directory is required.";
    }

    if (empty($data['product_id'])) {
        $errors[] = "Product ID is required.";
    }

    return $errors;
}

function checkLicenseValidity($license, $isReseller = false)
{
    // Check expiration
    if (!empty($license['expires_at']) && strtotime($license['expires_at']) < time()) {
        return ['valid' => false, 'status' => 'Expired', 'message' => 'License Expired. Please contact support.'];
    }

    // For reseller: accept Active and Reissued
    if ($isReseller) {
        if (in_array($license['status'], ['Expired', 'Inactive', 'Suspended'])) {
            return ['valid' => false, 'status' => $license['status'], 'message' => "License {$license['status']}. Please contact support."];
        }
    } else {
        // For non-reseller: only accept Active
        if ($license['status'] !== 'Active') {
            return ['valid' => false, 'status' => $license['status'], 'message' => "License {$license['status']}. Please contact support."];
        }
    }

    return ['valid' => true];
}

function validateResellerAccess($license, $domain, $ip, $directory)
{
    $validDomains = array_map('trim', explode(',', $license['validdomain']));
    $validIps = array_map('trim', explode(',', $license['validip']));
    $validDirs = array_map('trim', explode(',', $license['validdirectory']));

    if (!in_array($domain, $validDomains)) {
        return ['valid' => false, 'field' => 'Domain'];
    }
    if (!in_array($ip, $validIps)) {
        return ['valid' => false, 'field' => 'IP'];
    }
    if (!in_array($directory, $validDirs)) {
        return ['valid' => false, 'field' => 'Directory'];
    }

    return ['valid' => true];
}

// ============================================
// EXTENSION FUNCTIONS
// ============================================

function getExtensions($userId)
{
    $db = getDatabaseConnection();
    $extensions = [];

    $query = $db->prepare("SELECT product_id FROM licenses WHERE user_id = :user_id AND status = 'Active'");
    $query->execute(['user_id' => $userId]);
    $activeProducts = $query->fetchAll(PDO::FETCH_COLUMN);

    $addedExtensions = [];
    foreach ($activeProducts as $productId) {
        if (isset(EXTENSION_PRODUCT_MAP[$productId])) {
            foreach (explode(',', EXTENSION_PRODUCT_MAP[$productId]) as $ext) {
                $ext = trim($ext);
                if (!in_array($ext, $addedExtensions)) {
                    $extensions[] = $ext;
                    $addedExtensions[] = $ext;
                }
            }
        }
    }

    return implode(',', $extensions);
}

// ============================================
// RESPONSE BUILDERS
// ============================================

function buildBaseResponse($license, $validDomain, $validIp, $validDirectory, $productId)
{
    $durationText = LicenseHelpers::getDurationDescription($license['duration_months'] ?? 0);

    $response = [
        'license_key' => $license['license_key'],
        'status' => 'Active',
        'validdomain' => $validDomain,
        'validip' => $validIp,
        'validdirectory' => $validDirectory,
        'checkdate' => time(),
        'last_access' => $license['last_access'],
        'expires_at' => $license['expires_at'],
        'regdate' => $license['created_at'] ?? date('Y-m-d H:i:s'),
        'registeredname' => $license['owner'] ?? 'WHMCSNULLED.COM',
        'email' => $license['email_support'] ?? '[email protected]',
        'valid_until_hard' => strtotime('+1 days'),
        'valid_until_soft' => strtotime('+3 days'),
        'duration' => $license['duration_months'] ?? 0,
        'duration_text' => $durationText,
        'billingcycle' => $durationText,
        'nextduedate' => $license['expires_at'] ?? date('Y-m-d', strtotime('+1 year')),
    ];

    // Add extensions for Lagom products
    if (isLagomProduct($productId)) {
        $response['extensions'] = isMasterKey($license['license_key']) 
            ? ALL_EXTENSIONS 
            : getExtensions($license['user_id']);
    }

    return $response;
}

function buildLagomResponse($license, $validDomain, $validIp, $validDirectory, $version, $productId)
{
    $currentDate = date('Y-m-d');
    $durationText = LicenseHelpers::getDurationDescription($license['duration_months'] ?? 0);
    $nextDueDate = $license['expires_at'] ?? date('Y-m-d', strtotime('+1 year'));

    $response = [
        // Required fields for validateDetails
        'status' => 'Active',
        'service_status' => 'Active',
        'license_status' => 'Active',
        'nextduedate' => $nextDueDate,
        'version' => $version,
        'regdate' => $license['created_at'] ?? $currentDate,
        'first_payment_amount' => '$149.00',
        'recuring_amount' => '$149.00',
        'payment_method' => 'PayPal',

        // Domain/IP validation fields
        'validdomain' => $validDomain,
        'validip' => $validIp,
        'validdirectory' => $validDirectory,

        // Additional fields
        'license_key' => $license['license_key'],
        'checkdate' => time(),
        'last_access' => $license['last_access'] ?? $currentDate,
        'expires_at' => $license['expires_at'],
        'registeredname' => $license['owner'] ?? 'WHMCSNULLED.COM',
        'email' => $license['email_support'] ?? '[email protected]',
        'fullversion' => 'Lagom ' . $version,
        'billingcycle' => $durationText,
        'duration' => $license['duration_months'] ?? 0,
        'duration_text' => $durationText,

        // Encrypted date for integrity check
        'encryptedCurrentClientDate' => encodeString($currentDate),

        // Extensions
        'extensions' => isMasterKey($license['license_key']) 
            ? ALL_EXTENSIONS 
            : getExtensions($license['user_id'])
    ];

    return $response;
}

function buildResellerResponse($license, $productId)
{
    $response = buildBaseResponse(
        $license,
        $license['validdomain'],
        $license['validip'],
        $license['validdirectory'],
        $productId
    );

    return $response;
}

function buildStandardResponse($license, $domain, $ip, $directory, $productId)
{
    $cleanDomain = cleanDomain($domain);
    $validDomain = $cleanDomain . ',www.' . $cleanDomain . ',' . getMainDomain($domain) . ',' . $ip;

    return buildBaseResponse($license, $validDomain, $ip, $directory, $productId);
}

// ============================================
// MAIN HANDLER
// ============================================

function handleRequest()
{
    // Check method
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        http_response_code(404);
        echo json_encode(['error' => 'Page not found.']);
        exit;
    }

    // Parse input
    $request = json_decode(file_get_contents('php://input'), true);
    if (!$request) {
        http_response_code(400);
        echo json_encode(['status' => 'Invalid', 'message' => 'Invalid JSON input.']);
        exit;
    }

    // Validate API key
    if (!isset($request['api_key']) || !in_array($request['api_key'], VALID_API_KEYS)) {
        http_response_code(401);
        echo json_encode(['status' => 'Unauthorized', 'message' => 'Invalid API Key.']);
        exit;
    }

    // Validate input
    $errors = validateInput($request);
    if (!empty($errors)) {
        sendError(implode(', ', $errors));
    }

    // Extract params
    $licenseKey = $request['licensekey'];
    $domain = $request['domain'];
    $ip = $request['ip'];
    $directory = $request['dir'];
    $productId = $request['product_id'];
    $version = $request['version'] ?? '1.0.0';

    $domainList = buildDomainList($domain, $ip);

    // Check blocked
    if (isBlocked($domain, $ip)) {
        logAction(null, $domain, $directory, $ip, 'Access denied - Domain/IP is blocked', $licenseKey);
        http_response_code(403);
        sendError('Domain or IP is blocked due to policy violation.', 'Blocked', 403);
    }

    // Find license
    $license = findLicense($licenseKey, $productId);
    if (!$license) {
        logAction(null, $domainList, $directory, $ip, 'License key is incorrect', $licenseKey);
        sendError('License key is incorrect. Please contact support.');
    }

    // Master key - always valid
    if (isMasterKey($licenseKey)) {
        $response = isLagomProduct($productId)
            ? buildLagomResponse($license, $domain . ',www.' . $domain, $ip, $directory, $version, $productId)
            : buildStandardResponse($license, $domain, $ip, $directory, $productId);

        logAction($license, $domain, $directory, $ip, 'Admin License Active', $licenseKey);
        sendResponse($response);
    }

    // ============================================
    // XỬ LÝ LAGOM THEME (Product ID 18, 6, 19)
    // ============================================
    if (isLagomProduct($productId)) {
        
        // Lagom + Reseller
        if ($license['is_reseller'] == 1) {
            // Check validity - Reseller accept Active và Reissued
            $validity = checkLicenseValidity($license, true);
            if (!$validity['valid']) {
                logAction($license, $domainList, $directory, $ip, "License {$validity['status']}", $licenseKey);
                sendError($validity['message'], 'Invalid', 200, [
                    'service_status' => $validity['status'], 
                    'license_status' => $validity['status']
                ]);
            }

            // Handle Reissued status
            if ($license['status'] === 'Reissued') {
                $reissued = reissueLicense($license, $domain, $ip, $directory);
                $license['validdomain'] = $reissued['validdomain'];
                $license['validip'] = $reissued['validip'];
                $license['validdirectory'] = $reissued['validdirectory'];
                $license['status'] = 'Active';

                if ($license['reissues'] > 0) {
                    logAction($license, $domain, $directory, $ip, 'License Reissued', $licenseKey);
                }

                $response = buildLagomResponse($license, $reissued['validdomain'], $reissued['validip'], $reissued['validdirectory'], $version, $productId);
                logAction($license, $domain, $directory, $ip, 'License Active', $licenseKey);
                sendResponse($response);
            }

            // Active status - validate access
            $accessCheck = validateResellerAccess($license, $domain, $ip, $directory);
            if (!$accessCheck['valid']) {
                logAction(null, $domain, $directory, $ip, "{$accessCheck['field']} Invalid", $licenseKey);
                sendError("{$accessCheck['field']} Invalid. Please contact support.", 'Invalid', 200, [
                    'service_status' => 'Invalid',
                    'license_status' => 'Invalid'
                ]);
            }

            $response = buildLagomResponse($license, $license['validdomain'], $license['validip'], $license['validdirectory'], $version, $productId);
            logAction($license, $domain, $directory, $ip, 'License Active', $licenseKey);
            sendResponse($response);
        }

        // Lagom + Non-reseller
        $validity = checkLicenseValidity($license, false);
        if (!$validity['valid']) {
            logAction($license, $domainList, $directory, $ip, "License {$validity['status']}", $licenseKey);
            sendError($validity['message'], 'Invalid', 200, [
                'service_status' => $validity['status'], 
                'license_status' => $validity['status']
            ]);
        }

        updateLastAccess($license['id']);

        $cleanDomain = cleanDomain($domain);
        $validDomain = $cleanDomain . ',www.' . $cleanDomain;

        $response = buildLagomResponse($license, $validDomain, $ip, $directory, $version, $productId);
        logAction($license, $domain, $directory, $ip, 'License Active', $licenseKey);
        sendResponse($response);
    }

    // ============================================
    // XỬ LÝ RESELLER
    // ============================================
    if ($license['is_reseller'] == 1) {
        // Check validity - Reseller accept Active và Reissued
        $validity = checkLicenseValidity($license, true);
        if (!$validity['valid']) {
            logAction($license, $domainList, $directory, $ip, "License {$validity['status']}", $licenseKey);
            sendError($validity['message']);
        }

        // Handle Reissued status
        if ($license['status'] === 'Reissued') {
            $reissued = reissueLicense($license, $domain, $ip, $directory);
            $license['validdomain'] = $reissued['validdomain'];
            $license['validip'] = $reissued['validip'];
            $license['validdirectory'] = $reissued['validdirectory'];
            $license['status'] = 'Active';

            if ($license['reissues'] > 0) {
                logAction($license, $domain, $directory, $ip, 'License Reissued', $licenseKey);
            }

            $response = buildResellerResponse($license, $productId);
            logAction($license, $domain, $directory, $ip, 'License Active', $licenseKey);
            sendResponse($response);
        }

        // Active status - validate access
        $accessCheck = validateResellerAccess($license, $domain, $ip, $directory);
        if (!$accessCheck['valid']) {
            logAction(null, $domain, $directory, $ip, "{$accessCheck['field']} Invalid", $licenseKey);
            sendError("{$accessCheck['field']} Invalid. Please contact support.");
        }

        $response = buildResellerResponse($license, $productId);
        logAction($license, $domain, $directory, $ip, 'License Active', $licenseKey);
        sendResponse($response);
    }

    // ============================================
    // XỬ LÝ STANDARD PRODUCTS
    // ============================================
    
    // Check validity - Standard chỉ accept Active
    $validity = checkLicenseValidity($license, false);
    if (!$validity['valid']) {
        logAction($license, $domain, $directory, $ip, 'License Suspended', $licenseKey);
        sendError('License Suspended. Please contact support.');
    }

    updateLastAccess($license['id']);
    $response = buildStandardResponse($license, $domain, $ip, $directory, $productId);
    logAction($license, $domain, $directory, $ip, 'License Active', $licenseKey);
    sendResponse($response);
}

// Run
handleRequest();

What's New {#whats-new}

  • Complete Server Management: Full control over your VPS and dedicated servers
  • Domain Management: Create and manage unlimited domains with automatic Nginx configuration
  • SSL Certificates: One-click Let's Encrypt SSL with automatic renewal
  • Database Management: MySQL/MariaDB with phpMyAdmin integration
  • Automated Backups: Schedule backups to local or S3-compatible storage

Getting Started {#getting-started}

Install WisPanel with a single command:

curl -sSL https://wispanel.com/install.sh | bash

Supported Systems {#supported-systems}

  • Ubuntu 20.04/22.04/24.04 LTS
  • Debian 11/12
  • AlmaLinux 8/9

Thank you to everyone who participated in our beta testing program!

Share this article

Related Articles

Article Info

Published
Dec 20, 2025
Updated
Feb 3, 2026
Views
328
Reading time
1 min

Stay Updated

Get notified about new posts.