Remove to-do folder and documentation files

This commit is contained in:
master3395
2026-01-26 20:40:59 +01:00
parent 17421b6dfe
commit 399cb06f50
7 changed files with 0 additions and 809 deletions

View File

@@ -1,214 +0,0 @@
# Paid Plugins Support for CyberPanel
## Overview
CyberPanel now supports paid plugins that require Patreon subscription. Users can install paid plugins, but they cannot run them without an active Patreon subscription to the specified tier.
## Features
- ✅ Paid plugin detection from `meta.xml`
- ✅ Patreon subscription verification
- ✅ Installable but non-functional without subscription
- ✅ Visual indicators (badges) for paid plugins in all views:
- Grid View: Green "Free" or Yellow "Paid" badge next to version
- Table View: Green "Free" or Yellow "Paid" badge next to version
- Store View: Separate "Pricing" column with Free/Paid badges
- ✅ Subscription required page when accessing without subscription
- ✅ "Subscribe on Patreon" button in subscription warning
- ✅ API endpoint for checking subscription status
## Plugin Structure
### Meta.xml for Paid Plugins
Add the following fields to your plugin's `meta.xml`:
```xml
<paid>true</paid>
<patreon_tier>CyberPanel Paid Plugin</patreon_tier>
<patreon_url>https://www.patreon.com/membership/27789984</patreon_url>
```
### Example meta.xml
```xml
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<name>Premium Plugin Example</name>
<type>Utility</type>
<version>1.0.0</version>
<description>An example paid plugin</description>
<author>master3395</author>
<paid>true</paid>
<patreon_tier>CyberPanel Paid Plugin</patreon_tier>
<patreon_url>https://www.patreon.com/membership/27789984</patreon_url>
<url>/plugins/premiumPlugin/</url>
<settings_url>/plugins/premiumPlugin/settings/</settings_url>
</plugin>
```
## Implementation in Plugin Views
### Using the Premium Plugin Decorator
```python
from pluginHolder.plugin_access import check_plugin_access
def premium_plugin_required(view_func):
"""
Decorator that checks if user has Patreon subscription
"""
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
# Check login first
try:
userID = request.session['userID']
except KeyError:
from loginSystem.views import loadLoginPage
return redirect(loadLoginPage)
# Check plugin access
plugin_meta = {
'is_paid': True,
'patreon_tier': 'CyberPanel Paid Plugin',
'patreon_url': 'https://www.patreon.com/c/newstargeted/membership'
}
access_check = check_plugin_access(request, 'yourPluginName', plugin_meta)
if not access_check['has_access']:
# Show subscription required page
context = {
'plugin_name': 'Your Plugin Name',
'is_paid': True,
'patreon_tier': access_check.get('patreon_tier', 'CyberPanel Paid Plugin'),
'patreon_url': access_check.get('patreon_url'),
'message': access_check.get('message', 'Patreon subscription required')
}
proc = httpProc(request, 'yourPlugin/subscription_required.html', context, 'admin')
return proc.render()
# User has access - proceed
return view_func(request, *args, **kwargs)
return _wrapped_view
@cyberpanel_login_required
@premium_plugin_required
def your_view(request):
# Your view code here
pass
```
## Patreon Configuration
### Environment Variables
Set the following environment variables in CyberPanel:
```bash
export PATREON_CLIENT_ID="your_client_id"
export PATREON_CLIENT_SECRET="your_client_secret"
export PATREON_CREATOR_ID="your_creator_id"
```
Or add them to `/usr/local/CyberCP/CyberCP/settings.py`:
```python
import os
PATREON_CLIENT_ID = os.environ.get('PATREON_CLIENT_ID', '')
PATREON_CLIENT_SECRET = os.environ.get('PATREON_CLIENT_SECRET', '')
PATREON_CREATOR_ID = os.environ.get('PATREON_CREATOR_ID', '')
```
### User Token Storage
Users need to authorize CyberPanel to check their Patreon membership. Tokens are stored in:
```
/home/cyberpanel/patreon_tokens/{user_email}.token
```
## API Endpoints
### Check Subscription Status
```
GET /plugins/api/check-subscription/<plugin_name>/
```
Response:
```json
{
"success": true,
"has_access": true,
"is_paid": true,
"message": "Access granted",
"patreon_url": null
}
```
## Example Plugin
A complete example paid plugin is available at:
```
/home/cyberpanel-plugins/premiumPlugin/
```
This plugin demonstrates:
- Paid plugin meta.xml structure
- Subscription verification
- Subscription required page
- Protected views
## User Experience
### For Users Without Subscription
1. Plugin appears in installed plugins list with "Premium" badge and "Paid" pricing badge
2. Plugin appears in CyberPanel Plugin Store with "Paid" badge in the Pricing column
3. Plugin can be installed
4. When accessing plugin, subscription required page is shown
5. Link to Patreon subscription page is provided with "Subscribe on Patreon" button
### For Users With Subscription
1. Plugin works normally
2. All features are accessible
3. Settings page is available
4. No restrictions
## Files Created/Modified
### New Files
- `/home/cyberpanel-repo/pluginHolder/patreon_verifier.py` - Patreon API integration
- `/home/cyberpanel-repo/pluginHolder/plugin_access.py` - Plugin access control
- `/home/cyberpanel-plugins/premiumPlugin/` - Example paid plugin
### Modified Files
- `/home/cyberpanel-repo/pluginHolder/views.py` - Added paid plugin parsing and subscription check API
- `/home/cyberpanel-repo/pluginHolder/templates/pluginHolder/plugins.html` - Added paid plugin badges and warnings
- `/home/cyberpanel-repo/pluginHolder/urls.py` - Added subscription check endpoint
## Testing
1. Install the example premium plugin
2. Try accessing it without subscription (should show subscription required page)
3. Subscribe to Patreon tier "CyberPanel Paid Plugin"
4. Authorize CyberPanel to check membership
5. Access plugin again (should work normally)
## Notes
- Subscription checks are cached for 5 minutes to reduce API calls
- Users must authorize CyberPanel to check their Patreon membership
- The system checks for the exact tier name specified in `patreon_tier`
- Free plugins work normally without any changes
## Author
master3395

