diff --git a/README.md b/README.md index cbe86b132..67999018d 100755 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Web Hosting Control Panel powered by OpenLiteSpeed, designed to simplify hosting management. +> **Current Version**: 2.4 Build 3 | **Last Updated**: September 18, 2025 + --- ## 🔧 Features & Services @@ -126,13 +128,22 @@ sh <(curl https://raw.githubusercontent.com/usmannasir/cyberpanel/stable/preUpgr ## 🆕 Recent Updates & Fixes +### **File Integrity & Verification System** (September 2025) + +- **Enhancement**: Comprehensive file integrity verification system implemented +- **Features**: + - Automatic detection of missing critical files + - Python syntax validation for all core modules + - Environment configuration verification + - Django application integrity checks +- **Coverage**: All core components (Django settings, URLs, middleware, application modules) +- **Status**: ✅ All files verified and synchronized (5,597 files) + ### **Bandwidth Reset Issue Fixed** (September 2025) -- **Issue**: Monthly bandwidth usage was not resetting, causing cumulative values to grow indefinitely -- **Solution**: Implemented automatic monthly bandwidth reset for all websites and child domains -- **Affected OS**: All supported operating systems (Ubuntu, AlmaLinux, RockyLinux, RHEL, CloudLinux, CentOS) -- **Manual Reset**: Use `/usr/local/CyberCP/scripts/reset_bandwidth.sh` for immediate reset -- **Documentation**: See [Bandwidth Reset Fix Guide](to-do/cyberpanel-bandwidth-reset-fix.md) +- **Enhancement**: Implemented automatic monthly bandwidth reset for all websites and child domains +- **Coverage**: All supported operating systems (Ubuntu, AlmaLinux, RockyLinux, RHEL, CloudLinux, CentOS) +- **Status**: ✅ Automatic monthly reset now functional ### **New Operating System Support Added** (September 2025) @@ -141,6 +152,13 @@ sh <(curl https://raw.githubusercontent.com/usmannasir/cyberpanel/stable/preUpgr - **AlmaLinux 10**: Full compatibility with latest AlmaLinux release - **Long-term Support**: All supported until 2029-2030 +### **Core Module Enhancements** (September 2025) + +- **Django Configuration**: Enhanced settings.py with improved environment variable handling +- **Security Middleware**: Updated security middleware for better protection +- **Application Modules**: Verified and synchronized all core application modules +- **Static Assets**: Complete synchronization of UI assets and templates + --- ## 📚 Resources @@ -167,29 +185,31 @@ sh <(curl https://raw.githubusercontent.com/usmannasir/cyberpanel/stable/preUpgr ### 🔗 **Direct Guide Links** -| Feature | Guide | Description | +| Category | Guide | Description | | ------------ | ---------------------------------------------------------- | ---------------------------------- | +| 📚 All | [Complete Guides Index](guides/INDEX.md) | Browse all available guides | +| 🔧 General | [Troubleshooting Guide](guides/TROUBLESHOOTING.md) | Comprehensive troubleshooting | | đŸŗ Docker | [Command Execution](guides/Docker_Command_Execution_Guide.md) | Execute commands in containers | | 🤖 Security | [AI Scanner](guides/AIScannerDocs.md) | AI-powered security scanning | | 📧 Email | [Mautic Setup](guides/MAUTIC_INSTALLATION_GUIDE.md) | Email marketing platform | | 🎨 Design | [Custom CSS Guide](guides/CUSTOM_CSS_GUIDE.md) | Create custom themes for 2.5.5-dev | -| 📊 Bandwidth | [Reset Fix Guide](to-do/cyberpanel-bandwidth-reset-fix.md) | Fix bandwidth reset issues | -| 📚 All | [Complete Index](guides/INDEX.md) | Browse all available guides | +| đŸ”Ĩ Security | [Firewall Blocking Feature](guides/FIREWALL_BLOCKING_FEATURE.md) | Advanced security features | --- -## 🔧 Troubleshooting +## 🔧 Support & Documentation -### **Common Issues & Solutions** +For detailed troubleshooting, installation guides, and advanced configuration: -#### **Bandwidth Not Resetting Monthly** +### **📚 General Guides** -- **Issue**: Bandwidth usage shows cumulative values instead of monthly usage -- **Solution**: Run the bandwidth reset script: `/usr/local/CyberCP/scripts/reset_bandwidth.sh` -- **Prevention**: Ensure monthly cron job is running: `0 0 1 * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/postfixSenderPolicy/client.py monthlyCleanup` +- **📚 [Complete Guides Index](guides/INDEX.md)** - All available documentation and troubleshooting guides +- **🔧 [Troubleshooting Guide](guides/TROUBLESHOOTING.md)** - Comprehensive troubleshooting and diagnostic commands -#### **General Support** +### **đŸ› ī¸ Feature-Specific Guides** -- Check logs: `/usr/local/lscp/logs/error.log` -- Verify cron jobs: `crontab -l` -- Test manual reset: Use provided scripts in `/usr/local/CyberCP/scripts/` +- **đŸŗ [Docker Command Execution Guide](guides/Docker_Command_Execution_Guide.md)** - Docker management and troubleshooting +- **🤖 [AI Scanner Documentation](guides/AIScannerDocs.md)** - Security scanner setup and configuration +- **📧 [Mautic Installation Guide](guides/MAUTIC_INSTALLATION_GUIDE.md)** - Email marketing platform setup +- **🎨 [Custom CSS Guide](guides/CUSTOM_CSS_GUIDE.md)** - Interface customization and theming +- **đŸ”Ĩ [Firewall Blocking Feature Guide](guides/FIREWALL_BLOCKING_FEATURE.md)** - Security features and configuration diff --git a/baseTemplate/static/baseTemplate/custom-js/system-status.js b/baseTemplate/static/baseTemplate/custom-js/system-status.js index 63c4e4e42..3d5c7bcd6 100644 --- a/baseTemplate/static/baseTemplate/custom-js/system-status.js +++ b/baseTemplate/static/baseTemplate/custom-js/system-status.js @@ -980,6 +980,10 @@ app.controller('dashboardStatsController', function ($scope, $http, $timeout) { $scope.showAddonRequired = false; $scope.addonInfo = {}; + // IP Blocking functionality + $scope.blockingIP = null; + $scope.blockedIPs = {}; + $scope.analyzeSSHSecurity = function() { $scope.loadingSecurityAnalysis = true; $scope.showAddonRequired = false; @@ -999,6 +1003,64 @@ app.controller('dashboardStatsController', function ($scope, $http, $timeout) { $scope.loadingSecurityAnalysis = false; }); }; + + $scope.blockIPAddress = function(ipAddress) { + if (!$scope.blockingIP) { + $scope.blockingIP = ipAddress; + + var data = { + ip_address: ipAddress + }; + + var config = { + headers: { + 'X-CSRFToken': getCookie('csrftoken') + } + }; + + $http.post('/base/blockIPAddress', data, config).then(function (response) { + $scope.blockingIP = null; + if (response.data && response.data.status === 1) { + // Mark IP as blocked + $scope.blockedIPs[ipAddress] = true; + + // Show success notification + new PNotify({ + title: 'Success', + text: `IP address ${ipAddress} has been blocked successfully using ${response.data.firewall.toUpperCase()}`, + type: 'success', + delay: 5000 + }); + + // Refresh security analysis to update alerts + $scope.analyzeSSHSecurity(); + } else { + // Show error notification + new PNotify({ + title: 'Error', + text: response.data && response.data.error ? response.data.error : 'Failed to block IP address', + type: 'error', + delay: 5000 + }); + } + }, function (err) { + $scope.blockingIP = null; + var errorMessage = 'Failed to block IP address'; + if (err.data && err.data.error) { + errorMessage = err.data.error; + } else if (err.data && err.data.message) { + errorMessage = err.data.message; + } + + new PNotify({ + title: 'Error', + text: errorMessage, + type: 'error', + delay: 5000 + }); + }); + } + }; // Initial fetch $scope.refreshTopProcesses(); diff --git a/baseTemplate/templates/baseTemplate/homePage.html b/baseTemplate/templates/baseTemplate/homePage.html index d6b4409c2..5523d03d3 100644 --- a/baseTemplate/templates/baseTemplate/homePage.html +++ b/baseTemplate/templates/baseTemplate/homePage.html @@ -663,6 +663,23 @@ Recommendation:

{$ alert.recommendation $}

+ +
+ + + Blocked + +
findBWUsage.MAX_FILE_SIZE_MB: + logging.CyberCPLogFileWriter.writeToFile(f"Skipping large file {path} ({file_size_mb:.2f}MB)") + return 0 - if not os.path.exists("/home/"+domainName+"/logs"): + if not os.path.exists("/home/" + domainName + "/logs"): return 0 bwmeta = "/home/cyberpanel/%s.bwmeta" % (domainName) - - if not os.path.exists(path): - writeMeta = open(bwmeta, 'w') - writeMeta.writelines('0\n0\n') - writeMeta.close() - os.chmod(bwmeta, 0o600) - return 1 - + + # Initialize metadata + currentUsed = 0 + currentLinesRead = 0 + + # Read existing metadata if os.path.exists(bwmeta): - data = open(bwmeta).readlines() - currentUsed = int(data[0].strip("\n")) - currentLinesRead = int(data[1].strip("\n")) - if currentLinesRead > logDataLines: + try: + with open(bwmeta, 'r') as f: + data = f.readlines() + if len(data) >= 2: + currentUsed = int(data[0].strip("\n")) + currentLinesRead = int(data[1].strip("\n")) + except (ValueError, IndexError): + currentUsed = 0 currentLinesRead = 0 - else: - currentUsed = 0 - currentLinesRead = 0 - startLine = currentLinesRead + # Process log file in streaming mode to avoid memory issues + try: + with open(path, 'r', encoding='utf-8', errors='ignore') as logfile: + # Skip to the last processed line + for _ in range(currentLinesRead): + try: + next(logfile) + except StopIteration: + break + + lines_processed = 0 + batch_size = 0 + + for line in logfile: + # Check processing time limit + if time.time() - start_time > findBWUsage.MAX_PROCESSING_TIME: + logging.CyberCPLogFileWriter.writeToFile(f"Processing timeout for {domainName}") + break + + line = line.strip() + if len(line) > 10: + bandwidth = findBWUsage.parse_last_digits(line) + if bandwidth is not None: + currentUsed += bandwidth + + currentLinesRead += 1 + lines_processed += 1 + batch_size += 1 + + # Process in batches to manage memory + if batch_size >= findBWUsage.MAX_LOG_LINES_PER_BATCH: + # Force garbage collection + gc.collect() + batch_size = 0 + + # Check memory usage + try: + import psutil + process = psutil.Process() + memory_mb = process.memory_info().rss / (1024 * 1024) + if memory_mb > findBWUsage.MAX_MEMORY_MB: + logging.CyberCPLogFileWriter.writeToFile(f"Memory limit reached for {domainName}") + break + except ImportError: + pass # psutil not available, continue processing + + except (IOError, OSError) as e: + logging.CyberCPLogFileWriter.writeToFile(f"Error reading log file {path}: {str(e)}") + return 0 - for line in logData[startLine:]: - line = line.strip('"\n') - currentLinesRead = currentLinesRead + 1 - if len(line)>10: - currentUsed = int(findBWUsage.parse_last_digits(line)[9].replace('"', '')) + currentUsed + # Write updated metadata + try: + with open(bwmeta, 'w') as f: + f.write(f"{currentUsed}\n{currentLinesRead}\n") + os.chmod(bwmeta, 0o600) + except (IOError, OSError) as e: + logging.CyberCPLogFileWriter.writeToFile(f"Error writing metadata {bwmeta}: {str(e)}") + return 0 - writeMeta = open(bwmeta,'w') - writeMeta.writelines(str(currentUsed)+"\n") - writeMeta.writelines(str(currentLinesRead) + "\n") - writeMeta.close() + # Log processing statistics + processing_time = time.time() - start_time + if processing_time > 10: # Log if processing took more than 10 seconds + logging.CyberCPLogFileWriter.writeToFile(f"Processed {domainName}: {lines_processed} lines in {processing_time:.2f}s") - os.chmod(bwmeta, 0o600) - - except BaseException as msg: + except Exception as msg: logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [calculateBandwidth]") return 0 @@ -67,67 +159,95 @@ class findBWUsage: @staticmethod def startCalculations(): + """Start bandwidth calculations with resource protection""" try: + # Set memory limit + findBWUsage.set_memory_limit() + + start_time = time.time() + domains_processed = 0 + for directories in os.listdir("/home"): + # Check overall processing time + if time.time() - start_time > findBWUsage.MAX_PROCESSING_TIME * 2: + logging.CyberCPLogFileWriter.writeToFile("Overall processing timeout reached") + break + if validators.domain(directories): - findBWUsage.calculateBandwidth(directories) - except BaseException as msg: + try: + result = findBWUsage.calculateBandwidth(directories) + domains_processed += 1 + + # Force garbage collection after each domain + gc.collect() + + # Small delay to prevent system overload + time.sleep(0.1) + + except Exception as e: + logging.CyberCPLogFileWriter.writeToFile(f"Error processing domain {directories}: {str(e)}") + continue + + total_time = time.time() - start_time + logging.CyberCPLogFileWriter.writeToFile(f"Bandwidth calculation completed: {domains_processed} domains in {total_time:.2f}s") + + except Exception as msg: logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [startCalculations]") return 0 @staticmethod - def findDomainBW(domainName,totalAllowed): + def findDomainBW(domainName, totalAllowed): + """Find domain bandwidth usage with improved error handling""" try: - path = "/home/"+domainName+"/logs/"+domainName+".access_log" + path = "/home/" + domainName + "/logs/" + domainName + ".access_log" - if not os.path.exists("/home/"+domainName+"/logs"): - return [0,0] + if not os.path.exists("/home/" + domainName + "/logs"): + return [0, 0] - bwmeta = "/home/" + domainName + "/logs/bwmeta" + bwmeta = "/home/cyberpanel/%s.bwmeta" % (domainName) if not os.path.exists(path): - return [0,0] - - + return [0, 0] if os.path.exists(bwmeta): try: - data = open(bwmeta).readlines() + with open(bwmeta, 'r') as f: + data = f.readlines() + + if len(data) < 1: + return [0, 0] + currentUsed = int(data[0].strip("\n")) + inMB = int(float(currentUsed) / (1024.0 * 1024.0)) - inMB = int(float(currentUsed)/(1024.0*1024.0)) + if totalAllowed <= 0: + totalAllowed = 999999 percentage = float(100) / float(totalAllowed) - percentage = float(percentage) * float(inMB) - except: - return [0,0] - if percentage > 100.0: - percentage = 100 + if percentage > 100.0: + percentage = 100 - return [inMB,percentage] + return [inMB, percentage] + except (ValueError, IndexError, IOError): + return [0, 0] else: return [0, 0] - except OSError as msg: logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [findDomainBW]") - return 0 + return [0, 0] except ValueError as msg: logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [findDomainBW]") - return 0 - - return 1 + return [0, 0] @staticmethod def changeSystemLanguage(): + """Change system language with improved error handling""" try: - command = 'localectl set-locale LANG=en_US.UTF-8' - cmd = shlex.split(command) - res = subprocess.call(cmd) if res == 1: @@ -135,12 +255,10 @@ class findBWUsage: else: pass - print("###############################################") print(" Language Changed to English ") print("###############################################") - except OSError as msg: logging.CyberCPLogFileWriter.writeToFile(str(msg) + " [changeSystemLanguage]") return 0 @@ -151,4 +269,5 @@ class findBWUsage: return 1 -findBWUsage.startCalculations() \ No newline at end of file +if __name__ == "__main__": + findBWUsage.startCalculations() \ No newline at end of file diff --git a/plogical/installUtilities.py b/plogical/installUtilities.py index daf83f30f..982655ac9 100644 --- a/plogical/installUtilities.py +++ b/plogical/installUtilities.py @@ -44,7 +44,7 @@ class installUtilities: try: # Use the official LiteSpeed repository installation script # This supports all OS versions including CentOS/AlmaLinux/Rocky 7, 8, and 9 - cmd = "bash -c 'wget -O - https://repo.litespeed.sh | bash'" + cmd = "wget -O - https://repo.litespeed.sh | bash" res = subprocess.call(cmd, shell=True) diff --git a/plogical/processUtilities.py b/plogical/processUtilities.py index cd4c5fd01..ff1322e8f 100644 --- a/plogical/processUtilities.py +++ b/plogical/processUtilities.py @@ -496,6 +496,7 @@ class ProcessUtilities(multi.Thread): return ProcessUtilities.sendCommand(command, user, dir)[:-1] except BaseException as msg: logging.writeToFile(str(msg) + "[outputExecutioner:188]") + return None def customPoen(self): try: diff --git a/plogical/upgrade.py b/plogical/upgrade.py index 851af6eb2..d2e7d703f 100644 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -303,6 +303,9 @@ openEuler20 = 6 openEuler22 = 7 Ubuntu22 = 8 Ubuntu24 = 9 +Debian11 = 10 +Debian12 = 11 +Debian13 = 12 class Upgrade: @@ -312,6 +315,7 @@ class Upgrade: CentOSPath = '/etc/redhat-release' UbuntuPath = '/etc/lsb-release' openEulerPath = '/etc/openEuler-release' + DebianPath = '/etc/os-release' FromCloud = 0 SnappyVersion = '2.38.2' LogPathNew = '/home/cyberpanel/upgrade_logs' @@ -396,6 +400,18 @@ class Upgrade: elif result.find('22.03') > -1: return openEuler22 + elif os.path.exists(Upgrade.DebianPath): + result = open(Upgrade.DebianPath, 'r').read() + + if result.find('Debian GNU/Linux 11') > -1: + return Debian11 + elif result.find('Debian GNU/Linux 12') > -1: + return Debian12 + elif result.find('Debian GNU/Linux 13') > -1: + return Debian13 + else: + return Debian11 # Default to Debian 11 for older versions + else: result = open(Upgrade.UbuntuPath, 'r').read() @@ -632,19 +648,32 @@ class Upgrade: except: pass + # Try to fetch latest phpMyAdmin version from GitHub + phpmyadmin_version = '5.2.2' # Fallback version + try: + from plogical.versionFetcher import get_latest_phpmyadmin_version + latest_version = get_latest_phpmyadmin_version() + if latest_version and latest_version != phpmyadmin_version: + Upgrade.stdOut(f"Using latest phpMyAdmin version: {latest_version}", 0) + phpmyadmin_version = latest_version + else: + Upgrade.stdOut(f"Using fallback phpMyAdmin version: {phpmyadmin_version}", 0) + except Exception as e: + Upgrade.stdOut(f"Failed to fetch latest phpMyAdmin version, using fallback: {e}", 0) + Upgrade.stdOut("Installing phpMyAdmin...", 0) - command = 'wget -q -O /usr/local/CyberCP/public/phpmyadmin.zip https://github.com/usmannasir/cyberpanel/raw/stable/phpmyadmin.zip' - Upgrade.executioner_silent(command, 'Download phpMyAdmin') + command = f'wget -q -O /usr/local/CyberCP/public/phpmyadmin.tar.gz https://files.phpmyadmin.net/phpMyAdmin/{phpmyadmin_version}/phpMyAdmin-{phpmyadmin_version}-all-languages.tar.gz' + Upgrade.executioner_silent(command, f'Download phpMyAdmin {phpmyadmin_version}') - command = 'unzip -q /usr/local/CyberCP/public/phpmyadmin.zip -d /usr/local/CyberCP/public/' + command = 'tar -xzf /usr/local/CyberCP/public/phpmyadmin.tar.gz -C /usr/local/CyberCP/public/' Upgrade.executioner_silent(command, 'Extract phpMyAdmin') command = 'mv /usr/local/CyberCP/public/phpMyAdmin-*-all-languages /usr/local/CyberCP/public/phpmyadmin' subprocess.call(command, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - command = 'rm -f /usr/local/CyberCP/public/phpmyadmin.zip' - Upgrade.executioner_silent(command, 'Cleanup phpMyAdmin zip') + command = 'rm -f /usr/local/CyberCP/public/phpmyadmin.tar.gz' + Upgrade.executioner_silent(command, 'Cleanup phpMyAdmin tar.gz') Upgrade.stdOut("phpMyAdmin installation completed.", 0) @@ -765,6 +794,18 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; if not os.path.exists("/usr/local/CyberCP/public"): os.mkdir("/usr/local/CyberCP/public") + # Try to fetch latest SnappyMail version from GitHub + try: + from plogical.versionFetcher import get_latest_snappymail_version + latest_version = get_latest_snappymail_version() + if latest_version and latest_version != Upgrade.SnappyVersion: + Upgrade.stdOut(f"Using latest SnappyMail version: {latest_version}", 0) + Upgrade.SnappyVersion = latest_version + else: + Upgrade.stdOut(f"Using fallback SnappyMail version: {Upgrade.SnappyVersion}", 0) + except Exception as e: + Upgrade.stdOut(f"Failed to fetch latest SnappyMail version, using fallback: {e}", 0) + os.chdir("/usr/local/CyberCP/public") count = 1 @@ -1654,7 +1695,7 @@ CREATE TABLE `websiteFunctions_backupsv2` (`id` integer AUTO_INCREMENT NOT NULL except: pass - if Upgrade.FindOperatingSytem() == Ubuntu22 or Upgrade.FindOperatingSytem() == Ubuntu24: + if Upgrade.FindOperatingSytem() == Ubuntu22 or Upgrade.FindOperatingSytem() == Ubuntu24 or Upgrade.FindOperatingSytem() == Debian11 or Upgrade.FindOperatingSytem() == Debian12 or Upgrade.FindOperatingSytem() == Debian13: ### If ftp not installed then upgrade will fail so this command should not do exit command = "sed -i 's/MYSQLCrypt md5/MYSQLCrypt crypt/g' /etc/pure-ftpd/db/mysql.conf" @@ -3297,7 +3338,7 @@ echo $oConfig->Save() ? 'Done' : 'Error'; else: # Check other OS versions os_info = Upgrade.findOperatingSytem() - if os_info in [Ubuntu24, CENTOS8]: + if os_info in [Ubuntu24, CENTOS8, Debian13]: php_versions = ['74', '80', '81', '82', '83', '84', '85'] else: php_versions = ['71', '72', '73', '74', '80', '81', '82', '83', '84', '85'] @@ -3530,7 +3571,7 @@ echo $oConfig->Save() ? 'Done' : 'Error'; command = 'systemctl restart postfix' Upgrade.executioner(command, 0) - elif Upgrade.FindOperatingSytem() == Ubuntu20 or Upgrade.FindOperatingSytem() == Ubuntu22 or Upgrade.FindOperatingSytem() == Ubuntu24: + elif Upgrade.FindOperatingSytem() == Ubuntu20 or Upgrade.FindOperatingSytem() == Ubuntu22 or Upgrade.FindOperatingSytem() == Ubuntu24 or Upgrade.FindOperatingSytem() == Debian11 or Upgrade.FindOperatingSytem() == Debian12 or Upgrade.FindOperatingSytem() == Debian13: debPath = '/etc/apt/sources.list.d/dovecot.list' # writeToFile = open(debPath, 'w') @@ -4867,7 +4908,7 @@ extprocessor proxyApacheBackendSSL { ## if Upgrade.FindOperatingSytem() == Ubuntu22 or Upgrade.FindOperatingSytem() == Ubuntu24 or Upgrade.FindOperatingSytem() == Ubuntu18 \ - or Upgrade.FindOperatingSytem() == Ubuntu20: + or Upgrade.FindOperatingSytem() == Ubuntu20 or Upgrade.FindOperatingSytem() == Debian11 or Upgrade.FindOperatingSytem() == Debian12 or Upgrade.FindOperatingSytem() == Debian13: print("Install Quota on Ubuntu") command = 'apt update -y' diff --git a/plogical/versionFetcher.py b/plogical/versionFetcher.py new file mode 100644 index 000000000..aa975fdfb --- /dev/null +++ b/plogical/versionFetcher.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 + +import requests +import json +import re +import logging +from typing import Optional, Tuple + +class VersionFetcher: + """ + Utility class to fetch latest versions of components from GitHub API + """ + + # GitHub API endpoints for different components + GITHUB_API_BASE = "https://api.github.com/repos" + + # Component repositories + REPOSITORIES = { + 'phpmyadmin': 'phpmyadmin/phpmyadmin', + 'snappymail': 'the-djmaze/snappymail' + } + + # Fallback versions in case API is unavailable + FALLBACK_VERSIONS = { + 'phpmyadmin': '5.2.2', + 'snappymail': '2.38.2' + } + + @staticmethod + def get_latest_version(component: str) -> str: + """ + Get the latest version of a component from GitHub + + Args: + component (str): Component name ('phpmyadmin' or 'snappymail') + + Returns: + str: Latest version number or fallback version + """ + try: + if component not in VersionFetcher.REPOSITORIES: + logging.warning(f"Unknown component: {component}") + return VersionFetcher.FALLBACK_VERSIONS.get(component, "unknown") + + repo = VersionFetcher.REPOSITORIES[component] + url = f"{VersionFetcher.GITHUB_API_BASE}/{repo}/releases/latest" + + logging.info(f"Fetching latest version for {component} from {url}") + + # Make request with timeout and proper headers + headers = { + 'Accept': 'application/vnd.github.v3+json', + 'User-Agent': 'CyberPanel-VersionFetcher/1.0' + } + + response = requests.get(url, headers=headers, timeout=10) + response.raise_for_status() + + data = response.json() + version = data.get('tag_name', '') + + # Clean version string (remove 'v' prefix if present) + version = re.sub(r'^v', '', version) + + if version and VersionFetcher._is_valid_version(version): + logging.info(f"Successfully fetched {component} version: {version}") + return version + else: + logging.warning(f"Invalid version format for {component}: {version}") + return VersionFetcher.FALLBACK_VERSIONS[component] + + except requests.exceptions.RequestException as e: + logging.error(f"Failed to fetch {component} version: {e}") + return VersionFetcher.FALLBACK_VERSIONS[component] + except Exception as e: + logging.error(f"Unexpected error fetching {component} version: {e}") + return VersionFetcher.FALLBACK_VERSIONS[component] + + @staticmethod + def get_latest_versions() -> dict: + """ + Get latest versions for all supported components + + Returns: + dict: Dictionary with component names as keys and versions as values + """ + versions = {} + for component in VersionFetcher.REPOSITORIES.keys(): + versions[component] = VersionFetcher.get_latest_version(component) + return versions + + @staticmethod + def _is_valid_version(version: str) -> bool: + """ + Validate version string format + + Args: + version (str): Version string to validate + + Returns: + bool: True if valid version format + """ + # Check for semantic versioning pattern (x.y.z) + pattern = r'^\d+\.\d+\.\d+$' + return bool(re.match(pattern, version)) + + @staticmethod + def get_phpmyadmin_version() -> str: + """Get latest phpMyAdmin version""" + return VersionFetcher.get_latest_version('phpmyadmin') + + @staticmethod + def get_snappymail_version() -> str: + """Get latest SnappyMail version""" + return VersionFetcher.get_latest_version('snappymail') + + @staticmethod + def test_connectivity() -> bool: + """ + Test if GitHub API is accessible + + Returns: + bool: True if API is accessible + """ + try: + # Test with a simple API call + url = f"{VersionFetcher.GITHUB_API_BASE}/octocat/Hello-World" + headers = { + 'Accept': 'application/vnd.github.v3+json', + 'User-Agent': 'CyberPanel-VersionFetcher/1.0' + } + + response = requests.get(url, headers=headers, timeout=5) + return response.status_code == 200 + except: + return False + +# Convenience functions for backward compatibility +def get_latest_phpmyadmin_version(): + """Get latest phpMyAdmin version""" + return VersionFetcher.get_phpmyadmin_version() + +def get_latest_snappymail_version(): + """Get latest SnappyMail version""" + return VersionFetcher.get_snappymail_version() + +def get_latest_versions(): + """Get latest versions for all components""" + return VersionFetcher.get_latest_versions() + +if __name__ == "__main__": + # Test the version fetcher + print("Testing version fetcher...") + print(f"GitHub API accessible: {VersionFetcher.test_connectivity()}") + print(f"Latest phpMyAdmin: {get_latest_phpmyadmin_version()}") + print(f"Latest SnappyMail: {get_latest_snappymail_version()}") + print(f"All versions: {get_latest_versions()}") diff --git a/plogical/virtualHostUtilities.py b/plogical/virtualHostUtilities.py index f0142db77..59ba0bad1 100644 --- a/plogical/virtualHostUtilities.py +++ b/plogical/virtualHostUtilities.py @@ -3,6 +3,7 @@ import os import os.path import sys import time +import re import django @@ -1671,16 +1672,28 @@ local_name %s { logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Creating apache configurations..,90') if child: - ApacheVhost.perHostVirtualConfOLS(completePathToConfigFile, website.master.adminEmail) + # Handle None values for child domains + admin_email = website.master.adminEmail if website.master.adminEmail else website.master.admin.email + ApacheVhost.perHostVirtualConfOLS(completePathToConfigFile, admin_email) else: - ApacheVhost.perHostVirtualConfOLS(completePathToConfigFile, website.adminEmail) + # Handle None values for main domains + admin_email = website.adminEmail if website.adminEmail else website.admin.email + ApacheVhost.perHostVirtualConfOLS(completePathToConfigFile, admin_email) if child: - ApacheVhost.setupApacheVhostChild(website.master.adminEmail, website.master.externalApp, - website.master.externalApp, + # Handle None values for child domains + admin_email = website.master.adminEmail if website.master.adminEmail else website.master.admin.email + external_app = website.master.externalApp if website.master.externalApp else "".join(re.findall("[a-zA-Z]+", virtualHostName))[:5] + str(randint(1000, 9999)) + + ApacheVhost.setupApacheVhostChild(admin_email, external_app, + external_app, phpVersion, virtualHostName, website.path) else: - ApacheVhost.setupApacheVhost(website.adminEmail, website.externalApp, website.externalApp, + # Handle None values for main domains + admin_email = website.adminEmail if website.adminEmail else website.admin.email + external_app = website.externalApp if website.externalApp else "".join(re.findall("[a-zA-Z]+", virtualHostName))[:5] + str(randint(1000, 9999)) + + ApacheVhost.setupApacheVhost(admin_email, external_app, external_app, phpVersion, virtualHostName) logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, 'Restarting servers and phps..,90') diff --git a/scripts/test_ubuntu_24043_support.bat b/scripts/test_ubuntu_24043_support.bat deleted file mode 100644 index d4c1f92d2..000000000 --- a/scripts/test_ubuntu_24043_support.bat +++ /dev/null @@ -1,81 +0,0 @@ -@echo off -REM Test script for Ubuntu 24.04.3 support in CyberPanel -REM This script verifies that CyberPanel properly detects and handles Ubuntu 24.04.3 - -echo CyberPanel Ubuntu 24.04.3 Support Test -echo ====================================== -echo. - -REM Check if running on Ubuntu 24.04.3 -if exist /etc/os-release ( - echo Detected OS: Checking /etc/os-release - findstr "Ubuntu" /etc/os-release - echo. - echo ✅ Ubuntu 24.04.3 support verified -) else ( - echo ❌ Cannot detect OS version - echo This test is designed for Ubuntu 24.04.3 - echo Current system: Windows - echo Continuing with compatibility test... -) - -echo. - -REM Test 1: Version detection -echo Test 1: Version Detection -echo ------------------------- -if exist /etc/os-release ( - findstr "Ubuntu 24.04" /etc/os-release >nul - if %errorlevel% == 0 ( - echo ✅ Ubuntu 24.04 pattern match successful - ) else ( - echo ❌ Ubuntu 24.04 pattern match failed - ) -) else ( - echo âš ī¸ /etc/os-release not found (Windows system) -) - -echo. - -REM Test 2: CyberPanel installation check -echo Test 2: CyberPanel Installation Check -echo ------------------------------------- -if exist "C:\Program Files\CyberPanel\bin\python.exe" ( - echo ✅ CyberPanel installation found -) else ( - echo âš ī¸ CyberPanel not installed - this is normal for Windows -) - -echo. - -REM Test 3: System requirements -echo Test 3: System Requirements -echo --------------------------- -echo Architecture: %PROCESSOR_ARCHITECTURE% -echo OS: %OS% -echo. - -REM Test 4: Network connectivity -echo Test 4: Network Connectivity -echo ---------------------------- -ping -n 1 8.8.8.8 >nul 2>&1 -if %errorlevel% == 0 ( - echo ✅ Network connectivity working -) else ( - echo ❌ Network connectivity issues -) - -echo. -echo Ubuntu 24.04.3 Support Test Complete -echo ==================================== -echo. -echo Summary: -echo - Ubuntu 24.04.3 is fully supported by CyberPanel -echo - Version detection works correctly -echo - All required packages and dependencies are available -echo - Installation and upgrade scripts are compatible -echo. -echo For installation on Ubuntu 24.04.3, run: -echo sh ^<(curl https://cyberpanel.net/install.sh ^|^| wget -O - https://cyberpanel.net/install.sh^) -echo. -pause diff --git a/scripts/test_ubuntu_24043_support.sh b/scripts/test_ubuntu_24043_support.sh deleted file mode 100644 index a1b8c834e..000000000 --- a/scripts/test_ubuntu_24043_support.sh +++ /dev/null @@ -1,168 +0,0 @@ -#!/bin/bash - -# Test script for Ubuntu 24.04.3 support in CyberPanel -# This script verifies that CyberPanel properly detects and handles Ubuntu 24.04.3 - -echo "CyberPanel Ubuntu 24.04.3 Support Test" -echo "======================================" -echo "" - -# Check if running on Ubuntu 24.04.3 -if [ -f /etc/os-release ]; then - source /etc/os-release - echo "Detected OS: $NAME $VERSION" - - if [[ "$NAME" == "Ubuntu" ]] && [[ "$VERSION" == *"24.04.3"* ]]; then - echo "✅ Ubuntu 24.04.3 detected" - else - echo "âš ī¸ This test is designed for Ubuntu 24.04.3" - echo " Current system: $NAME $VERSION" - echo " Continuing with compatibility test..." - fi -else - echo "❌ Cannot detect OS version" - exit 1 -fi - -echo "" - -# Test 1: Version detection -echo "Test 1: Version Detection" -echo "-------------------------" -if grep -q -E "Ubuntu 24.04" /etc/os-release; then - echo "✅ Ubuntu 24.04 pattern match successful" -else - echo "❌ Ubuntu 24.04 pattern match failed" -fi - -# Test 2: Version parsing -echo "" -echo "Test 2: Version Parsing" -echo "-----------------------" -VERSION_ID=$(grep VERSION_ID /etc/os-release | awk -F[=,] '{print $2}' | tr -d \" | head -c2 | tr -d .) -echo "Parsed version: $VERSION_ID" -if [ "$VERSION_ID" = "24" ]; then - echo "✅ Version parsing correct (24)" -else - echo "❌ Version parsing incorrect (expected: 24, got: $VERSION_ID)" -fi - -# Test 3: Python version detection -echo "" -echo "Test 3: Python Version Detection" -echo "--------------------------------" -if command -v python3 &> /dev/null; then - PYTHON_VERSION=$(python3 --version | cut -d' ' -f2 | cut -d'.' -f1-2) - echo "Python version: $PYTHON_VERSION" - if [[ "$PYTHON_VERSION" == "3.12" ]]; then - echo "✅ Python 3.12 detected (expected for Ubuntu 24.04.3)" - else - echo "âš ī¸ Python version $PYTHON_VERSION (Ubuntu 24.04.3 typically has Python 3.12)" - fi -else - echo "❌ Python3 not found" -fi - -# Test 4: Package manager compatibility -echo "" -echo "Test 4: Package Manager Compatibility" -echo "------------------------------------" -if command -v apt &> /dev/null; then - echo "✅ APT package manager available" - - # Test if we can access Ubuntu repositories - if apt list --installed | grep -q "ubuntu-release"; then - echo "✅ Ubuntu release packages found" - else - echo "âš ī¸ Ubuntu release packages not found" - fi -else - echo "❌ APT package manager not found" -fi - -# Test 5: Virtual environment support -echo "" -echo "Test 5: Virtual Environment Support" -echo "-----------------------------------" -if command -v python3 -m venv --help &> /dev/null; then - echo "✅ Python3 venv module available" - - # Test creating a virtual environment - TEST_VENV="/tmp/cyberpanel_test_venv" - if python3 -m venv "$TEST_VENV" 2>/dev/null; then - echo "✅ Virtual environment creation successful" - rm -rf "$TEST_VENV" - else - echo "❌ Virtual environment creation failed" - fi -else - echo "❌ Python3 venv module not available" -fi - -# Test 6: CyberPanel version detection -echo "" -echo "Test 6: CyberPanel Version Detection" -echo "------------------------------------" -if [ -f /usr/local/CyberCP/plogical/upgrade.py ]; then - echo "✅ CyberPanel installation found" - - # Test if the version detection would work - if python3 -c " -import sys -sys.path.append('/usr/local/CyberCP') -try: - from plogical.upgrade import Upgrade - os_type = Upgrade.FindOperatingSytem() - print(f'Detected OS type: {os_type}') - if os_type == 9: # Ubuntu24 constant - print('✅ Ubuntu 24.04 detection working') - else: - print(f'âš ī¸ OS type {os_type} detected (expected: 9 for Ubuntu24)') -except Exception as e: - print(f'❌ Error testing OS detection: {e}') -" 2>/dev/null; then - echo "✅ CyberPanel OS detection test completed" - else - echo "❌ CyberPanel OS detection test failed" - fi -else - echo "âš ī¸ CyberPanel not installed - skipping detection test" -fi - -# Test 7: System requirements -echo "" -echo "Test 7: System Requirements" -echo "---------------------------" -echo "Architecture: $(uname -m)" -if uname -m | grep -qE 'x86_64|aarch64'; then - echo "✅ Supported architecture detected" -else - echo "❌ Unsupported architecture" -fi - -echo "" -echo "Memory: $(free -h | grep '^Mem:' | awk '{print $2}')" -echo "Disk space: $(df -h / | tail -1 | awk '{print $4}') available" - -# Test 8: Network connectivity -echo "" -echo "Test 8: Network Connectivity" -echo "----------------------------" -if ping -c 1 8.8.8.8 &> /dev/null; then - echo "✅ Network connectivity working" -else - echo "❌ Network connectivity issues" -fi - -echo "" -echo "Ubuntu 24.04.3 Support Test Complete" -echo "====================================" -echo "" -echo "Summary:" -echo "- Ubuntu 24.04.3 is fully supported by CyberPanel" -echo "- Version detection works correctly" -echo "- All required packages and dependencies are available" -echo "- Installation and upgrade scripts are compatible" -echo "" -echo "For installation, run:" -echo "sh <(curl https://cyberpanel.net/install.sh || wget -O - https://cyberpanel.net/install.sh)" diff --git a/test_firewall_blocking.py b/test_firewall_blocking.py new file mode 100644 index 000000000..21f485e03 --- /dev/null +++ b/test_firewall_blocking.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 +""" +Test script for the new firewall blocking functionality +This script tests the blockIPAddress API endpoint +""" + +import requests +import json +import sys + +def test_firewall_blocking(): + """ + Test the firewall blocking functionality + Note: This is a basic test script. In a real environment, you would need + proper authentication and a test IP address. + """ + + print("Testing Firewall Blocking Functionality") + print("=" * 50) + + # Test configuration + base_url = "https://localhost:8090" # Adjust based on your CyberPanel setup + test_ip = "192.168.1.100" # Use a test IP that won't block your access + + print(f"Base URL: {base_url}") + print(f"Test IP: {test_ip}") + print() + + # Test data + test_data = { + "ip_address": test_ip + } + + print("Test Data:") + print(json.dumps(test_data, indent=2)) + print() + + print("Note: This test requires:") + print("1. Valid CyberPanel session with admin privileges") + print("2. CyberPanel addons enabled") + print("3. Active firewalld service") + print() + + print("To test manually:") + print("1. Login to CyberPanel dashboard") + print("2. Go to Dashboard -> SSH Security Analysis") + print("3. Look for 'Brute Force Attack Detected' alerts") + print("4. Click the 'Block IP' button next to malicious IPs") + print() + + print("Expected behavior:") + print("- Button shows loading state during blocking") + print("- Success notification appears on successful blocking") + print("- IP is marked as 'Blocked' in the interface") + print("- Security analysis refreshes to update alerts") + print() + + print("Firewall Commands:") + print("- firewalld: firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address= drop'") + print("- firewalld reload: firewall-cmd --reload") + print() + +if __name__ == "__main__": + test_firewall_blocking() diff --git a/test_version_fetcher.py b/test_version_fetcher.py new file mode 100644 index 000000000..2b9a1eb53 --- /dev/null +++ b/test_version_fetcher.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 + +""" +Test script for the dynamic version fetcher +""" + +import sys +import os + +# Add the plogical directory to the path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'plogical')) + +try: + from versionFetcher import VersionFetcher, get_latest_phpmyadmin_version, get_latest_snappymail_version + + print("=== Testing Dynamic Version Fetcher ===") + print() + + # Test connectivity + print("1. Testing GitHub API connectivity...") + if VersionFetcher.test_connectivity(): + print(" ✅ GitHub API is accessible") + else: + print(" ❌ GitHub API is not accessible") + print() + + # Test phpMyAdmin version fetching + print("2. Testing phpMyAdmin version fetching...") + try: + phpmyadmin_version = get_latest_phpmyadmin_version() + print(f" Latest phpMyAdmin version: {phpmyadmin_version}") + if phpmyadmin_version != "5.2.2": + print(" ✅ Newer version found!") + else: + print(" â„šī¸ Using fallback version (API may be unavailable)") + except Exception as e: + print(f" ❌ Error: {e}") + print() + + # Test SnappyMail version fetching + print("3. Testing SnappyMail version fetching...") + try: + snappymail_version = get_latest_snappymail_version() + print(f" Latest SnappyMail version: {snappymail_version}") + if snappymail_version != "2.38.2": + print(" ✅ Newer version found!") + else: + print(" â„šī¸ Using fallback version (API may be unavailable)") + except Exception as e: + print(f" ❌ Error: {e}") + print() + + # Test all versions + print("4. Testing all versions...") + try: + all_versions = VersionFetcher.get_latest_versions() + print(" All latest versions:") + for component, version in all_versions.items(): + print(f" {component}: {version}") + except Exception as e: + print(f" ❌ Error: {e}") + print() + + print("=== Test Complete ===") + +except ImportError as e: + print(f"❌ Import error: {e}") + print("Make sure you're running this from the cyberpanel directory") +except Exception as e: + print(f"❌ Unexpected error: {e}") diff --git a/websiteFunctions/urls.py b/websiteFunctions/urls.py index ae8798501..891d8837c 100644 --- a/websiteFunctions/urls.py +++ b/websiteFunctions/urls.py @@ -197,6 +197,8 @@ urlpatterns = [ path('statusFunc', views.statusFunc, name='statusFunc'), path('tuneSettings', views.tuneSettings, name='tuneSettings'), path('saveApacheConfigsToFile', views.saveApacheConfigsToFile, name='saveApacheConfigsToFile'), + path('resetApacheConfigToDefault', views.resetApacheConfigToDefault, name='resetApacheConfigToDefault'), + path('resetVHostConfigToDefault', views.resetVHostConfigToDefault, name='resetVHostConfigToDefault'), path('getTerminalJWT', views.get_terminal_jwt, name='get_terminal_jwt'), # Catch all for domains diff --git a/websiteFunctions/views.py b/websiteFunctions/views.py index 9647a2fea..1dcc7fedf 100644 --- a/websiteFunctions/views.py +++ b/websiteFunctions/views.py @@ -1852,6 +1852,24 @@ def ApacheManager(request, domain): return redirect(loadLoginPage) +def resetVHostConfigToDefault(request): + try: + userID = request.session['userID'] + wm = WebsiteManager() + return wm.resetVHostConfigToDefault(userID, json.loads(request.body)) + except KeyError: + return redirect(loadLoginPage) + + +def resetApacheConfigToDefault(request): + try: + userID = request.session['userID'] + wm = WebsiteManager() + return wm.resetApacheConfigToDefault(userID, json.loads(request.body)) + except KeyError: + return redirect(loadLoginPage) + + def getSwitchStatus(request): try: userID = request.session['userID'] diff --git a/websiteFunctions/website.py b/websiteFunctions/website.py index eb9e60848..51cbeeff4 100644 --- a/websiteFunctions/website.py +++ b/websiteFunctions/website.py @@ -3902,6 +3902,91 @@ context /cyberpanel_suspension_page.html { final_json = json.dumps(status) return HttpResponse(final_json) + def resetVHostConfigToDefault(self, userID=None, data=None): + """Reset vHost configuration to default template""" + currentACL = ACLManager.loadedACL(userID) + + if currentACL['admin'] != 1: + return ACLManager.loadErrorJson('configstatus', 0) + + virtualHost = data['virtualHost'] + self.domain = virtualHost + + try: + # Get the default vHost configuration template + from plogical import vhostConfs + + # Determine if it's a child domain or main domain + try: + child_domain = ChildDomains.objects.get(domain=virtualHost) + is_child = True + master_domain = child_domain.master.domain + admin_email = child_domain.master.adminEmail if child_domain.master.adminEmail else child_domain.master.admin.email + path = child_domain.path + except: + is_child = False + try: + website = Websites.objects.get(domain=virtualHost) + admin_email = website.adminEmail if website.adminEmail else website.admin.email + except: + admin_email = "admin@" + virtualHost + + # Generate default configuration based on server type + if ProcessUtilities.decideServer() == ProcessUtilities.OLS: + if is_child: + # Use child domain template + default_config = vhostConfs.olsChildConf + default_config = default_config.replace('{path}', path) + default_config = default_config.replace('{masterDomain}', master_domain) + default_config = default_config.replace('{adminEmails}', admin_email) + default_config = default_config.replace('{externalApp}', "".join(re.findall("[a-zA-Z]+", virtualHost))[:5] + str(randint(1000, 9999))) + default_config = default_config.replace('{externalAppMaster}', "".join(re.findall("[a-zA-Z]+", master_domain))[:5] + str(randint(1000, 9999))) + default_config = default_config.replace('{php}', '8.1') # Default PHP version + default_config = default_config.replace('{open_basedir}', '') # Default open_basedir setting + else: + # Use main domain template + default_config = vhostConfs.olsMasterConf + default_config = default_config.replace('{virtualHostName}', virtualHost) + default_config = default_config.replace('{administratorEmail}', admin_email) + default_config = default_config.replace('{externalApp}', "".join(re.findall("[a-zA-Z]+", virtualHost))[:5] + str(randint(1000, 9999))) + default_config = default_config.replace('{php}', '8.1') # Default PHP version + else: + # For other server types, use basic template + default_config = f"""# Default vHost Configuration for {virtualHost} +# Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} + +# Basic configuration +# Add your custom configuration here +""" + + # Save the default configuration + mailUtilities.checkHome() + tempPath = "/home/cyberpanel/" + str(randint(1000, 9999)) + + vhost = open(tempPath, "w") + vhost.write(default_config) + vhost.close() + + filePath = installUtilities.Server_root_path + "/conf/vhosts/" + virtualHost + "/vhost.conf" + + execPath = "/usr/local/CyberCP/bin/python " + virtualHostUtilities.cyberPanel + "/plogical/virtualHostUtilities.py" + execPath = execPath + " saveVHostConfigs --path " + filePath + " --tempPath " + tempPath + + output = ProcessUtilities.outputExecutioner(execPath) + + if output.find("1,None") > -1: + status = {"configstatus": 1, "message": "vHost configuration reset to default successfully."} + else: + status = {"configstatus": 0, "error_message": f"Failed to reset configuration: {output}" + + final_json = json.dumps(status) + return HttpResponse(final_json) + + except Exception as e: + status = {"configstatus": 0, "error_message": f"Error resetting configuration: {str(e)}"} + final_json = json.dumps(status) + return HttpResponse(final_json) + def saveConfigsToFile(self, userID=None, data=None): currentACL = ACLManager.loadedACL(userID) @@ -5376,7 +5461,8 @@ StrictHostKeyChecking no data['pmMinSpareServers'] = pmMinSpareServers data['pmMaxSpareServers'] = pmMaxSpareServers data['phpPath'] = phpPath - data['configData'] = ProcessUtilities.outputExecutioner(f'cat {finalConfPath}') + config_output = ProcessUtilities.outputExecutioner(f'cat {finalConfPath}') + data['configData'] = config_output if config_output is not None else '' else: data = {} data['status'] = 1 @@ -7431,6 +7517,84 @@ StrictHostKeyChecking no {'domainName': self.domain, 'phps': phps, 'apachemanager': apachemanager, 'apachePHPs': apachePHPs}) return proc.render() + def resetApacheConfigToDefault(self, userID=None, data=None): + """Reset Apache configuration to default template""" + currentACL = ACLManager.loadedACL(userID) + + if currentACL['admin'] != 1: + return ACLManager.loadErrorJson('configstatus', 0) + + domainName = data['domainName'] + self.domain = domainName + + try: + # Get the default Apache configuration template + from plogical import vhostConfs + + # Determine if it's a child domain or main domain + try: + child_domain = ChildDomains.objects.get(domain=domainName) + is_child = True + master_domain = child_domain.master.domain + admin_email = child_domain.master.adminEmail if child_domain.master.adminEmail else child_domain.master.admin.email + path = child_domain.path + except: + is_child = False + try: + website = Websites.objects.get(domain=domainName) + admin_email = website.adminEmail if website.adminEmail else website.admin.email + except: + admin_email = "admin@" + domainName + + # Generate default Apache configuration + if is_child: + # Use child domain Apache template + default_config = vhostConfs.apacheConfChild + default_config = default_config.replace('{virtualHostName}', domainName) + default_config = default_config.replace('{administratorEmail}', admin_email) + default_config = default_config.replace('{php}', '8.1') # Default PHP version + default_config = default_config.replace('{adminEmails}', admin_email) + default_config = default_config.replace('{externalApp}', "".join(re.findall("[a-zA-Z]+", domainName))[:5] + str(randint(1000, 9999))) + default_config = default_config.replace('{path}', path) + default_config = default_config.replace('{sockPath}', '/var/run/php/') # Default socket path + else: + # Use main domain Apache template + default_config = vhostConfs.apacheConf + default_config = default_config.replace('{virtualHostName}', domainName) + default_config = default_config.replace('{administratorEmail}', admin_email) + default_config = default_config.replace('{php}', '8.1') # Default PHP version + default_config = default_config.replace('{adminEmails}', admin_email) + default_config = default_config.replace('{externalApp}', "".join(re.findall("[a-zA-Z]+", domainName))[:5] + str(randint(1000, 9999))) + default_config = default_config.replace('{sockPath}', '/var/run/php/') # Default socket path + + # Save the default configuration + mailUtilities.checkHome() + tempPath = "/home/cyberpanel/" + str(randint(1000, 9999)) + + vhost = open(tempPath, "w") + vhost.write(default_config) + vhost.close() + + filePath = ApacheVhost.configBasePath + domainName + '.conf' + + execPath = "/usr/local/CyberCP/bin/python " + virtualHostUtilities.cyberPanel + "/plogical/virtualHostUtilities.py" + execPath = execPath + " saveApacheConfigsToFile --path " + filePath + " --tempPath " + tempPath + + output = ProcessUtilities.outputExecutioner(execPath) + + if output.find("1,None") > -1: + status = {"status": 1, "message": "Apache configuration reset to default successfully."} + else: + status = {"status": 0, "error_message": f"Failed to reset Apache configuration: {output}" + + final_json = json.dumps(status) + return HttpResponse(final_json) + + except Exception as e: + status = {"status": 0, "error_message": f"Error resetting Apache configuration: {str(e)}"} + final_json = json.dumps(status) + return HttpResponse(final_json) + def saveApacheConfigsToFile(self, userID=None, data=None): currentACL = ACLManager.loadedACL(userID)