-
Notifications
You must be signed in to change notification settings - Fork 15.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Electron should be able to load local resources with enabled webSecurity #23393
Comments
Strong disagree, loading arbitrary local resources from a remote endpoint is a massive security violation and you should be aware of what you are doing if you intend for that to be possible. The correct way to handle this kind of thing is to expose a custom protocol handler Docs: https://www.electronjs.org/docs/api/protocol#protocolregisterfileprotocolscheme-handler-completion |
@MarshallOfSound sorry but that link doesn't help at all. There's no examples anywhere. Please, help us to figuire this out. What do you mean by specific files? Let's say I'm building a "Media player" app or an "Image viewer app" that dispalys all images on all local disks. How is the app supposed to do that? The electron-builder docs says that it already uses So if the <img src="app://C:/test.jpg"> That doesn't work. Is it because I didn't explicitly allow the app to serve specific file called Are you saying that it's actually impossible to display arbitrary local images with |
@aleksey-hoffman I strongly recommend you read the documentation on that
This is good from a security perspective but not from an developer-understanding perspective
No, see above, read the documentation on the
Kind of, see above answer RE each protocol having a handler which decides this kind of thing
No, I explicitly told you how to do it without turning off To do this securely you want to do some kind of routing thing, pseudo code included below. This code is not supposed to run. const files = {};
registerFileProtocol('my-magic-protocol', (req, cb) => {
const fileId = req.path;
if (files[fileId]) return cb(files[fileId]);
return cb(404);
});
ipcMain.handle('open-file', () => {
const filePath = await dialog.showOpenDialog();
const id = randomID();
files[id] = filePath;
return id;
});
// In Renderer
openFileButton.addEventListener('click', () => {
const id = await ipcRenderer.invoke('open-file');
mediaElem.src = `my-magic-protocol://anystringhere/${id}`;
}); |
@MarshallOfSound thank you very much for taking time and claifying it for me and especially for the example. I think I get it now. For someone who never worked with custom protocols, there was just too many layers of abstraction there to be able to understand how it all works. I did what you told me, and finally managed to make it work with I didn't find a single example on the internet on how to do this properly, every answer I ever found suggested to disable Please tell me if I'm doing something wrong here: Step 1: Create custom protocolMain process:app.on('ready', async () => {
protocol.registerFileProtocol('my-magic-protocol', (request, callback) => {
const url = request.url.replace('my-magic-protocol://getMediaFile/', '')
try {
return callback(url)
}
catch (error) {
console.error(error)
return callback(404)
}
})
... Step 2: get media file using the protocol:Renderer process | Home.vue<img class="file-thumb" data-path="C:/test.jpg"> function setImageSrc () {
const thumbHTMLElements = document.querySelectorAll('.file-thumb')
thumbHTMLElements.forEach(element => {
const path = element.dataset.path
element.src = `my-magic-protocol://getMediaFile/${element.dataset.path}`
})
} That's it. The image will be load even with @MarshallOfSound Could you please clarify 1 more thing, why do I need to put that I would imagine that protocol.registerFileProtocol('my-magic-protocol', (request, callback) => {
if (request.url.includes('my-magic-protocol://OPEN_PREVIEW') {
...
}
else if (request.url.includes('my-magic-protocol://OPEN_IN_NEW_WINDOW') {
...
}
})
app.setAsDefaultProtocolClient('my-magic-protocol') And then:
Is that what it's for? So you could open some file in the app from a URL in a specific way? |
@aleksey-hoffman hazarding a guess for the Thank you for including your example btw, very helpful. |
@cloverich yeah, I'm not sure. I'm using this in my file manger app, so I cannot define an allowlist, it has to load any specified image on the user's drive. I'm not sure how I would check whether a path is safe or not |
|
use docs: https://www.electronjs.org/docs/latest/api/protocol#protocolregisterschemesasprivilegedcustomschemes /**
* First, you need to register your scheme before the app starts.
*/
protocol.registerSchemesAsPrivileged([
{
scheme: 'media',
privileges: {
secure: true,
supportFetchAPI: true,
bypassCSP: true
}
}
]);
// ...
app.whenReady().then(() => {
// ...
/**
* If a request is made over the media protocol, you can hook it here.
* In my case, I'm creating a new request by switching to the file protocol to call a local file.
*/
protocol.handle('media', (req) => {
const pathToMedia = new URL(req.url).pathname;
return net.fetch(`file://${pathToMedia}`);
});
// ...
}); |
@dev2820 Strangely this works for images, but not audio files. Every time the custom protocol is interpreted I get a good response but the EDIT: Always read the documentation!!
I had to define the protocol like this: protocol.registerSchemesAsPrivileged([
{
scheme: "media",
privileges: {
secure: true,
supportFetchAPI: true,
bypassCSP: true,
stream: true
}
}
]); |
@MatijaNovosel @dev2820 |
I Followed the instructions above:
I even added a handler somewhere to verify if it has been handled
and the above always return
I would always get Same when I load it via video src:
|
Preflight Checklist
Issue Details
An Electron app can only display local images (located on the computer) with
webSecurity: false
:Renderer process
Main process
It doesn't make sense to completely disable all security features just to be able to load local images / videos, etc. There's should be a property that allows the app to load local resources without disabling all security features.
Electron Version: All
Operating System: All
Expected Behavior
Electron should be able to load local resources without disabling all security features.
Actual Behavior
Electron cannot load local resources without disabling all security features.
To Reproduce
Create an app with https://github.com/nklayman/vue-cli-plugin-electron-builder
vue create my-app cd my-app vue add electron-builder yarn
Then add an image, e.g. in
App.vue
Open
/dist_electron
and install the app. Then open the console and see the error:The text was updated successfully, but these errors were encountered: