ce9a926246
Backend (Python):
- Split app/routes.py (1,389 lines) into 6 Flask blueprints (upload, analysis,
results, doppelganger, management, api) under app/blueprints/, plus
service modules (rendering, summary, tool_check, error_handling) under
app/services/, and the shared RouteHelpers class in app/helpers.py.
app/__init__.py wires shared deps via app.extensions['litterbox'].
- Split app/utils.py (1,400 lines) into the app/utils/ package with
single-concern modules: file_io, validators, path_manager, risk_analyzer,
forensics, json_helpers, reporting. No facade — every caller migrated.
- Extracted BaseSubprocessAnalyzer in app/analyzers/base.py; refactored 9
subprocess analyzers (yara/checkplz/stringnalyzer static; yara/pe_sieve/
moneta/patriot/hsb/hollows_hunter dynamic) as thin subclasses that only
declare config + implement _parse_output.
Frontend (JS):
- Split results.js (2,060), holygrail.js (1,025), byovd_info.js (1,069),
and upload.js (974) into per-concern ES6 modules under
app/static/js/{results,holygrail,byovd,upload}/.
- Added app/static/js/utils/ with shared helpers: escape, formatters,
severity, fetch, modals, dom (single source of truth for escapeHtml,
formatBytes, severity-color mapping, etc.).
- Converted base.js, summary.js, blender.js, fuzzy.js to ES6 modules;
every <script> tag now uses type="module". window.X assignments preserved
so inline onclick handlers in templates keep resolving.
- Targeted XSS hardening at user-data interpolation sites in results
renderers (str.data, hex_dump, scan_info.target, list items).
Templates:
- New app/templates/partials/_macros.html with reusable scanner-table
macros + 3-card status grid; static_info.html and dynamic_info.html
migrated to use them, eliminating identical-HTML duplication.
CSS:
- Fixed broken @apply in .drag-over (no Tailwind build pipeline → @apply
was silently ignored, leaving drag-and-drop visual feedback broken).
Replaced with raw CSS equivalent.
- Dedented stray 8-space-indented block (lines 127-end) for consistency.
- Added header comment documenting the no-build-pipeline constraint.
Gitignore:
- Anchored Results/, Uploads/, DoppelgangerDB/Blender/, and Scanners/*
patterns to repo root with leading slash so they don't shadow same-
named directories elsewhere (notably the new app/static/js/results/
module directory and app/blueprints/results.py).
- Added /Scanners/PE-Sieve/process_*/ for runtime scan artifacts.
111 lines
3.4 KiB
Python
111 lines
3.4 KiB
Python
import logging
|
|
import os
|
|
from types import SimpleNamespace
|
|
|
|
import yaml
|
|
from colorama import Fore, Style, init
|
|
from flask import Flask, render_template, request
|
|
|
|
# Initialize colorama for Windows compatibility
|
|
init(autoreset=True)
|
|
|
|
|
|
def load_config():
|
|
config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config', 'config.yaml')
|
|
with open(config_path, 'r') as config_file:
|
|
return yaml.safe_load(config_file)
|
|
|
|
|
|
def create_app():
|
|
app = Flask(__name__)
|
|
|
|
# Load configuration from YAML
|
|
config = load_config()
|
|
app.config.update(config)
|
|
app.name = config['application']['name']
|
|
|
|
# Create all necessary directories
|
|
paths_to_create = {
|
|
config['utils']['upload_folder'],
|
|
config['utils']['result_folder'],
|
|
config['analysis']['doppelganger']['db']['path'],
|
|
os.path.join(
|
|
config['analysis']['doppelganger']['db']['path'],
|
|
config['analysis']['doppelganger']['db']['blender'],
|
|
),
|
|
os.path.join(
|
|
config['analysis']['doppelganger']['db']['path'],
|
|
config['analysis']['doppelganger']['db']['fuzzyhash'],
|
|
),
|
|
}
|
|
for path in paths_to_create:
|
|
os.makedirs(path, exist_ok=True)
|
|
|
|
# Wire shared dependencies once; blueprints read them via current_app.extensions
|
|
from .analyzers.manager import AnalysisManager
|
|
from .helpers import RouteHelpers
|
|
|
|
app.extensions['litterbox'] = SimpleNamespace(
|
|
manager=AnalysisManager(app.config, logger=app.logger),
|
|
helpers=RouteHelpers(app.config, app.logger),
|
|
config=app.config,
|
|
)
|
|
|
|
# Register blueprints
|
|
from .blueprints import (
|
|
analysis_bp,
|
|
api_bp,
|
|
doppelganger_bp,
|
|
management_bp,
|
|
results_bp,
|
|
upload_bp,
|
|
)
|
|
|
|
app.register_blueprint(upload_bp)
|
|
app.register_blueprint(analysis_bp)
|
|
app.register_blueprint(results_bp)
|
|
app.register_blueprint(doppelganger_bp)
|
|
app.register_blueprint(management_bp)
|
|
app.register_blueprint(api_bp)
|
|
|
|
@app.errorhandler(404)
|
|
def page_not_found(error):
|
|
app.logger.debug(f"Page not found: {request.path}")
|
|
return render_template('error.html', error=f"Page not found: {request.path}"), 404
|
|
|
|
return app
|
|
|
|
|
|
def setup_logging(app):
|
|
"""Configure logging with selective colors and avoid duplicate logs."""
|
|
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
|
|
return
|
|
|
|
if app.config['DEBUG']:
|
|
log_level = logging.DEBUG
|
|
|
|
from flask.logging import default_handler
|
|
app.logger.setLevel(log_level)
|
|
|
|
class ColoredFormatter(logging.Formatter):
|
|
LOG_COLORS = {
|
|
"DEBUG": Fore.CYAN,
|
|
"INFO": Fore.GREEN,
|
|
"WARNING": Fore.YELLOW,
|
|
"ERROR": Fore.RED,
|
|
"CRITICAL": Fore.MAGENTA + Style.BRIGHT,
|
|
}
|
|
|
|
def format(self, record):
|
|
log_color = self.LOG_COLORS.get(record.levelname, "")
|
|
levelname_color = f"{log_color}{record.levelname}{Style.RESET_ALL}"
|
|
message = f"{Style.RESET_ALL}{record.msg}"
|
|
record.levelname = levelname_color
|
|
record.msg = message
|
|
return super().format(record)
|
|
|
|
formatter = ColoredFormatter('[%(asctime)s - %(name)s] [%(levelname)s] - %(message)s')
|
|
default_handler.setFormatter(formatter)
|
|
|
|
app.logger.debug("Debug logging is enabled.")
|