origin-csp.js 9.5 KB

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