origin-csp.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. var t = require('assert')
  2. var defaults = require('./utils/defaults')
  3. module.exports = ({extensions, popup, advanced, content}) => {
  4. before(async () => {
  5. await defaults({popup, advanced, content})
  6. await advanced.bringToFront()
  7. // enable path matching
  8. await advanced.evaluate(() => {
  9. document.querySelector('.m-list li:nth-of-type(1) input').value = 'csp-match-path'
  10. document.querySelector('.m-list li:nth-of-type(1) input').dispatchEvent(new Event('keyup'))
  11. })
  12. // there is debounce timeout of 750ms in the options UI
  13. await advanced.waitForTimeout(800)
  14. })
  15. describe('not correct content-type + non matching path', () => {
  16. before(async () => {
  17. await advanced.bringToFront()
  18. // expand origin
  19. if (!await advanced.evaluate(() => document.querySelector('.m-list li:nth-of-type(1)').classList.contains('m-expanded'))) {
  20. await advanced.click('.m-list li:nth-of-type(1)')
  21. }
  22. // enable csp
  23. if (!await advanced.evaluate(() => origins.state.origins['http://localhost:3000'].csp)) {
  24. await advanced.click('.m-list li:nth-of-type(1) .m-switch')
  25. }
  26. // go to page serving content with strict csp
  27. await content.goto('http://localhost:3000/csp-no-header-no-path')
  28. await content.bringToFront()
  29. await content.waitForTimeout(300)
  30. })
  31. it('non matching urls should be skipped', async () => {
  32. t.strictEqual(
  33. await content.evaluate(() => {
  34. try {
  35. window.localStorage
  36. }
  37. catch (err) {
  38. return err.message.split(':')[1].trim()
  39. }
  40. }),
  41. `The document is sandboxed and lacks the 'allow-same-origin' flag.`,
  42. 'localStorage should not be accessible'
  43. )
  44. })
  45. })
  46. describe('correct content-type + non matching path', () => {
  47. before(async () => {
  48. await advanced.bringToFront()
  49. // expand origin
  50. if (!await advanced.evaluate(() => document.querySelector('.m-list li:nth-of-type(1)').classList.contains('m-expanded'))) {
  51. await advanced.click('.m-list li:nth-of-type(1)')
  52. }
  53. // enable csp
  54. if (!await advanced.evaluate(() => origins.state.origins['http://localhost:3000'].csp)) {
  55. await advanced.click('.m-list li:nth-of-type(1) .m-switch')
  56. }
  57. // go to page serving content with strict csp
  58. await content.goto('http://localhost:3000/csp-match-header')
  59. await content.bringToFront()
  60. await content.waitForTimeout(300)
  61. })
  62. it('non matching urls cannot be checked for enabled csp', async () => {
  63. t.strictEqual(
  64. await content.evaluate(() => {
  65. try {
  66. window.localStorage
  67. }
  68. catch (err) {
  69. return err.message.split(':')[1].trim()
  70. }
  71. }),
  72. `The document is sandboxed and lacks the 'allow-same-origin' flag.`,
  73. 'localStorage should not be accessible'
  74. )
  75. })
  76. })
  77. // TEST: localStorage is no longer available even with disabled CSP
  78. describe.skip('not correct content-type + matching path', () => {
  79. before(async () => {
  80. await advanced.bringToFront()
  81. // expand origin
  82. if (!await advanced.evaluate(() => document.querySelector('.m-list li:nth-of-type(1)').classList.contains('m-expanded'))) {
  83. await advanced.click('.m-list li:nth-of-type(1)')
  84. }
  85. // enable csp
  86. if (!await advanced.evaluate(() => origins.state.origins['http://localhost:3000'].csp)) {
  87. await advanced.click('.m-list li:nth-of-type(1) .m-switch')
  88. }
  89. // go to page serving content with strict csp
  90. await content.goto('http://localhost:3000/csp-match-path')
  91. await content.bringToFront()
  92. await content.waitForTimeout(300)
  93. })
  94. it('webRequest.onHeadersReceived event is enabled', async () => {
  95. t.strictEqual(
  96. await content.evaluate(() =>
  97. window.localStorage.toString()
  98. ),
  99. '[object Storage]',
  100. 'localStorage should be accessible'
  101. )
  102. })
  103. })
  104. // TEST: localStorage is no longer available even with disabled CSP
  105. describe.skip('disable - enable - disable', () => {
  106. it('full cycle', async () => {
  107. // 1. disable
  108. await advanced.bringToFront()
  109. // expand origin
  110. if (!await advanced.evaluate(() => document.querySelector('.m-list li:nth-of-type(1)').classList.contains('m-expanded'))) {
  111. await advanced.click('.m-list li:nth-of-type(1)')
  112. }
  113. // disable csp
  114. if (await advanced.evaluate(() => origins.state.origins['http://localhost:3000'].csp)) {
  115. await advanced.click('.m-list li:nth-of-type(1) .m-switch')
  116. }
  117. await advanced.waitForTimeout(300)
  118. // go to page serving content with strict csp
  119. await content.goto('http://localhost:3000/csp-match-path')
  120. await content.bringToFront()
  121. await content.waitForTimeout(300)
  122. t.strictEqual(
  123. await content.evaluate(() => {
  124. try {
  125. window.localStorage
  126. }
  127. catch (err) {
  128. return err.message.split(':')[1].trim()
  129. }
  130. }),
  131. `The document is sandboxed and lacks the 'allow-same-origin' flag.`,
  132. 'localStorage should not be accessible'
  133. )
  134. // 2. enable
  135. await advanced.bringToFront()
  136. // enable csp
  137. if (!await advanced.evaluate(() => origins.state.origins['http://localhost:3000'].csp)) {
  138. await advanced.click('.m-list li:nth-of-type(1) .m-switch')
  139. }
  140. await advanced.waitForTimeout(300)
  141. // go to page serving content with strict csp
  142. await content.goto('http://localhost:3000/csp-match-path')
  143. await content.bringToFront()
  144. await content.waitForTimeout(300)
  145. t.strictEqual(
  146. await content.evaluate(() =>
  147. window.localStorage.toString()
  148. ),
  149. '[object Storage]',
  150. 'localStorage should be accessible'
  151. )
  152. // 3. disable
  153. await advanced.bringToFront()
  154. // disable csp
  155. if (await advanced.evaluate(() => origins.state.origins['http://localhost:3000'].csp)) {
  156. await advanced.click('.m-list li:nth-of-type(1) .m-switch')
  157. }
  158. await advanced.waitForTimeout(300)
  159. // go to page serving content with strict csp
  160. await content.goto('http://localhost:3000/csp-match-path')
  161. await content.bringToFront()
  162. await content.waitForTimeout(300)
  163. t.strictEqual(
  164. await content.evaluate(() => {
  165. try {
  166. window.localStorage
  167. }
  168. catch (err) {
  169. return err.message.split(':')[1].trim()
  170. }
  171. }),
  172. `The document is sandboxed and lacks the 'allow-same-origin' flag.`,
  173. 'localStorage should not be accessible'
  174. )
  175. })
  176. })
  177. describe('persist state', () => {
  178. it('enable csp', async () => {
  179. await advanced.bringToFront()
  180. // expand origin
  181. if (!await advanced.evaluate(() => document.querySelector('.m-list li:nth-of-type(1)').classList.contains('m-expanded'))) {
  182. await advanced.click('.m-list li:nth-of-type(1)')
  183. }
  184. // enable csp
  185. if (!await advanced.evaluate(() => origins.state.origins['http://localhost:3000'].csp)) {
  186. await advanced.click('.m-list li:nth-of-type(1) .m-switch')
  187. }
  188. await advanced.reload()
  189. await advanced.waitForTimeout(300)
  190. // expand origin
  191. await advanced.click('.m-list li:nth-of-type(1)')
  192. t.strictEqual(
  193. await advanced.evaluate(() =>
  194. document.querySelector('.m-list li:nth-of-type(1) .m-switch').classList.contains('is-checked')
  195. ),
  196. true,
  197. 'csp checkbox should be enabled'
  198. )
  199. })
  200. it('disable csp', async () => {
  201. await advanced.bringToFront()
  202. // expand origin
  203. if (!await advanced.evaluate(() => document.querySelector('.m-list li:nth-of-type(1)').classList.contains('m-expanded'))) {
  204. await advanced.click('.m-list li:nth-of-type(1)')
  205. }
  206. // disable csp
  207. if (await advanced.evaluate(() => origins.state.origins['http://localhost:3000'].csp)) {
  208. await advanced.click('.m-list li:nth-of-type(1) .m-switch')
  209. }
  210. await advanced.reload()
  211. await advanced.waitForTimeout(300)
  212. // expand origin
  213. await advanced.click('.m-list li:nth-of-type(1)')
  214. t.strictEqual(
  215. await advanced.evaluate(() =>
  216. document.querySelector('.m-list li:nth-of-type(1) .m-switch').classList.contains('is-checked')
  217. ),
  218. false,
  219. 'csp checkbox should be disabled'
  220. )
  221. })
  222. })
  223. describe('enable csp + suspend the event page', () => {
  224. before(async () => {
  225. await advanced.bringToFront()
  226. // expand origin
  227. if (!await advanced.evaluate(() => document.querySelector('.m-list li:nth-of-type(1)').classList.contains('m-expanded'))) {
  228. await advanced.click('.m-list li:nth-of-type(1)')
  229. }
  230. // enable csp
  231. if (!await advanced.evaluate(() => origins.state.origins['http://localhost:3000'].csp)) {
  232. await advanced.click('.m-list li:nth-of-type(1) .m-switch')
  233. }
  234. // chrome://extensions
  235. await extensions.bringToFront()
  236. // enable developer mode
  237. await extensions.evaluate(() => {
  238. Array.from(
  239. document.querySelector('extensions-manager').shadowRoot
  240. .querySelector('extensions-item-list').shadowRoot
  241. .querySelectorAll('extensions-item'))[0].shadowRoot
  242. .querySelector('#enableToggle').click()
  243. })
  244. // disable the extension
  245. await extensions.evaluate(() => {
  246. Array.from(
  247. document.querySelector('extensions-manager').shadowRoot
  248. .querySelector('extensions-item-list').shadowRoot
  249. .querySelectorAll('extensions-item'))[0].shadowRoot
  250. .querySelector('#enableToggle').click()
  251. })
  252. await extensions.waitForTimeout(300)
  253. // check
  254. t.equal(
  255. await extensions.evaluate(() =>
  256. Array.from(
  257. document.querySelector('extensions-manager').shadowRoot
  258. .querySelector('extensions-item-list').shadowRoot
  259. .querySelectorAll('extensions-item'))[0].shadowRoot
  260. .querySelector('#inspect-views a').innerText
  261. ),
  262. 'background page (Inactive)',
  263. 'background page should be inactive'
  264. )
  265. // go to page serving content with strict csp
  266. await content.goto('http://localhost:3000/csp-match-path')
  267. await content.bringToFront()
  268. await content.waitForTimeout(300)
  269. })
  270. // TEST: localStorage is no longer available even with disabled CSP
  271. it.skip('the tab is reloaded on event page wakeup', async () => {
  272. t.strictEqual(
  273. await content.evaluate(() =>
  274. window.localStorage.toString()
  275. ),
  276. '[object Storage]',
  277. 'localStorage should be accessible'
  278. )
  279. })
  280. })
  281. }