Add HTTPS configuration management system

- Add HTTPSConfig model for managing HTTPS settings
- Add admin routes for HTTPS configuration management
- Add beautiful admin template for HTTPS configuration
- Add database migration for https_config table
- Add CLI utility for HTTPS management
- Add setup script for automated configuration
- Add Caddy configuration generator and manager
- Add comprehensive documentation (3 guides)
- Add HTTPS Configuration card to admin dashboard
- Implement input validation and security features
- Add admin-only access control with audit trail
- Add real-time configuration preview
- Integrate with existing Caddy reverse proxy

Features:
- Enable/disable HTTPS from web interface
- Configure domain, hostname, IP address, port
- Automatic SSL certificate management via Let's Encrypt
- Real-time Caddyfile generation and reload
- Full audit trail with admin username and timestamps
- Support for HTTPS and HTTP fallback access points
- Beautiful, mobile-responsive UI

Modified files:
- app/models/__init__.py (added HTTPSConfig import)
- app/blueprints/admin.py (added HTTPS routes)
- app/templates/admin/admin.html (added HTTPS card)
- docker-compose.yml (added Caddyfile mount and admin port)

New files:
- app/models/https_config.py
- app/blueprints/https_config.html
- app/utils/caddy_manager.py
- https_manager.py
- setup_https.sh
- migrations/add_https_config_table.py
- migrations/add_email_to_https_config.py
- HTTPS_STATUS.txt
- Documentation files (3 markdown guides)
This commit is contained in:
Quality App Developer
2026-01-14 12:02:49 +02:00
parent ef17abfe6b
commit 48f1bfbcad
108 changed files with 2835 additions and 43 deletions

155
app/blueprints/admin.py Normal file → Executable file
View File

@@ -8,8 +8,9 @@ from datetime import datetime
from typing import Optional
from app.extensions import db, bcrypt
from app.models import User, Player, Group, Content, ServerLog, Playlist
from app.models import User, Player, Group, Content, ServerLog, Playlist, HTTPSConfig
from app.utils.logger import log_action
from app.utils.caddy_manager import CaddyConfigGenerator
admin_bp = Blueprint('admin', __name__, url_prefix='/admin')
@@ -843,3 +844,155 @@ def delete_editing_user(user_id: int):
flash(f'Error deleting user: {str(e)}', 'danger')
return redirect(url_for('admin.manage_editing_users'))
# ============================================================================
# HTTPS Configuration Management Routes
# ============================================================================
@admin_bp.route('/https-config', methods=['GET'])
@login_required
@admin_required
def https_config():
"""Display HTTPS configuration management page."""
try:
config = HTTPSConfig.get_config()
return render_template('admin/https_config.html',
config=config)
except Exception as e:
log_action('error', f'Error loading HTTPS config page: {str(e)}')
flash('Error loading HTTPS configuration page.', 'danger')
return redirect(url_for('admin.admin_panel'))
@admin_bp.route('/https-config/update', methods=['POST'])
@login_required
@admin_required
def update_https_config():
"""Update HTTPS configuration."""
try:
https_enabled = request.form.get('https_enabled') == 'on'
hostname = request.form.get('hostname', '').strip()
domain = request.form.get('domain', '').strip()
ip_address = request.form.get('ip_address', '').strip()
email = request.form.get('email', '').strip()
port = request.form.get('port', '443').strip()
# Validation
errors = []
if https_enabled:
if not hostname:
errors.append('Hostname is required when HTTPS is enabled.')
if not domain:
errors.append('Domain name is required when HTTPS is enabled.')
if not ip_address:
errors.append('IP address is required when HTTPS is enabled.')
if not email:
errors.append('Email address is required when HTTPS is enabled.')
# Validate domain format (basic)
if domain and '.' not in domain:
errors.append('Please enter a valid domain name (e.g., example.com).')
# Validate IP format (basic)
if ip_address:
ip_parts = ip_address.split('.')
if len(ip_parts) != 4:
errors.append('Please enter a valid IPv4 address (e.g., 10.76.152.164).')
else:
try:
for part in ip_parts:
num = int(part)
if num < 0 or num > 255:
raise ValueError()
except ValueError:
errors.append('Please enter a valid IPv4 address.')
# Validate email format (basic)
if email and '@' not in email:
errors.append('Please enter a valid email address.')
# Validate port
try:
port_num = int(port)
if port_num < 1 or port_num > 65535:
errors.append('Port must be between 1 and 65535.')
port = port_num
except ValueError:
errors.append('Port must be a valid number.')
else:
port = 443
if errors:
for error in errors:
flash(error, 'warning')
return redirect(url_for('admin.https_config'))
# Update configuration
config = HTTPSConfig.create_or_update(
https_enabled=https_enabled,
hostname=hostname if https_enabled else None,
domain=domain if https_enabled else None,
ip_address=ip_address if https_enabled else None,
email=email if https_enabled else None,
port=port if https_enabled else 443,
updated_by=current_user.username
)
# Generate and update Caddyfile
try:
caddyfile_content = CaddyConfigGenerator.generate_caddyfile(config)
if CaddyConfigGenerator.write_caddyfile(caddyfile_content):
# Reload Caddy configuration
if CaddyConfigGenerator.reload_caddy():
caddy_status = '✅ Caddy configuration updated successfully!'
log_action('info', f'Caddy configuration reloaded by {current_user.username}')
else:
caddy_status = '⚠️ Caddyfile updated but reload failed. Please restart containers.'
log_action('warning', f'Caddy reload failed for {current_user.username}')
else:
caddy_status = '⚠️ Configuration saved but Caddyfile update failed.'
log_action('warning', f'Caddyfile write failed for {current_user.username}')
except Exception as caddy_error:
caddy_status = f'⚠️ Configuration saved but Caddy update failed: {str(caddy_error)}'
log_action('error', f'Caddy update error: {str(caddy_error)}')
if https_enabled:
log_action('info', f'HTTPS enabled by {current_user.username}: domain={domain}, hostname={hostname}, ip={ip_address}, email={email}')
flash(f'✅ HTTPS configuration saved successfully!\n{caddy_status}\nServer available at https://{domain}', 'success')
else:
log_action('info', f'HTTPS disabled by {current_user.username}')
flash(f'✅ HTTPS has been disabled. Server running on HTTP only.\n{caddy_status}', 'success')
return redirect(url_for('admin.https_config'))
except Exception as e:
db.session.rollback()
log_action('error', f'Error updating HTTPS config: {str(e)}')
flash(f'Error updating HTTPS configuration: {str(e)}', 'danger')
return redirect(url_for('admin.https_config'))
@admin_bp.route('/https-config/status')
@login_required
@admin_required
def https_config_status():
"""Get current HTTPS configuration status as JSON."""
try:
config = HTTPSConfig.get_config()
if config:
return jsonify(config.to_dict())
else:
return jsonify({
'https_enabled': False,
'hostname': None,
'domain': None,
'ip_address': None,
'port': 443,
})
except Exception as e:
log_action('error', f'Error getting HTTPS status: {str(e)}')
return jsonify({'error': str(e)}), 500