electron / electron/forge

"Not allowed to load local resource" for "file://" URI -- but only on npm start, not after it is packaged

Open
#3,098 7 comments 3 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
7.1k
Forks
641
Avg merge
3d 1h
Merged PRs (30d)
30

Description

### Pre-flight checklist

- [X] I have read the [contribution documentation](https://github.com/electron/forge/blob/main/CONTRIBUTING.md) for this project.
- [X] I agree to follow the [code of conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project uses.
- [X] I have searched the issue tracker for a bug that matches the one I want to file, without success.

### Electron Forge version

6.0.3

### Electron version

v21.2.2

### Operating system

Windows 10

### Last known working Electron Forge version

_No response_

### Expected behavior

This should successfully display an image:

- The renderer process tries to display an image using an `` element
- The *url* is formatted using `url.pathToFileURL(path).toString()` e.g. `file:///C:/Users/Christopher/Pictures/screenshot.png`
- The *path* is of an image file which exists on the local fie system, e.g. `C:\Users\Christopher\Pictures\screenshot.png`

The application is based on (i.e. built using) the Webpack Plugin template.

### Actual behavior

This works OK, when the application.exe is launched from the local file system -- after it has been packaged using `npm run package`.

But it fails when it's run using `npm start` which loads the script from a web server (for hot reloading).

The error message in the console is,

- `Not allowed to load local resource: file:///C:/Users/Christopher/Pictures/screenshot.png`

### Steps to reproduce

Try an element like this in the renderer when you load it using `npm start` (but change the path to that of a file which exists on your machine).

- ``

### Additional information

I *guess* that the error message ("Not allowed to load local resource") is coming from Electron not from the web server.

It's a common error message -- but different error causes -- on the Electron site:

- https://github.com/electron/electron/issues?q=+Not+allowed+to+load+local+resource

---

I found I can write a hack as follows which bypasses this problem:

- `convertPathToUrl` encodes any path as a URL using a non-standard `local://` scheme instead of the `file://` scheme
- `registerFileProtocol` is called once on app start to implement support for this non-standard `local://` scheme

```ts
import { protocol } from 'electron';
import url from 'node:url';

// use this to determine whether to hack behaviour because it's running from web server instead of from file system
const isRunningFromWebServer = __dirname.includes(".webpack");

// not defined in https://en.wikipedia.org/wiki/List_of_URI_schemes, used as a hack when running from web server
const schemeName = "local";
const scheme = `${schemeName}://`;

export const convertPathToUrl: (path: string) => string = (path: string) => {
return !isRunningFromWebServer ? url.pathToFileURL(path).toString() : `${scheme}${encodeURIComponent(path)}`;
};

export function registerFileProtocol() {
if (!isRunningFromWebServer) return;
protocol.registerFileProtocol(schemeName, (request, callback) => {
// undo the mangling that was done in convertPathToUrl
const path = decodeURIComponent(request.url.slice(scheme.length));
try {
return callback(path);
} catch (error) {
console.error(`ERROR: registerFileProtocol: Could not get file path: error: ${error}, path: ${path}`);
}
});
}
```

When it's run this causes a different error message i.e.:

- `Refused to load the image '' because it violates the following Content Security Policy directive: "default-src 'self' 'unsafe-inline' data:". Note that 'img-src' was not explicitly set, so 'default-src' is used as a fallback.`

And that error message can be fixed by adding `devContentSecurityPolicy` to the `WebpackPlugin` in `forge.config.ts` to add support for the `local:` scheme to `img-src`:

```ts
plugins: [
new WebpackPlugin({
devContentSecurityPolicy: `default-src 'self' 'unsafe-inline' data:; script-src 'self' 'unsafe-eval' 'unsafe-inline' data:; img-src local:`,
mainConfig,
renderer: {
```

---

So that's kind of OK: I can work with it.
But it's inconvenient for developers to discover this.
The reason I'm using Electron is to read files on the local file system, this was unexpectedly difficult.
So it would be nice if you could find a way to avoid this, in the default build-and-run.
It's bizarre that something (i.e. vanilla `file://` URLs) should work in the released/packaged build but not in the debug/start build.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.