1
0
simov 8 жил өмнө
parent
commit
cf82dd79f6

+ 52 - 49
background/detect.js

@@ -5,69 +5,72 @@ md.detect = ({storage: {state}, inject}) => {
 
   var code = `
     JSON.stringify({
-      location: window.location,
-      contentType: document.contentType,
+      url: window.location.href,
+      header: document.contentType,
       loaded: !!window.state,
     })
   `
 
-  var tab = (id) => {
-    chrome.tabs.executeScript(id, {code, runAt: 'document_start'}, (res) => {
-      if (chrome.runtime.lastError) {
-        // origin not allowed
-        return
-      }
-
-      try {
-        var win = JSON.parse(res)
-      }
-      catch (err) {
-        // JSON parse error
-        return
-      }
-
-      if (win.loaded) {
-        // anchor
-        return
-      }
+  var tab = (id, info, tab) => {
+    if (info.status === 'loading') {
+      // try
+      chrome.tabs.executeScript(id, {code, runAt: 'document_start'}, (res) => {
+        if (chrome.runtime.lastError) {
+          // origin not allowed
+          return
+        }
 
-      if (state.header && /text\/(?:x-)?markdown/i.test(win.contentType)) {
-        allowed(id)
-      }
-      else {
-        var path =
-          state.origins[win.location.origin] ||
-          state.origins['*://' + win.location.host] ||
-          state.origins['*://*']
+        try {
+          var win = JSON.parse(res)
+        }
+        catch (err) {
+          // JSON parse error
+          return
+        }
 
-        // ff: webRequest bug - does not match on `hostname:port`
-        if (!path && /Firefox/.test(navigator.userAgent)) {
-          var path =
-            state.origins[win.location.protocol + '//' + win.location.hostname] ||
-            state.origins['*://' + win.location.hostname] ||
-            state.origins['*://*']
+        if (win.loaded) {
+          // anchor
+          return
         }
 
-        if (path && new RegExp(path).test(win.location.href)) {
-          allowed(id)
+        if (match(win.header, win.url)) {
+          if (onwakeup && state.csp) {
+            onwakeup = false
+            chrome.tabs.reload(id)
+          }
+          else {
+            inject()
+          }
         }
-      }
-    })
+      })
+    }
   }
 
-  var allowed = (id) => {
-    if (onwakeup && state.csp) {
-      onwakeup = false
-      chrome.tabs.reload(id)
+  var match = (header, url) => {
+    if (state.header && header && /text\/(?:x-)?markdown/i.test(header)) {
+      return true
     }
     else {
-      inject()
-    }
-  }
+      var location = new URL(url)
 
-  return (id, info, _tab) => {
-    if (info.status === 'loading') {
-      tab(id)
+      var path =
+        state.origins[location.origin] ||
+        state.origins['*://' + location.host] ||
+        state.origins['*://*']
+
+      // ff: webRequest bug - does not match on `hostname:port`
+      if (!path && /Firefox/.test(navigator.userAgent)) {
+        var path =
+          state.origins[location.protocol + '//' + location.hostname] ||
+          state.origins['*://' + location.hostname] ||
+          state.origins['*://*']
+      }
+
+      if (path && new RegExp(path).test(location.href)) {
+        return true
+      }
     }
   }
+
+  return {tab, match}
 }

+ 34 - 17
background/headers.js

@@ -1,21 +1,38 @@
 
-md.headers = ({storage: {state}}) => {
-
-  var callback = ({responseHeaders}) => ({
-    responseHeaders: responseHeaders
-      .filter(({name}) => !state.csp || !/content-security-policy/i.test(name))
-      // ff: markdown `content-type` is not allowed
-      .map((header) => {
-        if (
-          /Firefox/.test(navigator.userAgent) &&
-          header.name.toLowerCase() === 'content-type' &&
-          /text\/(?:x-)?markdown/.test(header.value)
-        ) {
-          header.value = 'text/plain; charset=utf-8'
-        }
-        return header
-      })
-    })
+md.headers = ({storage: {state}, detect}) => {
+
+  var callback = ({method, url, responseHeaders}) => {
+    if (method !== 'GET') {
+      return {responseHeaders}
+    }
+
+    var header = responseHeaders.find(({name}) => /content-type/i.test(name))
+
+    if (!detect.match(header, url)) {
+      return {responseHeaders}
+    }
+
+    if (state.csp) {
+      responseHeaders = responseHeaders
+        .filter(({name}) => !/content-security-policy/i.test(name))
+    }
+
+    if (/Firefox/.test(navigator.userAgent)) {
+      responseHeaders = responseHeaders
+        // ff: markdown `content-type` is not allowed
+        .map((header) => {
+          if (
+            /content-type/i.test(header.name) &&
+            /text\/(?:x-)?markdown/.test(header.value)
+          ) {
+            header.value = 'text/plain; charset=utf-8'
+          }
+          return header
+        })
+    }
+
+    return {responseHeaders}
+  }
 
   var filter = {
     urls: ['<all_urls>'],

+ 2 - 2
background/index.js

@@ -1,9 +1,9 @@
 
 var storage = md.storage(md)
 
-var headers = md.headers({storage})
 var inject = md.inject({storage})
 var detect = md.detect({storage, inject})
+var headers = md.headers({storage, detect})
 var mathjax = md.mathjax()
 
 var compilers = Object.keys(md.compilers)
@@ -15,7 +15,7 @@ var compilers = Object.keys(md.compilers)
 var messages = md.messages({storage, compilers, mathjax, headers})
 
 
-chrome.tabs.onUpdated.addListener(detect)
+chrome.tabs.onUpdated.addListener(detect.tab)
 
 chrome.runtime.onMessage.addListener(messages)
 

+ 32 - 4
test/advanced-csp.js

@@ -20,7 +20,7 @@ module.exports = ({browser, extensions, popup, advanced, content}) => {
     // enable path matching
     await advanced.evaluate(() => {
       document.querySelector('.m-list li:nth-of-type(2) input')
-        .value = 'csp'
+        .value = 'csp-match-path'
       document.querySelector('.m-list li:nth-of-type(2) input')
         .dispatchEvent(new Event('keyup'))
     })
@@ -68,6 +68,34 @@ module.exports = ({browser, extensions, popup, advanced, content}) => {
     })
   })
 
+  describe('strip csp header only on matching content type or url', () => {
+    it('non matching urls should be skipped', async () => {
+      await advanced.bringToFront()
+      // enable csp
+      if (!await advanced.evaluate(() => state.csp)) {
+        await advanced.click('.m-switch:nth-of-type(2)')
+      }
+
+      // go to page serving content with strict csp
+      await content.goto('http://localhost:3000/csp-wrong-path')
+      await content.bringToFront()
+      await content.waitFor('pre')
+
+      t.strictEqual(
+        await content.evaluate(() => {
+          try {
+            window.localStorage
+          }
+          catch (err) {
+            return err.message.split(':')[1].trim()
+          }
+        }),
+        `The document is sandboxed and lacks the 'allow-same-origin' flag.`,
+        'localStorage should not be accessible'
+      )
+    })
+  })
+
   describe('enable csp', () => {
     it('webRequest.onHeadersReceived event is enabled', async () => {
       await advanced.bringToFront()
@@ -77,7 +105,7 @@ module.exports = ({browser, extensions, popup, advanced, content}) => {
       }
 
       // go to page serving content with strict csp
-      await content.goto('http://localhost:3000/csp')
+      await content.goto('http://localhost:3000/csp-match-path')
       await content.bringToFront()
       await content.waitFor('#_html')
 
@@ -100,7 +128,7 @@ module.exports = ({browser, extensions, popup, advanced, content}) => {
       }
 
       // go to page serving content with strict csp
-      await content.goto('http://localhost:3000/csp')
+      await content.goto('http://localhost:3000/csp-match-path')
       await content.bringToFront()
       await content.waitFor('#_html')
 
@@ -144,7 +172,7 @@ module.exports = ({browser, extensions, popup, advanced, content}) => {
       )
 
       // go to page serving content with strict csp
-      await content.goto('http://localhost:3000/csp')
+      await content.goto('http://localhost:3000/csp-match-path')
       await content.bringToFront()
       await content.waitFor('#_html')
 

+ 6 - 1
test/index.js

@@ -80,7 +80,12 @@ describe('markdown-viewer', () => {
             Array(500).fill('lorem ipsum').join(' '),
           ].join('\n\n'))
         }
-        else if (/csp/.test(req.url)) {
+        else if (/csp-match-path/.test(req.url)) {
+          res.setHeader('Content-Security-Policy',
+            `default-src 'none'; style-src 'unsafe-inline'; sandbox`)
+          res.end('# h1')
+        }
+        else if (/csp-wrong-path/.test(req.url)) {
           res.setHeader('Content-Security-Policy',
             `default-src 'none'; style-src 'unsafe-inline'; sandbox`)
           res.end('# h1')