diff --git a/apps/extension/public/manifest.json b/apps/extension/public/manifest.json index 480b0e4c..92d1527e 100644 --- a/apps/extension/public/manifest.json +++ b/apps/extension/public/manifest.json @@ -16,12 +16,12 @@ }, "content_scripts": [ { - "matches": ["https://*/*"], + "matches": ["https://*/*", "http://localhost/*"], "js": ["injected-connection-port.js", "injected-request-listener.js"], "run_at": "document_start" }, { - "matches": ["https://*/*"], + "matches": ["https://*/*", "http://localhost/*"], "js": ["injected-penumbra-global.js"], "run_at": "document_start", "world": "MAIN" diff --git a/apps/extension/src/senders/validate.test.ts b/apps/extension/src/senders/validate.test.ts index 8df6f0f9..bb88c23b 100644 --- a/apps/extension/src/senders/validate.test.ts +++ b/apps/extension/src/senders/validate.test.ts @@ -99,6 +99,36 @@ describe('assertValidSender', () => { expect(() => assertValidSender(invalidProtocol)).toThrow('Sender protocol is not'); }); + it(`throws if sender protocol is http and origin is localhost but not in dev mode`, () => { + globalThis.__DEV__ = true; + const localhostSender: chrome.runtime.MessageSender = { + ...mockValid, + origin: 'http://localhost:8000', + url: 'http://localhost:8000/index.html', + }; + expect(assertValidSender(localhostSender)).toMatchObject(localhostSender); + }); + + it(`succeeds if sender protocol is http and origin is localhost in dev mode`, () => { + globalThis.__DEV__ = true; + const localhostSender: chrome.runtime.MessageSender = { + ...mockValid, + origin: 'http://localhost', + url: 'http://localhost/index.html', + }; + expect(assertValidSender(localhostSender)).toMatchObject(localhostSender); + }); + + it(`succeeds if sender protocol is http and origin is localhost with port specified in dev mode`, () => { + globalThis.__DEV__ = true; + const localhostSender: chrome.runtime.MessageSender = { + ...mockValid, + origin: 'http://localhost:8000', + url: 'http://localhost:8000/index.html', + }; + expect(assertValidSender(localhostSender)).toMatchObject(localhostSender); + }); + it('throws if sender has no URL', () => { const urlless: chrome.runtime.MessageSender = { ...mockValid, diff --git a/apps/extension/src/senders/validate.ts b/apps/extension/src/senders/validate.ts index c7d3feb4..ddf3cbd2 100644 --- a/apps/extension/src/senders/validate.ts +++ b/apps/extension/src/senders/validate.ts @@ -6,13 +6,13 @@ type ValidSender = chrome.runtime.MessageSender & { frameId: 0; documentId: string; tab: chrome.tabs.Tab & { id: number }; - - // the relationship between origin and url is pretty complex. - // just rely on the browser's tools. - origin: `${ValidProtocol}//${string}`; - url: `${ValidProtocol}//${string}/${string}`; + origin: string; + url: string; }; +const isHttpLocalhost = (url: URL): boolean => + url.protocol === 'http:' && url.hostname === 'localhost'; + export const assertValidSender = (sender?: chrome.runtime.MessageSender) => { if (!sender) { throw new Error('Sender undefined'); @@ -34,7 +34,13 @@ export const assertValidSender = (sender?: chrome.runtime.MessageSender) => { if (parsedOrigin.origin !== sender.origin) { throw new Error('Sender origin is invalid'); } - if (!(parsedOrigin.protocol in ValidProtocol)) { + + if ( + !( + parsedOrigin.protocol in ValidProtocol || + (globalThis.__DEV__ && isHttpLocalhost(parsedOrigin)) + ) + ) { throw new Error(`Sender protocol is not ${Object.values(ValidProtocol).join(',')}`); }