security-warnings-spec.ts 7.5 KB

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