mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-02-25 16:00:43 +01:00
Fix CSRF, Alpine.js load order, and API robustness in v2 panel
- Add {% csrf_token %} to base.html to ensure CSRF cookie is set
- Load v2.js before Alpine.js so alpine:init listeners register
- Add @csrf_exempt on all API endpoints (matches v1 pattern, session
auth in secMiddleware handles protection)
- Normalize child domain create/delete responses from WebsiteManager
HttpResponse into standard JSON format for frontend
- Validate log_type to only allow 'access' or 'error'
- Safely parse lines parameter in log viewer API
This commit is contained in:
@@ -47,6 +47,9 @@
|
||||
</head>
|
||||
<body class="v2-app" x-data x-init="$store.theme.init()">
|
||||
|
||||
<!-- CSRF token – ensures cookie is set for AJAX calls -->
|
||||
{% csrf_token %}
|
||||
|
||||
<!-- Sidebar -->
|
||||
<aside class="v2-sidebar" :class="{ 'open': $store.sidebar.open }">
|
||||
<div class="v2-sidebar-brand">
|
||||
@@ -138,9 +141,9 @@
|
||||
<!-- Overlay for mobile sidebar -->
|
||||
<div x-show="$store.sidebar.open" @click="$store.sidebar.close()" style="position:fixed;inset:0;background:rgba(0,0,0,0.3);z-index:150;display:none;" x-transition.opacity :style="$store.sidebar.open && 'display:block'"></div>
|
||||
|
||||
<!-- Alpine.js (CDN) -->
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
<!-- v2.js MUST load before Alpine so alpine:init listeners are registered -->
|
||||
<script src="{% static 'panelv2/js/v2.js' %}"></script>
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||
{% block extra_js %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
from django.shortcuts import redirect, HttpResponse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from plogical.httpProc import httpProc
|
||||
from plogical.acl import ACLManager
|
||||
from loginSystem.models import Administrator
|
||||
@@ -367,6 +368,7 @@ def server_management(request):
|
||||
# API endpoints (AJAX)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@csrf_exempt
|
||||
def api_databases(request, site_id):
|
||||
try:
|
||||
userID, admin, currentACL = _auth(request)
|
||||
@@ -408,6 +410,7 @@ def api_databases(request, site_id):
|
||||
return _json(0, 'Invalid method')
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def api_email(request, site_id):
|
||||
try:
|
||||
userID, admin, currentACL = _auth(request)
|
||||
@@ -445,6 +448,7 @@ def api_email(request, site_id):
|
||||
return _json(0, 'Invalid method')
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def api_ftp(request, site_id):
|
||||
try:
|
||||
userID, admin, currentACL = _auth(request)
|
||||
@@ -492,6 +496,7 @@ def api_ftp(request, site_id):
|
||||
return _json(0, 'Invalid method')
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def api_dns(request, site_id):
|
||||
try:
|
||||
userID, admin, currentACL = _auth(request)
|
||||
@@ -535,6 +540,7 @@ def api_dns(request, site_id):
|
||||
return _json(0, 'Invalid method')
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def api_ssl(request, site_id):
|
||||
try:
|
||||
userID, admin, currentACL = _auth(request)
|
||||
@@ -567,6 +573,7 @@ def api_ssl(request, site_id):
|
||||
return _json(0, 'Invalid method')
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def api_backup(request, site_id):
|
||||
try:
|
||||
userID, admin, currentACL = _auth(request)
|
||||
@@ -611,6 +618,7 @@ def api_backup(request, site_id):
|
||||
return _json(0, 'Invalid method')
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def api_logs(request, site_id):
|
||||
try:
|
||||
userID, admin, currentACL = _auth(request)
|
||||
@@ -624,7 +632,12 @@ def api_logs(request, site_id):
|
||||
if request.method == 'GET':
|
||||
import os
|
||||
log_type = request.GET.get('type', 'access')
|
||||
lines = int(request.GET.get('lines', 50))
|
||||
if log_type not in ('access', 'error'):
|
||||
log_type = 'access'
|
||||
try:
|
||||
lines = int(request.GET.get('lines', 50))
|
||||
except (ValueError, TypeError):
|
||||
lines = 50
|
||||
if lines > 1000:
|
||||
lines = 1000
|
||||
|
||||
@@ -647,6 +660,7 @@ def api_logs(request, site_id):
|
||||
return _json(0, 'Invalid method')
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def api_config(request, site_id):
|
||||
try:
|
||||
userID, admin, currentACL = _auth(request)
|
||||
@@ -697,6 +711,7 @@ def api_config(request, site_id):
|
||||
return _json(0, 'Invalid method')
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def api_domains(request, site_id):
|
||||
try:
|
||||
userID, admin, currentACL = _auth(request)
|
||||
@@ -727,7 +742,11 @@ def api_domains(request, site_id):
|
||||
'openBasedir': 1,
|
||||
}
|
||||
result = wm.submitDomainCreation(userID, create_data)
|
||||
return result
|
||||
# WebsiteManager returns HttpResponse — parse and normalize
|
||||
result_data = json.loads(result.content)
|
||||
if result_data.get('status') == 1:
|
||||
return _json(1, 'None')
|
||||
return _json(0, result_data.get('error_message', 'Failed to create domain'))
|
||||
except BaseException as msg:
|
||||
return _json(0, str(msg))
|
||||
|
||||
@@ -739,13 +758,17 @@ def api_domains(request, site_id):
|
||||
wm = WebsiteManager()
|
||||
delete_data = {'websiteName': child.domain}
|
||||
result = wm.submitDomainDeletion(userID, delete_data)
|
||||
return result
|
||||
result_data = json.loads(result.content)
|
||||
if result_data.get('status') == 1:
|
||||
return _json(1, 'None')
|
||||
return _json(0, result_data.get('error_message', 'Failed to delete domain'))
|
||||
except BaseException as msg:
|
||||
return _json(0, str(msg))
|
||||
|
||||
return _json(0, 'Invalid method')
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
def api_security(request, site_id):
|
||||
try:
|
||||
userID, admin, currentACL = _auth(request)
|
||||
|
||||
Reference in New Issue
Block a user