mirror of
https://github.com/CyberMind-FR/secubox-deb.git
synced 2026-07-29 13:59:40 +00:00
* docs(media-buffer): design spec — dashcam capture + replay + metatag lifecycle (ref #812) * docs(media-buffer): phase-1 implementation plan (capture+janitor+API+DPI tab) (ref #812) * feat(sbxmitm): media buffer store + metatag writer (ref #812) * fix(sbxmitm): media-buffer review — 4096 atomic-append cap + *string buffer_ref (ref #812) Task 1 review (Important): mediaBufferLineMax 8192→4096 to match mediacatch.go's PIPE_BUF atomic-append guarantee across 4 workers; BufferRef string→*string so the janitor (Task 3) can flip it to JSON null on eviction. * feat(sbxmitm): tee media up/download bodies into the buffer (ref #812) Wire the R4 media buffer tees into mitmPipeline: the download hook wraps resp.Body and the upload path wraps req.Body via teeReadCloser, capturing whole-file media into the rolling /data buffer. Add the mbuf field + flags (--media-buffer default OFF, --media-buffer-root, --media-buffer-per-object). Design upgrade over the plan sketch: ObjectWriter.Write is now NON-BLOCKING. Instead of io.TeeReader driving a synchronous os.File.Write on the client read path (which would add latency / could stall large media on ARM eMMC), Write copies each chunk into a bounded channel and returns len(p),nil immediately; a background goroutine started at Capture drains the channel to disk. A full channel drops the chunk and flags truncated — never blocks, never errors the proxied flow (design 4.2/7). Close signals the drainer, waits for it to flush queued chunks + close the file, then appends the metatag; it is idempotent, deadlock-free (sole closer of ch) and safe if Write is never called or races Close. * fix(sbxmitm): media download tee — defer closure so w.Close runs (ref #812) defer resp.Body.Close() bound the ORIGINAL upstream body at the defer statement, before the media-buffer tee reassigned resp.Body — so the tee's Close() (and w.Close, which flushes the sink/metatag/drain goroutine) never ran on any download. Wrap the close in a closure so it reads resp.Body at return time instead. Adds TestTeeDeferOrderingMatchesMainGo, which replicates main.go's exact defer-then-reassign ordering and fails against the old plain defer form (verified manually, then restored the fix). Also: drop the dead write-only ObjectWriter.dropped field (truncated already covers it), document Capture's reserved contentLen param, and note that ObjectWriter.Close is allowed to block (post-stream finalisation), unlike Write. * feat(sbxmitm): media buffer janitor — time + LRU eviction, metatag survives (ref #812) SweepOnce evicts a session's bytes (RemoveAll, idempotent) once first_ts+retentionSecs elapses, then falls back to oldest-first LRU eviction if the buffer root (media bytes only, log excluded) still exceeds sizeCeilBytes. Eviction never rewrites the append-only metatag log in place — it appends a corrected line with the same id (expired:true, buffer_ref:null); readers dedup by id, last line wins, so the flip is durable and safe across the 4 concurrent sbxmitm worker processes each running their own RunJanitor (idempotent RemoveAll + harmless duplicate flip lines). RunJanitor ticks SweepOnce every 30s (test-overridable period) until its context is cancelled; wired at sbxmitm startup as a process-lifetime goroutine when --media-buffer is enabled. NewMediaBuffer's signature is unchanged; retentionSecs (1200), sizeCeilBytes (24 GiB) and nowFn now default inside the constructor. * feat(core): media-buffer metatag reader (dedup by id, fail-empty) (ref #812) * test(core): media-buffer reader — tail-read truncation + malformed-field regressions (ref #812) * chore(#812): keep SDD scratch reports out of the feature diff (restore to master) * feat(dpi): media-buffer list/replay/thumb API (admin/owner, audited, 410-on-evict, traversal-safe) (ref #812) * harden(dpi): media API — \Z-anchored id regex + role short-circuit security note (ref #812) * feat(sbxmitm): media-buffer retention/size-ceil flags + /data tmpfiles + opt-in worker env toggle (ref #812) - main.go: --media-buffer-retention / --media-buffer-size-ceil flags, applied onto the already-constructed mbuf's unexported retentionSecs/sizeCeilBytes fields (NewMediaBuffer signature unchanged). - tmpfiles/zz-secubox-media-buffer.conf: pre-creates /data/secubox (0755) and /data/secubox/media-buffer (0750 secubox:secubox), installed via the package's existing manual tmpfiles.d mechanism in debian/rules. - secubox-toolbox-ng-worker@.service: EnvironmentFile=-/etc/secubox/toolbox-ng.env + trailing $SBX_MEDIA_BUFFER_ARGS on ExecStart so an operator can opt in (SBX_MEDIA_BUFFER_ARGS=--media-buffer) without editing the shipped unit; default stays OFF. Added ReadWritePaths=/data/secubox/media-buffer. * fix(sbxmitm): media-buffer dir owned by writer (secubox-toolbox) + setgid group secubox; changelog 0.1.27 (ref #812) Task 6 review Critical: buffer dir was 0750 secubox:secubox but sbxmitm workers run as secubox-toolbox (not in group secubox) → EACCES on every capture, silently no-op'd (errors swallowed by design). Fix: 2750 secubox-toolbox:secubox — writer owns, dpi reader (secubox) is group, setgid propagates group secubox to created objects so the reader can read them. Important: add debian/changelog 0.1.27 stanza (version bump). * feat(dpi): Media tab — live capture gallery with replay/download, escaped fields (ref #812) Adds a Media Buffer card to the DPI dashboard (packages/secubox-dpi/www/dpi/index.html) that lists sbxmitm's live media-buffer captures via GET /api/v1/dpi/media/buffer. - Auth: dedicated apiAuthed() reads the canonical `sbx_token` localStorage key and sends it as a Bearer token (media/buffer requires JWT, unlike the rest of this page's endpoints which currently ride the SSO-lite session cookie); 401 redirects to /login.html, matching sibling dashboards (e.g. crowdsec). - Security: host/url/mac_hash are attacker-influenceable (captured live traffic). Every card is built via createElement + textContent (or the `.title` IDL property, never HTML-parsed) — no innerHTML string concatenation of these fields — so a captured value like `<img onerror=...>` renders as inert text. Replay/download URLs are built with encodeURIComponent(id) even though the id is hex-validated server-side. - UI: kind emoji (video/audio/manifest/file), short device id (shortDev, reused from the existing #785 helpers), ⬆/⬇ direction, human size (formatBytes) and age (agoStr) per card; expired captures grey out and show "métatag seul (expiré)" with no action links. - Refresh: wired into the existing refreshAll() plus its own ~15s interval. Verified with a Playwright harness stubbing fetch (incl. an XSS payload in host/url) against a local copy of the page: no console/page errors, XSS did not fire, no <img>/<script> element materialized from the captured strings, expired-card gating confirmed. * fix(sbxmitm): media buffer — upload tee needs a real body, download tee 200-only (whole-branch review); drop dead item.ts (ref #812) * docs(media-buffer): Phase 2 plan — HLS reassembly via read-time URL join (ref #812) --------- Co-authored-by: CyberMind-FR <gandalf@Gk2.net> |
||
|---|---|---|
| .. | ||
| apparmor | ||
| audit | ||
| nginx | ||
| secubox_core | ||