# AMO permission justification Submitted with every version bump in the AMO "Notes to Reviewer" field. Kept here so the justification is reviewed and versioned alongside the permission list itself (`manifest.json`), instead of living only in a web form. docs/05 §7 is the design-time version of this; this file is the submission-ready copy. ## What Velox is A download manager. It intercepts a response Firefox is about to download, hands the URL, request headers, and cookies to a companion native application (`veloxd`), and lets that application fetch the file with resumable, multi-connection transfers. The extension itself never stores or transfers file bytes — see `CLAUDE.md` §3 and the `no-download-logic` ESLint gate (`eslint.config.mjs`) that fails CI if it ever does. ## Permissions requested | Permission | Why | Narrowest alternative considered | |---|---|---| | `webRequest` + `webRequestBlocking` | The whole feature: inspect response headers on `onHeadersReceived` to decide whether to intercept a download, and `{cancel: true}` before Firefox starts its own download. This is the one thing MV3 Chrome removed and MV3 Firefox kept — it's why the extension can exist as designed (docs/05 §1). | None. Without blocking `webRequest` there is no way to stop Firefox's own download before it starts; polling `downloads.onCreated` alone (which we also use, see below) only catches what already started. | | `downloads` | Belt-and-braces safety net (`capture/downloads-api.ts`): some downloads (form POSTs, service-worker blobs) never reach `onHeadersReceived` in a way we can act on and only surface via `downloads.onCreated`. Also used to `cancel`/`erase` a download we're taking over so Firefox doesn't keep two copies. | Drop the safety net and accept that those cases silently bypass Velox. Rejected — docs/05 §2 calls this out explicitly as a known gap the safety net exists to close. | | `cookies` | A file behind a login (private CDN links, forum attachments) needs its session cookies handed to `veloxd`, or the daemon's fetch gets a 403 the browser's own request wouldn't have. Read via `cookies.getAll(url)` only for a URL we are about to offer to the daemon — never harvested in bulk or logged. | Skip cookies and only support anonymous URLs. Rejected — it's a top user-facing IDM-parity feature and the reason people leave Chrome download managers behind. | | `contextMenus` | "Download with Velox" on a link/image/video, and "Download all links…" (docs/05 §3). Table-stakes UI for a download manager extension. | None smaller — there's no partial grant for context menus. | | `storage` | `browser.storage.local` holds only extension-local state: the WebSocket pairing token, the manual transport override, the last-good WS port, and the user's default-category preference (`transport/storage.ts`, `options/prefs.ts`). No browsing data. | None — some persistence is required for pairing to survive a restart (M1 DoD), which is the point of the token existing at all. | | `notifications` | Tells the user when the daemon can't be reached for a download that fell back to Firefox, and (native-messaging path) surfaces pairing prompts if the GUI isn't running. | Silent failure. Rejected — capture fails open by design (CLAUDE.md §4) and a silent fallback with no notification would look like a bug. | | `nativeMessaging` | Opportunistic transport to `veloxd` over a Unix socket, for installs where it works (docs/adr/0003). Not the default path — WebSocket is — but shipped because it avoids the WebSocket port-scan on installs where the native host manifest is reachable. | Drop native messaging and use WebSocket exclusively. Considered and rejected in ADR 0003: keeping both means the extension keeps working across deb/snap/flatpak Firefox without per-flavour capture-logic forks. | | `` (host permission) | Downloads happen from every site on the web; `webRequest`'s header inspection and `cookies.getAll` both need to run against whatever site the user is on. This is the item AMO reviewers push back on hardest for extensions of this shape. | A fixed list of "known download sites" — unworkable for a general-purpose download manager, and defeats the point of an IDM-style interceptor. **Mitigation, not a narrower permission:** the exclusion list in Options is front-and-center (`options.html` → "Capture policy") so a user can scope capture down to nothing on sites they don't want Velox touching, and the bypass modifier (default Alt) lets a single click skip capture without changing settings. | ## What is explicitly *not* requested - No `` XHR/fetch use — `webRequest`/`cookies` read metadata about a request Firefox is already making; the extension never issues its own network request for file bytes (enforced by the ESLint gate above). - No `identity`, `history`, `bookmarks`, `tabs` beyond what `contextMenus`/`commands` already imply, `management`, or any permission unrelated to capturing and handing off a download. - No remote code: the manifest ships no CDN scripts and no `eval`; `web-ext lint` fails the build otherwise (CI's `extension-lint` job). ## Data handling - Cookies and headers are held in memory only long enough to answer one `capture.offer` call to the local daemon (`capture/headers.ts`'s ring buffer, 5-minute TTL) — never written to disk by the extension and never sent anywhere but `127.0.0.1`. - The daemon connection is local-only: `WebSocketTransport` connects to `ws://127.0.0.1:`, never a remote host (docs/05 §4, conformance-tested). - Nothing is sent to Anthropic, Mozilla, or any third party beyond the user's own local `veloxd` process.