View File

@@ -1,58 +0,0 @@
# Patreon Configuration for CyberPanel Paid Plugins
## Configuration Complete
Patreon credentials have been configured in CyberPanel settings.
### Credentials Configuration
**SECURITY WARNING**: Never commit secrets to the repository!
Set these via environment variables:
```bash
export PATREON_CLIENT_ID="your_client_id_here"
export PATREON_CLIENT_SECRET="your_client_secret_here"
export PATREON_MEMBERSHIP_TIER_ID="your_tier_id_here"
export PATREON_CREATOR_ACCESS_TOKEN="your_access_token_here"
export PATREON_CREATOR_REFRESH_TOKEN="your_refresh_token_here"
```
Or add to `/etc/environment` or systemd service file.
### Location
Credentials are stored in:
- `/usr/local/CyberCP/CyberCP/settings.py` (or `/home/cyberpanel-repo/CyberCP/settings.py`)
### How It Works
1. Users install paid plugins (no subscription required)
2. When accessing the plugin, system checks for Patreon membership
3. If user has active subscription to tier `27789984`, access is granted
4. If not, subscription required page is shown
### Testing
To test the configuration:
1. Install the `premiumPlugin` example plugin
2. Try accessing it without subscription (should show subscription page)
3. Subscribe to Patreon tier "CyberPanel Paid Plugin" (ID: 27789984)
4. Authorize CyberPanel to check membership
5. Access plugin again (should work)
### Membership Verification
The system checks for:
- Tier ID: `27789984`
- Tier Name: "CyberPanel Paid Plugin" (fallback)
- Active patron status
- Currently entitled amount > 0
### Notes
- Membership checks are cached for 5 minutes
- Users must authorize CyberPanel via OAuth to check membership
- Creator access token can be used for server-side verification

View File

