Files
CyberPanel/CyberCP/settings.py
master3395 1c6ab7a188 feat(baseTemplate): plugin sidebar context; LPMA link for grant-only users
- plugin_sidebar_context: show_plugins_menu, Limited phpMyAdmin for cpuser grants
- index.html: conditional Installed/Store vs grant-only LPMA submenu
2026-03-27 21:48:25 +01:00

335 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Django settings for CyberCP project.
Generated by 'django-admin startproject' using Django 1.11.3.
For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""
import os
import sys
from django.utils.translation import gettext_lazy as _
# Patreon OAuth (optional): for paid-plugin verification via Patreon membership.
# Set these only if you use Patreon-gated plugins; leave unset otherwise.
# Use environment variables; no defaults so the repo stays generic and safe to push to GitHub.
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', '')
PATREON_MEMBERSHIP_TIER_ID = os.environ.get('PATREON_MEMBERSHIP_TIER_ID', '')
PATREON_CREATOR_ACCESS_TOKEN = os.environ.get('PATREON_CREATOR_ACCESS_TOKEN', '')
PATREON_CREATOR_REFRESH_TOKEN = os.environ.get('PATREON_CREATOR_REFRESH_TOKEN', '')
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# 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'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
ALLOWED_HOSTS = ['*']
# When the panel is behind a reverse proxy (e.g. https://panel.example.com -> http://backend:port),
# the browser sends Origin/Referer with the public domain while the proxy may send Host as the
# backend address. Django then fails CSRF (Referer vs Host mismatch) and POSTs get 403.
# Set CSRF_TRUSTED_ORIGINS to your public origin(s) so CSRF passes. Optional; leave unset if
# you access the panel by IP:port only.
# Example: export CSRF_TRUSTED_ORIGINS="https://panel.example.com,http://panel.example.com"
_csrf_origins_env = os.environ.get('CSRF_TRUSTED_ORIGINS', '')
_csrf_origins_list = [o.strip() for o in _csrf_origins_env.split(',') if o.strip()]
# Add default trusted origins for common CyberPanel domains
_default_origins = [
'https://cyberpanel.newstargeted.com',
'http://cyberpanel.newstargeted.com',
]
# Merge environment and default origins, avoiding duplicates
CSRF_TRUSTED_ORIGINS = list(dict.fromkeys(_csrf_origins_list + _default_origins))
# Optional file: one trusted origin per line (e.g. https://203.0.113.1:2087) for IP:port panel access.
# Create /etc/cyberpanel/csrf_trusted_origins on the server if JSON POSTs get 403 CSRF when using HTTPS by IP.
_csrf_trusted_origins_file = '/etc/cyberpanel/csrf_trusted_origins'
if os.path.isfile(_csrf_trusted_origins_file):
try:
with open(_csrf_trusted_origins_file, 'r', encoding='utf-8', errors='replace') as _csrf_f:
for _csrf_line in _csrf_f:
_csrf_line = _csrf_line.strip()
if _csrf_line and not _csrf_line.startswith('#'):
if _csrf_line not in CSRF_TRUSTED_ORIGINS:
CSRF_TRUSTED_ORIGINS.append(_csrf_line)
except OSError:
pass
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Core apps (no dependencies on other custom apps)
'loginSystem', # Base app - many apps depend on Administrator model
'packages', # websiteFunctions depends on this
# Apps with single dependency
'websiteFunctions', # Depends on packages and loginSystem
'baseTemplate', # Depends on loginSystem
'userManagment', # Depends on loginSystem
'dns', # Depends on loginSystem
# Apps depending on websiteFunctions
'databases', # Depends on websiteFunctions
'ftp', # Depends on websiteFunctions
'filemanager', # Depends on websiteFunctions
'mailServer', # Depends on websiteFunctions, ChildDomains
# Apps with multiple or complex dependencies
'emailPremium',
# Optional plugins (e.g. emailMarketing, discordWebhooks) - install via Plugin Store
# from https://github.com/master3395/cyberpanel-plugins - plugin installer adds them
'cloudAPI', # Depends on websiteFunctions
'containerization', # Depends on websiteFunctions
'IncBackups', # Depends on websiteFunctions and loginSystem
'CLManager', # Depends on packages
# Apps with dependencies on loginSystem only
's3Backups', # Depends on loginSystem
'dockerManager', # Depends on loginSystem
'aiScanner', # Depends on loginSystem
# Independent apps (no model dependencies found)
'firewall',
'tuning',
'serverStatus',
'serverLogs',
'backup',
'managePHP',
'manageSSL',
'api',
'manageServices',
'pluginHolder',
'highAvailability',
'webmail',
'emailDelivery',
# 'WebTerminal'
]
# Add plugins that are installed (plugin installer handles adding/removing)
# Plugins are added by plugin installer when plugins are installed
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'CyberCP.secMiddleware.secMiddleware'
]
ROOT_URLCONF = 'CyberCP.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'baseTemplate.context_processors.version_context',
'baseTemplate.context_processors.cosmetic_context',
'baseTemplate.context_processors.notification_preferences_context',
'baseTemplate.context_processors.firewall_static_context',
'baseTemplate.context_processors.dns_static_context',
'baseTemplate.context_processors.plugin_sidebar_context',
],
},
},
]
WSGI_APPLICATION = 'CyberCP.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
# Prefer password from /etc/cyberpanel/mysqlPassword so panel stays in sync with CLI/install scripts.
_def_mysql_pass = '1XTy1XOV0BZPnM'
try:
_mysql_pass_file = '/etc/cyberpanel/mysqlPassword'
if os.path.exists(_mysql_pass_file):
with open(_mysql_pass_file, 'r') as _f:
_def_mysql_pass = (_f.read() or '').strip() or _def_mysql_pass
except Exception:
pass
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'cyberpanel',
'USER': 'cyberpanel',
'PASSWORD': _def_mysql_pass,
'HOST': 'localhost',
'PORT': ''
},
'rootdb': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mysql',
'USER': 'root',
'PASSWORD': _def_mysql_pass,
'HOST': 'localhost',
'PORT': '',
},
}
DATABASE_ROUTERS = ['backup.backupRouter.backupRouter']
# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = 'en'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
STATIC_URL = '/static/'
# Panel public directory (SnappyMail, phpMyAdmin, etc.) served so /snappymail/ and /phpmyadmin/ work when panel is behind Django
PUBLIC_ROOT = os.path.join(BASE_DIR, 'public')
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)
LANGUAGES = (
('en', _('English')),
('cn', _('Chinese')),
('br', _('Bulgarian')),
('pt', _('Portuguese')),
('ja', _('Japanese')),
('bs', _('Bosnian')),
('gr', _('Greek')),
('ru', _('Russian')),
('tr', _('Turkish')),
('es', _('Spanish')),
('fr', _('French')),
('pl', _('Polish')),
('vi', _('Vietnamese')),
('it', _('Italian')),
('de', _('Deutsch')),
('id', _('Indonesian')),
('bn', _('Bangla')),
('nb', _('Norwegian Bokmål')),
)
MEDIA_URL = '/usr/local/CyberCP/tmp/'
MEDIA_ROOT = MEDIA_URL
DATA_UPLOAD_MAX_MEMORY_SIZE = 2147483648
# Security settings
X_FRAME_OPTIONS = 'SAMEORIGIN'
# Login URL - CyberPanel uses root path for login
LOGIN_URL = '/'
LOGIN_REDIRECT_URL = '/'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# Sync INSTALLED_APPS with plugins on disk so /plugins/<name>/ and /plugins/<name>/settings/ work.
# Plugins installed under /usr/local/CyberCP/ (or BASE_DIR) are added here if they have meta.xml + urls.py.
_cybercp_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if os.path.isdir(_cybercp_root):
try:
# Allow importing plugin packages from the on-disk plugin store sources.
# This helps when /usr/local/CyberCP/<plugin>/ exists as an "installed marker"
# but the full plugin code is missing/incomplete.
_plugin_source_roots = [
'/home/cyberpanel/plugins',
'/home/cyberpanel-plugins',
]
for _src_root in _plugin_source_roots:
try:
if os.path.isdir(_src_root) and _src_root not in sys.path:
sys.path.append(_src_root)
except Exception:
pass
_existing_apps = set(INSTALLED_APPS)
for _name in os.listdir(_cybercp_root):
if _name.startswith('.'):
continue
_plugin_dir = os.path.join(_cybercp_root, _name)
if not os.path.isdir(_plugin_dir):
continue
if _name in _existing_apps:
continue
_installed_has_meta_and_urls = (
os.path.exists(os.path.join(_plugin_dir, 'meta.xml')) and
os.path.exists(os.path.join(_plugin_dir, 'urls.py'))
)
# Fallback: if the installed directory exists but is incomplete,
# try to treat the plugin as installed if we can find meta.xml + urls.py in source.
_source_has_meta_and_urls = False
for _src_root in (
'/home/cyberpanel/plugins',
'/home/cyberpanel-plugins',
):
_src_dir = os.path.join(_src_root, _name)
if not os.path.isdir(_src_dir):
continue
if os.path.exists(os.path.join(_src_dir, 'meta.xml')) and os.path.exists(os.path.join(_src_dir, 'urls.py')):
_source_has_meta_and_urls = True
break
if _installed_has_meta_and_urls or _source_has_meta_and_urls:
INSTALLED_APPS.append(_name)
_existing_apps.add(_name)
except (OSError, IOError):
pass