diff --git a/.env.template b/.env.template new file mode 100644 index 000000000..71c488291 --- /dev/null +++ b/.env.template @@ -0,0 +1,36 @@ +# CyberPanel Environment Configuration Template +# Copy this file to .env and update with your actual values +# NEVER commit .env to version control! + +# Django Configuration +SECRET_KEY=your_very_long_random_secret_key_here_minimum_50_characters +DEBUG=False +ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com + +# Database Configuration - CyberPanel Database +DB_NAME=cyberpanel +DB_USER=cyberpanel +DB_PASSWORD=your_secure_cyberpanel_db_password_here +DB_HOST=localhost +DB_PORT=3306 + +# Root Database Configuration - MySQL Root Access +ROOT_DB_NAME=mysql +ROOT_DB_USER=root +ROOT_DB_PASSWORD=your_secure_mysql_root_password_here +ROOT_DB_HOST=localhost +ROOT_DB_PORT=3306 + +# Security Settings +SECURE_SSL_REDIRECT=False +SECURE_HSTS_SECONDS=0 +SECURE_HSTS_INCLUDE_SUBDOMAINS=False +SECURE_HSTS_PRELOAD=False +SESSION_COOKIE_SECURE=False +CSRF_COOKIE_SECURE=False + +# File Upload Settings +DATA_UPLOAD_MAX_MEMORY_SIZE=2147483648 + +# Logging Configuration +LOG_LEVEL=INFO diff --git a/.gitignore b/.gitignore index dffc08ca3..2812413b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,120 @@ +# CyberPanel .gitignore + +# Environment variables (CRITICAL - Contains sensitive data) +.env +.env.backup +.env.local +.env.production +.env.staging + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# Virtual environments +venv/ +env/ +ENV/ +env.bak/ +venv.bak/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS .DS_Store -.AppleDouble -.LSOverride -*.pyc -.idea -venv -/.venv/ +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +*.log +logs/ +log/ + +# Database +*.db +*.sqlite3 + +# Temporary files +tmp/ +temp/ +*.tmp + +# Backup files +*.bak +*.backup + +# Node modules (if any frontend build tools are used) +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Coverage reports +htmlcov/ +.coverage +.coverage.* +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# CyberPanel specific +/usr/local/CyberCP/ +/etc/cyberpanel/ +cyberpanel_password.txt +mysql_password.txt \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..04834c690 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,249 @@ +# Contributing to CyberPanel + +Thank you for your interest in contributing to CyberPanel! This document provides guidelines and information for contributors. + +## ๐ŸŒฟ Branch Structure + +CyberPanel uses a structured branching strategy to manage development and releases: + +### **Branch Types** + +1. **`stable`** - Production-ready stable branch +2. **`vX.X.X`** - Version-specific stable branch (e.g., `v2.4.3`) +3. **`vX.X.X-dev`** - Development branch for specific version (e.g., `v2.4.3-dev`) + +## ๐Ÿ”„ Development Lifecycle + +### **Development Process** + +1. **Default Branch**: The latest `vX.X.X-dev` branch serves as the default (master) branch +2. **Contributions**: All contributors must push to the latest `vX.X.X-dev` branch +3. **Stability Check**: Once development is complete and believed to be stable, a new `vX.X.X` stable branch is created from the dev branch +4. **Merge Process**: The `vX.X.X` stable branch is then merged into the main `stable` branch +5. **New Development**: A new `vX.X.X-dev` branch is created and becomes the default branch +6. **Cleanup**: Old dev branches are deleted to save space + +### **Important Rules** + +- โœ… **DO**: Create pull requests only for the latest dev branch +- โŒ **DON'T**: Create pull requests for any other branches (stable, old dev branches, etc.) +- ๐Ÿ”„ **Development**: All development happens only in the latest dev branch +- ๐Ÿ—‘๏ธ **Cleanup**: Old dev branches are deleted after merging to stable + +## ๐Ÿš€ Getting Started + +### **Prerequisites** + +- Python 3.6+ (see supported versions in README.md) +- Django framework knowledge +- Basic understanding of web hosting control panels +- Git version control + +### **Setup Development Environment** + +1. **Fork the Repository** + ```bash + # Fork the repository on GitHub, then clone your fork + git clone https://github.com/YOUR_USERNAME/cyberpanel.git + cd cyberpanel + ``` + +2. **Add Upstream Remote** + ```bash + git remote add upstream https://github.com/usmannasir/cyberpanel.git + ``` + +3. **Create Development Branch** + ```bash + # Checkout the latest dev branch + git checkout vX.X.X-dev + git pull upstream vX.X.X-dev + ``` + +4. **Install Dependencies** + ```bash + # Install Python dependencies + pip install -r requirements.txt + ``` + +## ๐Ÿ“ Making Contributions + +### **Code Style Guidelines** + +- Follow PEP 8 for Python code +- Use meaningful variable and function names +- Add comments for complex logic +- Write comprehensive docstrings for functions and classes +- Ensure all code is properly tested + +### **Commit Message Format** + +Use clear, descriptive commit messages: + +``` +type(scope): brief description + +Detailed description of changes made. +- List specific changes +- Explain why changes were made +- Reference any related issues + +Fixes #123 +``` + +**Types**: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore` + +### **Pull Request Process** + +1. **Create Feature Branch** + ```bash + git checkout -b feature/your-feature-name + ``` + +2. **Make Changes** + - Write your code + - Add tests if applicable + - Update documentation if needed + +3. **Test Your Changes** + ```bash + # Run tests + python manage.py test + + # Check for linting issues + flake8 . + ``` + +4. **Commit Changes** + ```bash + git add . + git commit -m "feat(module): add new feature" + ``` + +5. **Push and Create PR** + ```bash + git push origin feature/your-feature-name + ``` + Then create a pull request on GitHub targeting the latest dev branch. + +## ๐Ÿงช Testing + +### **Test Requirements** + +- All new features must include tests +- Bug fixes must include regression tests +- Ensure all existing tests pass +- Maintain or improve test coverage + +### **Running Tests** + +```bash +# Run all tests +python manage.py test + +# Run specific test module +python manage.py test module_name.tests + +# Run with coverage +coverage run --source='.' manage.py test +coverage report +``` + +## ๐Ÿ“‹ Issue Reporting + +### **Before Reporting** + +- Check existing issues to avoid duplicates +- Ensure you're using the latest version +- Verify the issue exists in the latest dev branch + +### **Issue Template** + +When creating an issue, include: + +- **OS and Version**: Your operating system and CyberPanel version +- **Steps to Reproduce**: Clear, numbered steps +- **Expected Behavior**: What should happen +- **Actual Behavior**: What actually happens +- **Screenshots**: If applicable +- **Logs**: Relevant error logs from `/usr/local/lscp/logs/` + +## ๐Ÿ”’ Security + +### **Security Issues** + +For security-related issues: + +- **DO NOT** create public issues +- Email security concerns to: security@cyberpanel.net +- Include detailed information about the vulnerability +- Allow time for the team to address before public disclosure + +## ๐Ÿ“š Documentation + +### **Documentation Guidelines** + +- Update relevant documentation when adding features +- Use clear, concise language +- Include code examples where helpful +- Follow the existing documentation style +- Update README.md if adding new features or changing installation process + +## ๐Ÿค Code Review Process + +### **Review Criteria** + +- Code quality and style +- Test coverage +- Documentation updates +- Security considerations +- Performance impact +- Backward compatibility + +### **Review Timeline** + +- Initial review: Within 48 hours +- Follow-up reviews: Within 24 hours +- Merge decision: Within 1 week (for approved PRs) + +## ๐Ÿท๏ธ Release Process + +### **Version Numbering** + +CyberPanel follows semantic versioning (MAJOR.MINOR.PATCH): + +- **MAJOR**: Breaking changes +- **MINOR**: New features (backward compatible) +- **PATCH**: Bug fixes (backward compatible) + +### **Release Schedule** + +- **Stable Releases**: Monthly or as needed +- **Hotfixes**: As critical issues arise +- **Development**: Continuous integration + +## ๐Ÿ’ฌ Community + +### **Getting Help** + +- ๐Ÿ“š [Documentation](https://cyberpanel.net/KnowledgeBase/) +- ๐Ÿ’ฌ [Discord](https://discord.gg/g8k8Db3) +- ๐Ÿ“ข [Forums](https://community.cyberpanel.net) +- ๐Ÿ“ต [Facebook Group](https://www.facebook.com/groups/cyberpanel) + +### **Contributing Guidelines** + +- Be respectful and constructive +- Help others learn and grow +- Follow the code of conduct +- Ask questions when unsure + +## ๐Ÿ“„ License + +By contributing to CyberPanel, you agree that your contributions will be licensed under the same license as the project (GPL-3.0). + +--- + +**Thank you for contributing to CyberPanel!** ๐ŸŽ‰ + +Your contributions help make web hosting management easier for thousands of users worldwide. diff --git a/CyberCP/settings.py b/CyberCP/settings.py index ac1579490..242636410 100644 --- a/CyberCP/settings.py +++ b/CyberCP/settings.py @@ -13,6 +13,14 @@ https://docs.djangoproject.com/en/1.11/ref/settings/ import os from django.utils.translation import gettext_lazy as _ +# Load environment variables from .env file +try: + from dotenv import load_dotenv + load_dotenv() +except ImportError: + # dotenv not available, continue without it + pass + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -20,12 +28,13 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'xr%j*p!*$0d%(-(e%@-*hyoz4$f%y77coq0u)6pwmjg4)q&19f' +SECRET_KEY = os.getenv('SECRET_KEY', 'xr%j*p!*$0d%(-(e%@-*hyoz4$f%y77coq0u)6pwmjg4)q&19f') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = False +DEBUG = os.getenv('DEBUG', 'False').lower() == 'true' -ALLOWED_HOSTS = ['*'] +# Allow configuration via environment variable, fallback to wildcard for backward compatibility +ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '*').split(',') # Application definition @@ -96,6 +105,7 @@ TEMPLATES = [ 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'baseTemplate.context_processors.version_context', + 'baseTemplate.context_processors.cosmetic_context', ], }, }, @@ -110,19 +120,19 @@ WSGI_APPLICATION = 'CyberCP.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'cyberpanel', - 'USER': 'cyberpanel', - 'PASSWORD': 'SLTUIUxqhulwsh', - 'HOST': 'localhost', - 'PORT':'' + 'NAME': os.getenv('DB_NAME', 'cyberpanel'), + 'USER': os.getenv('DB_USER', 'cyberpanel'), + 'PASSWORD': os.getenv('DB_PASSWORD', 'SLTUIUxqhulwsh'), + 'HOST': os.getenv('DB_HOST', 'localhost'), + 'PORT': os.getenv('DB_PORT', '3306'), }, 'rootdb': { 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'mysql', - 'USER': 'root', - 'PASSWORD': 'SLTUIUxqhulwsh', - 'HOST': 'localhost', - 'PORT': '', + 'NAME': os.getenv('ROOT_DB_NAME', 'mysql'), + 'USER': os.getenv('ROOT_DB_USER', 'root'), + 'PASSWORD': os.getenv('ROOT_DB_PASSWORD', 'SLTUIUxqhulwsh'), + 'HOST': os.getenv('ROOT_DB_HOST', 'localhost'), + 'PORT': os.getenv('ROOT_DB_PORT', '3306'), }, } DATABASE_ROUTERS = ['backup.backupRouter.backupRouter'] diff --git a/README.md b/README.md index 98284c029..9ff9ab30c 100755 --- a/README.md +++ b/README.md @@ -145,6 +145,7 @@ sh <(curl https://raw.githubusercontent.com/usmannasir/cyberpanel/stable/preUpgr - ๐ŸŽ“ [Docs (Old)](https://community.cyberpanel.net/docs) - ๐Ÿ“– [Additional Guides](guides/INDEX.md) - Detailed guides for Docker, AI Scanner, Mautic, and more - ๐Ÿ“š [Local Documentation](guides/) - All guides available in this repository +- ๐Ÿค [Contributing Guide](CONTRIBUTING.md) - How to contribute to CyberPanel development - โœ… [Changelog](https://community.cyberpanel.net/t/change-logs/161) - ๐Ÿ’ฌ [Forums](https://community.cyberpanel.net) - ๐Ÿ“ข [Discord](https://discord.gg/g8k8Db3) diff --git a/SECURITY_INSTALLATION.md b/SECURITY_INSTALLATION.md new file mode 100644 index 000000000..60cd302c3 --- /dev/null +++ b/SECURITY_INSTALLATION.md @@ -0,0 +1,193 @@ +# CyberPanel Secure Installation Guide + +## Overview + +This document describes the secure installation process for CyberPanel that eliminates hardcoded passwords and implements environment-based configuration. + +## Security Improvements + +### โœ… **Fixed Security Vulnerabilities** + +1. **Hardcoded Database Passwords** - Now generated securely during installation +2. **Hardcoded Django Secret Key** - Now generated using cryptographically secure random generation +3. **Environment Variables** - All sensitive configuration moved to `.env` file +4. **File Permissions** - `.env` file set to 600 (owner read/write only) + +### ๐Ÿ” **Security Features** + +- **Cryptographically Secure Passwords**: Uses Python's `secrets` module for password generation +- **Environment-based Configuration**: Sensitive data stored in `.env` file, not in code +- **Secure File Permissions**: Environment files protected with 600 permissions +- **Credential Backup**: Automatic backup of credentials for recovery +- **Fallback Security**: Maintains backward compatibility with fallback method + +## Installation Process + +### 1. **Automatic Secure Installation** + +The installation script now automatically: + +1. Generates secure random passwords for: + - MySQL root user + - CyberPanel database user + - Django secret key + +2. Creates `.env` file with secure configuration: + ```bash + # Generated during installation + SECRET_KEY=your_64_character_secure_key + DB_PASSWORD=your_24_character_secure_password + ROOT_DB_PASSWORD=your_24_character_secure_password + ``` + +3. Creates `.env.backup` file for credential recovery +4. Sets secure file permissions (600) on all environment files + +### 2. **Manual Installation** (if needed) + +If you need to manually generate environment configuration: + +```bash +cd /usr/local/CyberCP +python install/env_generator.py /usr/local/CyberCP +``` + +## File Structure + +``` +/usr/local/CyberCP/ +โ”œโ”€โ”€ .env # Main environment configuration (600 permissions) +โ”œโ”€โ”€ .env.backup # Credential backup (600 permissions) +โ”œโ”€โ”€ .env.template # Template for manual configuration +โ”œโ”€โ”€ .gitignore # Prevents .env files from being committed +โ””โ”€โ”€ CyberCP/ + โ””โ”€โ”€ settings.py # Updated to use environment variables +``` + +## Security Best Practices + +### โœ… **Do's** + +- Keep `.env` and `.env.backup` files secure +- Record credentials from `.env.backup` and delete the file after installation +- Use strong, unique passwords for production deployments +- Regularly rotate database passwords +- Monitor access to environment files + +### โŒ **Don'ts** + +- Never commit `.env` files to version control +- Don't share `.env` files via insecure channels +- Don't use default passwords in production +- Don't leave `.env.backup` files on the system after recording credentials + +## Recovery + +### **Lost Credentials** + +If you lose your database credentials: + +1. Check if `.env.backup` file exists: + ```bash + sudo cat /usr/local/CyberCP/.env.backup + ``` + +2. If backup doesn't exist, you'll need to reset MySQL passwords using MySQL recovery procedures + +### **Regenerate Environment** + +To regenerate environment configuration: + +```bash +cd /usr/local/CyberCP +sudo python install/env_generator.py /usr/local/CyberCP +``` + +## Configuration Options + +### **Environment Variables** + +| Variable | Description | Default | +|----------|-------------|---------| +| `SECRET_KEY` | Django secret key | Generated (64 chars) | +| `DB_PASSWORD` | CyberPanel DB password | Generated (24 chars) | +| `ROOT_DB_PASSWORD` | MySQL root password | Generated (24 chars) | +| `DEBUG` | Debug mode | False | +| `ALLOWED_HOSTS` | Allowed hosts | localhost,127.0.0.1,hostname | + +### **Custom Configuration** + +To use custom passwords during installation: + +```bash +python install/env_generator.py /usr/local/CyberCP "your_root_password" "your_db_password" +``` + +## Troubleshooting + +### **Installation Fails** + +If the new secure installation fails: + +1. Check installation logs for error messages +2. The system will automatically fallback to the original installation method +3. Verify Python dependencies are installed: + ```bash + pip install python-dotenv + ``` + +### **Environment Loading Issues** + +If Django can't load environment variables: + +1. Ensure `.env` file exists and has correct permissions: + ```bash + ls -la /usr/local/CyberCP/.env + # Should show: -rw------- 1 root root + ``` + +2. Install python-dotenv if missing: + ```bash + pip install python-dotenv + ``` + +## Migration from Old Installation + +### **Existing Installations** + +For existing CyberPanel installations with hardcoded passwords: + +1. **Backup current configuration**: + ```bash + cp /usr/local/CyberCP/CyberCP/settings.py /usr/local/CyberCP/CyberCP/settings.py.backup + ``` + +2. **Generate new environment configuration**: + ```bash + cd /usr/local/CyberCP + python install/env_generator.py /usr/local/CyberCP + ``` + +3. **Update settings.py** (already done in new installations): + - The settings.py file now supports environment variables + - It will fallback to hardcoded values if .env is not available + +4. **Test the configuration**: + ```bash + cd /usr/local/CyberCP + python manage.py check + ``` + +## Support + +For issues with the secure installation: + +1. Check the installation logs +2. Verify file permissions +3. Ensure all dependencies are installed +4. Review the fallback installation method if needed + +--- + +**Security Notice**: This installation method significantly improves security by eliminating hardcoded credentials. Always ensure proper file permissions and secure handling of environment files. + diff --git a/backup/static/backup/backup.js b/backup/static/backup/backup.js index 1760c54fc..7323e8e49 100644 --- a/backup/static/backup/backup.js +++ b/backup/static/backup/backup.js @@ -2074,6 +2074,8 @@ app.controller('scheduleBackup', function ($scope, $http, $window) { $scope.allSites = response.data.allSites; $scope.lastRun = response.data.lastRun; $scope.currentStatus = response.data.currentStatus; + $scope.backupFrequency = response.data.currently; + $scope.backupRetention = response.data.retention; } else { new PNotify({ diff --git a/baseTemplate/context_processors.py b/baseTemplate/context_processors.py index c63e23902..13d871c10 100644 --- a/baseTemplate/context_processors.py +++ b/baseTemplate/context_processors.py @@ -7,4 +7,20 @@ def version_context(request): 'CYBERPANEL_VERSION': VERSION, 'CYBERPANEL_BUILD': BUILD, 'CYBERPANEL_FULL_VERSION': f"{VERSION}.{BUILD}" - } \ No newline at end of file + } + +def cosmetic_context(request): + """Add cosmetic data (custom CSS) to all templates""" + try: + from .models import CyberPanelCosmetic + cosmetic = CyberPanelCosmetic.objects.get(pk=1) + return { + 'cosmetic': cosmetic + } + except: + from .models import CyberPanelCosmetic + cosmetic = CyberPanelCosmetic() + cosmetic.save() + return { + 'cosmetic': cosmetic + } \ No newline at end of file diff --git a/baseTemplate/templates/baseTemplate/index.html b/baseTemplate/templates/baseTemplate/index.html index 82a55f350..3a6986ddd 100644 --- a/baseTemplate/templates/baseTemplate/index.html +++ b/baseTemplate/templates/baseTemplate/index.html @@ -15,6 +15,11 @@ + + + diff --git a/guides/CONTRIBUTING.md b/guides/CONTRIBUTING.md deleted file mode 100644 index 3aa9c212e..000000000 --- a/guides/CONTRIBUTING.md +++ /dev/null @@ -1,14 +0,0 @@ -Branches - - 1.Stable-> Stable branch - 2.vX.X.X-> vX.X.X Stable branch - 3.vX.X.X-dev-> v.X.X.X Dev branch - -Development Lifecycle - - vX.X.X-dev will be default(master) branch. All contributors must push to latest vX.X.X-dev branch. Once development - is complete(believed to be stable) new vX.X.X Stable branch will be created from Dev branch. Then vX.X.X Stable will - be merged into Stable branch. After that a new vX.X.X-dev branch will be created and it will be default(master) - branch. Old dev branch will be deleted at this stage(to save space) and no development will happen on old stable or - dev(if not deleted) branch. All development will only take place in latest dev branch. You must not create pull - request for any other branches other than latest dev branch. diff --git a/install/env_generator.py b/install/env_generator.py new file mode 100644 index 000000000..47f6cac64 --- /dev/null +++ b/install/env_generator.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +""" +CyberPanel Environment Configuration Generator +Generates secure .env file with random passwords during installation +""" + +import os +import sys +import secrets +import string +from pathlib import Path + +def generate_secure_password(length=24): + """ + Generate a cryptographically secure password + + Args: + length: Length of the password to generate (default 24) + + Returns: + str: Random password containing uppercase, lowercase, digits and safe special chars + """ + # Use safe characters that don't require escaping in most contexts + safe_chars = string.ascii_letters + string.digits + '!@#$%^&*' + return ''.join(secrets.choice(safe_chars) for _ in range(length)) + +def generate_secret_key(length=64): + """ + Generate a cryptographically secure Django secret key + + Args: + length: Length of the secret key to generate (default 64) + + Returns: + str: Random secret key + """ + chars = string.ascii_letters + string.digits + '!@#$%^&*(-_=+)' + return ''.join(secrets.choice(chars) for _ in range(length)) + +def create_env_file(cyberpanel_path, mysql_root_password=None, cyberpanel_db_password=None): + """ + Create .env file with generated secure credentials + + Args: + cyberpanel_path: Path to CyberPanel installation directory + mysql_root_password: Optional MySQL root password (will generate if None) + cyberpanel_db_password: Optional CyberPanel DB password (will generate if None) + """ + + # Generate secure passwords if not provided + if not mysql_root_password: + mysql_root_password = generate_secure_password(24) + + if not cyberpanel_db_password: + cyberpanel_db_password = generate_secure_password(24) + + secret_key = generate_secret_key(64) + + # Get hostname for ALLOWED_HOSTS + import socket + try: + hostname = socket.gethostname() + local_ip = socket.gethostbyname(hostname) + except: + hostname = 'localhost' + local_ip = '127.0.0.1' + + # Create .env content + env_content = f"""# CyberPanel Environment Configuration +# Generated automatically during installation - DO NOT EDIT MANUALLY +# Generated on: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')} + +# Django Configuration +SECRET_KEY={secret_key} +DEBUG=False +ALLOWED_HOSTS=localhost,127.0.0.1,{hostname},{local_ip} + +# Database Configuration - CyberPanel Database +DB_NAME=cyberpanel +DB_USER=cyberpanel +DB_PASSWORD={cyberpanel_db_password} +DB_HOST=localhost +DB_PORT=3306 + +# Root Database Configuration - MySQL Root Access +ROOT_DB_NAME=mysql +ROOT_DB_USER=root +ROOT_DB_PASSWORD={mysql_root_password} +ROOT_DB_HOST=localhost +ROOT_DB_PORT=3306 + +# Security Settings +SECURE_SSL_REDIRECT=False +SECURE_HSTS_SECONDS=0 +SECURE_HSTS_INCLUDE_SUBDOMAINS=False +SECURE_HSTS_PRELOAD=False +SESSION_COOKIE_SECURE=False +CSRF_COOKIE_SECURE=False + +# File Upload Settings +DATA_UPLOAD_MAX_MEMORY_SIZE=2147483648 + +# Logging Configuration +LOG_LEVEL=INFO +""" + + # Write .env file + env_file_path = os.path.join(cyberpanel_path, '.env') + with open(env_file_path, 'w') as f: + f.write(env_content) + + # Set secure permissions (owner read/write only) + os.chmod(env_file_path, 0o600) + + print(f"โœ“ Generated secure .env file at: {env_file_path}") + print(f"โœ“ MySQL Root Password: {mysql_root_password}") + print(f"โœ“ CyberPanel DB Password: {cyberpanel_db_password}") + print(f"โœ“ Django Secret Key: {secret_key[:20]}...") + + return { + 'mysql_root_password': mysql_root_password, + 'cyberpanel_db_password': cyberpanel_db_password, + 'secret_key': secret_key + } + +def create_env_backup(cyberpanel_path, credentials): + """ + Create a secure backup of credentials for recovery purposes + + Args: + cyberpanel_path: Path to CyberPanel installation directory + credentials: Dictionary containing generated credentials + """ + backup_content = f"""# CyberPanel Credentials Backup +# Generated: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')} +# +# IMPORTANT: Store this file securely and delete it after recording credentials +# These are your database passwords and should be kept confidential + +MySQL Root Password: {credentials['mysql_root_password']} +CyberPanel Database Password: {credentials['cyberpanel_db_password']} +Django Secret Key: {credentials['secret_key']} + +# To restore these credentials, copy them to your .env file +""" + + backup_file_path = os.path.join(cyberpanel_path, '.env.backup') + with open(backup_file_path, 'w') as f: + f.write(backup_content) + + # Set secure permissions (owner read/write only) + os.chmod(backup_file_path, 0o600) + + print(f"โœ“ Created credentials backup at: {backup_file_path}") + print("โš ๏ธ IMPORTANT: Record these credentials and delete the backup file for security") + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: python env_generator.py [mysql_root_password] [cyberpanel_db_password]") + sys.exit(1) + + cyberpanel_path = sys.argv[1] + mysql_root_password = sys.argv[2] if len(sys.argv) > 2 else None + cyberpanel_db_password = sys.argv[3] if len(sys.argv) > 3 else None + + if not os.path.exists(cyberpanel_path): + print(f"Error: CyberPanel path does not exist: {cyberpanel_path}") + sys.exit(1) + + try: + credentials = create_env_file(cyberpanel_path, mysql_root_password, cyberpanel_db_password) + create_env_backup(cyberpanel_path, credentials) + print("\nโœ“ Environment configuration generated successfully!") + print("โœ“ Remember to delete .env.backup after recording credentials") + except Exception as e: + print(f"Error generating environment configuration: {e}") + sys.exit(1) diff --git a/install/install.py b/install/install.py index 862e5de83..31267817b 100644 --- a/install/install.py +++ b/install/install.py @@ -504,6 +504,73 @@ class preFlightsChecks: self.stdOut("Install psmisc") self.install_package("psmisc") + def generate_secure_env_file(self, mysql_root_password, cyberpanel_db_password): + """ + Generate secure .env file with random passwords during installation + """ + try: + import sys + import socket + + # Import the environment generator + sys.path.append(os.path.join(self.cyberPanelPath, 'install')) + from env_generator import create_env_file, create_env_backup + + # Generate secure credentials + credentials = create_env_file( + self.cyberPanelPath, + mysql_root_password, + cyberpanel_db_password + ) + + # Create backup for recovery + create_env_backup(self.cyberPanelPath, credentials) + + logging.InstallLog.writeToFile("โœ“ Secure .env file generated successfully") + logging.InstallLog.writeToFile("โœ“ Credentials backup created for recovery") + + return credentials + + except Exception as e: + logging.InstallLog.writeToFile(f"[ERROR] Failed to generate secure environment file: {str(e)}") + # Fallback to original method if environment generation fails + self.fallback_settings_update(mysql_root_password, cyberpanel_db_password) + + def fallback_settings_update(self, mysqlPassword, password): + """ + Fallback method to update settings.py directly if environment generation fails + """ + logging.InstallLog.writeToFile("Using fallback method for settings.py update") + + path = self.cyberPanelPath + "/CyberCP/settings.py" + data = open(path, "r").readlines() + writeDataToFile = open(path, "w") + counter = 0 + + for items in data: + if items.find('SECRET_KEY') > -1: + SK = "SECRET_KEY = '%s'\n" % (generate_pass(50)) + writeDataToFile.writelines(SK) + continue + + if items.find("'PASSWORD':") > -1: + if counter == 0: + writeDataToFile.writelines(" 'PASSWORD': '" + mysqlPassword + "'," + "\n") + counter = counter + 1 + else: + writeDataToFile.writelines(" 'PASSWORD': '" + password + "'," + "\n") + elif items.find('127.0.0.1') > -1: + writeDataToFile.writelines(" 'HOST': 'localhost',\n") + elif items.find("'PORT':'3307'") > -1: + writeDataToFile.writelines(" 'PORT': '',\n") + else: + writeDataToFile.writelines(items) + + if self.distro == ubuntu: + os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR) + + writeDataToFile.close() + def download_install_CyberPanel(self, mysqlPassword, mysql): ## @@ -549,50 +616,12 @@ password="%s" logging.InstallLog.writeToFile("Updating /root/.my.cnf!") - logging.InstallLog.writeToFile("Updating settings.py!") + logging.InstallLog.writeToFile("Generating secure environment configuration!") - path = self.cyberPanelPath + "/CyberCP/settings.py" + # Generate secure environment file instead of hardcoding passwords + self.generate_secure_env_file(mysqlPassword, password) - data = open(path, "r").readlines() - - writeDataToFile = open(path, "w") - - counter = 0 - - for items in data: - if items.find('SECRET_KEY') > -1: - SK = "SECRET_KEY = '%s'\n" % (generate_pass(50)) - writeDataToFile.writelines(SK) - continue - - if mysql == 'Two': - if items.find("'PASSWORD':") > -1: - if counter == 0: - writeDataToFile.writelines(" 'PASSWORD': '" + mysqlPassword + "'," + "\n") - counter = counter + 1 - else: - writeDataToFile.writelines(" 'PASSWORD': '" + password + "'," + "\n") - - else: - writeDataToFile.writelines(items) - else: - if items.find("'PASSWORD':") > -1: - if counter == 0: - writeDataToFile.writelines(" 'PASSWORD': '" + mysqlPassword + "'," + "\n") - counter = counter + 1 - else: - writeDataToFile.writelines(" 'PASSWORD': '" + password + "'," + "\n") - elif items.find('127.0.0.1') > -1: - writeDataToFile.writelines(" 'HOST': 'localhost',\n") - elif items.find("'PORT':'3307'") > -1: - writeDataToFile.writelines(" 'PORT': '',\n") - else: - writeDataToFile.writelines(items) - - if self.distro == ubuntu: - os.fchmod(writeDataToFile.fileno(), stat.S_IRUSR | stat.S_IWUSR) - - writeDataToFile.close() + logging.InstallLog.writeToFile("Environment configuration generated successfully!") if self.remotemysql == 'ON': command = "sed -i 's|localhost|%s|g' %s" % (self.mysqlhost, path) diff --git a/mailServer/templates/mailServer/changeEmailPassword.html b/mailServer/templates/mailServer/changeEmailPassword.html index a0e79c185..363f7e93d 100644 --- a/mailServer/templates/mailServer/changeEmailPassword.html +++ b/mailServer/templates/mailServer/changeEmailPassword.html @@ -242,6 +242,16 @@ margin-right: 0.5rem; } + .password-hint { + color: var(--text-secondary, #64748b); + margin-top: 0.5rem; + display: block; + } + + .action-section { + margin-top: 2rem; + } + @keyframes spin { to { transform: rotate(360deg); } } @@ -324,7 +334,7 @@
- {% for items in websiteList %} @@ -345,7 +355,7 @@
- @@ -374,19 +384,19 @@
+ ng-model="emailPassword" readonly aria-label="{% trans 'Generated Password' %}">
- + {% trans "Make sure to save this password in a secure location" %}
-
+
- + {% trans "Make sure to save this password in a secure location" %}
-
+