Skip to content

Commit be65263

Browse files
committed
improvement(extension): enable page access across websites
1 parent f9939fc commit be65263

13 files changed

Lines changed: 111 additions & 341 deletions

File tree

‎apps/docs/content/docs/browser-extension/index.mdx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ To ask about a passage, select the text on the page, right-click, and choose **A
1515

1616
In version 0.1.3 or later, open **+ → Reference current page on send** to include the active tab each time you send a message. This is off by default. The setting appears above the workspace list, and Sim remembers your choice in this Chrome profile. The globe shows **Current page** while this is on. If you attached a page or selection yourself, Sim uses those snapshots instead. Turn the setting off in the same menu.
1717

18-
If Chrome needs access after you switch tabs, your message stays in the composer. Select **Request site access**. If Chrome hasn’t shared the site address with Sim, paste it into **Site address**. Check the site shown on **Allow access**, approve it in Chrome’s permission dialog, then send again. For one-time access, click the Sim toolbar icon on the active tab and retry. Open **+ → Site access** to remove a saved permission.
18+
In version 0.1.4 or later, choose **+ → Page access → Allow across websites** and approve the browser prompt once. Page attachments and send-time references then work across HTTP and HTTPS sites without per-site setup. If a message was waiting for access, its draft stays in the composer so you can send it after approval. Manage or revoke access in Chrome’s extension settings. In earlier versions, **+ → Site access** grants access to an individual site; clicking the Sim toolbar icon gives temporary access to the current page.
1919

2020
To share a screenshot, drag the image file onto the open chat. It uploads to Sim and appears as an attachment you can remove before sending. If a website supplies only an image URL, paste the image itself or use the file picker.
2121

2222
For faster access, press **Command + Shift + S** on macOS or **Alt + Shift + S** on Windows and Linux. In version 0.1.3 or later, the shortcut attaches highlighted text when you have a selection. It won't substitute the whole page for an unreadable selection. With no selection, it attaches the page or uses your send-time reference setting. On an already-open sidebar, Chrome may keep keyboard focus on the website. Click the message field, or use Chrome’s pane navigation (on Mac, **Command + Option + Up**).
2323

24-
If Chrome needs access to a new tab, the sidebar shows the shortcut assigned in this Chrome profile, or **Set shortcut** if none is assigned. You can change it under **Extensions → Keyboard shortcuts**.
24+
Change or assign the shortcut under **Extensions → Keyboard shortcuts**.
2525

2626
## Roll out to a team
2727

