Merge pull request #1620 from master3395/v2.5.5-dev

V2.5.5 dev
This commit is contained in:
Master3395
2025-12-17 19:22:16 +01:00
committed by GitHub
15 changed files with 1015 additions and 218 deletions

View File

@@ -825,6 +825,191 @@
top: 130px;
}
/* .htaccess Feature Banner */
.htaccess-feature-banner {
position: fixed;
top: 80px;
left: 260px;
right: 0;
background: linear-gradient(135deg, #10b981 0%, #059669 50%, #047857 100%);
border-bottom: 2px solid #065f46;
padding: 18px 30px;
z-index: 997;
box-shadow: 0 6px 25px rgba(16, 185, 129, 0.3);
animation: slideDown 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
display: none;
}
.htaccess-feature-banner.show {
display: block;
}
.htaccess-content {
display: flex;
align-items: center;
gap: 1.5rem;
max-width: 1400px;
margin: 0 auto;
}
.htaccess-icon {
background: rgba(255, 255, 255, 0.25);
border-radius: 14px;
padding: 14px;
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.4);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}
.htaccess-icon i {
color: white;
font-size: 1.75rem;
display: block;
}
.htaccess-text {
flex: 1;
display: flex;
flex-direction: column;
gap: 5px;
}
.htaccess-main-text {
color: white;
font-size: 1.1rem;
font-weight: 700;
line-height: 1.4;
letter-spacing: 0.3px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.htaccess-sub-text {
color: rgba(255, 255, 255, 0.9);
font-size: 0.875rem;
font-weight: 500;
display: flex;
align-items: center;
gap: 1rem;
}
.htaccess-sub-text span {
display: flex;
align-items: center;
gap: 0.4rem;
}
.htaccess-sub-text i {
font-size: 0.75rem;
}
.htaccess-actions {
display: flex;
gap: 12px;
}
.htaccess-btn {
background: white;
color: #047857;
padding: 14px 28px;
border-radius: 10px;
text-decoration: none;
font-weight: 700;
font-size: 0.9rem;
display: flex;
align-items: center;
gap: 10px;
transition: all 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15);
position: relative;
overflow: hidden;
border: 2px solid transparent;
}
.htaccess-btn:hover {
background: #f0fdf4;
color: #065f46;
transform: translateY(-2px) scale(1.02);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
text-decoration: none;
border-color: white;
}
.htaccess-btn::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(16, 185, 129, 0.1);
transform: translate(-50%, -50%);
transition: width 0.6s ease, height 0.6s ease;
}
.htaccess-btn:hover::before {
width: 300px;
height: 300px;
}
.htaccess-btn span {
position: relative;
z-index: 1;
}
.htaccess-btn i {
font-size: 1rem;
position: relative;
z-index: 1;
}
.htaccess-close {
background: rgba(255, 255, 255, 0.15);
border: 1px solid rgba(255, 255, 255, 0.3);
color: white;
font-size: 1.1rem;
cursor: pointer;
padding: 10px;
border-radius: 8px;
transition: all 0.3s ease;
backdrop-filter: blur(12px);
}
.htaccess-close:hover {
background: rgba(255, 255, 255, 0.25);
transform: scale(1.1) rotate(90deg);
}
/* Adjust main content when .htaccess banner is shown */
.htaccess-shown #main-content {
padding-top: 190px;
}
/* Multiple banners adjustments */
.notification-shown.htaccess-shown #main-content {
padding-top: 240px;
}
.ai-scanner-shown.htaccess-shown #main-content {
padding-top: 270px;
}
.notification-shown.ai-scanner-shown.htaccess-shown #main-content {
padding-top: 320px;
}
.notification-shown .htaccess-feature-banner {
top: 130px;
}
.ai-scanner-shown .htaccess-feature-banner {
top: 160px;
}
.notification-shown.ai-scanner-shown .htaccess-feature-banner {
top: 210px;
}
/* Mobile responsive styles for AI Scanner banner */
@media (max-width: 768px) {
.ai-scanner-banner {
@@ -1832,6 +2017,32 @@
</div>
</div>
<!-- .htaccess Feature Announcement -->
<div id="htaccess-notification" class="htaccess-feature-banner">
<div class="htaccess-content">
<div class="htaccess-icon">
<i class="fas fa-magic"></i>
</div>
<div class="htaccess-text">
<span class="htaccess-main-text">✨ Revolutionary .htaccess Support Now Live!</span>
<span class="htaccess-sub-text">
<span><i class="fas fa-check-circle"></i> Full .htaccess support</span>
<span><i class="fas fa-check-circle"></i> PHP configuration now works</span>
<span><i class="fas fa-check-circle"></i> Zero rule rewrites needed</span>
</span>
</div>
<div class="htaccess-actions">
<a href="https://cyberpanel.net/cyberpanel-htaccess-module" target="_blank" rel="noopener" class="htaccess-btn">
<i class="fas fa-book-open"></i>
<span>Learn More</span>
</a>
</div>
<button class="htaccess-close" onclick="dismissHtaccessNotification()">
<i class="fas fa-times"></i>
</button>
</div>
</div>
<!-- Main Content -->
<div id="main-content">
{% block content %}{% endblock %}
@@ -2053,11 +2264,49 @@
});
}
// Check both notification statuses when page loads
// .htaccess Feature Notification Functions
function checkHtaccessStatus() {
// Check if user has dismissed the notification permanently (localStorage for longer persistence)
if (localStorage.getItem('htaccessNotificationDismissed') === 'true') {
return;
}
// Check if notification has been shown today
const lastShown = localStorage.getItem('htaccessNotificationLastShown');
const today = new Date().toDateString();
if (lastShown === today) {
return;
}
// Show the notification
showHtaccessNotification();
localStorage.setItem('htaccessNotificationLastShown', today);
}
function showHtaccessNotification() {
const banner = document.getElementById('htaccess-notification');
const body = document.body;
banner.classList.add('show');
body.classList.add('htaccess-shown');
}
function dismissHtaccessNotification() {
const banner = document.getElementById('htaccess-notification');
const body = document.body;
banner.classList.remove('show');
body.classList.remove('htaccess-shown');
// Remember dismissal permanently
localStorage.setItem('htaccessNotificationDismissed', 'true');
}
// Check all notification statuses when page loads
document.addEventListener('DOMContentLoaded', function() {
checkBackupStatus();
// Show AI Scanner notification with a slight delay for better UX
setTimeout(checkAIScannerStatus, 1000);
// Show .htaccess notification with additional delay for staggered effect
setTimeout(checkHtaccessStatus, 1500);
// Set active menu state based on current URL
setActiveMenuState();

View File

@@ -1,185 +0,0 @@
# CyberPanel ModSecurity Rules Fix
## Overview
This fix addresses common issues with ModSecurity Rules Packages in CyberPanel where OWASP ModSecurity Core Rules show as "off" even after installation. The problem typically occurs due to:
1. **Incorrect status detection logic** - The system doesn't properly detect installed OWASP rules
2. **Outdated download URLs** - The OWASP rules download URL was incorrect
3. **JavaScript state synchronization issues** - Frontend toggle state doesn't sync with backend
4. **Missing error handling** - Insufficient logging and error reporting
## Issues Fixed
### 1. Status Detection Logic (`firewallManager.py`)
- **Problem**: The `getOWASPAndComodoStatus` method only checked for `modsec/owasp` in configuration files
- **Fix**: Added multiple detection methods:
- Check for `modsec/owasp` in configuration
- Check for `owasp-modsecurity-crs` in configuration
- Verify actual file existence in filesystem
- Added similar verification for Comodo rules
### 2. OWASP Rules Download (`modSec.py`)
- **Problem**: Used incorrect GitHub URL that resulted in 404 errors
- **Fix**: Updated to use correct GitHub repository URL:
- Old: `https://github.com/coreruleset/coreruleset/archive/v3.3.2/master.zip`
- New: `https://github.com/coreruleset/coreruleset/archive/refs/tags/v4.0.0.zip`
### 3. JavaScript State Synchronization (`firewall.js`)
- **Problem**: Toggle state variables weren't properly updated when status was fetched
- **Fix**: Added proper state variable updates (`owaspInstalled`, `comodoInstalled`) in both update scenarios
### 4. Error Handling and Logging (`modSec.py`)
- **Problem**: Insufficient logging made debugging difficult
- **Fix**: Added comprehensive logging throughout the installation process:
- Download progress logging
- Extraction progress logging
- File verification logging
- Installation verification
## Files Modified
1. **`cyberpanel/firewall/firewallManager.py`**
- Enhanced `getOWASPAndComodoStatus` method
- Added filesystem verification for rule packages
2. **`cyberpanel/plogical/modSec.py`**
- Updated OWASP download URL to v4.0.0
- Added comprehensive logging
- Added installation verification
- Improved error handling
- Updated to use simplified CRS v4.0.0 structure
3. **`cyberpanel/firewall/static/firewall/firewall.js`**
- Fixed JavaScript state synchronization
- Added proper variable updates
## Manual Fix Script
A comprehensive fix script is provided at `cyberpanel/cyberpanel-mods/security/modsecurity-fix.sh` that:
1. **Backs up** current configuration
2. **Downloads and installs** OWASP ModSecurity Core Rules v3.3.4
3. **Creates proper configuration files**
4. **Sets correct permissions**
5. **Updates LiteSpeed configuration**
6. **Restarts LiteSpeed**
7. **Verifies installation**
### Running the Fix Script
```bash
# Make the script executable
chmod +x cyberpanel/cyberpanel-mods/security/modsecurity-fix.sh
# Run the fix script
./cyberpanel/cyberpanel-mods/security/modsecurity-fix.sh
```
## Manual Installation Steps
If you prefer to fix the issue manually:
### 1. Download OWASP Rules
```bash
cd /tmp
wget https://github.com/coreruleset/coreruleset/archive/refs/tags/v4.0.0.zip -O owasp.zip
unzip owasp.zip -d /usr/local/lsws/conf/modsec/
mv /usr/local/lsws/conf/modsec/coreruleset-4.0.0 /usr/local/lsws/conf/modsec/owasp-modsecurity-crs-4.0.0
```
### 2. Set Up Configuration Files
```bash
cd /usr/local/lsws/conf/modsec/owasp-modsecurity-crs-4.0.0
cp crs-setup.conf.example crs-setup.conf
cp rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
cp rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf.example rules/RESPONSE-999-EXCLUSION-RULES-AFTER-CRS.conf
```
### 3. Create Master Configuration
Create `/usr/local/lsws/conf/modsec/owasp-modsecurity-crs-4.0.0/owasp-master.conf`:
```apache
include /usr/local/lsws/conf/modsec/owasp-modsecurity-crs-4.0.0/crs.conf
```
**Note**: CRS v4.0.0 uses a simplified structure with a single `crs.conf` file that includes all necessary rules, unlike v3.x which required individual rule file includes.
### Key Differences in CRS v4.0.0:
- **Simplified Configuration**: Single `crs.conf` file instead of multiple individual rule files
- **Plugin System**: Replaced application exclusion packages with a plugin system
- **Improved Performance**: Better rule organization and execution
- **Enhanced Security**: Updated attack patterns and detection methods
- **Better Documentation**: Improved configuration examples and guides
### 4. Update LiteSpeed Configuration
Add to `/usr/local/lsws/conf/httpd_config.conf`:
```apache
modsecurity_rules_file /usr/local/lsws/conf/modsec/owasp-modsecurity-crs-4.0.0/owasp-master.conf
```
### 5. Set Permissions and Restart
```bash
chown -R lsadm:lsadm /usr/local/lsws/conf/modsec
chmod -R 755 /usr/local/lsws/conf/modsec
systemctl restart lsws
```
## Verification
After applying the fix:
1. **Access CyberPanel** → Security → ModSecurity Rules Packages
2. **Check Status**: OWASP ModSecurity Core Rules should show as "enabled"
3. **Test Toggle**: The toggle should work properly (enable/disable)
4. **Check Logs**: Verify no errors in ModSecurity logs
## Troubleshooting
### Common Issues
1. **Rules still show as disabled**
- Check file permissions: `ls -la /usr/local/lsws/conf/modsec/owasp-modsecurity-crs-3.0-master/`
- Verify configuration: `grep -i owasp /usr/local/lsws/conf/httpd_config.conf`
- Check LiteSpeed logs: `tail -f /usr/local/lsws/logs/error.log`
2. **Download fails**
- Check internet connectivity
- Verify GitHub access: `curl -I https://github.com/coreruleset/coreruleset/archive/refs/tags/v3.3.4.zip`
- Try manual download and extraction
3. **LiteSpeed won't start**
- Check configuration syntax: `/usr/local/lsws/bin/lshttpd -t`
- Restore backup: `cp /usr/local/lsws/conf/httpd_config.conf.backup.* /usr/local/lsws/conf/httpd_config.conf`
- Check ModSecurity syntax
### Log Files
- **ModSecurity Log**: `/usr/local/lsws/logs/modsec.log`
- **Audit Log**: `/usr/local/lsws/logs/auditmodsec.log`
- **Installation Log**: `/home/cyberpanel/modSecInstallLog`
- **LiteSpeed Error Log**: `/usr/local/lsws/logs/error.log`
## Security Considerations
1. **Rule Updates**: Regularly update OWASP rules for latest security patterns
2. **False Positives**: Monitor logs for legitimate traffic being blocked
3. **Performance**: OWASP rules can impact performance - monitor server resources
4. **Custom Rules**: Add custom rules in `/usr/local/lsws/conf/modsec/rules.conf`
## Support
If you encounter issues after applying this fix:
1. Check the troubleshooting section above
2. Review log files for specific error messages
3. Verify all file permissions and ownership
4. Test with a simple configuration first
## Changelog
- **v1.0**: Initial fix for ModSecurity status detection issues
- **v1.1**: Added comprehensive logging and error handling
- **v1.2**: Updated to OWASP CRS v4.0.0 and improved verification
- **v1.3**: Simplified configuration structure for CRS v4.0.0 compatibility

View File

@@ -1043,6 +1043,13 @@ class FileManager:
if self.data['extractionType'] == 'zip':
command = 'unzip -o ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -d ' + self.returnPathEnclosed(self.data['extractionLocation'])
elif self.data['extractionType'] == '7z':
command = '7z x ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -o' + self.returnPathEnclosed(self.data['extractionLocation']) + ' -y'
elif self.data['extractionType'] == 'rar':
# Try unrar first (free), fallback to 7z if unrar not available
command = 'unrar x ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' ' + self.returnPathEnclosed(self.data['extractionLocation']) + ' -y'
else:
command = 'tar -xf ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -C ' + self.returnPathEnclosed(self.data['extractionLocation'])
@@ -1068,6 +1075,13 @@ class FileManager:
if self.data['extractionType'] == 'zip':
command = 'unzip -o ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -d ' + self.returnPathEnclosed(self.data['extractionLocation'])
elif self.data['extractionType'] == '7z':
command = '7z x ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -o' + self.returnPathEnclosed(self.data['extractionLocation']) + ' -y'
elif self.data['extractionType'] == 'rar':
# Try unrar first (free), fallback to 7z if unrar not available
command = 'unrar x ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' ' + self.returnPathEnclosed(self.data['extractionLocation']) + ' -y'
else:
command = 'tar -xf ' + self.returnPathEnclosed(
self.data['fileToExtract']) + ' -C ' + self.returnPathEnclosed(self.data['extractionLocation'])
@@ -1098,6 +1112,15 @@ class FileManager:
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.zip')
command = 'zip -r ' + compressedFileName + ' '
elif self.data['compressionType'] == '7z':
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.7z')
command = '7z a -t7z ' + compressedFileName + ' '
elif self.data['compressionType'] == 'rar':
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.rar')
# Use 7z to create RAR format (7z can create RAR archives)
command = '7z a -trar ' + compressedFileName + ' '
else:
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.tar.gz')
@@ -1127,6 +1150,15 @@ class FileManager:
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.zip')
command = 'zip -r ' + compressedFileName + ' '
elif self.data['compressionType'] == '7z':
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.7z')
command = '7z a -t7z ' + compressedFileName + ' '
elif self.data['compressionType'] == 'rar':
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.rar')
# Use 7z to create RAR format (7z can create RAR archives)
command = '7z a -trar ' + compressedFileName + ' '
else:
compressedFileName = self.returnPathEnclosed(
self.data['basePath'] + '/' + self.data['compressedFileName'] + '.tar.gz')

View File

@@ -1251,9 +1251,14 @@ fileManager.controller('fileManagerCtrl', function ($scope, $http, FileUploader,
var completeFileToExtract = pathbase + "/" + allFilesAndFolders[0];
var extractionType = "";
var fileExt = findFileExtension(completeFileToExtract);
if (findFileExtension(completeFileToExtract) == "gz") {
if (fileExt == "gz") {
extractionType = "tar.gz";
} else if (fileExt == "7z") {
extractionType = "7z";
} else if (fileExt == "rar") {
extractionType = "rar";
} else {
extractionType = "zip";
}

View File

@@ -976,12 +976,25 @@ function findFileExtension(fileName) {
var extractionLocation = $scope.extractionLocation;
var fileToExtract = allFilesAndFolders[0];
var extractionType = "";
var fileExt = findFileExtension(fileToExtract);
if (fileExt == "gz") {
extractionType = "tar.gz";
} else if (fileExt == "7z") {
extractionType = "7z";
} else if (fileExt == "rar") {
extractionType = "rar";
} else {
extractionType = "zip";
}
var data = {
method: "extract",
domainRandomSeed: domainRandomSeed,
domainName: domainName,
fileToExtract: fileToExtract,
extractionType: extractionType,
extractionLocation: extractionLocation,
completeStartingPath: $scope.completeStartingPath
};

View File

@@ -463,6 +463,8 @@
<select ng-model="compressionType" class="form-control">
<option>zip</option>
<option>tar.gz</option>
<option>7z</option>
<option>rar</option>
</select>
</div>
</form>

View File

@@ -807,6 +807,8 @@
<select ng-model="compressionType" class="form-control">
<option>zip</option>
<option>tar.gz</option>
<option>7z</option>
<option>rar</option>
</select>
</div>
</form>

View File

@@ -330,6 +330,8 @@
<select ng-model="compressionType" class="form-control" style="border-radius: 12px; border: 2px solid #f3f1ff; padding: 12px;">
<option value="zip">ZIP</option>
<option value="tar.gz">TAR.GZ</option>
<option value="7z">7ZIP</option>
<option value="rar">RAR</option>
</select>
</div>
</div>

View File

@@ -1040,6 +1040,25 @@ class FirewallManager:
elif items.find('modsec/owasp') > -1 or items.find('owasp-modsecurity-crs') > -1:
owaspInstalled = 1
if owaspInstalled == 1 and comodoInstalled == 1:
break
# Also check rules.conf for manual OWASP installations (case-insensitive)
if owaspInstalled == 0:
rulesConfPath = os.path.join(virtualHostUtilities.Server_root, "conf/modsec/rules.conf")
if os.path.exists(rulesConfPath):
try:
command = "sudo cat " + rulesConfPath
rulesConfig = ProcessUtilities.outputExecutioner(command).splitlines()
for items in rulesConfig:
# Check for OWASP includes in rules.conf (case-insensitive)
if ('owasp' in items.lower() or 'crs-setup' in items.lower()) and \
('include' in items.lower() or 'modsecurity_rules_file' in items.lower()):
owaspInstalled = 1
break
except:
pass
# Additional check: verify OWASP files actually exist
if owaspInstalled == 0:
owaspPath = os.path.join(virtualHostUtilities.Server_root, "conf/modsec/owasp-modsecurity-crs-4.18.0")

View File

@@ -794,6 +794,274 @@ class preFlightsChecks:
self.stdOut(f"Error applying OS-specific fixes: {str(e)}", 0)
return False
def detectArchitecture(self):
"""Detect system architecture - custom binaries only for x86_64"""
try:
import platform
arch = platform.machine()
return arch == "x86_64"
except Exception as msg:
self.stdOut(str(msg) + " [detectArchitecture]", 0)
return False
def detectPlatform(self):
"""Detect OS platform for binary selection (rhel8, rhel9, ubuntu)"""
try:
# Check for Ubuntu
if os.path.exists('/etc/lsb-release'):
with open('/etc/lsb-release', 'r') as f:
content = f.read()
if 'Ubuntu' in content or 'ubuntu' in content:
return 'ubuntu'
# Check for RHEL-based distributions
if os.path.exists('/etc/os-release'):
with open('/etc/os-release', 'r') as f:
content = f.read().lower()
# Check for version 8.x (RHEL, AlmaLinux, Rocky, CloudLinux, CentOS 8)
if 'version="8.' in content or 'version_id="8.' in content:
if any(distro in content for distro in ['red hat', 'almalinux', 'rocky', 'cloudlinux', 'centos']):
return 'rhel8'
# Check for version 9.x
if 'version="9.' in content or 'version_id="9.' in content:
if any(distro in content for distro in ['red hat', 'almalinux', 'rocky', 'cloudlinux', 'centos']):
return 'rhel9'
# Default to rhel9 if can't detect (safer default for newer systems)
self.stdOut("WARNING: Could not detect platform, defaulting to rhel9", 1)
return 'rhel9'
except Exception as msg:
self.stdOut(f"ERROR detecting platform: {msg}, defaulting to rhel9", 0)
return 'rhel9'
def downloadCustomBinary(self, url, destination, expected_sha256=None):
"""Download custom binary file with optional checksum verification"""
try:
self.stdOut(f"Downloading {os.path.basename(destination)}...", 1)
# Use wget for better progress display
command = f'wget -q --show-progress {url} -O {destination}'
res = self.call(command, self.distro, command, command, 1, 0, os.EX_OSERR)
# Check if file was downloaded successfully by verifying it exists and has reasonable size
if os.path.exists(destination):
file_size = os.path.getsize(destination)
# Verify file size is reasonable (at least 10KB to avoid error pages/empty files)
if file_size > 10240: # 10KB
if file_size > 1048576: # 1MB
self.stdOut(f"Downloaded successfully ({file_size / (1024*1024):.2f} MB)", 1)
else:
self.stdOut(f"Downloaded successfully ({file_size / 1024:.2f} KB)", 1)
# Verify checksum if provided
if expected_sha256:
self.stdOut("Verifying checksum...", 1)
import hashlib
sha256_hash = hashlib.sha256()
with open(destination, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
actual_sha256 = sha256_hash.hexdigest()
if actual_sha256 == expected_sha256:
self.stdOut("Checksum verified successfully", 1)
return True
else:
self.stdOut(f"ERROR: Checksum mismatch!", 1)
self.stdOut(f"Expected: {expected_sha256}", 1)
self.stdOut(f"Got: {actual_sha256}", 1)
return False
else:
return True
else:
self.stdOut(f"ERROR: Downloaded file too small ({file_size} bytes)", 1)
return False
else:
self.stdOut("ERROR: Download failed - file not found", 1)
return False
except Exception as msg:
self.stdOut(f"ERROR: {msg} [downloadCustomBinary]", 0)
return False
def installCustomOLSBinaries(self):
"""Install custom OpenLiteSpeed binaries with PHP config support"""
try:
self.stdOut("Installing Custom OpenLiteSpeed Binaries", 1)
self.stdOut("=" * 50, 1)
# Check architecture
if not self.detectArchitecture():
self.stdOut("WARNING: Custom binaries only available for x86_64", 1)
self.stdOut("Skipping custom binary installation", 1)
self.stdOut("Standard OLS will be used", 1)
return True # Not a failure, just skip
# Detect platform
platform = self.detectPlatform()
self.stdOut(f"Detected platform: {platform}", 1)
# Platform-specific URLs and checksums (OpenLiteSpeed v1.8.4.1 - v2.0.5 Static Build)
BINARY_CONFIGS = {
'rhel8': {
'url': 'https://cyberpanel.net/openlitespeed-phpconfig-x86_64-rhel8-static',
'sha256': '6ce688a237615102cc1603ee1999b3cede0ff3482d31e1f65705e92396d34b3a',
'module_url': None, # RHEL 8 doesn't have module (use RHEL 9 if needed)
'module_sha256': None
},
'rhel9': {
'url': 'https://cyberpanel.net/openlitespeed-phpconfig-x86_64-rhel9-static',
'sha256': '90468fb38767505185013024678d9144ae13100d2355097657f58719d98fbbc4',
'module_url': 'https://cyberpanel.net/cyberpanel_ols_x86_64_rhel.so',
'module_sha256': '127227db81bcbebf80b225fc747b69cfcd4ad2f01cea486aa02d5c9ba6c18109'
},
'ubuntu': {
'url': 'https://cyberpanel.net/openlitespeed-phpconfig-x86_64-ubuntu-static',
'sha256': '89aaf66474e78cb3c1666784e0e7a417550bd317e6ab148201bdc318d36710cb',
'module_url': 'https://cyberpanel.net/cyberpanel_ols_x86_64_ubuntu.so',
'module_sha256': 'e7734f1e6226c2a0a8e00c1f6534ea9f577df9081b046736a774b1c52c28e7e5'
}
}
config = BINARY_CONFIGS.get(platform)
if not config:
self.stdOut(f"ERROR: No binaries available for platform {platform}", 1)
self.stdOut("Skipping custom binary installation", 1)
return True # Not fatal
OLS_BINARY_URL = config['url']
OLS_BINARY_SHA256 = config['sha256']
MODULE_URL = config['module_url']
MODULE_SHA256 = config['module_sha256']
OLS_BINARY_PATH = "/usr/local/lsws/bin/openlitespeed"
MODULE_PATH = "/usr/local/lsws/modules/cyberpanel_ols.so"
# Create backup
from datetime import datetime
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
backup_dir = f"/usr/local/lsws/backup-{timestamp}"
try:
os.makedirs(backup_dir, exist_ok=True)
if os.path.exists(OLS_BINARY_PATH):
shutil.copy2(OLS_BINARY_PATH, f"{backup_dir}/openlitespeed.backup")
self.stdOut(f"Backup created at: {backup_dir}", 1)
except Exception as e:
self.stdOut(f"WARNING: Could not create backup: {e}", 1)
# Download binaries to temp location
tmp_binary = "/tmp/openlitespeed-custom"
tmp_module = "/tmp/cyberpanel_ols.so"
self.stdOut("Downloading custom binaries...", 1)
# Download OpenLiteSpeed binary with checksum verification
if not self.downloadCustomBinary(OLS_BINARY_URL, tmp_binary, OLS_BINARY_SHA256):
self.stdOut("ERROR: Failed to download or verify OLS binary", 1)
self.stdOut("Continuing with standard OLS", 1)
return True # Not fatal, continue with standard OLS
# Download module with checksum verification (if available)
module_downloaded = False
if MODULE_URL and MODULE_SHA256:
if not self.downloadCustomBinary(MODULE_URL, tmp_module, MODULE_SHA256):
self.stdOut("ERROR: Failed to download or verify module", 1)
self.stdOut("Continuing with standard OLS", 1)
return True # Not fatal, continue with standard OLS
module_downloaded = True
else:
self.stdOut("Note: No CyberPanel module for this platform", 1)
# Install OpenLiteSpeed binary
self.stdOut("Installing custom binaries...", 1)
try:
shutil.move(tmp_binary, OLS_BINARY_PATH)
os.chmod(OLS_BINARY_PATH, 0o755)
self.stdOut("Installed OpenLiteSpeed binary", 1)
except Exception as e:
self.stdOut(f"ERROR: Failed to install binary: {e}", 1)
return False
# Install module (if downloaded)
if module_downloaded:
try:
os.makedirs(os.path.dirname(MODULE_PATH), exist_ok=True)
shutil.move(tmp_module, MODULE_PATH)
os.chmod(MODULE_PATH, 0o644)
self.stdOut("Installed CyberPanel module", 1)
except Exception as e:
self.stdOut(f"ERROR: Failed to install module: {e}", 1)
return False
# Verify installation
if os.path.exists(OLS_BINARY_PATH):
if not module_downloaded or os.path.exists(MODULE_PATH):
self.stdOut("=" * 50, 1)
self.stdOut("Custom Binaries Installed Successfully", 1)
self.stdOut("Features enabled:", 1)
self.stdOut(" - Static-linked cross-platform binary", 1)
if module_downloaded:
self.stdOut(" - Apache-style .htaccess support", 1)
self.stdOut(" - php_value/php_flag directives", 1)
self.stdOut(" - Enhanced header control", 1)
self.stdOut(f"Backup: {backup_dir}", 1)
self.stdOut("=" * 50, 1)
# Configure module after installation
self.configureCustomModule()
return True
self.stdOut("ERROR: Installation verification failed", 1)
return False
except Exception as msg:
self.stdOut(f"ERROR: {msg} [installCustomOLSBinaries]", 0)
self.stdOut("Continuing with standard OLS", 1)
return True # Non-fatal error, continue
def configureCustomModule(self):
"""Configure CyberPanel module in OpenLiteSpeed config"""
try:
self.stdOut("Configuring CyberPanel module...", 1)
CONFIG_FILE = "/usr/local/lsws/conf/httpd_config.conf"
if not os.path.exists(CONFIG_FILE):
self.stdOut("WARNING: Config file not found", 1)
self.stdOut("Module will be auto-loaded", 1)
return True
# Check if module is already configured
with open(CONFIG_FILE, 'r') as f:
content = f.read()
if 'cyberpanel_ols' in content:
self.stdOut("Module already configured", 1)
return True
# Add module configuration
module_config = """
module cyberpanel_ols {
ls_enabled 1
}
"""
# Backup config
shutil.copy2(CONFIG_FILE, f"{CONFIG_FILE}.backup")
# Append module config
with open(CONFIG_FILE, 'a') as f:
f.write(module_config)
self.stdOut("Module configured successfully", 1)
return True
except Exception as msg:
self.stdOut(f"WARNING: Module configuration failed: {msg}", 1)
self.stdOut("Module may still work via auto-load", 1)
return True # Non-fatal
def installLiteSpeed(self, ent, serial):
"""Install LiteSpeed Web Server (OpenLiteSpeed or Enterprise)"""
try:
@@ -807,6 +1075,10 @@ class preFlightsChecks:
else:
self.install_package('openlitespeed')
# Install custom binaries with PHP config support
# This replaces the standard binary with enhanced version
self.installCustomOLSBinaries()
# Configure OpenLiteSpeed
self.fix_ols_configs()
self.changePortTo80()

View File

@@ -1635,51 +1635,130 @@ LogFile /var/log/clamav/clamav.log
@staticmethod
def reverse_dns_lookup(ip_address):
"""
Perform reverse DNS lookup for the given IP address using external DNS servers.
Args:
ip_address: The IP address to perform reverse DNS lookup on
Returns:
list: List of rDNS hostnames found, or empty list if lookup fails
"""
try:
import requests
from requests.exceptions import RequestException, Timeout, ConnectionError
fetchURLs = requests.get('https://cyberpanel.net/dnsServers.txt')
# Fetch DNS server URLs with proper error handling
try:
fetchURLs = requests.get('https://cyberpanel.net/dnsServers.txt', timeout=10)
except (ConnectionError, Timeout) as e:
logging.CyberCPLogFileWriter.writeToFile(f'Failed to fetch DNS server list from cyberpanel.net: {str(e)}')
return []
except RequestException as e:
logging.CyberCPLogFileWriter.writeToFile(f'Request error while fetching DNS server list: {str(e)}')
return []
if fetchURLs.status_code == 200:
if fetchURLs.status_code != 200:
logging.CyberCPLogFileWriter.writeToFile(f'Failed to fetch DNS server list: HTTP {fetchURLs.status_code}')
return []
urls = fetchURLs.json()['urls']
try:
urls_data = fetchURLs.json()
if 'urls' not in urls_data:
logging.CyberCPLogFileWriter.writeToFile('DNS server list response missing "urls" key')
return []
urls = urls_data['urls']
except (ValueError, KeyError) as e:
logging.CyberCPLogFileWriter.writeToFile(f'Failed to parse DNS server list JSON: {str(e)}')
return []
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'DNS urls {urls}.')
if not isinstance(urls, list) or len(urls) == 0:
logging.CyberCPLogFileWriter.writeToFile('DNS server list is empty or invalid')
return []
results = []
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'DNS urls {urls}.')
###
results = []
successful_queries = 0
for url in urls:
try:
response = requests.get(f'{url}/index.php?ip={ip_address}', timeout=5)
# Query each DNS server
for url in urls:
try:
response = requests.get(f'{url}/index.php?ip={ip_address}', timeout=5)
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'url to call {ip_address} is {url}')
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'url to call {ip_address} is {url}')
if response.status_code == 200:
if response.status_code == 200:
try:
data = response.json()
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'response from dns system {str(data)}')
# Validate response structure
if not isinstance(data, dict):
logging.CyberCPLogFileWriter.writeToFile(f'Invalid response format from {url}: not a dictionary')
continue
if 'status' not in data:
logging.CyberCPLogFileWriter.writeToFile(f'Response from {url} missing "status" key')
continue
if data['status'] == 1:
results.append(data['results']['8.8.8.8'])
results.append(data['results']['1.1.1.1'])
results.append(data['results']['9.9.9.9'])
except:
pass
# Validate results structure
if 'results' not in data or not isinstance(data['results'], dict):
logging.CyberCPLogFileWriter.writeToFile(f'Response from {url} missing or invalid "results" key')
continue
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'rDNS result of {ip_address} is {str(results)}')
results_dict = data['results']
# Safely extract results from different DNS servers
dns_servers = ['8.8.8.8', '1.1.1.1', '9.9.9.9']
for dns_server in dns_servers:
if dns_server in results_dict:
result_value = results_dict[dns_server]
if result_value and result_value not in results:
results.append(result_value)
successful_queries += 1
else:
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'DNS server {url} returned status != 1: {data.get("status", "unknown")}')
except ValueError as e:
logging.CyberCPLogFileWriter.writeToFile(f'Failed to parse JSON response from {url}: {str(e)}')
continue
except KeyError as e:
logging.CyberCPLogFileWriter.writeToFile(f'Missing key in response from {url}: {str(e)}')
continue
else:
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'DNS server {url} returned HTTP {response.status_code}')
except Timeout as e:
logging.CyberCPLogFileWriter.writeToFile(f'Timeout while querying DNS server {url}: {str(e)}')
continue
except ConnectionError as e:
logging.CyberCPLogFileWriter.writeToFile(f'Connection error while querying DNS server {url}: {str(e)}')
continue
except RequestException as e:
logging.CyberCPLogFileWriter.writeToFile(f'Request error while querying DNS server {url}: {str(e)}')
continue
except Exception as e:
logging.CyberCPLogFileWriter.writeToFile(f'Unexpected error while querying DNS server {url}: {str(e)}')
continue
###
if os.path.exists(ProcessUtilities.debugPath):
logging.CyberCPLogFileWriter.writeToFile(f'rDNS result of {ip_address} is {str(results)} (successful queries: {successful_queries}/{len(urls)})')
return results
# Return results (empty list if no successful queries)
return results
except ImportError as e:
logging.CyberCPLogFileWriter.writeToFile(f'Failed to import requests library: {str(e)}')
return []
except BaseException as e:
logging.CyberCPLogFileWriter.writeToFile(f'Error in fetch rDNS {str(msg)}')
# Handle errors, e.g., if reverse DNS lookup fails
logging.CyberCPLogFileWriter.writeToFile(f'Unexpected error in reverse_dns_lookup for IP {ip_address}: {str(e)}')
return []
@staticmethod

