Conversation
The web UI in PR #2 called Bun.serve({ port }) with no hostname — Bun defaults that to 0.0.0.0, not loopback — and exposed four state-changing POST routes (/api/auth, /api/logout, /api/download, and job cancel) with no Origin, Host, or CSRF validation, in a process that holds Epic OAuth tokens at ~/.config/epic-fab/auth.json. That is reachable both from anyone on the same LAN and, because localhost is not a browser security boundary, cross-origin from any visited website. The download route's caller-controlled 'into' path also made it an arbitrary filesystem write. The performance work from that PR is merged; the UI is not. This commit makes that durable: - scripts/no-listener-guard.ts fails the build on Bun.serve/createServer/ .listen(port)/0.0.0.0 in src/. Verified both directions: exit 1 on an injected listener, exit 0 clean. - SECURITY.md documents token storage, disclosure, and the four checks a future local UI must satisfy (loopback bind, Origin allowlist, Host allowlist, per-session header token). - CI runs typecheck + guard on every push and PR. - tsconfig now typechecks scripts/ too.
|
First — I'm sorry this sat for a month with no reply. I'm in school full time and The performance work is merged. Both commits, with your authorship:
The diagnosis behind those is the best thing that's happened to this tool. The The web UI I'm not taking, and I want to give you the real reason rather than
Bun.serve({ port: opts.port, fetch: handler })With no That's reachable two independent ways:
Also worth noting independently of the network exposure: None of that is a knock on the UI itself — it's a I've added If you want to come back at the UI against those four requirements I'd genuinely Thanks for the perf work, and sorry again for the wait. |
|
I'm glad to have made even a small contribution to the project, and I truly appreciate you taking the time—despite your busy schedule—to review the changes so carefully and provide such important, constructive feedback. The Web UI portion was indeed my oversight. I'm a game developer, and I initially built the UI mainly for my own convenience; I did not have enough knowledge of web security. Thank you for identifying these serious issues. Thank you again for such a thoughtful response. I learned a great deal from it. |
|
I’ve adjusted direction based on the security constraints from your review. Since this repository is primarily a CLI tool, opening a Web UI is not especially appropriate. A minimal interface that clearly presents asset information and supports downloads is sufficient, so I chose a TUI rather than continuing to rework the web portion. The new implementation has no HTTP listener, does not use Bun.serve(), and exposes no browser-accessible local API. Filtering and download selection happen entirely in the terminal; external Fab pages are opened only through explicit user action. Since the performance commits in this PR have already been merged, and the remaining Web UI changes have been superseded by the new implementation, I will close this PR and submit the TUI as a separate, focused PR. |
Summary
awaitper chunk part leftCHUNK_CONCURRENCYunused (effective ~1). A sliding prefetch window nowkeeps the bounded pool busy while assembling.
prefetch + whole-file
Uint8Arrayassembly held every decoded chunk and thefull file in RAM. Now:
concurrency * 3), not all GUIDs up front.partial+ incremental SHA1 → atomic renameforce with
--no-skip). Skip/plan pass runs before any CDN work.remaining
manifestPointersdistribution bases.--concurrency <n>(1–64),--no-skip; step/status on stderr;stdout stays JSON-pipeable and includes
skipped.Changes
src/download.tsChunkCache; stream assemble + hasher; multi-base fetch + retries;DownloadOptions(concurrency,skipExisting,retries,prefetchWindow); returnskipped.src/cli.ts--concurrency,--no-skip, help; stderr status for resolve/manifest/download/sync; pass options; JSONskipped.Behavior notes
--no-skipto force rewrite..partialcleaned up on error); successful files rename atomically.Commits
perf: fix download concurrency + skip/retry/progressfix: download out of memoryTest plan
bun run typecheck→ passesepic-fab --help→ shows--into,--concurrency,--no-skipepic-fab download <id> --into /tmp/fab-test→ stderr: resolve → check/skip → download with concurrency/window → per-file progress; stdout JSON valid +skippedNothing to fetch; no CDN chunk trafficout of memory--concurrency 4/12reflected in status line;--concurrency 0→ user error--no-skipforces redownloadepic-fab sync --project <ue-project>→ asset-level + file-level stderr statusUsage