Suite à la documentation de l'API , je ne comprends pas comment définir un en-tête HTTP Content-Security-Policy pour le rendu de mon application Electron. Je reçois toujours un avertissement dans les outils de développement.
J'ai essayé:
1) Copier/coller le code dans l'API Doc, à l'aveuglette:
app.on('ready', () => {
const {session} = require('electron')
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({responseHeaders: `default-src 'self'`})
})
win = new BrowserWindow(...)
win.loadUrl(...)
}
(Au fait, je ne comprends pas pourquoi "Content-Security-Policy:" est manquant dans la chaîne. Mais l'ajouter ne change rien.)
2) Modification de la session du moteur de rendu avec le même code:
win = new BrowserWindow(...)
win.loadUrl(...)
const ses = win.webContents.session;
ses.webRequest.onHeadersReceived((details, callback) => {
callback({responseHeaders: `default-src 'self'`})
})
3) Ajoutez un en-tête supplémentaire au moteur de rendu:
win = new BrowserWindow(...)
win.loadURL(`file://${__dirname}/renderer.html`,{
extraHeaders: `Content-Security-Policy: default-src 'self'`
});
...
La seule chose qui fonctionne consiste à utiliser une balise META dans le fichier HTML de rendu:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'>
Pas sûr pourquoi la documentation contient ce code cassé. Cela m'a dérouté mais j'ai trouvé une solution efficace par essais et erreurs:
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({ responseHeaders: Object.assign({
"Content-Security-Policy": [ "default-src 'self'" ]
}, details.responseHeaders)});
});
Ainsi, l'argument d'en-tête doit être un objet ayant la même structure que les en-têtes d'origine reçus dans details.responseHeaders
. Et les en-têtes d'origine doivent également être inclus dans l'objet transmis car cet objet semble remplacer complètement les en-têtes de réponse d'origine.
L'option extraHeaders
ne s'applique pas aux en-têtes de réponse. Il s’agit des en-têtes de requête envoyés au serveur.
Si votre objectif est de pouvoir utiliser CSP à la fois en mode dev (avec des ressources chargées par le protocole http://
) et en mode prod (protocole file://
), voici comment procéder:
Tout d’abord, supprimez la méta Content-Security-Policy
de src/index.html
- nous devons l’injecter uniquement pour le mode prod, car
onHeadersReceived
ne fonctionnera pas pour le protocole file://
car Electron docs confirm , et aussi parce que src/index.html
pour le mode Dev, il remplacera onHeadersReceived
au moins pour une partie des ressources, et pour le mode Dev, nous avons besoin de paramètres différents.Ensuite, nous pouvons l’injecter en mode Prod avec gulp-inject :
// in project dir
npm install --save-dev gulp-inject gulp
// src/index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<base href="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- inject:prod-headers -->
<!-- src/prod-headers.html content will be injected here -->
<!-- endinject -->
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root>Loading...</app-root>
</body>
</html>
// src/prod-headers.html
<meta http-equiv="Content-Security-Policy" content="default-src 'self'>
// gulpfile.js
var gulp = require('gulp');
var inject = require('gulp-inject');
gulp.task('insert-prod-headers', function () {
return gulp.src('./dist/index.html')
.pipe(inject(gulp.src('./src/prod-headers.html'), {
starttag: '<!-- inject:prod-headers -->',
transform: function (filePath, file) {
// return file contents as string
return file.contents.toString('utf8')
}
}))
.pipe(gulp.dest('./dist'));
});
Ensuite, assurez-vous que npx gulp insert-prod-headers
est exécuté après, par exemple. ng build
génère dist/index.html
.
Et pour le mode dev, utilisons onHeadersReceived de la même manière que Electron docs example :
const args = process.argv.slice(1);
const devMode = args.some((val) => val === '--serve');
app.on('ready', () => {
if (devMode) {
const {session} = require('electron')
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
callback({responseHeaders: `default-src http: ws:`})
})
}
win = new BrowserWindow(...)
win.loadUrl(...)
}
Cette solution a été testée sur Electron 4.0.3.