@@ -33,6 +33,6 @@ In version 0.1.3 or later, **+ → Browser shortcuts** can recover explicit `sim
3333

3434
## Page access and privacy
3535

36-
Sim reads a page or selection when you attach it, or when you send a message with **Reference current page** enabled. For repeat use on one site, choose **+ → Site access** to grant or revoke that site’s permission. Granting access doesn't start background capture. The page text goes to the hosted composer when attached and becomes part of the conversation when you send it.
36+
Sim reads a page or selection when you attach it, or when you send a message with **Reference current page** enabled. With version 0.1.4 or later, **Allow across websites** provides access across tabs without repeated site approvals. Granting access doesn't start background capture. The page text goes to the hosted composer when attached and becomes part of the conversation when you send it.
3737

3838
See [Sim’s browser extension privacy disclosure](https://www.sim.ai/privacy#browser-extension).

‎apps/extension/DESIGN.md‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ or create a conversation and explicitly attach the current page or highlighted t
1616
The composer’s + menu offers Current page and Selected text. Pending snapshots sit
1717
inside the composer as compact removable chips alongside file attachments. Opening one
1818
shows the captured text, source, capture time, and conversation-retention disclosure.
19-
Partial captures remain labeled in the attachment row. Site access lives in the
20-
composer’s Site access action, which opens an extension-owned dialog; successful delivery adds no persistent status banner.
19+
Partial captures remain labeled in the attachment row. Page access lives in the
20+
composer’s Page access action, which opens an extension-owned dialog; successful delivery adds no persistent status banner.
2121
Snapshots are immutable: navigating to another page cannot silently change an attached
2222
source. Removing an attachment, changing organization or workspace, or starting a new conversation
2323
clears pending page context. Several explicitly attached pages can support comparison.
@@ -34,7 +34,7 @@ Existing Sim server tools remain subject to their existing authorization and app
3434
## Ownership and data flow
3535

3636
1. `apps/extension`: packaged MV3 service worker, side-panel host, bounded content
37-
extraction, per-site permission controls, build artifacts, browser verification.
37+
extraction, browser-wide page permission setup, build artifacts, browser verification.
3838
2. `packages/browser-extension-protocol`: versioned, strictly validated messages and
3939
immutable page snapshots shared by the extension, app, and server.
4040
3. `apps/sim/app/extension`: session gate, organization landing, optional workspace picker, app providers,
@@ -57,9 +57,9 @@ other workspace resources or browser-control tools.
5757
and short-lived session storage for selection handoff. Required host access is
5858
limited to the configured Sim origin and to `http(s)://sim/*`, which exists only so
5959
one static redirect rule can send top-level navigations to that host to the Sim link resolver.
60-
- Other HTTP(S) origins are optional grants requested for the current site from a
61-
user gesture. Each grant can be revoked. Keeping the panel open is not a grant
62-
to read every subsequently selected tab.
60+
- HTTP(S) page access is one optional browser-wide grant, requested from a direct
61+
user gesture. The browser owns revocation and restrictions. Approval enables
62+
capture across sites; switching tabs alone does not extract content.
6363
- No history, bookmarks, cookie API, debugger, native messaging, external messaging,
6464
or arbitrary remote code execution. The only network interception is the static
6565
`sim/` redirect rule above.
@@ -126,7 +126,7 @@ An absent backend or account is an unverified gate, not a pass.
126126
- [Chrome activeTab](https://developer.chrome.com/docs/extensions/develop/concepts/activeTab)
127127
and [optional permissions](https://developer.chrome.com/docs/extensions/reference/api/permissions):
128128
temporary access follows user invocation; cross-origin navigation requires fresh
129-
authority. Request persistent access per site only when selected by the user.
129+
authority. Request optional access across HTTP(S) websites once, matching Glean’s all-websites page-context option.
130130
- [Chrome extension security](https://developer.chrome.com/docs/extensions/develop/security-privacy/stay-secure)
131131
and [OWASP extension guidance](https://cheatsheetseries.owasp.org/cheatsheets/Browser_Extension_Vulnerabilities_Cheat_Sheet.html):
132132
minimize privileges and treat all incoming page messages as attacker-controlled.

‎apps/extension/README.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ bun run --cwd apps/extension build
1717

1818
In Chrome, open `chrome://extensions`, enable Developer mode, choose **Load unpacked**, and select `apps/extension/dist`. Copy the extension ID into the Sim server's `BROWSER_EXTENSION_IDS` configuration. It accepts comma-separated Chrome extension IDs. Restart the app after changing that configuration. Unconfigured IDs cannot embed the app.
1919

20-
Click the Sim toolbar icon to open chat and attach the current page. **+ → Current page** adds a fresh snapshot; **Selected text** attaches the highlighted passage. Attachments appear as chips inside the composer. Attach up to three pages or selections to summarize, extract facts, or compare sources. To quote a passage, select it and choose **Ask Sim about selection** from the context menu. Review or remove the attachment before sending. **+ → Site access** opens the extension-owned permission dialog: **Allow access to [site]** grants access only to that site; **Remove access to [site]** revokes it. Persistent site permission never enables background capture.
20+
Click the Sim toolbar icon to open chat and attach the current page. **+ → Current page** adds a fresh snapshot; **Selected text** attaches the highlighted passage. Attachments appear as chips inside the composer. Attach up to three pages or selections to summarize, extract facts, or compare sources. To quote a passage, select it and choose **Ask Sim about selection** from the context menu. Review or remove the attachment before sending. **+ → Page access** offers **Allow across websites**. Approve the browser prompt once to use pages across HTTP and HTTPS sites without per-site setup. Manage access in the browser’s extension settings. Permission alone never enables background capture.
2121

2222
For local development:
2323

@@ -33,17 +33,17 @@ SIM_EXTENSION_DEV=1 SIM_EXTENSION_ORIGIN=http://localhost:3000 bun run --cwd app
3333
- Type `sim`, press Space, enter the name, and press Enter to open an organization's [Sim link](https://docs.sim.ai/search/sim-links). Chrome can treat bare `sim/<name>` as a search before the redirect rule runs. Typing `http://sim/<name>` once lets Chrome learn the short host in that profile. A trailing slash (`sim/<name>/`) also selects navigation without relying on that history. A single static redirect rule rewrites top-level navigations to `http(s)://sim/*` to `<Sim origin>/sim/*` with the path and query unchanged. The `sim` host permission exists only for that rule: every navigation to that host is redirected before it loads, and no other request is matched or observed. An organization that already serves an intranet host named `sim` should not install this build, since its links would be redirected to Sim.
3434
- The `sim` address-bar keyword (`sim`, then Space) lists matching Sim links while you type and opens what you enter through the same resolver. For these suggestions, the background worker sends the text typed before the first `/` or `?`, and nothing else, unless that text contains a space (a search) or is longer than a link name can be, to `<Sim origin>/api/sim-links/suggestions` with the signed-in session, and the extension's content security policy allows connections to that origin alone. Unlisted links are never suggested.
3535
- **+ → Browser shortcuts** separately opts into recovery for exact Google, Bing, DuckDuckGo, or Yahoo HTTPS search hosts. After a direct Chrome permission grant, dynamic request rules redirect only top-level GET requests with one query parameter containing a whole `sim/<name>` shortcut. Only that value reaches `/sim-links/recover`, which validates it and redirects to the existing authenticated resolver. Ordinary search terms, additional search parameters, subframes, and unsupported inputs are not forwarded. Chrome applies these rules without an extension search-URL observer. Turning a provider off removes its rules while preserving site access; revoking access clears its recovery choice. This does not enable page reference or change the default search provider.
36-
- Optional HTTP/HTTPS site access is requested only by a menu action naming that site. Chrome's `activeTab` access is temporary and does not follow arbitrary new sites.
36+
- Optional HTTP/HTTPS access is requested together by **Allow across websites**, from a direct user action. Chrome's `activeTab` access is temporary and does not follow arbitrary new sites.
3737
- Page capture runs on demand in Chrome's isolated world. It excludes editable fields, inputs, hidden elements, scripts, and embedded documents. It reads only the top frame. PDF viewers and canvas documents may have no accessible text.
3838
- Extraction stops at 50,000 text characters, 150,000 serialized UTF-8 bytes, 15,000 visited nodes, or 150ms. The composer exposes truncation.
3939
- Source URLs omit credentials, query parameters, and fragments. Human-readable text can still contain sensitive information; it is the user-selected material they review and send into their conversation.
4040
- Snapshots stay in memory until handed to Sim and acknowledged or expired after 30 seconds. Extension storage contains only a short-lived intent with a tab/document identity and a SHA-256 URL digest, never raw URLs, captured text, or credentials. Closing a tab or navigating invalidates its pending intent. Sim applies its normal conversation retention once a message is sent.
4141
- No browser history, bookmarks, cookie access, debugger access, remote extension JavaScript, arbitrary network proxy, or background content collection is requested. Incognito use is disabled.
42-
- The iframe bridge checks both the exact configured origin and the exact frame, then validates versioned messages. The hosted composer may request only page capture, selection capture, or the native site-access and browser-shortcut dialogs. Requests require the current conversation nonce and Chrome transient user activation; arbitrary URLs, tabs, script execution, and network operations are never accepted. Permission grants still require a click in the extension-owned dialog. Shortcut settings are advertised separately so older installed shells keep working without the new action.
42+
- The iframe bridge checks both the exact configured origin and the exact frame, then validates versioned messages. The hosted composer may request only page capture, selection capture, or the native site-access and browser-shortcut dialogs. Requests require the current conversation nonce and Chrome transient user activation; arbitrary URLs, tabs, script execution, and network operations are never accepted. Permission grants still require a click in the extension-owned page-access control and browser approval. Shortcut settings are advertised separately so older installed shells keep working without the new action.
4343
- Captures and queued toolbar intents are scoped to the receiving conversation. Changing conversation, workspace, or account discards an unfinished handoff. Captured attachments remain explicit snapshots when the source tab changes.
4444
- The complete hosted document, including portaled source dialogs and menus, is blocked from session replay. Clipboard writing is delegated only to the configured Sim origin. Clipboard reading and microphone capture are not delegated; voice input remains available in the main app.
4545

46-
With **Reference current page** enabled, a composer Send requests a single fresh snapshot for that conversation. The extension stores only the preference in local storage. A tab change does not read any content. Explicit snapshots take precedence; access denial, navigation and timeouts keep the draft unsent. When Chrome hides the active address, **Site access** lets the user enter a site and confirm its origin in Chrome’s permission dialog. The browser grants the selected scheme, host and port. Uploaded screenshot files stay in the hosted app’s normal attachment flow.
46+
With **Reference current page** enabled, a composer Send requests a single fresh snapshot for that conversation. The extension stores only the preference in local storage. A tab change does not read any content. Explicit snapshots take precedence; access denial, navigation and timeouts keep the draft unsent. **Allow across websites** works even when Chrome hides the active address; no address entry is required. The grant covers HTTP and HTTPS sites across tabs until the user revokes or restricts it in browser settings. Uploaded screenshot files stay in the hosted app’s normal attachment flow.
4747

4848
## Verification
4949

‎apps/extension/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sim/extension",
3-
"version": "0.1.3",
3+
"version": "0.1.4",
44
"private": true,
55
"type": "module",
66
"license": "Apache-2.0",

‎apps/extension/scripts/test-e2e.ts‎

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,7 @@ try {
10581058
)
10591059
await panel.bringToFront()
10601060
await openAccess()
1061-
const dialog = panel.getByRole('dialog', { name: 'Site access' })
1061+
const dialog = panel.getByRole('dialog', { name: 'Page access' })
10621062
await expect(dialog).toBeVisible()
10631063
await settleMessages()
10641064
assert(policyErrors.length === 0, `Site access violated CSP: ${policyErrors.join('\n')}`)
@@ -1321,7 +1321,7 @@ try {
13211321
}
13221322
)
13231323
await check(
1324-
'Site access requests only the address the user confirms, without reading the page',
1324+
'Page access asks the browser for website access without reading before approval',
13251325
async () => {
13261326
const source = 'https://private-source.example'
13271327
const privateUrl = `${source}/sensitive-path?token=PRIVATE_URL_SENTINEL#fragment`
@@ -1355,34 +1355,11 @@ try {
13551355
return execute(...args)
13561356
}) as typeof chrome.scripting.executeScript
13571357
})
1358-
await panel.getByRole('button', { name: 'Request site access' }).click()
1359-
const dialog = panel.getByRole('dialog', { name: 'Site access' })
1360-
await expect(dialog).toBeVisible()
1361-
const address = dialog.getByRole('textbox', { name: 'Site address' })
1362-
await expect(address).toHaveValue('')
1363-
const allow = dialog.getByRole('button', { name: /^Allow access/ })
1364-
for (const unsafe of [
1365-
'https://user:password@example.com/',
1366-
'https://*.example.com/',
1367-
'https://%2A.example.com/',
1368-
'https://*.example.com/',
1369-
'<all_urls>',
1370-
'chrome://settings/',
1371-
]) {
1372-
await address.fill(unsafe)
1373-
await expect(allow, `Do not offer to grant access for ${unsafe}`).toHaveAccessibleName(
1374-
'Allow access'
1375-
)
1376-
await expect(allow).toBeDisabled()
1377-
}
1378-
await address.fill('http://intranet.example:8080/private-path')
1379-
await expect(allow).toHaveAccessibleName('Allow access to http://intranet.example:8080')
1380-
const allowedHost = 'https://approved-site.example'
1381-
await address.fill(`${allowedHost}/private-path?token=INPUT_SECRET#fragment`)
1382-
await expect(allow).toHaveAccessibleName(`Allow access to ${allowedHost}`)
1358+
const allow = panel.getByRole('button', { name: 'Allow across websites', exact: true })
1359+
await expect(allow).toBeEnabled()
13831360
assert(
13841361
(await panel.locator('body').getAttribute('data-requested-access')) === null,
1385-
'Typing initiated a permission request'
1362+
'A failed capture initiated a permission request without an explicit action'
13861363
)
13871364
const grantedSites = () =>
13881365
worker.evaluate(async () => ((await chrome.permissions.getAll()).origins ?? []).sort())
@@ -1391,7 +1368,7 @@ try {
13911368
await expect(panel.locator('body')).toHaveAttribute('data-request-gesture', 'true')
13921369
const requested = await panel.locator('body').getAttribute('data-requested-access')
13931370
assert(requested, 'The user action never reached Chrome')
1394-
expect(JSON.parse(requested)).toEqual([{ origins: ['https://approved-site.example:443/*'] }])
1371+
expect(JSON.parse(requested)).toEqual([{ origins: ['https://*/*', 'http://*/*'] }])
13951372
expect(await grantedSites(), 'A site received persistent access without approval').toEqual(
13961373
previousAccess
13971374
)

‎apps/extension/src/capture.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export class SiteAccessRequiredError extends PageCaptureError {
3434
readonly tabId: number,
3535
readonly windowId: number
3636
) {
37-
super('Allow site access to attach this page.')
37+
super('Enable page access once to use pages across websites. ')
3838
}
3939
}
4040

0 commit comments

Comments
 (0)