mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2026-02-16 11:36:48 +01:00
Add modify firewall rule and improve export/import functionality
- Add modifyRule function to allow editing firewall rules without deletion - Add modify button and modal for firewall rules (similar to banned IPs) - Fix exportRules function to properly handle file downloads with blob response - Improve importRules function with better error handling and PNotify notifications - Add exportBannedIPs and importBannedIPs functionality - Add export/import buttons for banned IPs - Improve error handling and user feedback for all export/import operations - Add proper validation and duplicate detection for imports
This commit is contained in:
@@ -11,6 +11,7 @@ sys.path.append('/usr/local/CyberCP')
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings")
|
||||
django.setup()
|
||||
import json
|
||||
import tempfile
|
||||
from plogical.acl import ACLManager
|
||||
import plogical.CyberCPLogFileWriter as logging
|
||||
from plogical.virtualHostUtilities import virtualHostUtilities
|
||||
@@ -139,6 +140,107 @@ class FirewallManager:
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
def modifyRule(self, userID=None, data=None):
|
||||
"""
|
||||
Modify an existing firewall rule
|
||||
"""
|
||||
try:
|
||||
currentACL = ACLManager.loadedACL(userID)
|
||||
|
||||
if currentACL['admin'] == 1:
|
||||
pass
|
||||
else:
|
||||
return ACLManager.loadErrorJson('modify_status', 0)
|
||||
|
||||
ruleID = data.get('id')
|
||||
newRuleName = data.get('ruleName', '').strip()
|
||||
newRuleProtocol = data.get('ruleProtocol', '').strip()
|
||||
newRulePort = data.get('rulePort', '').strip()
|
||||
newRuleIP = data.get('ruleIP', '').strip()
|
||||
|
||||
# Validate inputs
|
||||
if not newRuleName:
|
||||
final_dic = {'status': 0, 'modify_status': 0, 'error_message': 'Rule name is required'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
if not newRuleProtocol or newRuleProtocol not in ['tcp', 'udp']:
|
||||
final_dic = {'status': 0, 'modify_status': 0, 'error_message': 'Valid protocol (tcp/udp) is required'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
if not newRulePort:
|
||||
final_dic = {'status': 0, 'modify_status': 0, 'error_message': 'Port is required'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
if not newRuleIP:
|
||||
final_dic = {'status': 0, 'modify_status': 0, 'error_message': 'IP address is required'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Get existing rule
|
||||
try:
|
||||
existingRule = FirewallRules.objects.get(id=ruleID)
|
||||
except FirewallRules.DoesNotExist:
|
||||
final_dic = {'status': 0, 'modify_status': 0, 'error_message': 'Rule not found'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Check if anything changed
|
||||
changed = False
|
||||
if (existingRule.name != newRuleName or
|
||||
existingRule.proto != newRuleProtocol or
|
||||
existingRule.port != newRulePort or
|
||||
existingRule.ipAddress != newRuleIP):
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
# Check if new rule already exists (different ID)
|
||||
existingDuplicate = FirewallRules.objects.filter(
|
||||
name=newRuleName,
|
||||
proto=newRuleProtocol,
|
||||
port=newRulePort,
|
||||
ipAddress=newRuleIP
|
||||
).exclude(id=ruleID).first()
|
||||
|
||||
if existingDuplicate:
|
||||
final_dic = {'status': 0, 'modify_status': 0, 'error_message': 'A rule with these settings already exists'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Delete old firewall rule
|
||||
try:
|
||||
FirewallUtilities.deleteRule(existingRule.proto, existingRule.port, existingRule.ipAddress)
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Removed old firewall rule: {existingRule.proto}/{existingRule.port}/{existingRule.ipAddress}')
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Warning: Could not remove old firewall rule: {str(e)}')
|
||||
|
||||
# Add new firewall rule
|
||||
try:
|
||||
FirewallUtilities.addRule(newRuleProtocol, newRulePort, newRuleIP)
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Added new firewall rule: {newRuleProtocol}/{newRulePort}/{newRuleIP}')
|
||||
except Exception as e:
|
||||
final_dic = {'status': 0, 'modify_status': 0, 'error_message': f'Failed to add firewall rule: {str(e)}'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Update database record
|
||||
existingRule.name = newRuleName
|
||||
existingRule.proto = newRuleProtocol
|
||||
existingRule.port = newRulePort
|
||||
existingRule.ipAddress = newRuleIP
|
||||
existingRule.save()
|
||||
|
||||
final_dic = {'status': 1, 'modify_status': 1, 'error_message': "None"}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
except BaseException as msg:
|
||||
final_dic = {'status': 0, 'modify_status': 0, 'error_message': str(msg)}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
def deleteRule(self, userID = None, data = None):
|
||||
try:
|
||||
|
||||
@@ -1829,24 +1931,72 @@ class FirewallManager:
|
||||
except:
|
||||
banned_ips = []
|
||||
|
||||
# Filter out expired bans
|
||||
# Filter out expired bans and format data consistently
|
||||
current_time = time.time()
|
||||
active_banned_ips = []
|
||||
|
||||
for banned_ip in banned_ips:
|
||||
if banned_ip.get('expires') == 'Never' or banned_ip.get('expires', 0) > current_time:
|
||||
banned_ip['active'] = True
|
||||
if banned_ip.get('expires') != 'Never':
|
||||
banned_ip['expires'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(banned_ip['expires']))
|
||||
else:
|
||||
banned_ip['expires'] = 'Never'
|
||||
banned_ip['banned_on'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(banned_ip.get('banned_on', current_time)))
|
||||
else:
|
||||
banned_ip['active'] = False
|
||||
banned_ip['expires'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(banned_ip.get('expires', current_time)))
|
||||
banned_ip['banned_on'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(banned_ip.get('banned_on', current_time)))
|
||||
# Get original values
|
||||
expires_val = banned_ip.get('expires')
|
||||
banned_on_val = banned_ip.get('banned_on', current_time)
|
||||
|
||||
active_banned_ips.append(banned_ip)
|
||||
# Convert banned_on to timestamp if it's a string
|
||||
if isinstance(banned_on_val, str):
|
||||
try:
|
||||
# Try parsing formatted date string
|
||||
banned_on_val = time.mktime(time.strptime(banned_on_val, '%Y-%m-%d %H:%M:%S'))
|
||||
except:
|
||||
banned_on_val = current_time
|
||||
elif not isinstance(banned_on_val, (int, float)):
|
||||
banned_on_val = current_time
|
||||
|
||||
# Check if expired
|
||||
is_expired = False
|
||||
if expires_val == 'Never' or expires_val is None:
|
||||
expires_timestamp = None
|
||||
expires_display = 'Never'
|
||||
elif isinstance(expires_val, str):
|
||||
if expires_val == 'Never':
|
||||
expires_timestamp = None
|
||||
expires_display = 'Never'
|
||||
else:
|
||||
try:
|
||||
expires_timestamp = time.mktime(time.strptime(expires_val, '%Y-%m-%d %H:%M:%S'))
|
||||
expires_display = expires_val
|
||||
except:
|
||||
expires_timestamp = None
|
||||
expires_display = 'Never'
|
||||
else:
|
||||
expires_timestamp = expires_val
|
||||
if expires_val > current_time:
|
||||
expires_display = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(expires_val))
|
||||
else:
|
||||
expires_display = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(expires_val))
|
||||
is_expired = True
|
||||
|
||||
# Determine if active
|
||||
if expires_timestamp is None:
|
||||
is_active = True
|
||||
else:
|
||||
is_active = expires_timestamp > current_time and not is_expired
|
||||
|
||||
# Format banned_on for display
|
||||
banned_on_display = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(banned_on_val))
|
||||
|
||||
# Create formatted entry
|
||||
formatted_ip = {
|
||||
'id': banned_ip.get('id'),
|
||||
'ip': banned_ip.get('ip'),
|
||||
'reason': banned_ip.get('reason', ''),
|
||||
'duration': banned_ip.get('duration', 'never'),
|
||||
'banned_on': banned_on_display, # String for display
|
||||
'banned_on_timestamp': banned_on_val * 1000, # Milliseconds for AngularJS date filter
|
||||
'expires': expires_display, # String for display
|
||||
'expires_timestamp': expires_timestamp * 1000 if expires_timestamp else None, # Milliseconds for AngularJS
|
||||
'active': is_active
|
||||
}
|
||||
|
||||
active_banned_ips.append(formatted_ip)
|
||||
|
||||
final_dic = {'status': 1, 'bannedIPs': active_banned_ips}
|
||||
final_json = json.dumps(final_dic)
|
||||
@@ -1927,12 +2077,23 @@ class FirewallManager:
|
||||
}
|
||||
banned_ips.append(new_banned_ip)
|
||||
|
||||
# Ensure directory exists
|
||||
os.makedirs(os.path.dirname(banned_ips_file), exist_ok=True)
|
||||
|
||||
# Save to file
|
||||
with open(banned_ips_file, 'w') as f:
|
||||
# Write to temp file in /tmp (web server user has write permissions here)
|
||||
temp_dir = tempfile.gettempdir()
|
||||
temp_file = os.path.join(temp_dir, f'banned_ips_{int(time.time())}.json')
|
||||
|
||||
with open(temp_file, 'w') as f:
|
||||
json.dump(banned_ips, f, indent=2)
|
||||
|
||||
# Ensure /etc/cyberpanel directory exists with proper permissions
|
||||
command = f'mkdir -p {os.path.dirname(banned_ips_file)} && chmod 755 {os.path.dirname(banned_ips_file)}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
# Move temp file to final location and set permissions using ProcessUtilities
|
||||
command = f'mv {temp_file} {banned_ips_file}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
command = f'chmod 644 {banned_ips_file} && chown root:root {banned_ips_file}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
# Apply firewall rule to block the IP
|
||||
try:
|
||||
@@ -1992,9 +2153,23 @@ class FirewallManager:
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Save updated banned IPs
|
||||
with open(banned_ips_file, 'w') as f:
|
||||
# Write to temp file in /tmp (web server user has write permissions here)
|
||||
temp_dir = tempfile.gettempdir()
|
||||
temp_file = os.path.join(temp_dir, f'banned_ips_{int(time.time())}.json')
|
||||
|
||||
with open(temp_file, 'w') as f:
|
||||
json.dump(banned_ips, f, indent=2)
|
||||
|
||||
# Ensure /etc/cyberpanel directory exists with proper permissions
|
||||
command = f'mkdir -p {os.path.dirname(banned_ips_file)} && chmod 755 {os.path.dirname(banned_ips_file)}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
# Move temp file to final location and set permissions using ProcessUtilities
|
||||
command = f'mv {temp_file} {banned_ips_file}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
command = f'chmod 644 {banned_ips_file} && chown root:root {banned_ips_file}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
# Remove iptables rule
|
||||
try:
|
||||
@@ -2019,6 +2194,153 @@ class FirewallManager:
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
def modifyBannedIP(self, userID=None, data=None):
|
||||
"""
|
||||
Modify a banned IP address (update reason and/or expiration)
|
||||
"""
|
||||
try:
|
||||
admin = Administrator.objects.get(pk=userID)
|
||||
if admin.acl.adminStatus != 1:
|
||||
return ACLManager.loadError()
|
||||
|
||||
banned_ip_id = data.get('id')
|
||||
new_ip = data.get('ip', '').strip()
|
||||
reason = data.get('reason', '').strip()
|
||||
duration = data.get('duration', 'never')
|
||||
|
||||
if not new_ip:
|
||||
final_dic = {'status': 0, 'error_message': 'IP address is required'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Validate IP address format
|
||||
import ipaddress
|
||||
try:
|
||||
ipaddress.ip_address(new_ip.split('/')[0]) # Handle CIDR notation
|
||||
except ValueError:
|
||||
final_dic = {'status': 0, 'error_message': 'Invalid IP address format'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
if not reason:
|
||||
final_dic = {'status': 0, 'error_message': 'Reason is required'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Load existing banned IPs
|
||||
banned_ips_file = '/etc/cyberpanel/banned_ips.json'
|
||||
banned_ips = []
|
||||
if os.path.exists(banned_ips_file):
|
||||
try:
|
||||
with open(banned_ips_file, 'r') as f:
|
||||
banned_ips = json.load(f)
|
||||
except:
|
||||
banned_ips = []
|
||||
|
||||
# Find and update the banned IP
|
||||
old_ip = None
|
||||
found = False
|
||||
for banned_ip in banned_ips:
|
||||
if banned_ip.get('id') == banned_ip_id:
|
||||
found = True
|
||||
old_ip = banned_ip['ip']
|
||||
|
||||
# Check if new IP is already banned (and not the same record)
|
||||
ip_changed = (new_ip != old_ip)
|
||||
if ip_changed:
|
||||
for other_banned_ip in banned_ips:
|
||||
if other_banned_ip.get('id') != banned_ip_id and other_banned_ip.get('ip') == new_ip and other_banned_ip.get('active', True):
|
||||
final_dic = {'status': 0, 'error_message': f'IP address {new_ip} is already banned'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Update IP address if changed
|
||||
if ip_changed:
|
||||
# Remove old iptables rule
|
||||
try:
|
||||
if '/' in old_ip:
|
||||
subprocess.run(['iptables', '-D', 'INPUT', '-s', old_ip, '-j', 'DROP'], check=False)
|
||||
else:
|
||||
subprocess.run(['iptables', '-D', 'INPUT', '-s', old_ip, '-j', 'DROP'], check=False)
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Removed iptables rule for old IP {old_ip}')
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Warning: Could not remove old iptables rule for {old_ip}: {str(e)}')
|
||||
|
||||
# Add new iptables rule
|
||||
try:
|
||||
if '/' in new_ip:
|
||||
subprocess.run(['iptables', '-A', 'INPUT', '-s', new_ip, '-j', 'DROP'], check=True)
|
||||
else:
|
||||
subprocess.run(['iptables', '-A', 'INPUT', '-s', new_ip, '-j', 'DROP'], check=True)
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Added iptables rule for new IP {new_ip}')
|
||||
except subprocess.CalledProcessError as e:
|
||||
final_dic = {'status': 0, 'error_message': f'Failed to add firewall rule for IP {new_ip}: {str(e)}'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
banned_ip['ip'] = new_ip
|
||||
|
||||
# Update reason
|
||||
banned_ip['reason'] = reason
|
||||
|
||||
# Update expiration if duration changed
|
||||
if duration == 'never' or duration == 'permanent':
|
||||
banned_ip['expires'] = 'Never'
|
||||
banned_ip['duration'] = 'never'
|
||||
else:
|
||||
# Calculate new expiration time
|
||||
current_time = time.time()
|
||||
duration_map = {
|
||||
'1h': 3600,
|
||||
'6h': 21600,
|
||||
'12h': 43200,
|
||||
'24h': 86400,
|
||||
'48h': 172800,
|
||||
'7d': 604800,
|
||||
'30d': 2592000
|
||||
}
|
||||
duration_seconds = duration_map.get(duration, 86400)
|
||||
banned_ip['expires'] = current_time + duration_seconds
|
||||
banned_ip['duration'] = duration
|
||||
|
||||
break
|
||||
|
||||
if not found:
|
||||
final_dic = {'status': 0, 'error_message': 'Banned IP record not found'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Write to temp file in /tmp (web server user has write permissions here)
|
||||
temp_dir = tempfile.gettempdir()
|
||||
temp_file = os.path.join(temp_dir, f'banned_ips_{int(time.time())}.json')
|
||||
|
||||
with open(temp_file, 'w') as f:
|
||||
json.dump(banned_ips, f, indent=2)
|
||||
|
||||
# Ensure /etc/cyberpanel directory exists with proper permissions
|
||||
command = f'mkdir -p {os.path.dirname(banned_ips_file)} && chmod 755 {os.path.dirname(banned_ips_file)}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
# Move temp file to final location and set permissions using ProcessUtilities
|
||||
command = f'mv {temp_file} {banned_ips_file}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
command = f'chmod 644 {banned_ips_file} && chown root:root {banned_ips_file}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
ip_display = new_ip if new_ip != old_ip else old_ip
|
||||
change_msg = f'IP changed from {old_ip} to {new_ip}' if new_ip != old_ip else f'IP unchanged ({old_ip})'
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Modified banned IP record: {change_msg}, reason={reason}, duration={duration}')
|
||||
|
||||
final_dic = {'status': 1, 'message': f'Banned IP has been modified successfully'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
except BaseException as msg:
|
||||
final_dic = {'status': 0, 'error_message': str(msg)}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
def deleteBannedIP(self, userID=None, data=None):
|
||||
"""
|
||||
Permanently delete a banned IP record
|
||||
@@ -2054,9 +2376,36 @@ class FirewallManager:
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Save updated banned IPs
|
||||
with open(banned_ips_file, 'w') as f:
|
||||
# Write to temp file in /tmp (web server user has write permissions here)
|
||||
temp_dir = tempfile.gettempdir()
|
||||
temp_file = os.path.join(temp_dir, f'banned_ips_{int(time.time())}.json')
|
||||
with open(temp_file, 'w') as f:
|
||||
json.dump(updated_banned_ips, f, indent=2)
|
||||
|
||||
# Ensure /etc/cyberpanel directory exists with proper permissions
|
||||
command = f'mkdir -p {os.path.dirname(banned_ips_file)} && chmod 755 {os.path.dirname(banned_ips_file)}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
# Move temp file to final location and set permissions using ProcessUtilities
|
||||
command = f'mv {temp_file} {banned_ips_file}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
command = f'chmod 644 {banned_ips_file} && chown root:root {banned_ips_file}'
|
||||
ProcessUtilities.executioner(command, None, True)
|
||||
|
||||
# Remove iptables rule to unban the IP
|
||||
try:
|
||||
# Remove iptables rule to unblock the IP
|
||||
if '/' in ip_to_delete:
|
||||
# CIDR notation
|
||||
subprocess.run(['iptables', '-D', 'INPUT', '-s', ip_to_delete, '-j', 'DROP'], check=False)
|
||||
else:
|
||||
# Single IP
|
||||
subprocess.run(['iptables', '-D', 'INPUT', '-s', ip_to_delete, '-j', 'DROP'], check=False)
|
||||
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Deleted and unbanned IP {ip_to_delete}')
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Failed to remove iptables rule for {ip_to_delete}: {str(e)}')
|
||||
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Deleted banned IP record for {ip_to_delete}')
|
||||
|
||||
@@ -2227,6 +2576,253 @@ class FirewallManager:
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
def exportBannedIPs(self, userID=None):
|
||||
"""
|
||||
Export all banned IPs to a JSON file
|
||||
"""
|
||||
try:
|
||||
currentACL = ACLManager.loadedACL(userID)
|
||||
|
||||
if currentACL['admin'] == 1:
|
||||
pass
|
||||
else:
|
||||
return ACLManager.loadErrorJson('exportStatus', 0)
|
||||
|
||||
# Load banned IPs from file
|
||||
banned_ips_file = '/etc/cyberpanel/banned_ips.json'
|
||||
banned_ips = []
|
||||
if os.path.exists(banned_ips_file):
|
||||
try:
|
||||
with open(banned_ips_file, 'r') as f:
|
||||
banned_ips = json.load(f)
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Error reading banned IPs file: {str(e)}")
|
||||
banned_ips = []
|
||||
|
||||
# Filter out expired bans for export (optional - you might want to include all)
|
||||
current_time = time.time()
|
||||
active_banned_ips = []
|
||||
for banned_ip in banned_ips:
|
||||
expires_val = banned_ip.get('expires')
|
||||
expires_timestamp = banned_ip.get('expires_timestamp')
|
||||
|
||||
# Include if never expires or not yet expired
|
||||
if expires_val == 'Never' or expires_timestamp is None:
|
||||
active_banned_ips.append(banned_ip)
|
||||
elif isinstance(expires_timestamp, (int, float)) and expires_timestamp > current_time:
|
||||
active_banned_ips.append(banned_ip)
|
||||
|
||||
# Create export data with metadata
|
||||
export_data = {
|
||||
'version': '1.0',
|
||||
'exported_at': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'total_banned_ips': len(active_banned_ips),
|
||||
'banned_ips': active_banned_ips
|
||||
}
|
||||
|
||||
# Create JSON response with file download
|
||||
json_content = json.dumps(export_data, indent=2)
|
||||
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Banned IPs exported successfully. Total IPs: {len(active_banned_ips)}")
|
||||
|
||||
# Return file as download
|
||||
response = HttpResponse(json_content, content_type='application/json')
|
||||
response['Content-Disposition'] = f'attachment; filename="banned_ips_export_{int(time.time())}.json"'
|
||||
|
||||
return response
|
||||
|
||||
except BaseException as msg:
|
||||
final_dic = {'exportStatus': 0, 'error_message': str(msg)}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
def importBannedIPs(self, userID=None, data=None):
|
||||
"""
|
||||
Import banned IPs from a JSON file
|
||||
"""
|
||||
try:
|
||||
currentACL = ACLManager.loadedACL(userID)
|
||||
|
||||
if currentACL['admin'] == 1:
|
||||
pass
|
||||
else:
|
||||
return ACLManager.loadErrorJson('importStatus', 0)
|
||||
|
||||
# Handle file upload
|
||||
if hasattr(self.request, 'FILES') and 'import_file' in self.request.FILES:
|
||||
import_file = self.request.FILES['import_file']
|
||||
|
||||
# Read file content
|
||||
import_data = json.loads(import_file.read().decode('utf-8'))
|
||||
else:
|
||||
# Fallback to file path method
|
||||
import_file_path = data.get('import_file_path', '') if data else ''
|
||||
|
||||
if not import_file_path or not os.path.exists(import_file_path):
|
||||
final_dic = {'importStatus': 0, 'error_message': 'Import file not found or invalid path'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
# Read and parse the import file
|
||||
with open(import_file_path, 'r') as f:
|
||||
import_data = json.load(f)
|
||||
|
||||
# Validate the import data structure
|
||||
if 'banned_ips' not in import_data:
|
||||
final_dic = {'importStatus': 0, 'error_message': 'Invalid import file format. Missing banned_ips array.'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
imported_count = 0
|
||||
skipped_count = 0
|
||||
error_count = 0
|
||||
errors = []
|
||||
|
||||
# Load existing banned IPs
|
||||
banned_ips_file = '/etc/cyberpanel/banned_ips.json'
|
||||
existing_banned_ips = []
|
||||
if os.path.exists(banned_ips_file):
|
||||
try:
|
||||
with open(banned_ips_file, 'r') as f:
|
||||
existing_banned_ips = json.load(f)
|
||||
except:
|
||||
existing_banned_ips = []
|
||||
|
||||
# Create a set of existing IPs for quick lookup
|
||||
existing_ips = {banned_ip.get('ip') for banned_ip in existing_banned_ips}
|
||||
|
||||
# Import IP address validation
|
||||
import ipaddress
|
||||
|
||||
for banned_ip_data in import_data['banned_ips']:
|
||||
try:
|
||||
ip_address = banned_ip_data.get('ip', '').strip()
|
||||
reason = banned_ip_data.get('reason', '').strip()
|
||||
|
||||
# Validate IP address
|
||||
if not ip_address:
|
||||
error_count += 1
|
||||
errors.append(f"Invalid entry: Missing IP address")
|
||||
continue
|
||||
|
||||
try:
|
||||
ipaddress.ip_address(ip_address.split('/')[0]) # Handle CIDR notation
|
||||
except ValueError:
|
||||
error_count += 1
|
||||
errors.append(f"IP '{ip_address}': Invalid IP address format")
|
||||
continue
|
||||
|
||||
# Check if IP already exists
|
||||
if ip_address in existing_ips:
|
||||
skipped_count += 1
|
||||
continue
|
||||
|
||||
# Validate reason
|
||||
if not reason:
|
||||
reason = 'Imported from backup'
|
||||
|
||||
# Get duration or calculate from expires
|
||||
duration = banned_ip_data.get('duration', 'never')
|
||||
expires = banned_ip_data.get('expires', 'Never')
|
||||
expires_timestamp = banned_ip_data.get('expires_timestamp')
|
||||
|
||||
# Calculate expiration if needed
|
||||
if expires == 'Never' or expires_timestamp is None:
|
||||
expires_timestamp = None
|
||||
expires_display = 'Never'
|
||||
duration = 'never'
|
||||
elif expires_timestamp and isinstance(expires_timestamp, (int, float)):
|
||||
expires_display = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(expires_timestamp))
|
||||
else:
|
||||
expires_display = expires if isinstance(expires, str) else 'Never'
|
||||
expires_timestamp = None
|
||||
|
||||
# Create banned IP entry
|
||||
banned_on = banned_ip_data.get('banned_on', time.time())
|
||||
if isinstance(banned_on, str):
|
||||
try:
|
||||
banned_on = time.mktime(time.strptime(banned_on, '%Y-%m-%d %H:%M:%S'))
|
||||
except:
|
||||
banned_on = time.time()
|
||||
|
||||
new_banned_ip = {
|
||||
'id': banned_ip_data.get('id', randint(100000, 999999)),
|
||||
'ip': ip_address,
|
||||
'reason': reason,
|
||||
'banned_on': banned_on,
|
||||
'banned_on_timestamp': banned_on if isinstance(banned_on, (int, float)) else time.time(),
|
||||
'expires': expires_display,
|
||||
'expires_timestamp': expires_timestamp,
|
||||
'duration': duration,
|
||||
'active': True
|
||||
}
|
||||
|
||||
# Add iptables rule
|
||||
try:
|
||||
if '/' in ip_address:
|
||||
subprocess.run(['iptables', '-A', 'INPUT', '-s', ip_address, '-j', 'DROP'], check=True)
|
||||
else:
|
||||
subprocess.run(['iptables', '-A', 'INPUT', '-s', ip_address, '-j', 'DROP'], check=True)
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Added iptables rule for imported IP {ip_address}')
|
||||
except subprocess.CalledProcessError as e:
|
||||
error_count += 1
|
||||
errors.append(f"IP '{ip_address}': Failed to add firewall rule - {str(e)}")
|
||||
continue
|
||||
|
||||
# Add to existing list
|
||||
existing_banned_ips.append(new_banned_ip)
|
||||
existing_ips.add(ip_address)
|
||||
imported_count += 1
|
||||
|
||||
except Exception as e:
|
||||
error_count += 1
|
||||
errors.append(f"IP '{banned_ip_data.get('ip', 'Unknown')}': {str(e)}")
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Error importing banned IP {banned_ip_data.get('ip', 'Unknown')}: {str(e)}")
|
||||
|
||||
# Save updated banned IPs
|
||||
if imported_count > 0 or error_count > 0:
|
||||
try:
|
||||
# Create temp file
|
||||
temp_file = f'/tmp/banned_ips_{randint(100000, 999999)}.json'
|
||||
with open(temp_file, 'w') as f:
|
||||
json.dump(existing_banned_ips, f, indent=2)
|
||||
|
||||
# Ensure directory exists
|
||||
command = f'mkdir -p {os.path.dirname(banned_ips_file)} && chmod 755 {os.path.dirname(banned_ips_file)}'
|
||||
ProcessUtilities.executioner(command)
|
||||
|
||||
# Move temp file to final location
|
||||
command = f'mv {temp_file} {banned_ips_file}'
|
||||
ProcessUtilities.executioner(command)
|
||||
|
||||
# Set permissions
|
||||
command = f'chmod 644 {banned_ips_file} && chown root:root {banned_ips_file}'
|
||||
ProcessUtilities.executioner(command)
|
||||
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Error saving imported banned IPs: {str(e)}")
|
||||
final_dic = {'importStatus': 0, 'error_message': f'Failed to save imported IPs: {str(e)}'}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Banned IPs import completed. Imported: {imported_count}, Skipped: {skipped_count}, Errors: {error_count}")
|
||||
|
||||
final_dic = {
|
||||
'importStatus': 1,
|
||||
'error_message': "None",
|
||||
'imported_count': imported_count,
|
||||
'skipped_count': skipped_count,
|
||||
'error_count': error_count,
|
||||
'errors': errors
|
||||
}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
except BaseException as msg:
|
||||
final_dic = {'importStatus': 0, 'error_message': str(msg)}
|
||||
final_json = json.dumps(final_dic)
|
||||
return HttpResponse(final_json)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -499,6 +499,281 @@ app.controller('firewallController', function ($scope, $http, $timeout, $window,
|
||||
|
||||
};
|
||||
|
||||
// Modify Firewall Rule Functions
|
||||
$scope.handleModifyRuleClick = function(rule, event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
if (!rule) {
|
||||
console.error('No rule provided');
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Error',
|
||||
text: 'No rule data provided',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$scope.showModifyRuleModal(rule, event);
|
||||
return false;
|
||||
};
|
||||
|
||||
$scope.showModifyRuleModal = function(rule, event) {
|
||||
console.log('=== showModifyRuleModal CALLED ===');
|
||||
console.log('Rule:', rule);
|
||||
|
||||
if (!rule) {
|
||||
console.error('No rule provided');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get modal element
|
||||
var modalElement = document.getElementById('modifyRuleModal');
|
||||
if (!modalElement) {
|
||||
console.error('Modal element not found');
|
||||
alert('Error: Modal element not found. Please refresh the page.');
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set form values
|
||||
var idField = document.getElementById('modifyRuleId');
|
||||
var nameField = document.getElementById('modifyRuleName');
|
||||
var protocolField = document.getElementById('modifyRuleProtocol');
|
||||
var ipField = document.getElementById('modifyRuleIP');
|
||||
var portField = document.getElementById('modifyRulePort');
|
||||
|
||||
if (idField) idField.value = rule.id || '';
|
||||
if (nameField) nameField.value = rule.name || '';
|
||||
if (protocolField) protocolField.value = rule.proto || 'tcp';
|
||||
if (ipField) ipField.value = rule.ipAddress || '';
|
||||
if (portField) portField.value = rule.port || '';
|
||||
|
||||
// Show modal using AngularJS $timeout
|
||||
$timeout(function() {
|
||||
// Clean up existing modals/backdrops
|
||||
var existingBackdrops = document.querySelectorAll('.modal-backdrop');
|
||||
existingBackdrops.forEach(function(b) { b.remove(); });
|
||||
|
||||
var existingModals = document.querySelectorAll('.modal.show');
|
||||
existingModals.forEach(function(m) {
|
||||
m.classList.remove('show');
|
||||
});
|
||||
|
||||
document.body.classList.remove('modal-open');
|
||||
|
||||
// Move modal to body if needed
|
||||
if (modalElement.parentElement !== document.body) {
|
||||
document.body.appendChild(modalElement);
|
||||
}
|
||||
|
||||
// Show modal
|
||||
modalElement.classList.add('show', 'fade');
|
||||
modalElement.style.cssText = 'display: flex !important; position: fixed !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; z-index: 99999 !important; opacity: 1 !important; visibility: visible !important; align-items: center !important; justify-content: center !important;';
|
||||
modalElement.removeAttribute('aria-hidden');
|
||||
modalElement.setAttribute('aria-hidden', 'false');
|
||||
modalElement.setAttribute('aria-modal', 'true');
|
||||
|
||||
document.body.classList.add('modal-open');
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
// Create backdrop
|
||||
var backdrop = document.createElement('div');
|
||||
backdrop.className = 'modal-backdrop fade show';
|
||||
backdrop.style.cssText = 'position: fixed !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; z-index: 99998 !important; background-color: rgba(0, 0, 0, 0.5) !important;';
|
||||
backdrop.id = 'modifyRuleModalBackdrop';
|
||||
document.body.appendChild(backdrop);
|
||||
|
||||
// Handle backdrop click
|
||||
backdrop.addEventListener('click', function(e) {
|
||||
if (e.target === backdrop) {
|
||||
$scope.closeModifyRuleModal();
|
||||
}
|
||||
});
|
||||
|
||||
// Try jQuery/Bootstrap modal if available
|
||||
if (typeof $ !== 'undefined' && $.fn.modal) {
|
||||
try {
|
||||
var $modal = $('#modifyRuleModal');
|
||||
if ($modal.length > 0) {
|
||||
if ($modal.parent()[0] !== document.body) {
|
||||
$modal.appendTo('body');
|
||||
}
|
||||
if (!$modal.data('bs.modal')) {
|
||||
$modal.modal({show: false, backdrop: true, keyboard: true});
|
||||
}
|
||||
$modal.modal('show');
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('jQuery modal failed, using direct display:', e);
|
||||
}
|
||||
}
|
||||
}, 10);
|
||||
};
|
||||
|
||||
$scope.closeModifyRuleModal = function() {
|
||||
var modalElement = document.getElementById('modifyRuleModal');
|
||||
if (modalElement) {
|
||||
// Try jQuery/Bootstrap modal first
|
||||
if (typeof $ !== 'undefined' && $.fn.modal) {
|
||||
try {
|
||||
$('#modifyRuleModal').modal('hide');
|
||||
} catch (e) {
|
||||
// Fall through to manual cleanup
|
||||
}
|
||||
}
|
||||
|
||||
// Manual cleanup
|
||||
modalElement.classList.remove('show', 'fade');
|
||||
modalElement.style.display = 'none';
|
||||
modalElement.setAttribute('aria-hidden', 'true');
|
||||
|
||||
// Remove backdrop
|
||||
var backdrops = document.querySelectorAll('.modal-backdrop');
|
||||
backdrops.forEach(function(b) { b.remove(); });
|
||||
|
||||
document.body.classList.remove('modal-open');
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
};
|
||||
|
||||
$scope.modifyRule = function() {
|
||||
var ruleId = document.getElementById('modifyRuleId').value;
|
||||
var ruleName = document.getElementById('modifyRuleName').value.trim();
|
||||
var ruleProtocol = document.getElementById('modifyRuleProtocol').value;
|
||||
var ruleIP = document.getElementById('modifyRuleIP').value.trim();
|
||||
var rulePort = document.getElementById('modifyRulePort').value.trim();
|
||||
|
||||
// Validation
|
||||
if (!ruleName) {
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Validation Error',
|
||||
text: 'Please enter a rule name',
|
||||
type: 'error'
|
||||
});
|
||||
} else {
|
||||
alert('Please enter a rule name');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ruleProtocol || (ruleProtocol !== 'tcp' && ruleProtocol !== 'udp')) {
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Validation Error',
|
||||
text: 'Please select a valid protocol (TCP or UDP)',
|
||||
type: 'error'
|
||||
});
|
||||
} else {
|
||||
alert('Please select a valid protocol');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ruleIP) {
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Validation Error',
|
||||
text: 'Please enter an IP address',
|
||||
type: 'error'
|
||||
});
|
||||
} else {
|
||||
alert('Please enter an IP address');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rulePort) {
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Validation Error',
|
||||
text: 'Please enter a port number',
|
||||
type: 'error'
|
||||
});
|
||||
} else {
|
||||
alert('Please enter a port number');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.rulesLoading = false;
|
||||
$scope.actionFailed = true;
|
||||
$scope.actionSuccess = true;
|
||||
$scope.couldNotConnect = true;
|
||||
|
||||
var url = "/firewall/modifyRule";
|
||||
var data = {
|
||||
id: ruleId,
|
||||
ruleName: ruleName,
|
||||
ruleProtocol: ruleProtocol,
|
||||
rulePort: rulePort,
|
||||
ruleIP: ruleIP
|
||||
};
|
||||
|
||||
var config = {
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
};
|
||||
|
||||
$http.post(url, data, config).then(function(response) {
|
||||
$scope.rulesLoading = true;
|
||||
|
||||
if (response.data && response.data.modify_status === 1) {
|
||||
// Close modal
|
||||
$scope.closeModifyRuleModal();
|
||||
|
||||
// Refresh rules list
|
||||
populateCurrentRecords();
|
||||
|
||||
$scope.actionFailed = true;
|
||||
$scope.actionSuccess = false;
|
||||
$scope.canNotAddRule = true;
|
||||
$scope.ruleAdded = false;
|
||||
$scope.couldNotConnect = true;
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Success!',
|
||||
text: 'Firewall rule modified successfully',
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
$scope.actionFailed = false;
|
||||
$scope.actionSuccess = true;
|
||||
$scope.errorMessage = (response.data && response.data.error_message) || 'Failed to modify firewall rule';
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Error!',
|
||||
text: (response.data && response.data.error_message) || 'Failed to modify firewall rule',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
}, function(error) {
|
||||
$scope.rulesLoading = true;
|
||||
$scope.couldNotConnect = false;
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Connection Error',
|
||||
text: 'Could not connect to server. Please refresh this page.',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Make modify rule functions available globally
|
||||
window.showModifyRuleModalScope = $scope.showModifyRuleModal;
|
||||
window.closeModifyRuleModalScope = $scope.closeModifyRuleModal;
|
||||
window.modifyRuleScope = $scope.modifyRule;
|
||||
|
||||
$scope.reloadFireWall = function () {
|
||||
|
||||
@@ -3828,53 +4103,325 @@ app.controller('litespeed_ent_conf', function ($scope, $http, $timeout, $window)
|
||||
});
|
||||
};
|
||||
|
||||
// Export/Import Banned IPs Functions
|
||||
$scope.exportBannedIPs = function () {
|
||||
$scope.bannedIPsLoading = false;
|
||||
$scope.bannedIPActionFailed = true;
|
||||
$scope.bannedIPActionSuccess = true;
|
||||
|
||||
var url = "/firewall/exportBannedIPs";
|
||||
var data = {};
|
||||
|
||||
var config = {
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
},
|
||||
responseType: 'blob'
|
||||
};
|
||||
|
||||
$http.post(url, data, config).then(function(response) {
|
||||
$scope.bannedIPsLoading = true;
|
||||
|
||||
// Check if response is JSON (error) or file download
|
||||
if (response.data instanceof Blob) {
|
||||
// Create blob URL and trigger download
|
||||
var blob = new Blob([response.data], { type: 'application/json' });
|
||||
var url = window.URL.createObjectURL(blob);
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'banned_ips_export_' + Math.floor(Date.now() / 1000) + '.json';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
|
||||
$scope.bannedIPActionFailed = true;
|
||||
$scope.bannedIPActionSuccess = false;
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Success!',
|
||||
text: 'Banned IPs exported successfully',
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Handle error response
|
||||
try {
|
||||
var errorData = typeof response.data === 'string' ? JSON.parse(response.data) : response.data;
|
||||
if (errorData.exportStatus === 0) {
|
||||
$scope.bannedIPActionFailed = false;
|
||||
$scope.bannedIPActionSuccess = true;
|
||||
$scope.bannedIPErrorMessage = errorData.error_message;
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Export Failed',
|
||||
text: errorData.error_message,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// If not JSON, try reading as text
|
||||
var reader = new FileReader();
|
||||
reader.onload = function() {
|
||||
try {
|
||||
var errorData = JSON.parse(reader.result);
|
||||
if (errorData.exportStatus === 0) {
|
||||
$scope.bannedIPActionFailed = false;
|
||||
$scope.bannedIPActionSuccess = true;
|
||||
$scope.bannedIPErrorMessage = errorData.error_message;
|
||||
}
|
||||
} catch (e2) {
|
||||
$scope.bannedIPActionFailed = false;
|
||||
$scope.bannedIPActionSuccess = true;
|
||||
$scope.bannedIPErrorMessage = 'Failed to export banned IPs';
|
||||
}
|
||||
};
|
||||
reader.readAsText(response.data);
|
||||
}
|
||||
}
|
||||
}, function(error) {
|
||||
$scope.bannedIPsLoading = true;
|
||||
$scope.bannedIPActionFailed = false;
|
||||
$scope.bannedIPActionSuccess = true;
|
||||
$scope.bannedIPErrorMessage = 'Could not connect to server. Please refresh this page.';
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Connection Error',
|
||||
text: 'Could not connect to server. Please refresh this page.',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.importBannedIPs = function () {
|
||||
// Create file input element
|
||||
var input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.accept = '.json';
|
||||
input.style.display = 'none';
|
||||
|
||||
input.onchange = function(event) {
|
||||
var file = event.target.files[0];
|
||||
if (file) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
try {
|
||||
var importData = JSON.parse(e.target.result);
|
||||
|
||||
// Validate file format
|
||||
if (!importData.banned_ips || !Array.isArray(importData.banned_ips)) {
|
||||
$scope.$apply(function() {
|
||||
$scope.bannedIPActionFailed = false;
|
||||
$scope.bannedIPActionSuccess = true;
|
||||
$scope.bannedIPErrorMessage = "Invalid import file format. Please select a valid banned IPs export file.";
|
||||
});
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Invalid File',
|
||||
text: 'Invalid import file format. Please select a valid banned IPs export file.',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Upload file to server
|
||||
uploadBannedIPsImportFile(file);
|
||||
} catch (error) {
|
||||
$scope.$apply(function() {
|
||||
$scope.bannedIPActionFailed = false;
|
||||
$scope.bannedIPActionSuccess = true;
|
||||
$scope.bannedIPErrorMessage = "Invalid JSON file. Please select a valid banned IPs export file.";
|
||||
});
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Invalid File',
|
||||
text: 'Invalid JSON file. Please select a valid banned IPs export file.',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
};
|
||||
|
||||
document.body.appendChild(input);
|
||||
input.click();
|
||||
document.body.removeChild(input);
|
||||
};
|
||||
|
||||
function uploadBannedIPsImportFile(file) {
|
||||
$scope.bannedIPsLoading = false;
|
||||
$scope.bannedIPActionFailed = true;
|
||||
$scope.bannedIPActionSuccess = true;
|
||||
$scope.bannedIPCouldNotConnect = true;
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('import_file', file);
|
||||
|
||||
var config = {
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken'),
|
||||
'Content-Type': undefined
|
||||
},
|
||||
transformRequest: angular.identity
|
||||
};
|
||||
|
||||
$http.post("/firewall/importBannedIPs", formData, config).then(function(response) {
|
||||
$scope.bannedIPsLoading = true;
|
||||
|
||||
if (response.data.importStatus === 1) {
|
||||
$scope.bannedIPActionSuccess = false;
|
||||
populateBannedIPs(); // Refresh the list
|
||||
|
||||
var message = `Import completed: ${response.data.imported_count} imported, ${response.data.skipped_count} skipped`;
|
||||
if (response.data.error_count > 0) {
|
||||
message += `, ${response.data.error_count} errors`;
|
||||
if (response.data.errors && response.data.errors.length > 0) {
|
||||
message += '\nErrors: ' + response.data.errors.slice(0, 5).join('; ');
|
||||
if (response.data.errors.length > 5) {
|
||||
message += ` ... and ${response.data.errors.length - 5} more`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Import Completed!',
|
||||
text: message,
|
||||
type: response.data.error_count > 0 ? 'notice' : 'success'
|
||||
});
|
||||
} else {
|
||||
alert(message);
|
||||
}
|
||||
} else {
|
||||
$scope.bannedIPActionFailed = false;
|
||||
$scope.bannedIPErrorMessage = response.data.error_message || 'Failed to import banned IPs';
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Import Failed',
|
||||
text: response.data.error_message || 'Failed to import banned IPs',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
}, function(error) {
|
||||
$scope.bannedIPsLoading = true;
|
||||
$scope.bannedIPCouldNotConnect = false;
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Connection Error',
|
||||
text: 'Could not connect to server. Please refresh this page.',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Export/Import Firewall Rules Functions
|
||||
$scope.exportRules = function () {
|
||||
$scope.rulesLoading = false;
|
||||
$scope.actionFailed = true;
|
||||
$scope.actionSuccess = true;
|
||||
|
||||
url = "/firewall/exportFirewallRules";
|
||||
|
||||
var url = "/firewall/exportFirewallRules";
|
||||
var data = {};
|
||||
|
||||
var config = {
|
||||
headers: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
},
|
||||
responseType: 'blob'
|
||||
};
|
||||
|
||||
$http.post(url, data, config).then(exportSuccess, exportError);
|
||||
|
||||
function exportSuccess(response) {
|
||||
$http.post(url, data, config).then(function(response) {
|
||||
$scope.rulesLoading = true;
|
||||
|
||||
// Check if response is JSON (error) or file download
|
||||
if (typeof response.data === 'string' && response.data.includes('{')) {
|
||||
try {
|
||||
var errorData = JSON.parse(response.data);
|
||||
if (errorData.exportStatus === 0) {
|
||||
$scope.actionFailed = false;
|
||||
$scope.actionSuccess = true;
|
||||
$scope.errorMessage = errorData.error_message;
|
||||
return;
|
||||
if (response.data instanceof Blob) {
|
||||
// Check if it's actually a JSON error by reading the blob
|
||||
var reader = new FileReader();
|
||||
reader.onload = function() {
|
||||
try {
|
||||
var text = reader.result;
|
||||
// Check if it's JSON error
|
||||
if (text.trim().startsWith('{')) {
|
||||
var errorData = JSON.parse(text);
|
||||
if (errorData.exportStatus === 0) {
|
||||
$scope.$apply(function() {
|
||||
$scope.actionFailed = false;
|
||||
$scope.actionSuccess = true;
|
||||
$scope.errorMessage = errorData.error_message;
|
||||
});
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Export Failed',
|
||||
text: errorData.error_message,
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Not JSON, proceed with download
|
||||
}
|
||||
} catch (e) {
|
||||
// If not JSON, assume it's the file content
|
||||
}
|
||||
|
||||
// It's a valid file, trigger download
|
||||
var blob = new Blob([response.data], { type: 'application/json' });
|
||||
var url = window.URL.createObjectURL(blob);
|
||||
var a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'firewall_rules_export_' + Math.floor(Date.now() / 1000) + '.json';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
document.body.removeChild(a);
|
||||
|
||||
$scope.$apply(function() {
|
||||
$scope.actionFailed = true;
|
||||
$scope.actionSuccess = false;
|
||||
});
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Success!',
|
||||
text: 'Firewall rules exported successfully',
|
||||
type: 'success'
|
||||
});
|
||||
}
|
||||
};
|
||||
reader.readAsText(response.data);
|
||||
} else {
|
||||
// Handle as text response (shouldn't happen with blob)
|
||||
$scope.actionFailed = true;
|
||||
$scope.actionSuccess = false;
|
||||
}
|
||||
|
||||
// If we get here, it's a successful file download
|
||||
$scope.actionFailed = true;
|
||||
$scope.actionSuccess = false;
|
||||
}
|
||||
|
||||
function exportError(response) {
|
||||
}, function(error) {
|
||||
$scope.rulesLoading = true;
|
||||
$scope.actionFailed = false;
|
||||
$scope.actionSuccess = true;
|
||||
$scope.errorMessage = "Could not connect to server. Please refresh this page.";
|
||||
}
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Connection Error',
|
||||
text: 'Could not connect to server. Please refresh this page.',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.importRules = function () {
|
||||
@@ -3942,7 +4489,7 @@ app.controller('litespeed_ent_conf', function ($scope, $http, $timeout, $window)
|
||||
function importSuccess(response) {
|
||||
$scope.rulesLoading = true;
|
||||
|
||||
if (response.data.importStatus === 1) {
|
||||
if (response.data && response.data.importStatus === 1) {
|
||||
$scope.actionFailed = true;
|
||||
$scope.actionSuccess = false;
|
||||
|
||||
@@ -3950,20 +4497,38 @@ app.controller('litespeed_ent_conf', function ($scope, $http, $timeout, $window)
|
||||
populateCurrentRecords();
|
||||
|
||||
// Show import summary
|
||||
var summary = `Import completed successfully!\n` +
|
||||
`Imported: ${response.data.imported_count} rules\n` +
|
||||
`Skipped: ${response.data.skipped_count} rules\n` +
|
||||
`Errors: ${response.data.error_count} rules`;
|
||||
|
||||
if (response.data.errors && response.data.errors.length > 0) {
|
||||
summary += `\n\nErrors:\n${response.data.errors.join('\n')}`;
|
||||
var message = `Import completed: ${response.data.imported_count} imported, ${response.data.skipped_count} skipped`;
|
||||
if (response.data.error_count > 0) {
|
||||
message += `, ${response.data.error_count} errors`;
|
||||
if (response.data.errors && response.data.errors.length > 0) {
|
||||
message += '\nErrors: ' + response.data.errors.slice(0, 5).join('; ');
|
||||
if (response.data.errors.length > 5) {
|
||||
message += ` ... and ${response.data.errors.length - 5} more`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alert(summary);
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Import Completed!',
|
||||
text: message,
|
||||
type: response.data.error_count > 0 ? 'notice' : 'success'
|
||||
});
|
||||
} else {
|
||||
alert(message);
|
||||
}
|
||||
} else {
|
||||
$scope.actionFailed = false;
|
||||
$scope.actionSuccess = true;
|
||||
$scope.errorMessage = response.data.error_message;
|
||||
$scope.errorMessage = (response.data && response.data.error_message) || 'Failed to import firewall rules';
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Import Failed',
|
||||
text: (response.data && response.data.error_message) || 'Failed to import firewall rules',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3972,6 +4537,14 @@ app.controller('litespeed_ent_conf', function ($scope, $http, $timeout, $window)
|
||||
$scope.actionFailed = false;
|
||||
$scope.actionSuccess = true;
|
||||
$scope.errorMessage = "Could not connect to server. Please refresh this page.";
|
||||
|
||||
if (typeof PNotify !== 'undefined') {
|
||||
new PNotify({
|
||||
title: 'Connection Error',
|
||||
text: 'Could not connect to server. Please refresh this page.',
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -618,7 +618,7 @@
|
||||
}
|
||||
|
||||
/* Modal Styles - Ensure it's above everything */
|
||||
#modifyBannedIPModal {
|
||||
#modifyBannedIPModal, #modifyRuleModal {
|
||||
z-index: 99999 !important;
|
||||
position: fixed !important;
|
||||
top: 0 !important;
|
||||
@@ -627,7 +627,7 @@
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
#modifyBannedIPModal.show {
|
||||
#modifyBannedIPModal.show, #modifyRuleModal.show {
|
||||
display: flex !important;
|
||||
opacity: 1 !important;
|
||||
visibility: visible !important;
|
||||
@@ -635,11 +635,11 @@
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
#modifyBannedIPModal.fade.show {
|
||||
#modifyBannedIPModal.fade.show, #modifyRuleModal.fade.show {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
#modifyBannedIPModal .modal-dialog {
|
||||
#modifyBannedIPModal .modal-dialog, #modifyRuleModal .modal-dialog {
|
||||
z-index: 100000 !important;
|
||||
position: relative !important;
|
||||
margin: 1.75rem auto !important;
|
||||
@@ -664,7 +664,9 @@
|
||||
|
||||
/* Make sure modal is not hidden by parent containers */
|
||||
.modern-container #modifyBannedIPModal,
|
||||
.banned-ips-panel #modifyBannedIPModal {
|
||||
.banned-ips-panel #modifyBannedIPModal,
|
||||
.modern-container #modifyRuleModal,
|
||||
.rules-panel #modifyRuleModal {
|
||||
position: fixed !important;
|
||||
z-index: 99999 !important;
|
||||
}
|
||||
@@ -851,6 +853,52 @@
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(33, 150, 243, 0.3);
|
||||
}
|
||||
|
||||
.export-import-buttons {
|
||||
display: flex;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.btn-export, .btn-import {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-export {
|
||||
background: #10b981;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-export:hover:not(:disabled) {
|
||||
background: #059669;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(16, 185, 129, 0.3);
|
||||
}
|
||||
|
||||
.btn-import {
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-import:hover:not(:disabled) {
|
||||
background: #2563eb;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.btn-export:disabled, .btn-import:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Ensure actions column and buttons are always visible */
|
||||
.banned-table td.actions {
|
||||
@@ -1114,7 +1162,14 @@
|
||||
<td>
|
||||
<span class="port-number">{$ rule.port $}</span>
|
||||
</td>
|
||||
<td>
|
||||
<td class="actions" style="display: flex !important; gap: 0.5rem !important; align-items: center !important;">
|
||||
<button type="button"
|
||||
ng-click="handleModifyRuleClick(rule, $event)"
|
||||
class="btn-modify"
|
||||
title="{% trans 'Modify Rule' %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
{% trans "Modify" %}
|
||||
</button>
|
||||
<button type="button"
|
||||
ng-click="deleteRule(rule.id, rule.proto, rule.port, rule.ipAddress)"
|
||||
class="btn-delete"
|
||||
@@ -1162,7 +1217,25 @@
|
||||
</div>
|
||||
{% trans "Banned IP Addresses" %}
|
||||
</div>
|
||||
<div ng-show="bannedIPsLoading" class="loading-spinner"></div>
|
||||
<div style="display: flex; align-items: center; gap: 1rem;">
|
||||
<div ng-show="bannedIPsLoading" class="loading-spinner"></div>
|
||||
<div class="export-import-buttons">
|
||||
<button type="button"
|
||||
ng-click="exportBannedIPs()"
|
||||
class="btn-export"
|
||||
ng-disabled="bannedIPsLoading">
|
||||
<i class="fas fa-download"></i>
|
||||
{% trans "Export Banned IPs" %}
|
||||
</button>
|
||||
<button type="button"
|
||||
ng-click="importBannedIPs()"
|
||||
class="btn-import"
|
||||
ng-disabled="bannedIPsLoading">
|
||||
<i class="fas fa-upload"></i>
|
||||
{% trans "Import Banned IPs" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Banned IP Section -->
|
||||
@@ -1296,6 +1369,75 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modify Firewall Rule Modal -->
|
||||
<div class="modal fade" id="modifyRuleModal" tabindex="-1" role="dialog" aria-labelledby="modifyRuleModalLabel" style="display: none;">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="modifyRuleModalLabel">
|
||||
<i class="fas fa-edit"></i> {% trans "Modify Firewall Rule" %}
|
||||
</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close" ng-click="closeModifyRuleModal()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="modifyRuleForm">
|
||||
<input type="hidden" id="modifyRuleId" name="rule_id">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="modifyRuleName">
|
||||
<i class="fas fa-tag"></i> {% trans "Rule Name" %}
|
||||
</label>
|
||||
<input type="text" class="form-control" id="modifyRuleName" name="rule_name" placeholder="{% trans 'e.g., Allow SSH' %}">
|
||||
<small class="form-text text-muted">{% trans "Enter a descriptive name for this rule" %}</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="modifyRuleProtocol">
|
||||
<i class="fas fa-network-wired"></i> {% trans "Protocol" %}
|
||||
</label>
|
||||
<select class="form-control" id="modifyRuleProtocol" name="protocol">
|
||||
<option value="tcp">TCP</option>
|
||||
<option value="udp">UDP</option>
|
||||
</select>
|
||||
<small class="form-text text-muted">{% trans "Select the network protocol" %}</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="modifyRuleIP">
|
||||
<i class="fas fa-globe"></i> {% trans "IP Address" %}
|
||||
</label>
|
||||
<input type="text" class="form-control" id="modifyRuleIP" name="ip_address" placeholder="{% trans '0.0.0.0/0 for all IPs' %}">
|
||||
<small class="form-text text-muted">{% trans "Enter IP address or CIDR notation (e.g., 192.168.1.0/24)" %}</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="modifyRulePort">
|
||||
<i class="fas fa-plug"></i> {% trans "Port" %}
|
||||
</label>
|
||||
<input type="text" class="form-control" id="modifyRulePort" name="port" placeholder="{% trans 'e.g., 80 or 8000-8010' %}">
|
||||
<small class="form-text text-muted">{% trans "Enter port number or range" %}</small>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
<strong>{% trans "Note:" %}</strong> {% trans "Modifying a rule will update the firewall configuration. The old rule will be removed and replaced with the new settings." %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal" ng-click="closeModifyRuleModal()">
|
||||
<i class="fas fa-times"></i> {% trans "Cancel" %}
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" ng-click="modifyRule()">
|
||||
<i class="fas fa-save"></i> {% trans "Save Changes" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modify Banned IP Modal - Inside controller for AngularJS scope access -->
|
||||
<div class="modal fade" id="modifyBannedIPModal" tabindex="-1" role="dialog" aria-labelledby="modifyBannedIPModalLabel" style="display: none;">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
|
||||
@@ -6,6 +6,7 @@ urlpatterns = [
|
||||
path('', views.firewallHome, name='firewallHome'),
|
||||
path('getCurrentRules', views.getCurrentRules, name='getCurrentRules'),
|
||||
path('addRule', views.addRule, name='addRule'),
|
||||
path('modifyRule', views.modifyRule, name='modifyRule'),
|
||||
path('deleteRule', views.deleteRule, name='deleteRule'),
|
||||
|
||||
path('reloadFirewall', views.reloadFirewall, name='reloadFirewall'),
|
||||
@@ -36,8 +37,11 @@ urlpatterns = [
|
||||
# Banned IPs
|
||||
path('getBannedIPs', views.getBannedIPs, name='getBannedIPs'),
|
||||
path('addBannedIP', views.addBannedIP, name='addBannedIP'),
|
||||
path('modifyBannedIP', views.modifyBannedIP, name='modifyBannedIP'),
|
||||
path('removeBannedIP', views.removeBannedIP, name='removeBannedIP'),
|
||||
path('deleteBannedIP', views.deleteBannedIP, name='deleteBannedIP'),
|
||||
path('exportBannedIPs', views.exportBannedIPs, name='exportBannedIPs'),
|
||||
path('importBannedIPs', views.importBannedIPs, name='importBannedIPs'),
|
||||
path('getRulesFiles', views.getRulesFiles, name='getRulesFiles'),
|
||||
path('enableDisableRuleFile', views.enableDisableRuleFile, name='enableDisableRuleFile'),
|
||||
|
||||
|
||||
@@ -66,6 +66,15 @@ def addRule(request):
|
||||
return redirect(loadLoginPage)
|
||||
|
||||
|
||||
def modifyRule(request):
|
||||
try:
|
||||
userID = request.session['userID']
|
||||
fm = FirewallManager()
|
||||
return fm.modifyRule(userID, json.loads(request.body))
|
||||
except KeyError:
|
||||
return redirect(loadLoginPage)
|
||||
|
||||
|
||||
def deleteRule(request):
|
||||
try:
|
||||
userID = request.session['userID']
|
||||
@@ -666,6 +675,14 @@ def addBannedIP(request):
|
||||
except KeyError:
|
||||
return redirect(loadLoginPage)
|
||||
|
||||
def modifyBannedIP(request):
|
||||
try:
|
||||
userID = request.session['userID']
|
||||
fm = FirewallManager()
|
||||
return fm.modifyBannedIP(userID, json.loads(request.body))
|
||||
except KeyError:
|
||||
return redirect(loadLoginPage)
|
||||
|
||||
def removeBannedIP(request):
|
||||
try:
|
||||
userID = request.session['userID']
|
||||
@@ -703,5 +720,30 @@ def importFirewallRules(request):
|
||||
else:
|
||||
# Handle JSON data
|
||||
return fm.importFirewallRules(userID, json.loads(request.body))
|
||||
except KeyError:
|
||||
return redirect(loadLoginPage)
|
||||
|
||||
|
||||
def exportBannedIPs(request):
|
||||
try:
|
||||
userID = request.session['userID']
|
||||
fm = FirewallManager()
|
||||
return fm.exportBannedIPs(userID)
|
||||
except KeyError:
|
||||
return redirect(loadLoginPage)
|
||||
|
||||
|
||||
def importBannedIPs(request):
|
||||
try:
|
||||
userID = request.session['userID']
|
||||
fm = FirewallManager()
|
||||
fm.request = request # Set request for file upload handling
|
||||
|
||||
# Handle file upload
|
||||
if request.method == 'POST' and 'import_file' in request.FILES:
|
||||
return fm.importBannedIPs(userID, None)
|
||||
else:
|
||||
# Handle JSON data
|
||||
return fm.importBannedIPs(userID, json.loads(request.body))
|
||||
except KeyError:
|
||||
return redirect(loadLoginPage)
|
||||
Reference in New Issue
Block a user