diff --git a/extension/background.js b/extension/background.js index 9b9217b..b9a256a 100644 --- a/extension/background.js +++ b/extension/background.js @@ -8,10 +8,6 @@ const DEFAULTS = { apiBase: 'http://localhost:3000', pollSeconds: 3, - // Chrome match pattern, e.g. "https://*.tradovate.com/*". Empty = whichever - // tab is active in the last focused window — which would mean scraping your - // banking or email tab if you switched to one. Default it to the broker. - targetUrlPattern: 'https://*.tradeify.co/*', // Optional CSS selector — matching elements get their on-screen position // measured alongside the HTML. elementSelector: '', @@ -97,22 +93,27 @@ function pageCapture(selector) { // ── Capture pipeline ──────────────────────────────────────────────────────── -async function pickTab(cfg) { - if (cfg.targetUrlPattern) { - try { - const tabs = await chrome.tabs.query({ url: cfg.targetUrlPattern }); - return tabs.find((t) => /^https?:/.test(t.url || '')); - } catch { - throw new Error(`Invalid target URL pattern: ${cfg.targetUrlPattern}`); - } - } +/** The sites this extension is allowed to touch, taken from the manifest rather + * than from a setting. + * + * These are the same hosts host_permissions grants, so they cannot drift out of + * sync with what the extension can actually read, and adding a firm — which + * means adding its host to the manifest anyway — scopes capture automatically. + * localhost is filtered out: that is the dashboard, and capturing it would just + * mirror our own output back. */ +function firmPatterns() { + return chrome.runtime.getManifest().host_permissions + .filter((p) => !/\/\/(localhost|127\.0\.0\.1)/.test(p)); +} - const [tab] = await chrome.tabs.query({ active: true, lastFocusedWindow: true }); - // chrome://, about:, the Web Store and PDF viewers can't be scripted. - if (!tab || !/^https?:/.test(tab.url || '')) return undefined; - // Skip the dashboard itself, otherwise it just captures its own output. - if (tab.url.startsWith(cfg.apiBase)) return undefined; - return tab; +async function pickTab(cfg) { + const tabs = (await chrome.tabs.query({ url: firmPatterns() })) + .filter((t) => /^https?:/.test(t.url || '')); + if (tabs.length === 0) return undefined; + + // Prefer the one being looked at, so with two firms open the capture follows + // attention rather than tab order. + return tabs.find((t) => t.active) ?? tabs[0]; } async function captureAndSend(cfg) { @@ -245,7 +246,9 @@ function waitForTabLoad(tabId, timeoutMs = 15000) { } async function resolveLocateTab(cfg, request) { - const pattern = request.urlPattern || cfg.targetUrlPattern; + // Every step carries its firm's pattern; the manifest hosts are the fallback + // for a bare request (the CLI's locate without --url). + const pattern = request.urlPattern || firmPatterns(); if (pattern) { const tabs = await chrome.tabs.query({ url: pattern }); const tab = tabs.find((t) => /^https?:/.test(t.url || '')); diff --git a/extension/manifest.json b/extension/manifest.json index 1f240df..819cbe6 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 3, "name": "AutoFirmer Capture", - "version": "0.5.0", + "version": "0.6.0", "description": "Scrapes the HTML of the target tab and posts it to the AutoFirmer dashboard while the AutoBuyer is switched on.", "permissions": ["scripting", "tabs", "storage", "alarms"], "host_permissions": [ diff --git a/extension/popup.html b/extension/popup.html index 28d74f3..b9c758e 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -27,9 +27,6 @@ - - - diff --git a/extension/popup.js b/extension/popup.js index 35c7eaf..aaa593c 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -1,8 +1,7 @@ -const FIELDS = ['apiBase', 'pollSeconds', 'targetUrlPattern', 'elementSelector']; +const FIELDS = ['apiBase', 'pollSeconds', 'elementSelector']; const DEFAULTS = { apiBase: 'http://localhost:3000', pollSeconds: 3, - targetUrlPattern: 'https://*.tradeify.co/*', elementSelector: '', };