AUTARCH v1.9 — remote monitoring, SSH manager, daemon, vault, cleanup
- Add Remote Monitoring Station with PIAP device profile system - Add SSH/SSHD manager with fail2ban integration - Add privileged daemon architecture for safe root operations - Add encrypted vault, HAL memory, HAL auto-analyst - Add network security suite, module creator, codex training - Add start.sh launcher script and GTK3 desktop launcher - Remove Output/ build artifacts, installer files, loose docs - Update .gitignore for runtime data and build artifacts - Update README for v1.9 with new launch method, screenshots, and features Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
262
web/routes/module_creator.py
Normal file
262
web/routes/module_creator.py
Normal file
@@ -0,0 +1,262 @@
|
||||
"""Module Creator route - create, edit, validate, and manage AUTARCH modules"""
|
||||
|
||||
import ast
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from flask import Blueprint, render_template, request, jsonify
|
||||
from web.auth import login_required
|
||||
|
||||
module_creator_bp = Blueprint('module_creator', __name__, url_prefix='/module-creator')
|
||||
|
||||
MODULES_DIR = Path(__file__).parent.parent.parent / 'modules'
|
||||
|
||||
CATEGORIES = ['defense', 'offense', 'counter', 'analyze', 'osint', 'simulate', 'core', 'hardware']
|
||||
|
||||
CATEGORY_DESCRIPTIONS = {
|
||||
'defense': 'Defensive security module for monitoring, hardening, and threat detection',
|
||||
'offense': 'Offensive security module for penetration testing and exploitation',
|
||||
'counter': 'Counter-intelligence module for anti-surveillance and evasion',
|
||||
'analyze': 'Analysis module for forensics, traffic inspection, and data processing',
|
||||
'osint': 'Open-source intelligence gathering and reconnaissance module',
|
||||
'simulate': 'Simulation module for attack modeling and scenario testing',
|
||||
'core': 'Core infrastructure module for platform internals and utilities',
|
||||
'hardware': 'Hardware interface module for RF, BLE, RFID, SDR, and embedded devices',
|
||||
}
|
||||
|
||||
|
||||
def _module_skeleton(name, category, description, author):
|
||||
"""Generate skeleton code for a new module."""
|
||||
return f'''"""
|
||||
{description}
|
||||
"""
|
||||
|
||||
DESCRIPTION = "{description}"
|
||||
AUTHOR = "{author}"
|
||||
VERSION = "1.0"
|
||||
CATEGORY = "{category}"
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
sys.path.insert(0, str(Path(__file__).parent.parent))
|
||||
from core.banner import Colors, clear_screen, display_banner
|
||||
|
||||
|
||||
def run():
|
||||
"""Main entry point."""
|
||||
clear_screen()
|
||||
display_banner()
|
||||
print(f"{{Colors.BOLD}}{name}{{Colors.RESET}}")
|
||||
print(f"{{Colors.DIM}}{{"─" * 50}}{{Colors.RESET}}\\n")
|
||||
|
||||
# TODO: Implement module logic here
|
||||
print(f"{{Colors.GREEN}}[+] Module loaded successfully{{Colors.RESET}}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run()
|
||||
'''
|
||||
|
||||
|
||||
def _parse_module_metadata(filepath):
|
||||
"""Extract metadata from a module file."""
|
||||
meta = {
|
||||
'name': filepath.stem,
|
||||
'category': 'unknown',
|
||||
'description': '',
|
||||
'version': '',
|
||||
'author': '',
|
||||
'file_size': filepath.stat().st_size,
|
||||
'last_modified': datetime.fromtimestamp(filepath.stat().st_mtime).strftime('%Y-%m-%d %H:%M'),
|
||||
}
|
||||
try:
|
||||
source = filepath.read_text(errors='replace')
|
||||
tree = ast.parse(source)
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Assign):
|
||||
for target in node.targets:
|
||||
if isinstance(target, ast.Name) and isinstance(node.value, ast.Constant):
|
||||
if target.id == 'DESCRIPTION':
|
||||
meta['description'] = str(node.value.value)
|
||||
elif target.id == 'CATEGORY':
|
||||
meta['category'] = str(node.value.value)
|
||||
elif target.id == 'VERSION':
|
||||
meta['version'] = str(node.value.value)
|
||||
elif target.id == 'AUTHOR':
|
||||
meta['author'] = str(node.value.value)
|
||||
except Exception:
|
||||
pass
|
||||
return meta
|
||||
|
||||
|
||||
@module_creator_bp.route('/')
|
||||
@login_required
|
||||
def index():
|
||||
return render_template('module_creator.html')
|
||||
|
||||
|
||||
@module_creator_bp.route('/templates')
|
||||
@login_required
|
||||
def templates():
|
||||
"""Return skeleton templates for each category."""
|
||||
result = []
|
||||
for cat in CATEGORIES:
|
||||
result.append({
|
||||
'name': f'new_{cat}_module',
|
||||
'category': cat,
|
||||
'description': CATEGORY_DESCRIPTIONS.get(cat, ''),
|
||||
'code': _module_skeleton(f'new_{cat}_module', cat, CATEGORY_DESCRIPTIONS.get(cat, ''), 'darkHal'),
|
||||
})
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@module_creator_bp.route('/create', methods=['POST'])
|
||||
@login_required
|
||||
def create():
|
||||
"""Create a new module file."""
|
||||
data = request.get_json(silent=True)
|
||||
if not data:
|
||||
return jsonify({'success': False, 'error': 'Invalid JSON payload'}), 400
|
||||
|
||||
name = data.get('name', '').strip()
|
||||
category = data.get('category', '').strip()
|
||||
description = data.get('description', '').strip()
|
||||
author = data.get('author', 'darkHal').strip()
|
||||
code = data.get('code', '').strip()
|
||||
|
||||
# Validate name
|
||||
if not name:
|
||||
return jsonify({'success': False, 'error': 'Module name is required'}), 400
|
||||
if not re.match(r'^[A-Za-z0-9_]+$', name):
|
||||
return jsonify({'success': False, 'error': 'Module name must be alphanumeric and underscores only'}), 400
|
||||
|
||||
# Check category
|
||||
if category not in CATEGORIES:
|
||||
return jsonify({'success': False, 'error': f'Invalid category. Must be one of: {", ".join(CATEGORIES)}'}), 400
|
||||
|
||||
# Check existence
|
||||
target = MODULES_DIR / f'{name}.py'
|
||||
if target.exists():
|
||||
return jsonify({'success': False, 'error': f'Module "{name}" already exists'}), 409
|
||||
|
||||
# Use provided code or generate skeleton
|
||||
if not code:
|
||||
code = _module_skeleton(name, category, description, author)
|
||||
|
||||
try:
|
||||
target.write_text(code)
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': f'Failed to write module: {e}'}), 500
|
||||
|
||||
return jsonify({'success': True, 'message': f'Module "{name}" created successfully', 'path': str(target)})
|
||||
|
||||
|
||||
@module_creator_bp.route('/validate', methods=['POST'])
|
||||
@login_required
|
||||
def validate():
|
||||
"""Validate Python syntax and required attributes."""
|
||||
data = request.get_json(silent=True)
|
||||
if not data or 'code' not in data:
|
||||
return jsonify({'valid': False, 'errors': ['No code provided']}), 400
|
||||
|
||||
code = data['code']
|
||||
errors = []
|
||||
warnings = []
|
||||
|
||||
# Syntax check
|
||||
try:
|
||||
tree = ast.parse(code)
|
||||
except SyntaxError as e:
|
||||
return jsonify({
|
||||
'valid': False,
|
||||
'errors': [f'Syntax error at line {e.lineno}: {e.msg}'],
|
||||
'warnings': [],
|
||||
})
|
||||
|
||||
# Check required attributes
|
||||
found_attrs = set()
|
||||
found_run = False
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Assign):
|
||||
for target in node.targets:
|
||||
if isinstance(target, ast.Name) and target.id in ('DESCRIPTION', 'CATEGORY'):
|
||||
found_attrs.add(target.id)
|
||||
if isinstance(node, ast.FunctionDef) and node.name == 'run':
|
||||
found_run = True
|
||||
|
||||
if 'DESCRIPTION' not in found_attrs:
|
||||
errors.append('Missing required attribute: DESCRIPTION')
|
||||
if 'CATEGORY' not in found_attrs:
|
||||
errors.append('Missing required attribute: CATEGORY')
|
||||
if not found_run:
|
||||
errors.append('Missing required function: run()')
|
||||
|
||||
valid = len(errors) == 0
|
||||
if valid:
|
||||
warnings.append('All checks passed')
|
||||
|
||||
return jsonify({'valid': valid, 'errors': errors, 'warnings': warnings})
|
||||
|
||||
|
||||
@module_creator_bp.route('/list')
|
||||
@login_required
|
||||
def list_modules():
|
||||
"""Return JSON list of all existing modules."""
|
||||
modules = []
|
||||
if MODULES_DIR.exists():
|
||||
for f in sorted(MODULES_DIR.glob('*.py')):
|
||||
if f.name.startswith('__'):
|
||||
continue
|
||||
modules.append(_parse_module_metadata(f))
|
||||
return jsonify(modules)
|
||||
|
||||
|
||||
@module_creator_bp.route('/preview', methods=['POST'])
|
||||
@login_required
|
||||
def preview():
|
||||
"""Load and return source code of an existing module."""
|
||||
data = request.get_json(silent=True)
|
||||
if not data or 'name' not in data:
|
||||
return jsonify({'success': False, 'error': 'Module name is required'}), 400
|
||||
|
||||
name = data['name'].strip()
|
||||
target = MODULES_DIR / f'{name}.py'
|
||||
if not target.exists():
|
||||
return jsonify({'success': False, 'error': f'Module "{name}" not found'}), 404
|
||||
|
||||
try:
|
||||
code = target.read_text(errors='replace')
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
meta = _parse_module_metadata(target)
|
||||
return jsonify({'success': True, 'code': code, 'metadata': meta})
|
||||
|
||||
|
||||
@module_creator_bp.route('/save', methods=['POST'])
|
||||
@login_required
|
||||
def save():
|
||||
"""Save edits to an existing module file."""
|
||||
data = request.get_json(silent=True)
|
||||
if not data:
|
||||
return jsonify({'success': False, 'error': 'Invalid JSON payload'}), 400
|
||||
|
||||
name = data.get('name', '').strip()
|
||||
code = data.get('code', '')
|
||||
|
||||
if not name:
|
||||
return jsonify({'success': False, 'error': 'Module name is required'}), 400
|
||||
if not re.match(r'^[A-Za-z0-9_]+$', name):
|
||||
return jsonify({'success': False, 'error': 'Invalid module name'}), 400
|
||||
|
||||
target = MODULES_DIR / f'{name}.py'
|
||||
if not target.exists():
|
||||
return jsonify({'success': False, 'error': f'Module "{name}" does not exist'}), 404
|
||||
|
||||
try:
|
||||
target.write_text(code)
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': f'Failed to save: {e}'}), 500
|
||||
|
||||
return jsonify({'success': True, 'message': f'Module "{name}" saved successfully'})
|
||||
Reference in New Issue
Block a user