Jun 28 Optimize code
This commit is contained in:
@@ -20,13 +20,17 @@ Env vars required (same /etc/jqc/control.env sourced by the main app):
|
||||
|
||||
import os
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from logging.handlers import RotatingFileHandler
|
||||
|
||||
from flask import Flask
|
||||
from flask_wtf.csrf import CSRFProtect
|
||||
|
||||
from .auth import bp as auth_bp
|
||||
from .tenants import bp as tenants_bp
|
||||
|
||||
csrf = CSRFProtect()
|
||||
|
||||
|
||||
def create_panel_app():
|
||||
app = Flask(__name__, template_folder='templates')
|
||||
@@ -39,6 +43,20 @@ def create_panel_app():
|
||||
)
|
||||
app.secret_key = secret
|
||||
|
||||
# ── Session lifetime ──────────────────────────────────────────────────
|
||||
# Superadmin sessions expire after 4 hours of inactivity.
|
||||
# Flask default when permanent=True is 31 days — too long for privileged access.
|
||||
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=4)
|
||||
|
||||
# ── CSRF protection ───────────────────────────────────────────────────
|
||||
# Protects all POST routes in the panel against cross-site request forgery.
|
||||
# Templates include: <input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
csrf.init_app(app)
|
||||
|
||||
# Make csrf_token() available in all panel templates
|
||||
from flask_wtf.csrf import generate_csrf
|
||||
app.jinja_env.globals['csrf_token'] = generate_csrf
|
||||
|
||||
# ── Logging ──────────────────────────────────────────────────────────
|
||||
log_level = logging.INFO
|
||||
formatter = logging.Formatter(
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
{% endif %}
|
||||
|
||||
<form method="POST" action="{{ url_for('auth.login') }}">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Username</label>
|
||||
<input type="text" name="username" class="form-control" placeholder="superadmin" required autofocus>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ url_for('tenants.provision_tenant') }}">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-semibold" style="font-size:.85rem;">Slug <span class="text-danger">*</span></label>
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
<form method="POST"
|
||||
action="{{ url_for('tenants.migrate_tenant', tenant_id=tenant.id) }}"
|
||||
onsubmit="return confirm('Run upgrade_tenant for {{ tenant.slug }}?')">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-arrow-up-circle me-1"></i> Upgrade to Head
|
||||
</button>
|
||||
@@ -110,6 +111,7 @@
|
||||
<form method="POST"
|
||||
action="{{ url_for('tenants.verify_domain', tenant_id=tenant.id, domain_id=d.id) }}"
|
||||
class="d-inline">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn btn-xs btn-outline-success" style="font-size:.72rem; padding:.1rem .4rem;">
|
||||
Verify
|
||||
</button>
|
||||
@@ -124,6 +126,7 @@
|
||||
action="{{ url_for('tenants.delete_domain', tenant_id=tenant.id, domain_id=d.id) }}"
|
||||
class="d-inline"
|
||||
onsubmit="return confirm('Delete domain {{ d.domain }}?')">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn btn-xs btn-outline-danger" style="font-size:.72rem; padding:.1rem .4rem;">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
@@ -141,6 +144,7 @@
|
||||
<form method="POST"
|
||||
action="{{ url_for('tenants.add_domain', tenant_id=tenant.id) }}"
|
||||
class="row g-2 align-items-end">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="col-auto">
|
||||
<input type="text" name="domain" class="form-control form-control-sm"
|
||||
placeholder="custom.example.com" style="width:220px;">
|
||||
@@ -208,6 +212,7 @@
|
||||
<div class="card-body py-2">
|
||||
<form method="POST"
|
||||
action="{{ url_for('tenants.change_plan', tenant_id=tenant.id) }}">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="mb-2">
|
||||
<select name="plan_id" class="form-select form-select-sm">
|
||||
{% for p in plans %}
|
||||
@@ -252,6 +257,7 @@
|
||||
<form method="POST"
|
||||
action="{{ url_for('tenants.resume_tenant', tenant_id=tenant.id) }}"
|
||||
onsubmit="return confirm('Resume tenant {{ tenant.slug }}?')">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn btn-sm btn-outline-success w-100">
|
||||
<i class="bi bi-play-circle me-1"></i> Resume
|
||||
</button>
|
||||
@@ -292,6 +298,7 @@
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form method="POST" action="{{ url_for('tenants.suspend_tenant', tenant_id=tenant.id) }}">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="modal-body">
|
||||
<label class="form-label" style="font-size:.85rem;">Reason (optional)</label>
|
||||
<input type="text" name="reason" class="form-control form-control-sm"
|
||||
|
||||
Reference in New Issue
Block a user