Shell:
- Brand (logo + name) moves from sidebar header into the titlebar so the
top-left reads `[logo] LitterBox | <breadcrumb>` instead of having two
separate brand strips.
- The bottom IDE-style status bar is removed; it duplicated the
sidebar-foot status indicator. The sidebar foot now also shows the
version on the right (`[dot] Active v5.0.0`).
- Titlebar height bumped 36 → 44px and the brand mark to 28px so the
logo has breathing room and balances the wordmark.
- file_info header: Back / Static Analysis / Dynamic Analysis buttons
consolidated into the panel header on the right. Dynamic gets a
yellow border to flag that it executes the payload.
Bug fix:
- /results/<hash>/static was rendering YARA as "Suspicious" with a
matching count even when the static scan returned zero matches. Cause:
RouteHelpers.get_detection_counts(data) prefers `dynamic_results` if
any dynamic scan exists, so the static page was rendering its row
count from the dynamic scope while the row's match list came from the
static scope. render_analysis_info now extracts counts from the actual
analysis_results being rendered.
Misc:
- Drop unused .lb-tb-right, .lb-tb-version, .lb-sidebar-brand, and all
.lb-statusbar* rules from style.css; remove dead statusbar_left block
override in error.html.
- Bump app version to 5.0.0 in Config/config.yaml.
Full visual redesign onto a dense terminal/IDE layout: breadcrumb titlebar,
iconed sidebar, optional tab row, IDE-style status bar, JetBrains Mono
throughout, semantic severity palette, and a calm-red rule that reserves
bright red for severity tags, destructive buttons, and the brand dot.
Splits the 1,598-line tools.js into a 66-line registry plus one module per
scanner under app/static/js/results/tools/ (yara, checkplz, stringnalyzer,
pe_sieve, moneta, patriot, hsb, rededr, summary), with shared rendering
helpers in tools/_shared.js. Each module exports
{id, elementId, statsElementId?, render(results, ctx)}, and the registry
does lazy DOM lookups so a module loaded on a page that doesn't have its
tab silently no-ops.
Switches Tailwind from the precompiled v2.2.19 file (~2.8MB) to a v4 build
generated locally by the standalone CLI binary (~284KB). End-user setup is
unchanged: the committed tailwind.min.css ships ready to use; only the
maintainer needs the binary, which lives outside the repo.
Fixes:
- ModalHandler crash on dynamic results pages (null-deref against the old
.bg-gray-900 selector)
- AnalysisCore.updateStageToComplete null-deref against removed
stage-indicator markup
- summary.render silently skipped because elementId pointed at the
removed summaryWrapper div — points at scannerResultsBody now
- Per-tool render failures no longer suppress the rest of the rendering
- Drag-and-drop highlight no longer null-derefs against the removed
.upload-icon selector
- Upload "Unsupported file type" false positive — extensions now sourced
from window.serverConfig instead of DOM scraping
- XSS hardening at user-data interpolation sites in results renderers
Visual unification:
- New :root design tokens + .lb-* component classes in style.css
(cards, buttons, badges, section headers, hash display, empty
state, animated grid backdrop, critical-state pulse).
- holygrail.html and byovd_info.html lose their cyber-themed inline
<style> blocks (567 + 164 lines) and the cyber-card / cyber-chip /
cyber-button / verdict-* classes; both pages now draw from the
shared lb-* vocabulary. The cyber-glow accent is preserved but
applied only on critical/severe states instead of page-wide.
- Templates swept to use component classes: file_info, summary,
results, dynamic_info, static_info, doppelganger, error, upload,
partials/_macros. JS renderers in results/tools.js,
results/renderers.js, and the holygrail/byovd/upload core.js
modules updated to emit the new classes. Risk-level 4-way
conditional in file_info.html collapsed to a single
lb-badge-{{ risk_level|lower }} lookup.
- Bug fix: duplicate .logo-wrapper rule in style.css merged.
Self-contained report (report.html rewritten):
- Drops the https://cdn.tailwindcss.com runtime-JIT dependency and
the inline tailwind.config script. No <script> tags anywhere.
- All CSS inlined in a single <style> block: design tokens, the
subset of lb-* component classes the report uses, and only the
layout rules the report itself needs.
- Hand-written typography and layout: tabular-numeric risk scores,
restrained pill badges, severity-coded detection chips,
generous whitespace, dedicated @media print.
- Status icons use locked SVG dimensions so the green checkmark on
clean scans no longer renders at default-huge size.
- The LitterBox logo is embedded as a base64 PNG data URI so the
brand strip displays correctly when the file is downloaded and
opened offline. Logo sized at 64x64 in the brand strip.
CHANGELOG.md: v4.2.0 entry extended with "UI design system &
visual unification" and "Fully self-contained downloadable report"
sections.
No backend or API changes. Setup story unchanged. No new
dependencies; deploy stays Python-only with the precompiled
tailwind.min.css.
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.