Skip to content

🍕 feat(permissions): user-controlled per-site host access (v2.1.0)#7

Open
jjpaulino wants to merge 1 commit into
masterfrom
feat/per-site-host-permissions
Open

🍕 feat(permissions): user-controlled per-site host access (v2.1.0)#7
jjpaulino wants to merge 1 commit into
masterfrom
feat/per-site-host-permissions

Conversation

@jjpaulino
Copy link
Copy Markdown
Member

Why

Chrome Web Store flagged our last upload with Broad Host Permissions:

Because of the following issue, your extension may require an in-depth review:

  • Broad Host Permissions
    Instead of requesting broad host permissions, consider using the activeTab permission, or specify the sites that your extension needs access to.

We can't ship a hard-coded site list — Clay Slip needs to work on whatever Clay deployments the install owner happens to use. The fix is to drop the broad install grant entirely and let the user opt in per-site at runtime.

What

  • Manifest: host_permissions is now []. Broad access lives in optional_host_permissions: ["<all_urls>"], which is gated behind a Chrome consent prompt the user triggers themselves. The static content_scripts.matches keeps <all_urls> as the upper bound, but Chrome only auto-injects on origins the user has granted — i.e. nothing on a fresh install.
  • src/lib/permissions.ts (new): clean wrapper around chrome.permissions that talks bare hostnames (www.thecut.com) instead of origin patterns. Handles request / remove / list / has + helpers for popup/SW callers. 16 unit tests.
  • Options page → new Allowed sites section at the top: list of currently granted hosts (with Revoke buttons), text input + button to grant a new one, and a Pending strip listing hostnames referenced by site mappings that aren't yet granted (with one-click Grant all).
  • Popup: now state-aware. On a host the user hasn't granted, it shows Allow Clay Slip on this site → triggers Chrome's prompt → reloads the tab. On a granted host that isn't a Clay page, it shows Not a Clay page + a Revoke button. On chrome:// / file:// pages it explains why it can't run.
  • README + PRIVACY.md: rewritten to describe the new permission model with separate "required at install" and "granted by you at runtime" tables.
  • Version: 2.0.2 → 2.1.0 (behavioral change).

Migration story for existing users

Existing v2.0.x installs already have <all_urls> granted from when it was a required permission. Per Chrome's MV3 docs, when an extension update drops a required permission, Chrome keeps the previously-granted access in place (the user doesn't get re-prompted, and they don't lose anything).

For new installs the flow is:

  1. Install → no host access yet → toolbar icon shows the popup on every page.
  2. Open a Clay tab → click the icon → click Allow Clay Slip on this site → Chrome native prompt → tab reloads → panel/FAB appears.
  3. Or: open Options → Allowed sites → type the hostname → Grant access.

Why this should clear the review flag

The reviewer's two suggested alternatives are:

The activeTab permission allows access to a tab in response to an explicit user gesture.
If your extension only needs to run on certain sites, simply specify those sites in the extension manifest.

We're effectively combining both: the install-time permission set is minimal (no host_permissions), and the user explicitly grants each origin via Chrome's own permission UI before any content script ever runs there. `optional_host_permissions` is the documented MV3 mechanism for exactly this pattern.

Test plan

  • `npm run validate` (typecheck + lint + format + 100 tests)
  • `npm run build` produces a manifest with `host_permissions: []` and `optional_host_permissions: ["<all_urls>"]`
  • `npm run zip` produces `clay-slip-v2.1.0.zip` (103 KB) with the expected manifest at the root
  • Load unpacked → confirm panel does not appear on any site by default
  • Click toolbar icon on a Clay page → click Allow Clay Slip on this site → confirm Chrome shows native prompt → confirm panel/FAB appear after reload
  • Options → Allowed sites → revoke → confirm panel disappears on next reload
  • Add a site mapping with a hostname not yet granted → confirm Pending strip appears → click Grant all → confirm prompts cycle through

Files

  • New: `src/lib/permissions.ts`, `tests/lib/permissions.test.ts`
  • Updated: `src/manifest.ts`, `src/options/Options.tsx`, `src/options/options.css`, `src/popup/Popup.tsx`, `src/popup/popup.css`, `PRIVACY.md`, `README.md`, `package.json`

Made with Cursor

Drops the broad `host_permissions: ["<all_urls>"]` install grant — the one
that was triggering Chrome Web Store's "Broad Host Permissions" review
delay — and replaces it with a per-site model the user controls at runtime.

Changes
- Manifest: `host_permissions: []`, `optional_host_permissions: ["<all_urls>"]`.
  The static content_scripts entry keeps its `<all_urls>` matcher as the
  upper bound; Chrome only auto-injects on origins the user has granted.
- New `src/lib/permissions.ts` wrapping `chrome.permissions` with a clean
  bare-hostname API (request / remove / list / has) plus URL helpers.
- Options page: new "Allowed sites" section at the top — list current
  granted hosts with a Revoke button, add new ones via a text input that
  triggers the native Chrome consent prompt, and a "Pending" strip that
  surfaces hostnames referenced by site mappings but not yet granted (with
  a one-click "Grant all" button).
- Popup: detects the active tab's host and shows either "Allow Clay Slip
  on this site" (with reload after grant) or "Not a Clay page" + Revoke,
  depending on whether the host is already granted.
- README and PRIVACY.md updated to describe the new permission model and
  per-permission justification table (required vs runtime-granted).
- Version bumped to 2.1.0.

Tests: 16 new unit tests for the permissions module; full suite stays
green at 100/100.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant