lxieyang / chrome-extension-boilerplate-react

A Chrome Extensions boilerplate using React 18 and Webpack 5.
MIT License
3.47k stars 1.08k forks source link

Uncaught Error: SecurityError: An insecure SockJS connection may not be initiated from a page loaded over HTTPS #150

Open chanzer0 opened 1 year ago

chanzer0 commented 1 year ago

I am having a similar issue to this. I am trying to inject a content script into a 3rd party website using https, and receiving the following error:

Uncaught Error: SecurityError: An insecure SockJS connection may not be initiated from a page loaded over HTTPS
    at new SockJS (fanduel.bundle.js:9519:13)
    at new SockJSClient (fanduel.bundle.js:7020:17)
    at initSocket (fanduel.bundle.js:14279:12)
    at ./node_modules/webpack-dev-server/client/index.js?protocol=ws%3A&hostname=localhost&port=3000&pathname=%2Fws&logging=info&overlay=true&reconnect=10&hot=true&live-reload=false (fanduel.bundle.js:7474:55)
    at options.factory (fanduel.bundle.js:17300:31)
    at __webpack_require__ (fanduel.bundle.js:16758:33)
    at fanduel.bundle.js:17875:11
    at fanduel.bundle.js:17880:12

My code is as follows manifest.json

{
    "manifest_version": 3,
    "background": { "service_worker": "background.bundle.js" },
    "action": {},
    "permissions": [
        "identity",
        "storage",
        "tabs",
        "activeTab",
        "scripting",
        "downloads"
    ],
    "host_permissions": ["<all_urls>"]
}

index.js (background script)

chrome.windows.create(
    {
        url: "https://www.fanduel.com/history",
        focused: false,
        state: "minimized",
    },
    async (hiddenWindow) => {
        const tab = hiddenWindow.tabs[0];

        const res = await chrome.scripting.executeScript({
            target: { tabId: tab.id },
            files: ["fanduel.bundle.js"],
        });
        console.log(res);
    }
);

fanduel.js (fanduel.bundle.js)

chrome.runtime.sendMessage({
    message: "from fanduel.js",
});
console.log("from fanduel.js");
window.onload = () => {
    chrome.runtime.sendMessage({
        message: "onload event from fanduel.js",
    });

    console.log("onload event from fanduel.js");
};
chanzer0 commented 1 year ago

The only way to workaround this is to execute npm run build everytime you make a change and re-load the unpacked extension. Hope this helps solving @lxieyang

monokaijs commented 1 year ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image

Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

AriTavakoli commented 1 year ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image

Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

Thank you!! Absolutely clutch.

hadnet commented 1 year ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image

Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

Didn't work, I got [webpack-dev-server] [object Event] error Stack Trace contentScript.bundle.js:8007 (logger) contentScript.bundle.js:8176 (anonymous function) contentScript.bundle.js:7626 (error) contentScript.bun

monokaijs commented 1 year ago

@hadnet can you provide a full log of error?

naps62 commented 1 year ago

FYI, if you testing only against local webpages it's enough to set chrome://flags/#allow-insecure-localhost

hadnet commented 1 year ago

@hadnet can you provide a full log of error?

Too many issues with this bp. Just gave up and built my own using React 18 + TS + Webpack 5

naps62 commented 1 year ago

@hadnet is it public? I'd be interested in incorporating some ideas if you happened to get a better setup

kiennt commented 1 year ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image

Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

That works for me, thanks :+1:

uri3000 commented 1 year ago

It did not work for me I am getting another error:

WebSocket connection to 'wss://github.com/ws' failed: 
WebSocketClient @ WebSocketClient.js:16
initWDSSocket @ WDSSocket.js:23
initSocket @ ErrorOverlayEntry.js:83
executeWithRetryAndTimeout @ retry.js:9
runWithRetry @ retry.js:17
setupOverlay @ ErrorOverlayEntry.js:82
runWithPatchedUrl @ patchUrl.js:29
./node_modules/@pmmmwh/react-refresh-webpack-plugin/client/ErrorOverlayEntry.js @ ErrorOverlayEntry.js:77
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:24
(anonymous) @ startup:7
(anonymous) @ startup:8
index.js:561 [webpack-dev-server] EventΒ {isTrusted: true, type: 'error', target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}
image
monokaijs commented 1 year ago

It did not work for me I am getting another error:

WebSocket connection to 'wss://github.com/ws' failed: 
WebSocketClient @ WebSocketClient.js:16
initWDSSocket @ WDSSocket.js:23
initSocket @ ErrorOverlayEntry.js:83
executeWithRetryAndTimeout @ retry.js:9
runWithRetry @ retry.js:17
setupOverlay @ ErrorOverlayEntry.js:82
runWithPatchedUrl @ patchUrl.js:29
./node_modules/@pmmmwh/react-refresh-webpack-plugin/client/ErrorOverlayEntry.js @ ErrorOverlayEntry.js:77
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:24
(anonymous) @ startup:7
(anonymous) @ startup:8
index.js:561 [webpack-dev-server] EventΒ {isTrusted: true, type: 'error', target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}
image

Verify if it's working by do some modifications. In my case, I just ignore the error, it keeps working as the error is unrelevant (maybe).

ahmedragabshaban commented 1 year ago

For Developers still getting errors This Should Works publicPath: `http://localhost to publicPath: `wss://localhost

Try with wss://, which indicates you want a secure WebSocket connection.

If you have your WebSocket server running with your Web server, it will probably use the same security certificate and you do not need to do anything. If it does not work, please check your WebSocket server documentation about how to add certificates and enable wss://.

  https: true,
    hot: true,
    liveReload: false,
    client: {
      webSocketTransport: 'sockjs',
    },
    webSocketServer: 'sockjs',
    host: 'localhost',
    port: env.PORT,
    static: {
      directory: path.join(__dirname, '../build'),
    },
    devMiddleware: {
      publicPath: `wss://localhost:${env.PORT}/`,
      writeToDisk: true,
    },
MirzaHasnat commented 1 year ago

Make https: true, in webpackdevserver Initialtor in webserver.js file image

cmsax commented 1 year ago

This bug will also cause the issue that content js is not working. After changed webserver.js, it works well.

slc3a2 commented 1 year ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image

Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

Thanks! This works for me.

masihjahangiri commented 1 year ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image

Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

After applying these changes, when you change anything, the dev server reload the page infinitely (infinity loop)

alexburlis commented 1 year ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

After applying these changes, when you change anything, the dev server reload the page infinitely (infinity loop)

Exact same issue. Tried all of the solutions from above and more.

chanzer0 commented 1 year ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image

Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

For anyone still viewing, this solved my issues. The other alternative being building a static package each change (which sucks, but works)

alexburlis commented 1 year ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

For anyone still viewing, this solved my issues. The other alternative being building a static package each change (which sucks, but works)

Did you have any issues with infinite reloading when changing the content script? For some reason it doesn't stop for me.

chanzer0 commented 1 year ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

For anyone still viewing, this solved my issues. The other alternative being building a static package each change (which sucks, but works)

Did you have any issues with infinite reloading when changing the content script? For some reason it doesn't stop for me.

No, the hot reloads worked fine for me afterwards

FSou1 commented 1 year ago

Nothing helped, so I ended up using this boilerplate instead: https://github.com/Jonghakseo/chrome-extension-boilerplate-react-vite

twigs67 commented 1 year ago

I got it working , but the hot loading doesn't seem to work now... or at least for the background page

twigs67 commented 1 year ago

I tested out @FSou1 suggestion and it works without this issue. I would pay someone to fix this issue for this repo.

cworsley4 commented 1 year ago

FYI, if you testing only against local webpages it's enough to set chrome://flags/#allow-insecure-localhost

This is the way.

cmosguy commented 1 year ago

Things still do infinite loops after editing the content/index.js, not sure what to do here.

phamvankhang commented 1 year ago

FYI, if you testing only against local webpages it's enough to set chrome://flags/#allow-insecure-localhost

thanks, change sockjs to ws and enable chrome allow insecure flag it's work for me

aayush-sinha commented 1 year ago

All tabs opened on chrome goes on infinite reload loop once I make any changes on the code. I have already changed sockjs to ws and also enable enabled "allow-insecure-flag"

megatunger commented 1 year ago

Facing infinite reload loop also. It happened when you made any changes. Ended up with turned off Hot Reload

ajzaradichMV commented 1 year ago

Had a similar issue on my end. I'm loading a content script whenever the extension runs which then sends a message back to the popup. For me, when I would load the extension the first time the content script messages would properly get sent but any time loading the extension after the messages would stop.

A combination below seemed to work well for me:

Change webSocketTransport: 'sockjs' to webSocketTransport: 'ws' Change webSocketServer: 'sockjs' to webSocketServer: 'ws' Change https: false to https: true

Termtime commented 1 year ago

Alright, I've been dealing with this issue for a few days and found a solution that worked out for me. The TLDR (with some explanatory comments) for the solution is:

Solution TLDR:

In webserver.js:

Example

# webserver.js
...

// Set hot entry points manually
for (let entryName in config.entry) {
  if (excludeEntriesToHotReload.indexOf(entryName) === -1) {
    // Enable HMR for all entries except those in the "notHMR" list
    // See "Manual entry points" in https://webpack.js.org/guides/hot-module-replacement/#enabling-hmr
    config.entry[entryName] = [
      'webpack/hot/dev-server.js',
      `webpack-dev-server/client/index.js?hot=true&hostname=localhost&port=${env.PORT}`,
    ].concat(config.entry[entryName]);
  }
}

// Add HotModuleReplacementPlugin to plugin list
config.plugins = [new webpack.HotModuleReplacementPlugin({})].concat(
  config.plugins || []
);
...

var server = new WebpackDevServer(
  {
    https: false,
    // We do not enable hot mode because we are defining above HMR only for some entries
    hot: false,
    liveReload: false,
    client: false,
    // From here and below the rest of the options don't need changing, just posted the most important ones here for clarity
    host: 'localhost',
    port: env.PORT,
    static: {
      directory: path.join(__dirname, '../build'),
    },
    devMiddleware: {
      publicPath: `http://localhost:${env.PORT}/`,
      writeToDisk: true,
    },
    ...
  }
)

Explanation

Let me preface my explanation by clarifying I am not an expert and this is what I've come to understand from reading documentation and debugging the issue for a few days.

As I understand it, the issueAn insecure SockJS connection may not be initiated from a page loaded over HTTPS comes from using sockjs as the webSocketServer option in the webserver.js file.

However, if you change webSocketServer to ws you will notice that the error is gone but now you will get an infinite refresh loop whenever you refresh a page or make a change to your code.

This stems from the fact that HMR is enabled for ALL entry points via hot:true in the dev server config. Which includes the modules that should not have HMR enabled, content script being the culprit in this case for the infinite reload. If you open the dev console on the webpage that is reloading you will notice that it is attempting to create a websocket connection to the site that you are on currently, this would usually throw an exception when using sockjs due to it being insecure and stop further code execution, preventing HMR from attempting to get updates (this is why when using sockjs you don't have infinite reload loops), but now that we are using ws and no exception is thrown HMR will try to find updates which it will never get and prompt it to refresh the page in search for updates, causing an infinite loop.

To fix this we declare hot:false and instead define manual entry points for HMR following webpack's documentation. And we also need to explicitly add the HotModuleReplacementPlugin that webpack would automatically add when hot:true.

Closing Notes & Improved implementation

If you want to implement an even better version of HMR + the ability to reload the extension automatically when content or background scripts change, you can use this fork which implements that later feature and apply the changes mentioned to achieve both

habibi4webdesign commented 1 year ago

If you're developing in a modern browser that supports native WebSockets and you don't need to worry about network restrictions, you can consider using native WebSockets instead of SockJS. You can do this by setting the client.webSocketTransport and webSocketServer options to 'ws'

azretkenzhaliev commented 1 year ago

Faced the same issue, I applied:

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image

Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

and then I also got:

It did not work for me I am getting another error:

WebSocket connection to 'wss://github.com/ws' failed: 
WebSocketClient @ WebSocketClient.js:16
initWDSSocket @ WDSSocket.js:23
initSocket @ ErrorOverlayEntry.js:83
executeWithRetryAndTimeout @ retry.js:9
runWithRetry @ retry.js:17
setupOverlay @ ErrorOverlayEntry.js:82
runWithPatchedUrl @ patchUrl.js:29
./node_modules/@pmmmwh/react-refresh-webpack-plugin/client/ErrorOverlayEntry.js @ ErrorOverlayEntry.js:77
options.factory @ react refresh:6
__webpack_require__ @ bootstrap:24
(anonymous) @ startup:7
(anonymous) @ startup:8
index.js:561 [webpack-dev-server] EventΒ {isTrusted: true, type: 'error', target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …}
image
azretkenzhaliev commented 1 year ago

Then, I applied several more suggestions:

Make https: true, in webpackdevserver Initialtor in webserver.js file image

FYI, if you testing only against local webpages it's enough to set chrome://flags/#allow-insecure-localhost

For Developers still getting errors This Should Works publicPath: http://localhost to publicPath: wss://localhost

Try with wss://, which indicates you want a secure WebSocket connection.

And it worked πŸ‘πŸΌ

Colliot2 commented 10 months ago

A quick fix for this. In utils of project's root folder, look for webserver.js. Change server.client.webSocketTransport to ws. Change server.webSocketServer to ws. So it will look like this: image Restart dev server and the problem is gone πŸŽ‰πŸŽ‰πŸŽ‰

After applying these changes, when you change anything, the dev server reload the page infinitely (infinity loop)

Same. Would definitely recommend not using this boilerplate due to this reason.

Austin5925 commented 4 months ago

Then, I applied several more suggestions:

Make https: true, in webpackdevserver Initialtor in webserver.js file image

FYI, if you testing only against local webpages it's enough to set chrome://flags/#allow-insecure-localhost

For Developers still getting errors This Should Works publicPath: http://localhost to publicPath: wss://localhost Try with wss://, which indicates you want a secure WebSocket connection.

And it worked πŸ‘πŸΌ

I tried your solution but that didn't work for me. I still have the issue that wobsocket connection to xxx failed.

Anonymous-Humanoid commented 4 months ago

If you're willing to settle with recompiling files on save but no fancy client-side hot reloading, you can remove @pmmmwh/react-refresh-webpack-plugin and react-refresh-typescript, update your webpack configuration accordingly and use the following web server configuration:

let server = new WebpackDevServer(
    {
        hot: false,
        liveReload: false,
        client: false,
        webSocketServer: false,
        bonjour: false,
        static: {
            directory: path.join(__dirname, '..', 'build'),
        },
        devMiddleware: {
            writeToDisk: true,
        },
    },
    compiler
);

With this, your tsconfig.json may complain about something along the lines of "bonjour is an implicit entry point", which can be fixed as follows:

{
    "compilerOptions": {
        // ...
        "typeRoots": ["./node_modules/@types"],
    },
    // ...
}

With Chrome extensions in particular, there are many instances where recompiling files and reloading them is enough to see changes. However, with scripts, such as state-dependent React components or content scripts, reloading the extension may be necessary. Depends on your use-case.