mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-02-18 16:36:27 +00:00
Update security_manager.py
This commit is contained in:
@@ -1143,18 +1143,33 @@ def run_lynis_audit():
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Clean ANSI escape codes and control chars from output file
|
# Clean ALL ANSI/terminal escape codes and control chars from output
|
||||||
if os.path.isfile(output_log):
|
if os.path.isfile(output_log):
|
||||||
try:
|
try:
|
||||||
import re as _re
|
import re as _re
|
||||||
with open(output_log, 'r', errors='replace') as fout:
|
with open(output_log, 'r', errors='replace') as fout:
|
||||||
raw = fout.read()
|
raw = fout.read()
|
||||||
cleaned = _re.sub(r'\x1b\[[0-9;]*[a-zA-Z]', '', raw)
|
# Remove ALL ANSI escape sequences comprehensively:
|
||||||
cleaned = _re.sub(r'\x1b\([A-Z]', '', cleaned)
|
# CSI sequences: \x1b[ ... (letter) e.g. \x1b[0m, \x1b[?25h
|
||||||
|
cleaned = _re.sub(r'\x1b\[[\x20-\x3f]*[\x40-\x7e]', '', raw)
|
||||||
|
# OSC sequences: \x1b] ... \x07 or \x1b\\
|
||||||
|
cleaned = _re.sub(r'\x1b\].*?(?:\x07|\x1b\\)', '', cleaned)
|
||||||
|
# Other escape sequences: \x1b followed by one char
|
||||||
|
cleaned = _re.sub(r'\x1b[\x20-\x7e]', '', cleaned)
|
||||||
|
# Remove remaining control characters except \n and \t
|
||||||
|
cleaned = _re.sub(r'[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]', '', cleaned)
|
||||||
|
# Remove carriage returns
|
||||||
cleaned = cleaned.replace('\r', '')
|
cleaned = cleaned.replace('\r', '')
|
||||||
# Remove 'Script started/done' lines added by script cmd
|
# Remove 'Script started/done' lines added by script cmd
|
||||||
lines = cleaned.splitlines()
|
lines = cleaned.splitlines()
|
||||||
lines = [l for l in lines if not l.startswith('Script started') and not l.startswith('Script done')]
|
lines = [l for l in lines
|
||||||
|
if not l.strip().startswith('Script started')
|
||||||
|
and not l.strip().startswith('Script done')]
|
||||||
|
# Remove empty lines at start/end
|
||||||
|
while lines and not lines[0].strip():
|
||||||
|
lines.pop(0)
|
||||||
|
while lines and not lines[-1].strip():
|
||||||
|
lines.pop()
|
||||||
cleaned = '\n'.join(lines)
|
cleaned = '\n'.join(lines)
|
||||||
with open(output_log, 'w') as fout:
|
with open(output_log, 'w') as fout:
|
||||||
fout.write(cleaned)
|
fout.write(cleaned)
|
||||||
@@ -1351,17 +1366,21 @@ def parse_lynis_report():
|
|||||||
stripped = line.strip()
|
stripped = line.strip()
|
||||||
|
|
||||||
# Detect section headers: "[+] Boot and services"
|
# Detect section headers: "[+] Boot and services"
|
||||||
section_match = re.match(r'^\[\+\]\s+(.+)', stripped)
|
# Use 'in' check first for speed, then regex for extraction
|
||||||
if section_match:
|
if '[+]' in stripped:
|
||||||
# Save previous section
|
section_match = re.search(r'\[\+\]\s+(.+)', stripped)
|
||||||
if current_section and current_checks:
|
if section_match:
|
||||||
report["sections"].append({
|
# Save previous section
|
||||||
"name": current_section,
|
if current_section and current_checks:
|
||||||
"checks": current_checks,
|
report["sections"].append({
|
||||||
})
|
"name": current_section,
|
||||||
current_section = section_match.group(1).strip()
|
"checks": current_checks,
|
||||||
current_checks = []
|
})
|
||||||
continue
|
current_section = section_match.group(1).strip()
|
||||||
|
# Remove trailing dashes from names like "Boot and services ------"
|
||||||
|
current_section = re.sub(r'\s*-+\s*$', '', current_section)
|
||||||
|
current_checks = []
|
||||||
|
continue
|
||||||
|
|
||||||
# Skip separator lines, empty, banner lines
|
# Skip separator lines, empty, banner lines
|
||||||
if stripped.startswith('---') or not stripped:
|
if stripped.startswith('---') or not stripped:
|
||||||
@@ -1371,14 +1390,22 @@ def parse_lynis_report():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Detect any line with [ STATUS ] pattern (covers -, File:, Directory:, etc.)
|
# Detect any line with [ STATUS ] pattern (covers -, File:, Directory:, etc.)
|
||||||
check_match = re.match(
|
# After ANSI cleaning, cursor-positioning sequences are removed so
|
||||||
r'^[\s]*[-*]?\s*(.+?)\s{2,}\[\s*(.+?)\s*\]\s*$', stripped
|
# there may be only 1 space between the name and [ STATUS ].
|
||||||
)
|
# Strategy: find the LAST occurrence of [ ... ] on the line.
|
||||||
if check_match and current_section:
|
bracket_match = re.search(r'\[\s*([A-Za-z0-9_ /.:!-]+?)\s*\]\s*$', stripped)
|
||||||
check_name = check_match.group(1).strip()
|
if bracket_match and current_section:
|
||||||
check_status = check_match.group(2).strip()
|
# Everything before the bracket is the check name
|
||||||
# Skip noise lines
|
bracket_start = bracket_match.start()
|
||||||
if check_name and not check_name.startswith('..') and len(check_name) > 2:
|
check_name = stripped[:bracket_start].strip()
|
||||||
|
check_status = bracket_match.group(1).strip()
|
||||||
|
# Remove leading - or * from name
|
||||||
|
check_name = re.sub(r'^[-*]+\s*', '', check_name).strip()
|
||||||
|
# Skip noise lines (too short, dots-only, plugin progress)
|
||||||
|
if (check_name
|
||||||
|
and not check_name.startswith('..')
|
||||||
|
and len(check_name) > 2
|
||||||
|
and check_name not in ('..', '...', '....')):
|
||||||
current_checks.append({
|
current_checks.append({
|
||||||
"name": check_name,
|
"name": check_name,
|
||||||
"status": check_status,
|
"status": check_status,
|
||||||
@@ -1446,8 +1473,17 @@ def parse_lynis_report():
|
|||||||
if len(s["checks"]) > 0
|
if len(s["checks"]) > 0
|
||||||
]
|
]
|
||||||
|
|
||||||
except Exception:
|
# Store debug info about parsing
|
||||||
|
report["_parse_debug"] = {
|
||||||
|
"source": log_file,
|
||||||
|
"total_lines": len(log_lines),
|
||||||
|
"sections_found": len(report["sections"]),
|
||||||
|
"section_names": [s["name"] for s in report["sections"]],
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
report["sections"] = []
|
report["sections"] = []
|
||||||
|
report["_parse_debug"] = {"error": str(e)}
|
||||||
|
|
||||||
# Post-processing: extract firewall/malware status from parsed sections
|
# Post-processing: extract firewall/malware status from parsed sections
|
||||||
# This catches cases where report.dat doesn't have firewall_active but the
|
# This catches cases where report.dat doesn't have firewall_active but the
|
||||||
|
|||||||
Reference in New Issue
Block a user