mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-11-12 08:16:11 +01:00
conflict fix
This commit is contained in:
BIN
ModuleDeveloperGuide.pdf
Normal file
BIN
ModuleDeveloperGuide.pdf
Normal file
Binary file not shown.
@@ -805,10 +805,195 @@
|
||||
.notification-shown.ai-scanner-shown #main-content {
|
||||
padding-top: 220px;
|
||||
}
|
||||
|
||||
|
||||
.notification-shown .ai-scanner-banner {
|
||||
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) {
|
||||
@@ -816,54 +1001,110 @@
|
||||
left: 0;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
|
||||
|
||||
.ai-scanner-content {
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
|
||||
.ai-scanner-text {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
|
||||
.ai-scanner-main-text {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
|
||||
.ai-scanner-sub-text {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
|
||||
.ai-scanner-btn {
|
||||
padding: 10px 20px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
|
||||
.ai-scanner-icon {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
.ai-scanner-icon i {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
/* .htaccess banner mobile styles */
|
||||
.htaccess-feature-banner {
|
||||
left: 0;
|
||||
padding: 14px 20px;
|
||||
}
|
||||
|
||||
.htaccess-content {
|
||||
gap: 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.htaccess-text {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.htaccess-main-text {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.htaccess-sub-text {
|
||||
font-size: 0.8rem;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.htaccess-btn {
|
||||
padding: 12px 22px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.htaccess-icon {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.htaccess-icon i {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.ai-scanner-content {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
|
||||
.ai-scanner-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
.ai-scanner-close {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
|
||||
/* .htaccess banner small mobile styles */
|
||||
.htaccess-content {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.htaccess-actions {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.htaccess-close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
@@ -1760,7 +2001,33 @@
|
||||
</button>
|
||||
</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 %}
|
||||
@@ -1841,10 +2108,10 @@
|
||||
|
||||
// Backup notification banner logic
|
||||
function checkBackupStatus() {
|
||||
// Check if user has dismissed the notification permanently (from server-side context)
|
||||
{% if backup_notification_dismissed %}
|
||||
return; // Notification already dismissed permanently
|
||||
{% endif %}
|
||||
// Check if user has dismissed the notification in this session
|
||||
if (sessionStorage.getItem('backupNotificationDismissed') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if user has backup configured (you'll need to implement this API)
|
||||
// For now, we'll show it by default unless they have a backup plan
|
||||
@@ -1871,81 +2138,83 @@
|
||||
const body = document.body;
|
||||
banner.classList.remove('show');
|
||||
body.classList.remove('notification-shown');
|
||||
|
||||
// Dismiss permanently via API
|
||||
fetch('/base/dismiss_backup_notification', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === 1) {
|
||||
console.log('Backup notification dismissed permanently');
|
||||
} else {
|
||||
console.error('Failed to dismiss backup notification:', data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error dismissing backup notification:', error);
|
||||
});
|
||||
// Remember dismissal for this session
|
||||
sessionStorage.setItem('backupNotificationDismissed', 'true');
|
||||
}
|
||||
|
||||
// AI Scanner Notification Functions
|
||||
function checkAIScannerStatus() {
|
||||
// Check if user has dismissed the notification permanently (from server-side context)
|
||||
{% if ai_scanner_notification_dismissed %}
|
||||
return; // Notification already dismissed permanently
|
||||
{% endif %}
|
||||
|
||||
// Check if user has dismissed the notification in this session
|
||||
if (sessionStorage.getItem('aiScannerNotificationDismissed') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if we're not already on the AI Scanner page
|
||||
if (!window.location.href.includes('aiscanner')) {
|
||||
showAIScannerNotification();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function showAIScannerNotification() {
|
||||
const banner = document.getElementById('ai-scanner-notification');
|
||||
const body = document.body;
|
||||
banner.classList.add('show');
|
||||
body.classList.add('ai-scanner-shown');
|
||||
}
|
||||
|
||||
|
||||
function dismissAIScannerNotification() {
|
||||
const banner = document.getElementById('ai-scanner-notification');
|
||||
const body = document.body;
|
||||
banner.classList.remove('show');
|
||||
body.classList.remove('ai-scanner-shown');
|
||||
|
||||
// Dismiss permanently via API
|
||||
fetch('/base/dismiss_ai_scanner_notification', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === 1) {
|
||||
console.log('AI scanner notification dismissed permanently');
|
||||
} else {
|
||||
console.error('Failed to dismiss AI scanner notification:', data.error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error dismissing AI scanner notification:', error);
|
||||
});
|
||||
// Remember dismissal for this session
|
||||
sessionStorage.setItem('aiScannerNotificationDismissed', 'true');
|
||||
}
|
||||
|
||||
// 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();
|
||||
});
|
||||
|
||||
@@ -1986,9 +1986,30 @@ Current_Dir="$(pwd)"
|
||||
rm -f /usr/local/lsws/cyberpanel-tmp
|
||||
mkdir /usr/local/lsws/cyberpanel-tmp
|
||||
cd /usr/local/lsws/cyberpanel-tmp || exit
|
||||
|
||||
# Try to download timezonedb, but continue if it fails
|
||||
wget -O timezonedb.tgz https://cyberpanel.sh/pecl.php.net/get/timezonedb
|
||||
if [ ! -f timezonedb.tgz ] || [ ! -s timezonedb.tgz ]; then
|
||||
log_info "WARNING: Failed to download timezonedb, skipping installation"
|
||||
cd "$Current_Dir" || exit
|
||||
rm -rf /usr/local/lsws/cyberpanel-tmp
|
||||
return 0
|
||||
fi
|
||||
|
||||
tar xzvf timezonedb.tgz
|
||||
cd timezonedb-* || exit
|
||||
if [ ! -d timezonedb-* ]; then
|
||||
log_info "WARNING: Failed to extract timezonedb, skipping installation"
|
||||
cd "$Current_Dir" || exit
|
||||
rm -rf /usr/local/lsws/cyberpanel-tmp
|
||||
return 0
|
||||
fi
|
||||
|
||||
cd timezonedb-* || {
|
||||
log_info "WARNING: Cannot enter timezonedb directory, skipping installation"
|
||||
cd "$Current_Dir" || exit
|
||||
rm -rf /usr/local/lsws/cyberpanel-tmp
|
||||
return 0
|
||||
}
|
||||
|
||||
# Install required packages for building PHP extensions
|
||||
if [[ "$Server_OS" = "Ubuntu" ]] ; then
|
||||
|
||||
@@ -1471,8 +1471,8 @@ app.controller('modSecRulesPack', function ($scope, $http, $timeout, $window) {
|
||||
|
||||
var owaspInstalled = false;
|
||||
var comodoInstalled = false;
|
||||
var counterOWASP = 0;
|
||||
var counterComodo = 0;
|
||||
var owaspInitialized = false;
|
||||
var comodoInitialized = false;
|
||||
|
||||
|
||||
$('#owaspInstalled').change(function () {
|
||||
@@ -1480,15 +1480,13 @@ app.controller('modSecRulesPack', function ($scope, $http, $timeout, $window) {
|
||||
owaspInstalled = $(this).prop('checked');
|
||||
$scope.ruleFiles = true;
|
||||
|
||||
if (counterOWASP !== 0) {
|
||||
if (owaspInitialized) {
|
||||
if (owaspInstalled === true) {
|
||||
installModSecRulesPack('installOWASP');
|
||||
} else {
|
||||
installModSecRulesPack('disableOWASP')
|
||||
}
|
||||
}
|
||||
|
||||
counterOWASP = counterOWASP + 1;
|
||||
});
|
||||
|
||||
$('#comodoInstalled').change(function () {
|
||||
@@ -1496,7 +1494,7 @@ app.controller('modSecRulesPack', function ($scope, $http, $timeout, $window) {
|
||||
$scope.ruleFiles = true;
|
||||
comodoInstalled = $(this).prop('checked');
|
||||
|
||||
if (counterComodo !== 0) {
|
||||
if (comodoInitialized) {
|
||||
|
||||
if (comodoInstalled === true) {
|
||||
installModSecRulesPack('installComodo');
|
||||
@@ -1505,8 +1503,6 @@ app.controller('modSecRulesPack', function ($scope, $http, $timeout, $window) {
|
||||
}
|
||||
}
|
||||
|
||||
counterComodo = counterComodo + 1;
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -1545,6 +1541,9 @@ app.controller('modSecRulesPack', function ($scope, $http, $timeout, $window) {
|
||||
$('#owaspInstalled').prop('checked', false);
|
||||
$scope.owaspDisable = true;
|
||||
}
|
||||
// Mark as initialized after setting initial state
|
||||
owaspInitialized = true;
|
||||
|
||||
if (response.data.comodoInstalled === 1) {
|
||||
$('#comodoInstalled').prop('checked', true);
|
||||
$scope.comodoDisable = false;
|
||||
@@ -1552,6 +1551,8 @@ app.controller('modSecRulesPack', function ($scope, $http, $timeout, $window) {
|
||||
$('#comodoInstalled').prop('checked', false);
|
||||
$scope.comodoDisable = true;
|
||||
}
|
||||
// Mark as initialized after setting initial state
|
||||
comodoInitialized = true;
|
||||
} else {
|
||||
|
||||
if (response.data.owaspInstalled === 1) {
|
||||
|
||||
@@ -270,10 +270,346 @@ class InstallCyberPanel:
|
||||
# Fallback to known latest version
|
||||
return "6.3.4"
|
||||
|
||||
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:
|
||||
logging.InstallLog.writeToFile(str(msg) + " [detectArchitecture]")
|
||||
return False
|
||||
|
||||
def detectBinarySuffix(self):
|
||||
"""Detect which binary suffix to use based on OS distribution
|
||||
Returns 'ubuntu' for Ubuntu/Debian systems
|
||||
Returns 'rhel8' for RHEL/AlmaLinux/Rocky 8.x systems
|
||||
Returns 'rhel9' for RHEL/AlmaLinux/Rocky 9.x systems
|
||||
"""
|
||||
try:
|
||||
# Check /etc/os-release first for more accurate detection
|
||||
if os.path.exists('/etc/os-release'):
|
||||
with open('/etc/os-release', 'r') as f:
|
||||
os_release = f.read().lower()
|
||||
|
||||
# Check for Ubuntu/Debian FIRST
|
||||
if 'ubuntu' in os_release or 'debian' in os_release:
|
||||
return 'ubuntu'
|
||||
|
||||
# Check for RHEL-based distributions and extract version
|
||||
if any(x in os_release for x in ['almalinux', 'rocky', 'rhel', 'centos stream']):
|
||||
# Extract version number
|
||||
for line in os_release.split('\n'):
|
||||
if 'version_id' in line:
|
||||
version = line.split('=')[1].strip('"').split('.')[0]
|
||||
if version == '9':
|
||||
return 'rhel9'
|
||||
elif version == '8':
|
||||
return 'rhel8'
|
||||
# Default to rhel9 if version extraction fails
|
||||
return 'rhel9'
|
||||
|
||||
# Fallback: Use distro variable
|
||||
# Ubuntu/Debian → ubuntu suffix
|
||||
if self.distro == ubuntu:
|
||||
return 'ubuntu'
|
||||
|
||||
# CentOS 8+/AlmaLinux/Rocky/OpenEuler → rhel9 by default
|
||||
elif self.distro == cent8 or self.distro == openeuler:
|
||||
return 'rhel9'
|
||||
|
||||
# CentOS 7 → ubuntu suffix (uses libcrypt.so.1)
|
||||
elif self.distro == centos:
|
||||
return 'ubuntu'
|
||||
|
||||
# Default to ubuntu for unknown distros
|
||||
else:
|
||||
InstallCyberPanel.stdOut("Unknown OS distribution, defaulting to Ubuntu binaries", 1)
|
||||
return 'ubuntu'
|
||||
|
||||
except Exception as msg:
|
||||
logging.InstallLog.writeToFile(str(msg) + " [detectBinarySuffix]")
|
||||
InstallCyberPanel.stdOut("Error detecting OS, defaulting to Ubuntu binaries", 1)
|
||||
return 'ubuntu'
|
||||
|
||||
def downloadCustomBinary(self, url, destination):
|
||||
"""Download custom binary file"""
|
||||
try:
|
||||
InstallCyberPanel.stdOut(f"Downloading {os.path.basename(destination)}...", 1)
|
||||
|
||||
# Use wget for better progress display
|
||||
command = f'wget -q --show-progress {url} -O {destination}'
|
||||
install_utils.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
|
||||
InstallCyberPanel.stdOut(f"Downloaded successfully ({file_size / (1024*1024):.2f} MB)", 1)
|
||||
else:
|
||||
InstallCyberPanel.stdOut(f"Downloaded successfully ({file_size / 1024:.2f} KB)", 1)
|
||||
return True
|
||||
else:
|
||||
InstallCyberPanel.stdOut(f"ERROR: Downloaded file too small ({file_size} bytes)", 1)
|
||||
return False
|
||||
else:
|
||||
InstallCyberPanel.stdOut("ERROR: Download failed - file not found", 1)
|
||||
return False
|
||||
|
||||
except Exception as msg:
|
||||
logging.InstallLog.writeToFile(str(msg) + " [downloadCustomBinary]")
|
||||
InstallCyberPanel.stdOut(f"ERROR: {msg}", 1)
|
||||
return False
|
||||
|
||||
def verifyCustomBinary(self, binary_path):
|
||||
"""Verify custom binary has correct dependencies and can run"""
|
||||
try:
|
||||
InstallCyberPanel.stdOut("Verifying custom binary compatibility...", 1)
|
||||
|
||||
# Check library dependencies
|
||||
command = f'ldd {binary_path}'
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
InstallCyberPanel.stdOut("ERROR: Failed to check binary dependencies", 1)
|
||||
return False
|
||||
|
||||
# Check for missing libraries
|
||||
if 'not found' in result.stdout:
|
||||
InstallCyberPanel.stdOut("ERROR: Binary has missing library dependencies:", 1)
|
||||
for line in result.stdout.split('\n'):
|
||||
if 'not found' in line:
|
||||
InstallCyberPanel.stdOut(f" {line.strip()}", 1)
|
||||
return False
|
||||
|
||||
# Try to run the binary with -v to check if it can execute
|
||||
command = f'{binary_path} -v'
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=5)
|
||||
|
||||
if result.returncode != 0:
|
||||
InstallCyberPanel.stdOut("ERROR: Binary failed to execute", 1)
|
||||
if result.stderr:
|
||||
InstallCyberPanel.stdOut(f" Error: {result.stderr.strip()}", 1)
|
||||
return False
|
||||
|
||||
InstallCyberPanel.stdOut("Binary verification successful", 1)
|
||||
return True
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
InstallCyberPanel.stdOut("ERROR: Binary verification timed out", 1)
|
||||
return False
|
||||
except Exception as msg:
|
||||
logging.InstallLog.writeToFile(str(msg) + " [verifyCustomBinary]")
|
||||
InstallCyberPanel.stdOut(f"ERROR: Verification failed: {msg}", 1)
|
||||
return False
|
||||
|
||||
def rollbackCustomBinary(self, backup_dir, binary_path, module_path):
|
||||
"""Rollback to original binary if custom binary fails"""
|
||||
try:
|
||||
InstallCyberPanel.stdOut("Rolling back to original binary...", 1)
|
||||
|
||||
backup_binary = f"{backup_dir}/openlitespeed.backup"
|
||||
|
||||
# Restore original binary if backup exists
|
||||
if os.path.exists(backup_binary):
|
||||
shutil.copy2(backup_binary, binary_path)
|
||||
os.chmod(binary_path, 0o755)
|
||||
InstallCyberPanel.stdOut("Original binary restored successfully", 1)
|
||||
else:
|
||||
InstallCyberPanel.stdOut("WARNING: No backup found, cannot restore", 1)
|
||||
|
||||
# Remove failed custom module
|
||||
if os.path.exists(module_path):
|
||||
os.remove(module_path)
|
||||
InstallCyberPanel.stdOut("Custom module removed", 1)
|
||||
|
||||
InstallCyberPanel.stdOut("Rollback completed", 1)
|
||||
return True
|
||||
|
||||
except Exception as msg:
|
||||
logging.InstallLog.writeToFile(str(msg) + " [rollbackCustomBinary]")
|
||||
InstallCyberPanel.stdOut(f"ERROR: Rollback failed: {msg}", 1)
|
||||
return False
|
||||
|
||||
def installCustomOLSBinaries(self):
|
||||
"""Install custom OpenLiteSpeed binaries with PHP config support"""
|
||||
try:
|
||||
InstallCyberPanel.stdOut("Installing Custom OpenLiteSpeed Binaries", 1)
|
||||
InstallCyberPanel.stdOut("=" * 50, 1)
|
||||
|
||||
# Check architecture
|
||||
if not self.detectArchitecture():
|
||||
InstallCyberPanel.stdOut("WARNING: Custom binaries only available for x86_64", 1)
|
||||
InstallCyberPanel.stdOut("Skipping custom binary installation", 1)
|
||||
InstallCyberPanel.stdOut("Standard OLS will be used", 1)
|
||||
return True # Not a failure, just skip
|
||||
|
||||
# Detect OS and select appropriate binary suffix
|
||||
binary_suffix = self.detectBinarySuffix()
|
||||
InstallCyberPanel.stdOut(f"Detected OS type: using '{binary_suffix}' binaries", 1)
|
||||
|
||||
# URLs for custom binaries with OS-specific paths
|
||||
BASE_URL = "https://cyberpanel.net/binaries"
|
||||
|
||||
# Set URLs based on OS type
|
||||
if binary_suffix == 'rhel8':
|
||||
OLS_BINARY_URL = f"{BASE_URL}/rhel8/openlitespeed-phpconfig-x86_64-rhel8"
|
||||
MODULE_URL = f"{BASE_URL}/rhel8/cyberpanel_ols_x86_64_rhel8.so"
|
||||
elif binary_suffix == 'rhel9':
|
||||
OLS_BINARY_URL = f"{BASE_URL}/rhel9/openlitespeed-phpconfig-x86_64-rhel"
|
||||
MODULE_URL = f"{BASE_URL}/rhel9/cyberpanel_ols_x86_64_rhel.so"
|
||||
else: # ubuntu
|
||||
OLS_BINARY_URL = f"{BASE_URL}/ubuntu/openlitespeed-phpconfig-x86_64-ubuntu"
|
||||
MODULE_URL = f"{BASE_URL}/ubuntu/cyberpanel_ols_x86_64_ubuntu.so"
|
||||
|
||||
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")
|
||||
InstallCyberPanel.stdOut(f"Backup created at: {backup_dir}", 1)
|
||||
except Exception as e:
|
||||
InstallCyberPanel.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"
|
||||
|
||||
InstallCyberPanel.stdOut("Downloading custom binaries...", 1)
|
||||
|
||||
# Download OpenLiteSpeed binary
|
||||
if not self.downloadCustomBinary(OLS_BINARY_URL, tmp_binary):
|
||||
InstallCyberPanel.stdOut("ERROR: Failed to download OLS binary", 1)
|
||||
InstallCyberPanel.stdOut("Continuing with standard OLS", 1)
|
||||
return True # Not fatal, continue with standard OLS
|
||||
|
||||
# Download module
|
||||
if not self.downloadCustomBinary(MODULE_URL, tmp_module):
|
||||
InstallCyberPanel.stdOut("ERROR: Failed to download module", 1)
|
||||
InstallCyberPanel.stdOut("Continuing with standard OLS", 1)
|
||||
return True # Not fatal, continue with standard OLS
|
||||
|
||||
# Install OpenLiteSpeed binary
|
||||
InstallCyberPanel.stdOut("Installing custom binaries...", 1)
|
||||
|
||||
try:
|
||||
shutil.move(tmp_binary, OLS_BINARY_PATH)
|
||||
os.chmod(OLS_BINARY_PATH, 0o755)
|
||||
InstallCyberPanel.stdOut("Installed OpenLiteSpeed binary", 1)
|
||||
except Exception as e:
|
||||
InstallCyberPanel.stdOut(f"ERROR: Failed to install binary: {e}", 1)
|
||||
logging.InstallLog.writeToFile(str(e) + " [installCustomOLSBinaries - binary install]")
|
||||
return False
|
||||
|
||||
# Install module
|
||||
try:
|
||||
os.makedirs(os.path.dirname(MODULE_PATH), exist_ok=True)
|
||||
shutil.move(tmp_module, MODULE_PATH)
|
||||
os.chmod(MODULE_PATH, 0o644)
|
||||
InstallCyberPanel.stdOut("Installed CyberPanel module", 1)
|
||||
except Exception as e:
|
||||
InstallCyberPanel.stdOut(f"ERROR: Failed to install module: {e}", 1)
|
||||
logging.InstallLog.writeToFile(str(e) + " [installCustomOLSBinaries - module install]")
|
||||
return False
|
||||
|
||||
# Verify installation files exist
|
||||
if not (os.path.exists(OLS_BINARY_PATH) and os.path.exists(MODULE_PATH)):
|
||||
InstallCyberPanel.stdOut("ERROR: Installation verification failed - files not found", 1)
|
||||
return False
|
||||
|
||||
# Verify binary compatibility
|
||||
if not self.verifyCustomBinary(OLS_BINARY_PATH):
|
||||
InstallCyberPanel.stdOut("ERROR: Custom binary verification failed", 1)
|
||||
InstallCyberPanel.stdOut("This usually means wrong binary type for your OS", 1)
|
||||
|
||||
# Rollback to original binary
|
||||
if os.path.exists(backup_dir):
|
||||
self.rollbackCustomBinary(backup_dir, OLS_BINARY_PATH, MODULE_PATH)
|
||||
InstallCyberPanel.stdOut("Continuing with standard OLS", 1)
|
||||
else:
|
||||
InstallCyberPanel.stdOut("WARNING: Cannot rollback, no backup found", 1)
|
||||
|
||||
return True # Non-fatal, continue with standard OLS
|
||||
|
||||
# Success!
|
||||
InstallCyberPanel.stdOut("=" * 50, 1)
|
||||
InstallCyberPanel.stdOut("Custom Binaries Installed Successfully", 1)
|
||||
InstallCyberPanel.stdOut("Features enabled:", 1)
|
||||
InstallCyberPanel.stdOut(" - Apache-style .htaccess support", 1)
|
||||
InstallCyberPanel.stdOut(" - php_value/php_flag directives", 1)
|
||||
InstallCyberPanel.stdOut(" - Enhanced header control", 1)
|
||||
InstallCyberPanel.stdOut(f"Backup: {backup_dir}", 1)
|
||||
InstallCyberPanel.stdOut("=" * 50, 1)
|
||||
return True
|
||||
|
||||
except Exception as msg:
|
||||
logging.InstallLog.writeToFile(str(msg) + " [installCustomOLSBinaries]")
|
||||
InstallCyberPanel.stdOut(f"ERROR: {msg}", 1)
|
||||
InstallCyberPanel.stdOut("Continuing with standard OLS", 1)
|
||||
return True # Non-fatal error, continue
|
||||
|
||||
def configureCustomModule(self):
|
||||
"""Configure CyberPanel module in OpenLiteSpeed config"""
|
||||
try:
|
||||
InstallCyberPanel.stdOut("Configuring CyberPanel module...", 1)
|
||||
|
||||
CONFIG_FILE = "/usr/local/lsws/conf/httpd_config.conf"
|
||||
|
||||
if not os.path.exists(CONFIG_FILE):
|
||||
InstallCyberPanel.stdOut("WARNING: Config file not found", 1)
|
||||
InstallCyberPanel.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:
|
||||
InstallCyberPanel.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)
|
||||
|
||||
InstallCyberPanel.stdOut("Module configured successfully", 1)
|
||||
return True
|
||||
|
||||
except Exception as msg:
|
||||
logging.InstallLog.writeToFile(str(msg) + " [configureCustomModule]")
|
||||
InstallCyberPanel.stdOut(f"WARNING: Module configuration failed: {msg}", 1)
|
||||
InstallCyberPanel.stdOut("Module may still work via auto-load", 1)
|
||||
return True # Non-fatal
|
||||
|
||||
def installLiteSpeed(self):
|
||||
if self.ent == 0:
|
||||
# Install standard OpenLiteSpeed package
|
||||
self.install_package('openlitespeed')
|
||||
|
||||
# Install custom binaries with PHP config support
|
||||
# This replaces the standard binary with enhanced version
|
||||
self.installCustomOLSBinaries()
|
||||
|
||||
# Configure the custom module
|
||||
self.configureCustomModule()
|
||||
|
||||
else:
|
||||
try:
|
||||
try:
|
||||
|
||||
@@ -308,7 +308,9 @@ extprocessor docker{port} {{
|
||||
logging.writeToFile("Context already exists, skipping...")
|
||||
return True
|
||||
|
||||
# Add proxy context with proper headers for n8n
|
||||
# Add proxy context with Origin header for n8n
|
||||
# Note: OLS proxy automatically adds X-Forwarded-* headers
|
||||
# Only Origin header needs explicit configuration
|
||||
proxy_context = f'''
|
||||
|
||||
# N8N Proxy Configuration
|
||||
@@ -319,11 +321,7 @@ context / {{
|
||||
websocket 1
|
||||
|
||||
extraHeaders <<<END_extraHeaders
|
||||
RequestHeader set X-Forwarded-For $ip
|
||||
RequestHeader set X-Forwarded-Proto https
|
||||
RequestHeader set X-Forwarded-Host "{domain}"
|
||||
RequestHeader set Origin "{domain}, {domain}"
|
||||
RequestHeader set Host "{domain}"
|
||||
RequestHeader set Origin "https://{domain}"
|
||||
END_extraHeaders
|
||||
}}
|
||||
'''
|
||||
@@ -1380,7 +1378,8 @@ services:
|
||||
'N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS': 'true',
|
||||
'DB_POSTGRESDB_SCHEMA': 'public',
|
||||
'N8N_PROTOCOL': 'https',
|
||||
'N8N_SECURE_COOKIE': 'true'
|
||||
'N8N_SECURE_COOKIE': 'true',
|
||||
'N8N_PROXY_HOPS': '1'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from plogical.virtualHostUtilities import virtualHostUtilities
|
||||
import os
|
||||
import tarfile
|
||||
import shutil
|
||||
import time
|
||||
from plogical.mailUtilities import mailUtilities
|
||||
from plogical.processUtilities import ProcessUtilities
|
||||
from plogical.installUtilities import installUtilities
|
||||
@@ -19,11 +20,184 @@ class modSec:
|
||||
mirrorPath = "cyberpanel.net"
|
||||
|
||||
@staticmethod
|
||||
def installModSec():
|
||||
def isCustomOLSBinaryInstalled():
|
||||
"""Detect if custom OpenLiteSpeed binary is installed"""
|
||||
try:
|
||||
OLS_BINARY_PATH = "/usr/local/lsws/bin/openlitespeed"
|
||||
|
||||
if not os.path.exists(OLS_BINARY_PATH):
|
||||
return False
|
||||
|
||||
# Check for PHPConfig function signature in binary
|
||||
command = f'strings {OLS_BINARY_PATH}'
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=10)
|
||||
|
||||
if result.returncode == 0:
|
||||
# Look for custom binary markers
|
||||
return 'set_php_config_value' in result.stdout or 'PHPConfig LSIAPI' in result.stdout
|
||||
|
||||
return False
|
||||
|
||||
except Exception as msg:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"WARNING: Could not detect OLS binary type: {msg}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def detectBinarySuffix():
|
||||
"""Detect which binary suffix to use based on OS distribution
|
||||
Returns 'ubuntu' for Ubuntu/Debian systems
|
||||
Returns 'rhel8' for RHEL/AlmaLinux/Rocky 8.x systems
|
||||
Returns 'rhel9' for RHEL/AlmaLinux/Rocky 9.x systems
|
||||
"""
|
||||
try:
|
||||
# Check if we're on RHEL/CentOS/AlmaLinux or Ubuntu/Debian
|
||||
if os.path.exists('/etc/os-release'):
|
||||
with open('/etc/os-release', 'r') as f:
|
||||
os_release = f.read().lower()
|
||||
|
||||
# Check for Ubuntu/Debian FIRST
|
||||
if 'ubuntu' in os_release or 'debian' in os_release:
|
||||
return 'ubuntu'
|
||||
|
||||
# Check for RHEL-based distributions
|
||||
if any(x in os_release for x in ['almalinux', 'rocky', 'rhel', 'centos stream']):
|
||||
# Extract version number
|
||||
for line in os_release.split('\n'):
|
||||
if 'version_id' in line:
|
||||
version = line.split('=')[1].strip('"').split('.')[0]
|
||||
if version == '9':
|
||||
return 'rhel9'
|
||||
elif version == '8':
|
||||
return 'rhel8'
|
||||
|
||||
# Check CentOS/RHEL path (legacy method)
|
||||
if os.path.exists('/etc/redhat-release'):
|
||||
data = open('/etc/redhat-release', 'r').read()
|
||||
if 'release 9' in data:
|
||||
return 'rhel9'
|
||||
elif 'release 8' in data:
|
||||
return 'rhel8'
|
||||
|
||||
# Default to ubuntu
|
||||
return 'ubuntu'
|
||||
|
||||
except Exception as msg:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Error detecting OS: {msg}, defaulting to Ubuntu binaries")
|
||||
return 'ubuntu'
|
||||
|
||||
@staticmethod
|
||||
def installCompatibleModSecurity():
|
||||
"""Install ModSecurity compatible with custom OpenLiteSpeed binary"""
|
||||
try:
|
||||
mailUtilities.checkHome()
|
||||
|
||||
with open(modSec.installLogPath, 'w') as f:
|
||||
f.write("Installing ModSecurity compatible with custom OpenLiteSpeed binary...\n")
|
||||
|
||||
MODSEC_PATH = "/usr/local/lsws/modules/mod_security.so"
|
||||
|
||||
# Detect OS and select appropriate ModSecurity binary
|
||||
binary_suffix = modSec.detectBinarySuffix()
|
||||
BASE_URL = "https://cyberpanel.net/binaries"
|
||||
|
||||
if binary_suffix == 'rhel8':
|
||||
MODSEC_URL = f"{BASE_URL}/rhel8/mod_security-compatible-rhel8.so"
|
||||
EXPECTED_SHA256 = "8c769dfb42711851ec539e9b6ea649616c14b0e85a53eb18755d200ce29bc442"
|
||||
elif binary_suffix == 'rhel9':
|
||||
MODSEC_URL = f"{BASE_URL}/rhel9/mod_security-compatible-rhel.so"
|
||||
EXPECTED_SHA256 = "db580afc431fda40d46bdae2249ac74690d9175ff6d8b1843f2837d86f8d602f"
|
||||
else: # ubuntu
|
||||
MODSEC_URL = f"{BASE_URL}/ubuntu/mod_security-compatible-ubuntu.so"
|
||||
EXPECTED_SHA256 = "115971fcd44b74bc7c7b097b9cec33ddcfb0fb07bb9b562ec9f4f0691c388a6b"
|
||||
|
||||
# Download to temp location
|
||||
tmp_modsec = "/tmp/mod_security_custom.so"
|
||||
|
||||
with open(modSec.installLogPath, 'a') as f:
|
||||
f.write(f"Downloading compatible ModSecurity for {binary_suffix}...\n")
|
||||
|
||||
command = f'wget -q --show-progress {MODSEC_URL} -O {tmp_modsec}'
|
||||
result = subprocess.call(shlex.split(command))
|
||||
|
||||
if result != 0 or not os.path.exists(tmp_modsec):
|
||||
with open(modSec.installLogPath, 'a') as f:
|
||||
f.write("ERROR: Failed to download ModSecurity\n")
|
||||
f.write("Can not be installed.[404]\n")
|
||||
logging.CyberCPLogFileWriter.writeToFile("[Could not download compatible ModSecurity]")
|
||||
return 0
|
||||
|
||||
# Verify checksum
|
||||
with open(modSec.installLogPath, 'a') as f:
|
||||
f.write("Verifying checksum...\n")
|
||||
|
||||
result = subprocess.run(f'sha256sum {tmp_modsec}', shell=True, capture_output=True, text=True)
|
||||
actual_sha256 = result.stdout.split()[0]
|
||||
|
||||
if actual_sha256 != EXPECTED_SHA256:
|
||||
with open(modSec.installLogPath, 'a') as f:
|
||||
f.write(f"ERROR: Checksum verification failed\n")
|
||||
f.write(f" Expected: {EXPECTED_SHA256}\n")
|
||||
f.write(f" Got: {actual_sha256}\n")
|
||||
f.write("Can not be installed.[404]\n")
|
||||
os.remove(tmp_modsec)
|
||||
logging.CyberCPLogFileWriter.writeToFile("[ModSecurity checksum verification failed]")
|
||||
return 0
|
||||
|
||||
# Backup existing ModSecurity if present
|
||||
if os.path.exists(MODSEC_PATH):
|
||||
backup_path = f"{MODSEC_PATH}.backup.{int(time.time())}"
|
||||
shutil.copy2(MODSEC_PATH, backup_path)
|
||||
with open(modSec.installLogPath, 'a') as f:
|
||||
f.write(f"Backed up existing ModSecurity to: {backup_path}\n")
|
||||
|
||||
# Stop OpenLiteSpeed
|
||||
subprocess.run(['/usr/local/lsws/bin/lswsctrl', 'stop'], timeout=30)
|
||||
time.sleep(2)
|
||||
|
||||
# Install compatible ModSecurity
|
||||
os.makedirs(os.path.dirname(MODSEC_PATH), exist_ok=True)
|
||||
shutil.copy2(tmp_modsec, MODSEC_PATH)
|
||||
os.chmod(MODSEC_PATH, 0o755)
|
||||
os.remove(tmp_modsec)
|
||||
|
||||
# Start OpenLiteSpeed
|
||||
subprocess.run(['/usr/local/lsws/bin/lswsctrl', 'start'], timeout=30)
|
||||
|
||||
with open(modSec.installLogPath, 'a') as f:
|
||||
f.write("Compatible ModSecurity installed successfully\n")
|
||||
f.write("ModSecurity Installed (ABI-compatible version).[200]\n")
|
||||
|
||||
logging.CyberCPLogFileWriter.writeToFile("[Compatible ModSecurity installed successfully]")
|
||||
return 1
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
with open(modSec.installLogPath, 'a') as f:
|
||||
f.write("ERROR: Timeout during OpenLiteSpeed restart\n")
|
||||
f.write("Can not be installed.[404]\n")
|
||||
logging.CyberCPLogFileWriter.writeToFile("[Timeout during ModSecurity installation]")
|
||||
return 0
|
||||
except Exception as msg:
|
||||
with open(modSec.installLogPath, 'a') as f:
|
||||
f.write(f"ERROR: {str(msg)}\n")
|
||||
f.write("Can not be installed.[404]\n")
|
||||
logging.CyberCPLogFileWriter.writeToFile(str(msg) + "[installCompatibleModSecurity]")
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
def installModSec():
|
||||
try:
|
||||
mailUtilities.checkHome()
|
||||
|
||||
# Check if custom OLS binary is installed
|
||||
if modSec.isCustomOLSBinaryInstalled():
|
||||
# Install compatible ModSecurity for custom OLS
|
||||
with open(modSec.installLogPath, 'w') as f:
|
||||
f.write("Detected custom OpenLiteSpeed binary\n")
|
||||
f.write("Installing ABI-compatible ModSecurity...\n")
|
||||
|
||||
return modSec.installCompatibleModSecurity()
|
||||
|
||||
# Stock OLS binary - use package manager as usual
|
||||
if ProcessUtilities.decideDistro() == ProcessUtilities.centos or ProcessUtilities.decideDistro() == ProcessUtilities.cent8:
|
||||
command = 'sudo yum install ols-modsecurity -y'
|
||||
else:
|
||||
|
||||
@@ -619,6 +619,471 @@ 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 detectBinarySuffix():
|
||||
"""Detect which binary suffix to use based on OS distribution
|
||||
Returns 'ubuntu' for Ubuntu/Debian systems
|
||||
Returns 'rhel8' for RHEL/AlmaLinux/Rocky 8.x systems
|
||||
Returns 'rhel9' for RHEL/AlmaLinux/Rocky 9.x systems
|
||||
"""
|
||||
try:
|
||||
# Check if we're on RHEL/CentOS/AlmaLinux or Ubuntu/Debian
|
||||
if os.path.exists('/etc/os-release'):
|
||||
with open('/etc/os-release', 'r') as f:
|
||||
os_release = f.read().lower()
|
||||
|
||||
# Check for Ubuntu/Debian FIRST
|
||||
if 'ubuntu' in os_release or 'debian' in os_release:
|
||||
return 'ubuntu'
|
||||
|
||||
# Check for RHEL-based distributions
|
||||
if any(x in os_release for x in ['almalinux', 'rocky', 'rhel', 'centos stream']):
|
||||
# Extract version number
|
||||
for line in os_release.split('\n'):
|
||||
if 'version_id' in line:
|
||||
version = line.split('=')[1].strip('"').split('.')[0]
|
||||
if version == '9':
|
||||
return 'rhel9'
|
||||
elif version == '8':
|
||||
return 'rhel8'
|
||||
|
||||
# Check CentOS/RHEL path (legacy method)
|
||||
if os.path.exists(Upgrade.CentOSPath):
|
||||
data = open(Upgrade.CentOSPath, 'r').read()
|
||||
if 'release 9' in data:
|
||||
return 'rhel9'
|
||||
elif 'release 8' in data:
|
||||
return 'rhel8'
|
||||
# CentOS 7 → ubuntu suffix (uses libcrypt.so.1)
|
||||
else:
|
||||
return 'ubuntu'
|
||||
|
||||
# OpenEuler → rhel9 suffix (assuming latest version)
|
||||
if os.path.exists(Upgrade.openEulerPath):
|
||||
return 'rhel9'
|
||||
|
||||
# Ubuntu/Debian → ubuntu suffix (default for unknown)
|
||||
return 'ubuntu'
|
||||
|
||||
except Exception as msg:
|
||||
Upgrade.stdOut(f"Error detecting OS: {msg}, defaulting to Ubuntu binaries", 0)
|
||||
return 'ubuntu'
|
||||
|
||||
@staticmethod
|
||||
def downloadCustomBinary(url, destination):
|
||||
"""Download custom binary file"""
|
||||
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)
|
||||
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 verifyCustomBinary(binary_path):
|
||||
"""Verify custom binary has correct dependencies and can run"""
|
||||
try:
|
||||
Upgrade.stdOut("Verifying custom binary compatibility...", 0)
|
||||
|
||||
# Check library dependencies
|
||||
command = f'ldd {binary_path}'
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
Upgrade.stdOut("ERROR: Failed to check binary dependencies", 0)
|
||||
return False
|
||||
|
||||
# Check for missing libraries
|
||||
if 'not found' in result.stdout:
|
||||
Upgrade.stdOut("ERROR: Binary has missing library dependencies:", 0)
|
||||
for line in result.stdout.split('\n'):
|
||||
if 'not found' in line:
|
||||
Upgrade.stdOut(f" {line.strip()}", 0)
|
||||
return False
|
||||
|
||||
# Try to run the binary with -v to check if it can execute
|
||||
command = f'{binary_path} -v'
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=5)
|
||||
|
||||
if result.returncode != 0:
|
||||
Upgrade.stdOut("ERROR: Binary failed to execute", 0)
|
||||
if result.stderr:
|
||||
Upgrade.stdOut(f" Error: {result.stderr.strip()}", 0)
|
||||
return False
|
||||
|
||||
Upgrade.stdOut("Binary verification successful", 0)
|
||||
return True
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
Upgrade.stdOut("ERROR: Binary verification timed out", 0)
|
||||
return False
|
||||
except Exception as msg:
|
||||
Upgrade.stdOut(f"ERROR: Verification failed: {msg}", 0)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def rollbackCustomBinary(backup_dir, binary_path, module_path):
|
||||
"""Rollback to original binary if custom binary fails"""
|
||||
try:
|
||||
Upgrade.stdOut("Rolling back to original binary...", 0)
|
||||
|
||||
backup_binary = f"{backup_dir}/openlitespeed.backup"
|
||||
|
||||
# Restore original binary if backup exists
|
||||
if os.path.exists(backup_binary):
|
||||
shutil.copy2(backup_binary, binary_path)
|
||||
os.chmod(binary_path, 0o755)
|
||||
Upgrade.stdOut("Original binary restored successfully", 0)
|
||||
else:
|
||||
Upgrade.stdOut("WARNING: No backup found, cannot restore", 0)
|
||||
|
||||
# Remove failed custom module
|
||||
if os.path.exists(module_path):
|
||||
os.remove(module_path)
|
||||
Upgrade.stdOut("Custom module removed", 0)
|
||||
|
||||
Upgrade.stdOut("Rollback completed", 0)
|
||||
return True
|
||||
|
||||
except Exception as msg:
|
||||
Upgrade.stdOut(f"ERROR: Rollback failed: {msg}", 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 OS and select appropriate binary suffix
|
||||
binary_suffix = Upgrade.detectBinarySuffix()
|
||||
Upgrade.stdOut(f"Detected OS type: using '{binary_suffix}' binaries", 0)
|
||||
|
||||
# URLs for custom binaries with OS-specific paths
|
||||
BASE_URL = "https://cyberpanel.net/binaries"
|
||||
|
||||
# Set URLs based on OS type
|
||||
if binary_suffix == 'rhel8':
|
||||
OLS_BINARY_URL = f"{BASE_URL}/rhel8/openlitespeed-phpconfig-x86_64-rhel8"
|
||||
MODULE_URL = f"{BASE_URL}/rhel8/cyberpanel_ols_x86_64_rhel8.so"
|
||||
elif binary_suffix == 'rhel9':
|
||||
OLS_BINARY_URL = f"{BASE_URL}/rhel9/openlitespeed-phpconfig-x86_64-rhel"
|
||||
MODULE_URL = f"{BASE_URL}/rhel9/cyberpanel_ols_x86_64_rhel.so"
|
||||
else: # ubuntu
|
||||
OLS_BINARY_URL = f"{BASE_URL}/ubuntu/openlitespeed-phpconfig-x86_64-ubuntu"
|
||||
MODULE_URL = f"{BASE_URL}/ubuntu/cyberpanel_ols_x86_64_ubuntu.so"
|
||||
|
||||
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
|
||||
if not Upgrade.downloadCustomBinary(OLS_BINARY_URL, tmp_binary):
|
||||
Upgrade.stdOut("ERROR: Failed to download OLS binary", 0)
|
||||
Upgrade.stdOut("Continuing with standard OLS", 0)
|
||||
return True # Not fatal, continue with standard OLS
|
||||
|
||||
# Download module
|
||||
if not Upgrade.downloadCustomBinary(MODULE_URL, tmp_module):
|
||||
Upgrade.stdOut("ERROR: Failed to download module", 0)
|
||||
Upgrade.stdOut("Continuing with standard OLS", 0)
|
||||
return True # Not fatal, continue with standard OLS
|
||||
|
||||
# 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
|
||||
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 files exist
|
||||
if not (os.path.exists(OLS_BINARY_PATH) and os.path.exists(MODULE_PATH)):
|
||||
Upgrade.stdOut("ERROR: Installation verification failed - files not found", 0)
|
||||
return False
|
||||
|
||||
# Verify binary compatibility
|
||||
if not Upgrade.verifyCustomBinary(OLS_BINARY_PATH):
|
||||
Upgrade.stdOut("ERROR: Custom binary verification failed", 0)
|
||||
Upgrade.stdOut("This usually means wrong binary type for your OS", 0)
|
||||
|
||||
# Rollback to original binary
|
||||
if os.path.exists(backup_dir):
|
||||
Upgrade.rollbackCustomBinary(backup_dir, OLS_BINARY_PATH, MODULE_PATH)
|
||||
Upgrade.stdOut("Continuing with standard OLS", 0)
|
||||
else:
|
||||
Upgrade.stdOut("WARNING: Cannot rollback, no backup found", 0)
|
||||
|
||||
return True # Non-fatal, continue with standard OLS
|
||||
|
||||
# Success!
|
||||
Upgrade.stdOut("=" * 50, 0)
|
||||
Upgrade.stdOut("Custom Binaries Installed Successfully", 0)
|
||||
Upgrade.stdOut("Features enabled:", 0)
|
||||
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)
|
||||
return True
|
||||
|
||||
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 isCustomOLSBinaryInstalled():
|
||||
"""Detect if custom OpenLiteSpeed binary is installed"""
|
||||
try:
|
||||
OLS_BINARY_PATH = "/usr/local/lsws/bin/openlitespeed"
|
||||
|
||||
if not os.path.exists(OLS_BINARY_PATH):
|
||||
return False
|
||||
|
||||
# Check for PHPConfig function signature in binary
|
||||
command = f'strings {OLS_BINARY_PATH}'
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=10)
|
||||
|
||||
if result.returncode == 0:
|
||||
# Look for custom binary markers
|
||||
return 'set_php_config_value' in result.stdout or 'PHPConfig LSIAPI' in result.stdout
|
||||
|
||||
return False
|
||||
|
||||
except Exception as msg:
|
||||
Upgrade.stdOut(f"WARNING: Could not detect OLS binary type: {msg}", 0)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def installCompatibleModSecurity():
|
||||
"""Install ModSecurity compatible with custom OpenLiteSpeed binary"""
|
||||
try:
|
||||
Upgrade.stdOut("Installing ModSecurity compatible with custom OpenLiteSpeed binary...", 0)
|
||||
|
||||
MODSEC_PATH = "/usr/local/lsws/modules/mod_security.so"
|
||||
|
||||
# Detect OS and select appropriate ModSecurity binary
|
||||
binary_suffix = Upgrade.detectBinarySuffix()
|
||||
BASE_URL = "https://cyberpanel.net/binaries"
|
||||
|
||||
if binary_suffix == 'rhel8':
|
||||
MODSEC_URL = f"{BASE_URL}/rhel8/mod_security-compatible-rhel8.so"
|
||||
EXPECTED_SHA256 = "8c769dfb42711851ec539e9b6ea649616c14b0e85a53eb18755d200ce29bc442"
|
||||
EXPECTED_MD5 = "b7b9eb20de42b7f8c9c8f4c7a019d6ff"
|
||||
elif binary_suffix == 'rhel9':
|
||||
MODSEC_URL = f"{BASE_URL}/rhel9/mod_security-compatible-rhel.so"
|
||||
EXPECTED_SHA256 = "db580afc431fda40d46bdae2249ac74690d9175ff6d8b1843f2837d86f8d602f"
|
||||
EXPECTED_MD5 = "1efa1e442fe8eedf4705584ac194fc95"
|
||||
else: # ubuntu
|
||||
MODSEC_URL = f"{BASE_URL}/ubuntu/mod_security-compatible-ubuntu.so"
|
||||
EXPECTED_SHA256 = "115971fcd44b74bc7c7b097b9cec33ddcfb0fb07bb9b562ec9f4f0691c388a6b"
|
||||
EXPECTED_MD5 = "c3987c41182355c1290530b6553658db"
|
||||
|
||||
# Download to temp location
|
||||
tmp_modsec = "/tmp/mod_security_custom.so"
|
||||
|
||||
Upgrade.stdOut(f"Downloading compatible ModSecurity for {binary_suffix}...", 0)
|
||||
command = f'wget -q --show-progress {MODSEC_URL} -O {tmp_modsec}'
|
||||
result = subprocess.call(shlex.split(command))
|
||||
|
||||
if result != 0 or not os.path.exists(tmp_modsec):
|
||||
Upgrade.stdOut("ERROR: Failed to download ModSecurity", 0)
|
||||
return False
|
||||
|
||||
# Verify checksum
|
||||
Upgrade.stdOut("Verifying checksum...", 0)
|
||||
result = subprocess.run(f'sha256sum {tmp_modsec}', shell=True, capture_output=True, text=True)
|
||||
actual_sha256 = result.stdout.split()[0]
|
||||
|
||||
if actual_sha256 != EXPECTED_SHA256:
|
||||
Upgrade.stdOut(f"ERROR: Checksum verification failed", 0)
|
||||
Upgrade.stdOut(f" Expected: {EXPECTED_SHA256}", 0)
|
||||
Upgrade.stdOut(f" Got: {actual_sha256}", 0)
|
||||
os.remove(tmp_modsec)
|
||||
return False
|
||||
|
||||
Upgrade.stdOut("Checksum verified successfully", 0)
|
||||
|
||||
# Backup existing ModSecurity if present
|
||||
if os.path.exists(MODSEC_PATH):
|
||||
backup_path = f"{MODSEC_PATH}.backup.{int(time.time())}"
|
||||
shutil.copy2(MODSEC_PATH, backup_path)
|
||||
Upgrade.stdOut(f"Backed up existing ModSecurity to: {backup_path}", 0)
|
||||
|
||||
# Stop OpenLiteSpeed
|
||||
Upgrade.stdOut("Stopping OpenLiteSpeed...", 0)
|
||||
subprocess.run(['/usr/local/lsws/bin/lswsctrl', 'stop'], timeout=30)
|
||||
time.sleep(2)
|
||||
|
||||
# Install compatible ModSecurity
|
||||
os.makedirs(os.path.dirname(MODSEC_PATH), exist_ok=True)
|
||||
shutil.copy2(tmp_modsec, MODSEC_PATH)
|
||||
os.chmod(MODSEC_PATH, 0o755)
|
||||
os.remove(tmp_modsec)
|
||||
|
||||
Upgrade.stdOut("Compatible ModSecurity installed successfully", 0)
|
||||
|
||||
# Start OpenLiteSpeed
|
||||
Upgrade.stdOut("Starting OpenLiteSpeed...", 0)
|
||||
subprocess.run(['/usr/local/lsws/bin/lswsctrl', 'start'], timeout=30)
|
||||
|
||||
Upgrade.stdOut("✓ ModSecurity updated to compatible version", 0)
|
||||
return True
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
Upgrade.stdOut("ERROR: Timeout during OpenLiteSpeed restart", 0)
|
||||
return False
|
||||
except Exception as msg:
|
||||
Upgrade.stdOut(f"ERROR: ModSecurity installation failed: {msg}", 0)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def handleModSecurityCompatibility():
|
||||
"""Check and update ModSecurity if custom OLS binary is installed"""
|
||||
try:
|
||||
MODSEC_PATH = "/usr/local/lsws/modules/mod_security.so"
|
||||
|
||||
# Check if ModSecurity is installed
|
||||
if not os.path.exists(MODSEC_PATH):
|
||||
Upgrade.stdOut("ModSecurity not installed, skipping compatibility check", 0)
|
||||
return True
|
||||
|
||||
# Check if custom OLS binary is installed
|
||||
if not Upgrade.isCustomOLSBinaryInstalled():
|
||||
Upgrade.stdOut("Stock OLS binary detected, ModSecurity compatibility check not needed", 0)
|
||||
return True
|
||||
|
||||
Upgrade.stdOut("=" * 50, 0)
|
||||
Upgrade.stdOut("Detected ModSecurity with custom OpenLiteSpeed binary", 0)
|
||||
Upgrade.stdOut("Updating to ABI-compatible ModSecurity version...", 0)
|
||||
Upgrade.stdOut("=" * 50, 0)
|
||||
|
||||
# Install compatible version
|
||||
if Upgrade.installCompatibleModSecurity():
|
||||
Upgrade.stdOut("ModSecurity compatibility update completed", 0)
|
||||
return True
|
||||
else:
|
||||
Upgrade.stdOut("WARNING: ModSecurity compatibility update failed", 0)
|
||||
Upgrade.stdOut("Server may experience crashes. Please contact support.", 0)
|
||||
return False
|
||||
|
||||
except Exception as msg:
|
||||
Upgrade.stdOut(f"ERROR in ModSecurity compatibility check: {msg}", 0)
|
||||
return False
|
||||
|
||||
@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:
|
||||
@@ -4287,7 +4752,7 @@ pm.max_spare_servers = 3
|
||||
## Add LSPHP7.4 TO LSWS Ent configs
|
||||
|
||||
if not os.path.exists('/usr/local/lsws/bin/openlitespeed'):
|
||||
|
||||
# This is Enterprise LSWS
|
||||
if os.path.exists('httpd_config.xml'):
|
||||
os.remove('httpd_config.xml')
|
||||
|
||||
@@ -4295,6 +4760,25 @@ pm.max_spare_servers = 3
|
||||
Upgrade.executioner(command, command, 0)
|
||||
# os.remove('/usr/local/lsws/conf/httpd_config.xml')
|
||||
# shutil.copy('httpd_config.xml', '/usr/local/lsws/conf/httpd_config.xml')
|
||||
else:
|
||||
# This is OpenLiteSpeed - install/upgrade custom binaries
|
||||
Upgrade.stdOut("Detected OpenLiteSpeed installation", 0)
|
||||
Upgrade.stdOut("Installing/upgrading custom binaries with .htaccess PHP config support...", 0)
|
||||
|
||||
# Install custom binaries
|
||||
if Upgrade.installCustomOLSBinaries():
|
||||
# Configure the custom module
|
||||
Upgrade.configureCustomModule()
|
||||
|
||||
# Check and update ModSecurity compatibility if needed
|
||||
Upgrade.handleModSecurityCompatibility()
|
||||
|
||||
# Restart OpenLiteSpeed to apply changes
|
||||
Upgrade.stdOut("Restarting OpenLiteSpeed...", 0)
|
||||
command = '/usr/local/lsws/bin/lswsctrl restart'
|
||||
Upgrade.executioner(command, 'Restart OpenLiteSpeed', 0)
|
||||
else:
|
||||
Upgrade.stdOut("Custom binary installation failed, continuing with upgrade...", 0)
|
||||
|
||||
Upgrade.updateRepoURL()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user