@@ -1,115 +0,0 @@
# Secure Patreon Configuration Setup
## ⚠️ SECURITY WARNING
**NEVER commit Patreon secrets to the repository!**
All secrets must be configured via environment variables on the production server.
## Setup Instructions
### 1. Get Your Patreon Credentials
From your Patreon Developer Dashboard:
- Client ID
- Client Secret
- Membership Tier ID (e.g., `27789984`)
- Creator Access Token (optional, for server-side verification)
- Creator Refresh Token (optional)
### 2. Configure Environment Variables
#### Option A: Systemd Service (Recommended)
Edit `/etc/systemd/system/lscpd.service`:
```ini
[Service]
Environment="PATREON_CLIENT_ID=your_client_id"
Environment="PATREON_CLIENT_SECRET=your_client_secret"
Environment="PATREON_MEMBERSHIP_TIER_ID=your_tier_id"
Environment="PATREON_CREATOR_ACCESS_TOKEN=your_access_token"
Environment="PATREON_CREATOR_REFRESH_TOKEN=your_refresh_token"
```
Then reload and restart:
```bash
systemctl daemon-reload
systemctl restart lscpd
```
#### Option B: /etc/environment
Add to `/etc/environment`:
```bash
PATREON_CLIENT_ID=your_client_id
PATREON_CLIENT_SECRET=your_client_secret
PATREON_MEMBERSHIP_TIER_ID=your_tier_id
PATREON_CREATOR_ACCESS_TOKEN=your_access_token
PATREON_CREATOR_REFRESH_TOKEN=your_refresh_token
```
#### Option C: Secure Config File (Not in Repo)
Create `/usr/local/CyberCP/patreon_config.py` (add to .gitignore):
```python
# Patreon Configuration - DO NOT COMMIT TO REPOSITORY
PATREON_CLIENT_ID = 'your_client_id'
PATREON_CLIENT_SECRET = 'your_client_secret'
PATREON_MEMBERSHIP_TIER_ID = 'your_tier_id'
PATREON_CREATOR_ACCESS_TOKEN = 'your_access_token'
PATREON_CREATOR_REFRESH_TOKEN = 'your_refresh_token'
```
Then import in settings.py:
```python
try:
from .patreon_config import *
except ImportError:
pass # Use environment variables instead
```
### 3. Verify Configuration
Test that secrets are loaded:
```bash
python3 -c "
import os
print('Client ID:', 'SET' if os.environ.get('PATREON_CLIENT_ID') else 'NOT SET')
print('Client Secret:', 'SET' if os.environ.get('PATREON_CLIENT_SECRET') else 'NOT SET')
print('Tier ID:', os.environ.get('PATREON_MEMBERSHIP_TIER_ID', 'NOT SET'))
"
```
### 4. Security Checklist
- [ ] Secrets removed from repository
- [ ] Environment variables set on production server
- [ ] `/usr/local/CyberCP/patreon_config.py` added to .gitignore (if used)
- [ ] CyberPanel service restarted
- [ ] Configuration verified working
## For Plugin Developers
When creating paid plugins:
1. **Never hardcode secrets** in plugin code
2. **Use environment variables** or Django settings
3. **Document required variables** in README
4. **Provide example** with placeholder values only
Example meta.xml:
```xml
<paid>true</paid>
<patreon_tier>Your Tier Name</patreon_tier>
<patreon_url>https://www.patreon.com/c/yourname/membership</patreon_url>
```
## Troubleshooting
If membership checks fail:
1. Verify environment variables are set: `env | grep PATREON`
2. Check CyberPanel logs: `/home/lscp/logs/error.log`
3. Verify tier ID matches your Patreon tier
4. Ensure user has authorized OAuth access

View File

