security-warnings-spec.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. import { expect } from 'chai';
  2. import * as http from 'http';
  3. import * as fs from 'fs';
  4. import * as path from 'path';
  5. import * as url from 'url';
  6. import { BrowserWindow, WebPreferences } from 'electron';
  7. import { closeWindow } from './window-helpers';
  8. import { AddressInfo } from 'net';
  9. import { emittedUntil } from './events-helpers';
  10. const messageContainsSecurityWarning = (event: Event, level: number, message: string) => {
  11. return message.indexOf('Electron Security Warning') > -1;
  12. };
  13. const isLoaded = (event: Event, level: number, message: string) => {
  14. return (message === 'loaded');
  15. };
  16. describe('security warnings', () => {
  17. let server: http.Server;
  18. let w: BrowserWindow;
  19. let useCsp = true;
  20. let useTrustedTypes = false;
  21. let serverUrl: string;
  22. before((done) => {
  23. // Create HTTP Server
  24. server = http.createServer((request, response) => {
  25. const uri = url.parse(request.url!).pathname!;
  26. let filename = path.join(__dirname, '..', 'spec', 'fixtures', 'pages', uri);
  27. fs.stat(filename, (error, stats) => {
  28. if (error) {
  29. response.writeHead(404, { 'Content-Type': 'text/plain' });
  30. response.end();
  31. return;
  32. }
  33. if (stats.isDirectory()) {
  34. filename += '/index.html';
  35. }
  36. fs.readFile(filename, 'binary', (err, file) => {
  37. if (err) {
  38. response.writeHead(404, { 'Content-Type': 'text/plain' });
  39. response.end();
  40. return;
  41. }
  42. const cspHeaders = [
  43. ...(useCsp ? ['script-src \'self\' \'unsafe-inline\''] : []),
  44. ...(useTrustedTypes ? ['require-trusted-types-for \'script\'; trusted-types *'] : [])
  45. ];
  46. response.writeHead(200, { 'Content-Security-Policy': cspHeaders });
  47. response.write(file, 'binary');
  48. response.end();
  49. });
  50. });
  51. }).listen(0, '127.0.0.1', () => {
  52. serverUrl = `http://127.0.0.1:${(server.address() as AddressInfo).port}`;
  53. done();
  54. });
  55. });
  56. after(() => {
  57. // Close server
  58. server.close();
  59. server = null as unknown as any;
  60. });
  61. afterEach(async () => {
  62. useCsp = true;
  63. useTrustedTypes = false;
  64. await closeWindow(w);
  65. w = null as unknown as any;
  66. });
  67. it('should warn about Node.js integration with remote content', async () => {
  68. w = new BrowserWindow({
  69. show: false,
  70. webPreferences: {
  71. nodeIntegration: true
  72. }
  73. });
  74. w.loadURL(`${serverUrl}/base-page-security.html`);
  75. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  76. expect(message).to.include('Node.js Integration with Remote Content');
  77. });
  78. it('should not warn about Node.js integration with remote content from localhost', async () => {
  79. w = new BrowserWindow({
  80. show: false,
  81. webPreferences: {
  82. nodeIntegration: true
  83. }
  84. });
  85. w.loadURL(`${serverUrl}/base-page-security-onload-message.html`);
  86. const [,, message] = await emittedUntil(w.webContents, 'console-message', isLoaded);
  87. expect(message).to.not.include('Node.js Integration with Remote Content');
  88. });
  89. const generateSpecs = (description: string, webPreferences: WebPreferences) => {
  90. describe(description, () => {
  91. it('should warn about disabled webSecurity', async () => {
  92. w = new BrowserWindow({
  93. show: false,
  94. webPreferences: {
  95. webSecurity: false,
  96. ...webPreferences
  97. }
  98. });
  99. w.loadURL(`${serverUrl}/base-page-security.html`);
  100. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  101. expect(message).to.include('Disabled webSecurity');
  102. });
  103. it('should warn about insecure Content-Security-Policy', async () => {
  104. w = new BrowserWindow({
  105. show: false,
  106. webPreferences: {
  107. enableRemoteModule: false,
  108. ...webPreferences
  109. }
  110. });
  111. useCsp = false;
  112. w.loadURL(`${serverUrl}/base-page-security.html`);
  113. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  114. expect(message).to.include('Insecure Content-Security-Policy');
  115. });
  116. it('should warn about insecure Content-Security-Policy (Trusted Types)', async () => {
  117. w = new BrowserWindow({
  118. show: false,
  119. webPreferences: {
  120. enableRemoteModule: false,
  121. ...webPreferences
  122. }
  123. });
  124. useCsp = false;
  125. useTrustedTypes = true;
  126. w.loadURL(`${serverUrl}/base-page-security.html`);
  127. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  128. expect(message).to.include('Insecure Content-Security-Policy');
  129. });
  130. it('should warn about allowRunningInsecureContent', async () => {
  131. w = new BrowserWindow({
  132. show: false,
  133. webPreferences: {
  134. allowRunningInsecureContent: true,
  135. ...webPreferences
  136. }
  137. });
  138. w.loadURL(`${serverUrl}/base-page-security.html`);
  139. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  140. expect(message).to.include('allowRunningInsecureContent');
  141. });
  142. it('should warn about experimentalFeatures', async () => {
  143. w = new BrowserWindow({
  144. show: false,
  145. webPreferences: {
  146. experimentalFeatures: true,
  147. ...webPreferences
  148. }
  149. });
  150. w.loadURL(`${serverUrl}/base-page-security.html`);
  151. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  152. expect(message).to.include('experimentalFeatures');
  153. });
  154. it('should warn about enableBlinkFeatures', async () => {
  155. w = new BrowserWindow({
  156. show: false,
  157. webPreferences: {
  158. enableBlinkFeatures: 'my-cool-feature',
  159. ...webPreferences
  160. }
  161. });
  162. w.loadURL(`${serverUrl}/base-page-security.html`);
  163. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  164. expect(message).to.include('enableBlinkFeatures');
  165. });
  166. it('should warn about allowpopups', async () => {
  167. w = new BrowserWindow({
  168. show: false,
  169. webPreferences
  170. });
  171. w.loadURL(`${serverUrl}/webview-allowpopups.html`);
  172. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  173. expect(message).to.include('allowpopups');
  174. });
  175. it('should warn about insecure resources', async () => {
  176. w = new BrowserWindow({
  177. show: false,
  178. webPreferences: { ...webPreferences }
  179. });
  180. w.loadURL(`${serverUrl}/insecure-resources.html`);
  181. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  182. expect(message).to.include('Insecure Resources');
  183. });
  184. it('should not warn about loading insecure-resources.html from localhost', async () => {
  185. w = new BrowserWindow({
  186. show: false,
  187. webPreferences
  188. });
  189. w.loadURL(`${serverUrl}/insecure-resources.html`);
  190. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  191. expect(message).to.not.include('insecure-resources.html');
  192. });
  193. it('should warn about enabled remote module with remote content', async () => {
  194. w = new BrowserWindow({
  195. show: false,
  196. webPreferences
  197. });
  198. w.loadURL(`${serverUrl}/base-page-security.html`);
  199. const [,, message] = await emittedUntil(w.webContents, 'console-message', messageContainsSecurityWarning);
  200. expect(message).to.include('enableRemoteModule');
  201. });
  202. it('should not warn about enabled remote module with remote content from localhost', async () => {
  203. w = new BrowserWindow({
  204. show: false,
  205. webPreferences
  206. });
  207. w.loadURL(`${serverUrl}/base-page-security-onload-message.html`);
  208. const [,, message] = await emittedUntil(w.webContents, 'console-message', isLoaded);
  209. expect(message).to.not.include('enableRemoteModule');
  210. });
  211. });
  212. };
  213. generateSpecs('without sandbox', {});
  214. generateSpecs('with sandbox', { sandbox: true });
  215. });