View File

@@ -637,6 +637,279 @@ class Upgrade:
except IOError as err:
pass
@staticmethod
def detectArchitecture():
"""Detect system architecture - custom binaries only for x86_64"""
try:
import platform
arch = platform.machine()
return arch == "x86_64"
except Exception as msg:
Upgrade.stdOut(str(msg) + " [detectArchitecture]", 0)
return False
@staticmethod
def detectPlatform():
"""Detect OS platform for binary selection (rhel8, rhel9, ubuntu)"""
try:
# Check for Ubuntu
if os.path.exists('/etc/lsb-release'):
with open('/etc/lsb-release', 'r') as f:
content = f.read()
if 'Ubuntu' in content or 'ubuntu' in content:
return 'ubuntu'
# Check for RHEL-based distributions
if os.path.exists('/etc/os-release'):
with open('/etc/os-release', 'r') as f:
content = f.read().lower()
# Check for version 8.x (RHEL, AlmaLinux, Rocky, CloudLinux, CentOS 8)
if 'version="8.' in content or 'version_id="8.' in content:
if any(distro in content for distro in ['red hat', 'almalinux', 'rocky', 'cloudlinux', 'centos']):
return 'rhel8'
# Check for version 9.x
if 'version="9.' in content or 'version_id="9.' in content:
if any(distro in content for distro in ['red hat', 'almalinux', 'rocky', 'cloudlinux', 'centos']):
return 'rhel9'
# Default to rhel9 if can't detect (safer default for newer systems)
Upgrade.stdOut("WARNING: Could not detect platform, defaulting to rhel9", 0)
return 'rhel9'
except Exception as msg:
Upgrade.stdOut(f"ERROR detecting platform: {msg}, defaulting to rhel9", 0)
return 'rhel9'
@staticmethod
def downloadCustomBinary(url, destination, expected_sha256=None):
"""Download custom binary file with optional checksum verification"""
try:
Upgrade.stdOut(f"Downloading {os.path.basename(destination)}...", 0)
# Use wget for better progress display
command = f'wget -q --show-progress {url} -O {destination}'
res = subprocess.call(shlex.split(command))
# Check if file was downloaded successfully by verifying it exists and has reasonable size
if os.path.exists(destination):
file_size = os.path.getsize(destination)
# Verify file size is reasonable (at least 10KB to avoid error pages/empty files)
if file_size > 10240: # 10KB
if file_size > 1048576: # 1MB
Upgrade.stdOut(f"Downloaded successfully ({file_size / (1024*1024):.2f} MB)", 0)
else:
Upgrade.stdOut(f"Downloaded successfully ({file_size / 1024:.2f} KB)", 0)
# Verify checksum if provided
if expected_sha256:
Upgrade.stdOut("Verifying checksum...", 0)
import hashlib
sha256_hash = hashlib.sha256()
with open(destination, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
actual_sha256 = sha256_hash.hexdigest()
if actual_sha256 == expected_sha256:
Upgrade.stdOut("Checksum verified successfully", 0)
return True
else:
Upgrade.stdOut(f"ERROR: Checksum mismatch!", 0)
Upgrade.stdOut(f"Expected: {expected_sha256}", 0)
Upgrade.stdOut(f"Got: {actual_sha256}", 0)
return False
else:
return True
else:
Upgrade.stdOut(f"ERROR: Downloaded file too small ({file_size} bytes)", 0)
return False
else:
Upgrade.stdOut("ERROR: Download failed - file not found", 0)
return False
except Exception as msg:
Upgrade.stdOut(f"ERROR: {msg} [downloadCustomBinary]", 0)
return False
@staticmethod
def installCustomOLSBinaries():
"""Install custom OpenLiteSpeed binaries with PHP config support"""
try:
Upgrade.stdOut("Installing Custom OpenLiteSpeed Binaries", 0)
Upgrade.stdOut("=" * 50, 0)
# Check architecture
if not Upgrade.detectArchitecture():
Upgrade.stdOut("WARNING: Custom binaries only available for x86_64", 0)
Upgrade.stdOut("Skipping custom binary installation", 0)
Upgrade.stdOut("Standard OLS will be used", 0)
return True # Not a failure, just skip
# Detect platform
platform = Upgrade.detectPlatform()
Upgrade.stdOut(f"Detected platform: {platform}", 0)
# Platform-specific URLs and checksums (OpenLiteSpeed v1.8.4.1 - v2.0.5 Static Build)
BINARY_CONFIGS = {
'rhel8': {
'url': 'https://cyberpanel.net/openlitespeed-phpconfig-x86_64-rhel8-static',
'sha256': '6ce688a237615102cc1603ee1999b3cede0ff3482d31e1f65705e92396d34b3a',
'module_url': None, # RHEL 8 doesn't have module (use RHEL 9 if needed)
'module_sha256': None
},
'rhel9': {
'url': 'https://cyberpanel.net/openlitespeed-phpconfig-x86_64-rhel9-static',
'sha256': '90468fb38767505185013024678d9144ae13100d2355097657f58719d98fbbc4',
'module_url': 'https://cyberpanel.net/cyberpanel_ols_x86_64_rhel.so',
'module_sha256': '127227db81bcbebf80b225fc747b69cfcd4ad2f01cea486aa02d5c9ba6c18109'
},
'ubuntu': {
'url': 'https://cyberpanel.net/openlitespeed-phpconfig-x86_64-ubuntu-static',
'sha256': '89aaf66474e78cb3c1666784e0e7a417550bd317e6ab148201bdc318d36710cb',
'module_url': 'https://cyberpanel.net/cyberpanel_ols_x86_64_ubuntu.so',
'module_sha256': 'e7734f1e6226c2a0a8e00c1f6534ea9f577df9081b046736a774b1c52c28e7e5'
}
}
config = BINARY_CONFIGS.get(platform)
if not config:
Upgrade.stdOut(f"ERROR: No binaries available for platform {platform}", 0)
Upgrade.stdOut("Skipping custom binary installation", 0)
return True # Not fatal
OLS_BINARY_URL = config['url']
OLS_BINARY_SHA256 = config['sha256']
MODULE_URL = config['module_url']
MODULE_SHA256 = config['module_sha256']
OLS_BINARY_PATH = "/usr/local/lsws/bin/openlitespeed"
MODULE_PATH = "/usr/local/lsws/modules/cyberpanel_ols.so"
# Create backup
from datetime import datetime
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
backup_dir = f"/usr/local/lsws/backup-{timestamp}"
try:
os.makedirs(backup_dir, exist_ok=True)
if os.path.exists(OLS_BINARY_PATH):
shutil.copy2(OLS_BINARY_PATH, f"{backup_dir}/openlitespeed.backup")
Upgrade.stdOut(f"Backup created at: {backup_dir}", 0)
except Exception as e:
Upgrade.stdOut(f"WARNING: Could not create backup: {e}", 0)
# Download binaries to temp location
tmp_binary = "/tmp/openlitespeed-custom"
tmp_module = "/tmp/cyberpanel_ols.so"
Upgrade.stdOut("Downloading custom binaries...", 0)
# Download OpenLiteSpeed binary with checksum verification
if not Upgrade.downloadCustomBinary(OLS_BINARY_URL, tmp_binary, OLS_BINARY_SHA256):
Upgrade.stdOut("ERROR: Failed to download or verify OLS binary", 0)
Upgrade.stdOut("Continuing with standard OLS", 0)
return True # Not fatal, continue with standard OLS
# Download module with checksum verification (if available)
module_downloaded = False
if MODULE_URL and MODULE_SHA256:
if not Upgrade.downloadCustomBinary(MODULE_URL, tmp_module, MODULE_SHA256):
Upgrade.stdOut("ERROR: Failed to download or verify module", 0)
Upgrade.stdOut("Continuing with standard OLS", 0)
return True # Not fatal, continue with standard OLS
module_downloaded = True
else:
Upgrade.stdOut("Note: No CyberPanel module for this platform", 0)
# Install OpenLiteSpeed binary
Upgrade.stdOut("Installing custom binaries...", 0)
try:
shutil.move(tmp_binary, OLS_BINARY_PATH)
os.chmod(OLS_BINARY_PATH, 0o755)
Upgrade.stdOut("Installed OpenLiteSpeed binary", 0)
except Exception as e:
Upgrade.stdOut(f"ERROR: Failed to install binary: {e}", 0)
return False
# Install module (if downloaded)
if module_downloaded:
try:
os.makedirs(os.path.dirname(MODULE_PATH), exist_ok=True)
shutil.move(tmp_module, MODULE_PATH)
os.chmod(MODULE_PATH, 0o644)
Upgrade.stdOut("Installed CyberPanel module", 0)
except Exception as e:
Upgrade.stdOut(f"ERROR: Failed to install module: {e}", 0)
return False
# Verify installation
if os.path.exists(OLS_BINARY_PATH):
if not module_downloaded or os.path.exists(MODULE_PATH):
Upgrade.stdOut("=" * 50, 0)
Upgrade.stdOut("Custom Binaries Installed Successfully", 0)
Upgrade.stdOut("Features enabled:", 0)
Upgrade.stdOut(" - Static-linked cross-platform binary", 0)
if module_downloaded:
Upgrade.stdOut(" - Apache-style .htaccess support", 0)
Upgrade.stdOut(" - php_value/php_flag directives", 0)
Upgrade.stdOut(" - Enhanced header control", 0)
Upgrade.stdOut(f"Backup: {backup_dir}", 0)
Upgrade.stdOut("=" * 50, 0)
# Configure module after installation
Upgrade.configureCustomModule()
return True
Upgrade.stdOut("ERROR: Installation verification failed", 0)
return False
except Exception as msg:
Upgrade.stdOut(f"ERROR: {msg} [installCustomOLSBinaries]", 0)
Upgrade.stdOut("Continuing with standard OLS", 0)
return True # Non-fatal error, continue
@staticmethod
def configureCustomModule():
"""Configure CyberPanel module in OpenLiteSpeed config"""
try:
Upgrade.stdOut("Configuring CyberPanel module...", 0)
CONFIG_FILE = "/usr/local/lsws/conf/httpd_config.conf"
if not os.path.exists(CONFIG_FILE):
Upgrade.stdOut("WARNING: Config file not found", 0)
Upgrade.stdOut("Module will be auto-loaded", 0)
return True
# Check if module is already configured
with open(CONFIG_FILE, 'r') as f:
content = f.read()
if 'cyberpanel_ols' in content:
Upgrade.stdOut("Module already configured", 0)
return True
# Add module configuration
module_config = """
module cyberpanel_ols {
ls_enabled 1
}
"""
# Backup config
shutil.copy2(CONFIG_FILE, f"{CONFIG_FILE}.backup")
# Append module config
with open(CONFIG_FILE, 'a') as f:
f.write(module_config)
Upgrade.stdOut("Module configured successfully", 0)
return True
except Exception as msg:
Upgrade.stdOut(f"WARNING: Module configuration failed: {msg}", 0)
Upgrade.stdOut("Module may still work via auto-load", 0)
return True # Non-fatal
@staticmethod
def download_install_phpmyadmin():
try:
@@ -4892,6 +5165,10 @@ slowlog = /var/log/php{version}-fpm-slow.log
Upgrade.dockerUsers()
Upgrade.setupPHPSymlink()
Upgrade.setupComposer()
# Install custom OpenLiteSpeed binaries if OLS is installed
if os.path.exists('/usr/local/lsws/bin/openlitespeed'):
Upgrade.installCustomOLSBinaries()
##

View File

@@ -124,8 +124,14 @@ class virtualHostUtilities:
else:
try:
rDNS = mailUtilities.reverse_dns_lookup(serverIP)
# Check if rDNS lookup returned empty results (indicating lookup failure)
if not rDNS or len(rDNS) == 0:
message = f'Failed to perform reverse DNS lookup for server IP {serverIP}. The DNS lookup service may be unavailable or the IP address may not have rDNS configured. Please verify your rDNS settings with your hosting provider or check the "Skip rDNS/PTR Check" option if you do not need email services. [404]'
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, message)
logging.CyberCPLogFileWriter.writeToFile(message)
return 0
except Exception as e:
message = f'Failed to perform reverse DNS lookup: {str(e)} [404]'
message = f'Failed to perform reverse DNS lookup for server IP {serverIP}: {str(e)}. Please verify your rDNS settings with your hosting provider or check the "Skip rDNS/PTR Check" option if you do not need email services. [404]'
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, message)
logging.CyberCPLogFileWriter.writeToFile(message)
return 0
@@ -329,9 +335,22 @@ class virtualHostUtilities:
#first check if hostname is already configured as rDNS, if not return error
# Validate that we have rDNS results before checking
if not rDNS or len(rDNS) == 0:
message = f'Reverse DNS lookup failed for server IP {serverIP}. Unable to verify if domain "{Domain}" is configured as rDNS. Please check your rDNS configuration with your hosting provider or select "Skip rDNS/PTR Check" if you do not need email services. [404]'
print(message)
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, message)
logging.CyberCPLogFileWriter.writeToFile(message)
config['hostname'] = Domain
config['onboarding'] = 3
config['skipRDNSCheck'] = skipRDNSCheck
admin.config = json.dumps(config)
admin.save()
return 0
if Domain not in rDNS:
message = 'Domain that you have provided is not configured as rDNS for your server IP. [404]'
rDNS_list_str = ', '.join(rDNS) if rDNS else 'none'
message = f'Domain "{Domain}" that you have provided is not configured as rDNS for your server IP {serverIP}. Current rDNS records: {rDNS_list_str}. Please configure rDNS (PTR record) for your IP address to point to "{Domain}" with your hosting provider, or select "Skip rDNS/PTR Check" if you do not need email services. [404]'
print(message)
logging.CyberCPLogFileWriter.statusWriter(tempStatusPath, message)
logging.CyberCPLogFileWriter.writeToFile(message)

View File

@@ -1285,28 +1285,36 @@ app.controller('modSecRulesPack', function ($scope, $http, $timeout, $window) {
if (response.data.owaspInstalled === 1) {
$('#owaspInstalled').bootstrapToggle('on');
$scope.owaspDisable = false;
owaspInstalled = true;
} else {
$('#owaspInstalled').bootstrapToggle('off');
$scope.owaspDisable = true;
owaspInstalled = false;
}
if (response.data.comodoInstalled === 1) {
$('#comodoInstalled').bootstrapToggle('on');
$scope.comodoDisable = false;
comodoInstalled = true;
} else {
$('#comodoInstalled').bootstrapToggle('off');
$scope.comodoDisable = true;
comodoInstalled = false;
}
} else {
if (response.data.owaspInstalled === 1) {
$scope.owaspDisable = false;
owaspInstalled = true;
} else {
$scope.owaspDisable = true;
owaspInstalled = false;
}
if (response.data.comodoInstalled === 1) {
$scope.comodoDisable = false;
comodoInstalled = true;
} else {
$scope.comodoDisable = true;
comodoInstalled = false;
}
}

View File

@@ -2563,11 +2563,12 @@ Require valid-user
childDomains = []
for web in websites:
for child in web.childdomains_set.filter(alais=0):
if child.domain == f'mail.{web.domain}':
pass
else:
childDomains.append(child)
for child in web.childdomains_set.all():
if child.alais == 0:
if child.domain == f'mail.{web.domain}':
pass
else:
childDomains.append(child)
pagination = self.getPagination(len(childDomains), recordsToShow)
json_data = self.findChildsListJson(childDomains[finalPageNumber:endPageNumber])
@@ -2577,6 +2578,8 @@ Require valid-user
final_json = json.dumps(final_dic)
return HttpResponse(final_json)
except BaseException as msg:
import traceback
logging.CyberCPLogFileWriter.writeToFile(f"fetchChildDomainsMain error for userID {userID}: {str(msg)}\n{traceback.format_exc()}")
dic = {'status': 1, 'listWebSiteStatus': 0, 'error_message': str(msg)}
json_data = json.dumps(dic)
return HttpResponse(json_data)