@@ -1,89 +0,0 @@
# Remote Verification Architecture for Paid Plugins
## Problem
When users install plugins, they can see all files on their system, which could expose:
- Patreon API credentials
- Verification logic
- Access tokens
## Solution: Remote Verification Server
Move all Patreon verification to **YOUR server** (not the user's server).
### Architecture
```
User's Server (Plugin) Your Server Patreon API
| | |
|-- Verify Request ----------->| |
| |-- Check Membership --->|
| |<-- Membership Status --|
|<-- Access Granted/Denied ----| |
```
### Benefits
1. **No secrets on user's server** - All credentials stay on your server
2. **Users can't intercept** - Verification happens server-to-server
3. **Centralized control** - You can revoke access, update logic, etc.
4. **Plugin code can be public** - Only makes API calls, no secrets
## Implementation
### 1. Your Verification Server
Create an API endpoint on your server (e.g., `api.newstargeted.com`):
```python
# Your server endpoint: /api/verify-patreon-membership
POST /api/verify-patreon-membership
{
"user_email": "user@example.com",
"plugin_name": "premiumPlugin",
"tier_id": "27789984"
}
Response:
{
"has_access": true,
"expires_at": "2026-02-25T00:00:00Z"
}
```
### 2. Plugin Code (Public, No Secrets)
The plugin only makes HTTP requests to your server:
```python
def check_remote_membership(user_email, plugin_name):
response = requests.post(
'https://api.newstargeted.com/api/verify-patreon-membership',
json={
'user_email': user_email,
'plugin_name': plugin_name,
'tier_id': '27789984'
},
headers={'X-Plugin-Version': '1.0.0'}
)
return response.json()
```
### 3. Security Measures
- **Rate limiting** - Prevent abuse
- **IP whitelisting** - Only allow from CyberPanel servers (optional)
- **Plugin signature** - Verify requests come from legitimate plugins
- **Caching** - Reduce API calls to Patreon
- **HTTPS only** - Encrypt all communication
## Alternative: Encrypted Plugin Package
If you want to encrypt the entire plugin:
1. **Encrypt plugin files** before distribution
2. **Decrypt on install** using a license key
3. **License key** tied to user's Patreon subscription
4. **Your server** generates license keys
This is more complex but provides stronger protection.

View File

@@ -1,115 +0,0 @@
# Remote Verification Setup Complete ✅
## Summary
All components are now set up for secure remote verification of paid plugins. Users can install plugins and see all code, but **NO secrets are exposed** because all Patreon API calls happen on YOUR server.
## ✅ What Was Completed
### 1. Remote Verification API
- **Endpoint**: `https://api.newstargeted.com/api/verify-patreon-membership`
- **Location**: `/home/newstargeted.com/api.newstargeted.com/api/verify-patreon-membership.php`
- **Status**: ✅ Working and tested
- **Permissions**: ✅ newst3922:newst3922 (644)
### 2. Plugin Updated
- **File**: `/home/cyberpanel-plugins/premiumPlugin/views.py`
- **Method**: Remote verification (no secrets)
- **Status**: ✅ Updated and tested
- **Permissions**: ✅ newst3922:newst3922 (644)
### 3. Configuration
- **Patreon credentials**: Added to `/home/newstargeted.com/api.newstargeted.com/config.php`
- **Permissions**: ✅ 600 (secure, readable only by owner)
- **Owner**: ✅ newst3922:newst3922
### 4. Routing
- **.htaccess**: Updated with API routing rules
- **API Router**: Created at `/api/index.php`
- **Status**: ✅ Working
## 🔒 Security Features
**No secrets in plugin** - All code is public-safe
**Credentials on your server only** - Never exposed to users
**Rate limiting** - 60 requests/hour per IP
**Caching** - 5 minute cache to reduce API calls
**HTTPS only** - All communication encrypted
**Proper permissions** - Config files protected (600)
## 📁 File Permissions Summary
### API Files
- `/home/newstargeted.com/api.newstargeted.com/api/verify-patreon-membership.php`: 644, newst3922:newst3922
- `/home/newstargeted.com/api.newstargeted.com/api/index.php`: 644, newst3922:newst3922
- `/home/newstargeted.com/api.newstargeted.com/config.php`: 600, newst3922:newst3922 (secure)
- `/home/newstargeted.com/api.newstargeted.com/.htaccess`: 644, newst3922:newst3922
### Plugin Files
- `/home/cyberpanel-plugins/premiumPlugin/`: All files 644, directories 755, newst3922:newst3922
- `/home/cyberpanel/plugins/premiumPlugin/`: All files 644, directories 755, newst3922:newst3922
## 🧪 Testing
### API Endpoint Test
```bash
curl -X POST https://api.newstargeted.com/api/verify-patreon-membership \
-H "Content-Type: application/json" \
-d '{"user_email":"test@example.com","plugin_name":"premiumPlugin","tier_id":"27789984"}'
```
**Result**: ✅ Returns proper JSON response
### Plugin Test
1. Install plugin from CyberPanel
2. Try accessing plugin
3. Should show subscription required page (if not subscribed)
4. Plugin makes API call to your server (no secrets exposed)
## 📋 Next Steps
1. **Implement OAuth Flow** (optional but recommended)
- Users authorize CyberPanel via Patreon OAuth
- Store access tokens securely (database recommended)
- Link tokens to user emails
2. **Test Full Flow**
- Subscribe to Patreon tier
- Authorize CyberPanel
- Access plugin (should work)
3. **Monitor**
- Check API logs for errors
- Monitor rate limiting
- Verify caching is working
## 🎯 Plugin is Safe to Publish
The `premiumPlugin` can now be:
- ✅ Published to public repositories
- ✅ Shared with users
- ✅ Installed on any server
- ✅ Code reviewed by anyone
**No secrets will be exposed** because all verification happens on your server!
## 📝 Files Created/Modified
### Created
- `/home/newstargeted.com/api.newstargeted.com/api/verify-patreon-membership.php`
- `/home/newstargeted.com/api.newstargeted.com/api/index.php`
- `/home/cyberpanel-plugins/premiumPlugin/views.py` (remote version)
- `/home/cyberpanel-plugins/premiumPlugin/SECURITY.md`
### Modified
- `/home/newstargeted.com/api.newstargeted.com/config.php` (added Patreon credentials)
- `/home/newstargeted.com/api.newstargeted.com/.htaccess` (added API routing)
- `/home/cyberpanel-plugins/premiumPlugin/views.py` (updated to remote verification)
## ✨ Benefits
1. **Security**: Secrets never leave your server
2. **Control**: You can revoke access, update logic centrally
3. **Transparency**: Plugin code can be open source
4. **Scalability**: Centralized verification handles all requests
5. **Maintenance**: Update verification logic in one place

View File

@@ -1,86 +0,0 @@
# Remote Verification Setup Complete ✅
## What Was Done
### 1. Remote Verification API Created
- **Location**: `/home/newstargeted.com/api.newstargeted.com/modules/patreon/verify-membership.php`
- **URL**: `https://api.newstargeted.com/api/verify-patreon-membership`
- **Route**: Added to `.htaccess` for clean URL routing
### 2. Plugin Updated to Use Remote Verification
- **File**: `/home/cyberpanel-plugins/premiumPlugin/views.py`
- **Method**: All Patreon checks now go through your server
- **No Secrets**: Plugin code contains zero credentials
### 3. Configuration Added
- **Patreon credentials** added to `/home/newstargeted.com/api.newstargeted.com/config.php`
- **Secure permissions**: config.php set to 600 (readable only by owner)
### 4. File Permissions Set
- ✅ API files: `newst3922:newst3922` (644 for files, 755 for directories)
- ✅ Plugin files: `newst3922:newst3922` (644 for files, 755 for directories)
- ✅ Config file: `newst3922:newst3922` (600 - secure)
## Security Features
**No secrets in plugin** - Users can see all code
**All credentials on your server** - Never exposed
**Rate limiting** - 60 requests/hour per IP
**Caching** - 5 minute cache to reduce API calls
**HTTPS only** - All communication encrypted
**Error handling** - Graceful failures
## How It Works
1. User installs plugin (no subscription needed)
2. User tries to access plugin
3. Plugin makes API call to YOUR server
4. Your server checks Patreon API (credentials stay on your server)
5. Your server returns access status
6. Plugin shows content or subscription page
## Testing
### Test API Endpoint
```bash
curl -X POST https://api.newstargeted.com/api/verify-patreon-membership \
-H "Content-Type: application/json" \
-d '{
"user_email": "test@example.com",
"plugin_name": "premiumPlugin",
"tier_id": "27789984"
}'
```
### Expected Response
```json
{
"success": true,
"has_access": false,
"patreon_tier": "CyberPanel Paid Plugin",
"patreon_url": "https://www.patreon.com/c/newstargeted/membership",
"message": "Patreon subscription required..."
}
```
## Next Steps
1. **Test the API endpoint** - Verify it's accessible
2. **Implement OAuth flow** - For users to authorize Patreon access
3. **Store user tokens** - Link Patreon tokens to user emails
4. **Test full flow** - Install plugin and verify access control
## Files Modified
- `/home/newstargeted.com/api.newstargeted.com/config.php` - Added Patreon credentials
- `/home/newstargeted.com/api.newstargeted.com/.htaccess` - Added API route
- `/home/newstargeted.com/api.newstargeted.com/modules/patreon/verify-membership.php` - Created
- `/home/cyberpanel-plugins/premiumPlugin/views.py` - Updated to use remote verification
- `/home/cyberpanel/plugins/premiumPlugin/views.py` - Updated (installed version)
## Plugin is Now Safe to Publish
✅ No secrets in code
✅ All verification happens on your server
✅ Users can see all plugin files without security risk
✅ Centralized control and updates

View File

@@ -1,132 +0,0 @@
# CyberPanel v2.5.5-dev Installation Fixes
## Issues Identified
### Issue 1: install.sh Module Loading Failure
**Problem**: When executing `install.sh` via `sh <(curl ...)`, the script tries to load modules from `/dev/fd/.../modules/` which doesn't exist because the script is executed directly from stdin.
**Error Message**:
```
❌ Module not found: /dev/fd/modules/os/detect.sh
❌ Failed to load OS detection module
```
**Root Cause**: The script assumes it's running from a cloned repository directory, but when executed via curl, `SCRIPT_DIR` becomes `/dev/fd/...` which doesn't contain the modules.
### Issue 2: MariaDB 10.x to 12.x Upgrade Blocked
**Problem**: The installer attempts to install MariaDB 12.1 on systems that already have MariaDB 10.11.15 installed. MariaDB's package pre-installation script blocks the upgrade because direct upgrades from 10.x to 12.x are not safe without manual dump/restore.
**Error Message**:
```
error: %prein(MariaDB-server-12.1.2-1.el9.x86_64) scriptlet failed, exit status 1
Error in PREIN scriptlet in rpm package MariaDB-server
```
**Root Cause**: The installer doesn't check for existing MariaDB installations before attempting to install MariaDB 12.1.
## Fixes Implemented
### Fix 1: install.sh - Handle Curl/Wget Execution
**Location**: `install/install.sh`
**Changes**:
1. Added detection for curl/wget execution (checks if `SCRIPT_DIR` is `/dev/fd/*` or modules directory doesn't exist)
2. When detected, the script now:
- Clones the CyberPanel repository to a temporary directory
- Extracts branch name from command-line arguments
- Falls back to legacy installer if git clone fails
3. Properly handles branch argument parsing for both `-b` and `--branch` flags
**Code Added**:
```bash
# Check if script is being executed via curl/wget
if [[ "$SCRIPT_DIR" == /dev/fd/* ]] || [[ ! -d "$SCRIPT_DIR/modules" ]]; then
# Clone repository first
# ... (see install.sh for full implementation)
fi
```
### Fix 2: install.py - MariaDB Installation Detection and Upgrade Attempt
**Location**: `install/install.py`
**Changes**:
1. Added `checkExistingMariaDB()` method that:
- Checks for installed MariaDB/MySQL server packages (RPM or DEB)
- Detects MariaDB data directory existence
- Extracts version information from `mysql --version` output
- Returns version info including major.minor version
2. Added `_attemptMariaDBUpgrade()` method that:
- Attempts to install MariaDB 12.1 on systems with MariaDB 10.x
- Sets up MariaDB 12.1 repository
- Attempts installation with appropriate flags (`--allowerasing` for RHEL)
- Returns `True` if successful, `False` if blocked or fails
- Handles upgrade restriction errors gracefully
3. Modified `installMySQL()` method to:
- Check for existing MariaDB installation before attempting install
- **If MariaDB 10.x is detected**: Attempt to upgrade to 12.1 first
- If upgrade succeeds: Use new MariaDB 12.1 installation
- If upgrade fails/blocked: Fall back to existing MariaDB 10.x
- If MariaDB 12.x or higher is detected: Skip installation and use existing
- Only attempt new installation if no MariaDB is found
**Key Logic**:
```python
# Check if MariaDB is already installed
is_installed, installed_version, major_minor = self.checkExistingMariaDB()
if is_installed:
if major_minor and major_minor != "unknown":
major_ver = float(major_minor)
if major_ver < 12.0:
# Try to upgrade to 12.1 first
upgrade_success = self._attemptMariaDBUpgrade()
if upgrade_success:
# Use new MariaDB 12.1
return True
else:
# Fall back to existing MariaDB 10.x
self.startMariaDB()
return True
# Use existing MariaDB 12.x+ installation
self.startMariaDB()
return True
```
## Testing Recommendations
1. **Test install.sh with curl**:
```bash
sh <(curl -s https://raw.githubusercontent.com/master3395/cyberpanel/v2.5.5-dev/install.sh)
```
2. **Test on AlmaLinux 9 with existing MariaDB 10.x**:
- System should detect existing MariaDB 10.x
- Should attempt to upgrade to MariaDB 12.1 first
- If upgrade is blocked, should fall back to using existing MariaDB 10.x
- Should log appropriate messages about upgrade attempt and fallback
3. **Test on clean AlmaLinux 9 system**:
- Should install MariaDB 12.1 successfully
- Should complete full installation
## Files Modified
1. `install/install.sh` - Added curl/wget execution handling
2. `install/install.py` - Added MariaDB detection and existing installation handling
## Notes
- The installer now **attempts to upgrade MariaDB 10.x to 12.1 first**, and only falls back to using existing 10.x if the upgrade is blocked by the package manager
- This provides the best of both worlds: tries to get the latest version, but safely falls back if upgrade restrictions prevent it
- The upgrade attempt uses `--allowerasing` flag for RHEL-based systems to allow package replacements
- If MariaDB's pre-installation scriptlet blocks the upgrade (as it does for 10.x to 12.x), the installer gracefully falls back to the existing installation
- The curl/wget execution now properly clones the repository before attempting to load modules
## Related Issues
- MariaDB 10.x to 12.x upgrades require manual dump/restore per MariaDB documentation
- The installer now respects existing installations to prevent data loss