From 7d4c6e926ee51cee2914c9e651b4eea43ffcfcf7 Mon Sep 17 00:00:00 2001
From: Manoj Vivek
Date: Fri, 9 Aug 2019 15:06:14 +0530
Subject: [PATCH] Modifying content security policy
---
browser-extension/package-lock.json | 9 +++++++
browser-extension/package.json | 1 +
.../{background.js => background/index.js} | 24 +++++++++++++++--
browser-extension/src/background/utils.js | 15 +++++++++++
.../src/background/utils.test.js | 27 +++++++++++++++++++
browser-extension/webpack.config.js | 4 +--
6 files changed, 76 insertions(+), 4 deletions(-)
rename browser-extension/src/{background.js => background/index.js} (56%)
create mode 100644 browser-extension/src/background/utils.js
create mode 100644 browser-extension/src/background/utils.test.js
diff --git a/browser-extension/package-lock.json b/browser-extension/package-lock.json
index 1415ca2f..3f02dcaf 100644
--- a/browser-extension/package-lock.json
+++ b/browser-extension/package-lock.json
@@ -15918,6 +15918,15 @@
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
},
+ "rewire": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/rewire/-/rewire-4.0.1.tgz",
+ "integrity": "sha512-+7RQ/BYwTieHVXetpKhT11UbfF6v1kGhKFrtZN7UDL2PybMsSt/rpLWeEUGF5Ndsl1D5BxiCB14VDJyoX+noYw==",
+ "dev": true,
+ "requires": {
+ "eslint": "^4.19.1"
+ }
+ },
"rgb-regex": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
diff --git a/browser-extension/package.json b/browser-extension/package.json
index 7c9e2beb..0a825cfc 100644
--- a/browser-extension/package.json
+++ b/browser-extension/package.json
@@ -40,6 +40,7 @@
"enzyme-adapter-react-16": "^1.14.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^24.8.0",
+ "rewire": "^4.0.1",
"sinon": "^7.3.2",
"style-loader": "^0.23.1",
"web-ext-webpack-plugin": "github:hiikezoe/web-ext-webpack-plugin",
diff --git a/browser-extension/src/background.js b/browser-extension/src/background/index.js
similarity index 56%
rename from browser-extension/src/background.js
rename to browser-extension/src/background/index.js
index 2c038bad..93e7ab27 100644
--- a/browser-extension/src/background.js
+++ b/browser-extension/src/background/index.js
@@ -1,6 +1,7 @@
import 'webextension-polyfill';
-import {MESSAGE_TYPES} from './app/commons/postMan';
+import {MESSAGE_TYPES} from '../app/commons/postMan';
import normalizeUrl from 'normalize-url';
+import {processCSPHeader} from './utils';
chrome.browserAction.onClicked.addListener(activeTab => {
const newURL = chrome.runtime.getURL(`/app/index.html?url=${activeTab.url}`);
@@ -13,7 +14,15 @@ function onHeadersReceived(details) {
console.log('currentUrls', currentUrls, details.url, details.responseHeaders && currentUrls[details.url], details.responseHeaders, currentUrls[details.url]);
const normalizedUrl = normalizeUrl(details.url);
if (details.responseHeaders && currentUrls[normalizedUrl]) {
- const newHeaders = removeHeader(details.responseHeaders, 'X-Frame-Options');
+ const extensionURL = chrome.runtime.getURL('/');
+ const CSPHeader = getHeader(details.responseHeaders, 'Content-Security-Policy');
+ const newCSPHeaderValue = processCSPHeader(CSPHeader, extensionURL);
+ let newHeaders = removeHeader(details.responseHeaders, 'Content-Security-Policy');
+ newHeaders = addHeader(newHeaders, 'Content-Security-Policy', newCSPHeaderValue);
+ newHeaders = removeHeader(newHeaders, 'X-Frame-Options');
+ /*console.log('After X-frameOptions removal', newHeaders)
+ newHeaders = addHeader(newHeaders, 'x-frame-options', `allow-from ${extensionURL}`)
+ */
console.log('newHeaders', newHeaders);
return { responseHeaders: newHeaders };
}
@@ -25,10 +34,21 @@ function removeHeader(headers, headerToRemove) {
return headers.filter(({ name }) => name.toLowerCase() != headerToRemove);
}
+function addHeader(headers, name, value) {
+ headers.push({name, value});
+ return headers;
+}
+
+function getHeader(headers, headerToFind) {
+ headerToFind = headerToFind.toLowerCase();
+ return headers.filter(({name}) => name.toLowerCase() === headerToFind)[0];
+}
+
chrome.webRequest.onHeadersReceived.addListener(
onHeadersReceived,
{
urls: [""],
+ types: ["main_frame", "sub_frame"]
},
['blocking', 'responseHeaders']
);
diff --git a/browser-extension/src/background/utils.js b/browser-extension/src/background/utils.js
new file mode 100644
index 00000000..3b5ddaee
--- /dev/null
+++ b/browser-extension/src/background/utils.js
@@ -0,0 +1,15 @@
+export function processCSPHeader(header, extensionURL) {
+ const defaultFrameAccessor = `frame-ancestors ${extensionURL}`;
+ if (!header || !header.value) {
+ return defaultFrameAccessor;
+ }
+ const directives = header.value.split(';').map(value => value.trim()).filter(value => value.length);
+ const frameAccessorDirective = directives.filter(directive => directive.indexOf('frame-ancestors') === 0)[0];
+ if (!frameAccessorDirective) {
+ return [...directives, defaultFrameAccessor].join('; ');
+ }
+ const frameAccessorDirectiveValues = frameAccessorDirective.split(' ').map(value => value.trim()).filter(value => value.length);
+ frameAccessorDirectiveValues.push(extensionURL);
+ const nonFrameAccessorDirectives = directives.filter(directive => directive.indexOf('frame-ancestors') === -1);
+ return [...nonFrameAccessorDirectives, frameAccessorDirectiveValues.join(' ')].join('; ');
+}
\ No newline at end of file
diff --git a/browser-extension/src/background/utils.test.js b/browser-extension/src/background/utils.test.js
new file mode 100644
index 00000000..4a2d0504
--- /dev/null
+++ b/browser-extension/src/background/utils.test.js
@@ -0,0 +1,27 @@
+import {expect} from 'chai';
+import {processCSPHeader} from './utils';
+
+describe('background/utils', () => {
+ describe('processCSPHeader', () => {
+ const extensionURL = 'chrome-extension://ahichoemcjmdgdojboecnokgfolkmfmo/';
+
+ it('should return the frame-accessor director if the response header is null', () => {
+ const result = processCSPHeader(null, extensionURL);
+ expect(result).to.be.equals(`frame-ancestors ${extensionURL}`);
+ });
+
+ it('should return the frame-accessor directive in addition to the existing directives', () => {
+ const oldValue = "default-src 'self';"
+ const result = processCSPHeader({name: 'Content-Security-Policy', value: oldValue}, extensionURL);
+ expect(result).to.be.equals(`${oldValue} frame-ancestors ${extensionURL}`);
+ });
+
+ it('should append the current source the existing frame-accessor directive', () => {
+ const oldValue = "upgrade-insecure-requests; frame-ancestors 'self' https://stackexchange.com"
+ const result = processCSPHeader({name: 'Content-Security-Policy', value: oldValue}, extensionURL);
+ expect(result).to.be.equals(`${oldValue} ${extensionURL}`);
+ });
+
+ });
+});
+
diff --git a/browser-extension/webpack.config.js b/browser-extension/webpack.config.js
index 15c7eef3..7a032fd6 100755
--- a/browser-extension/webpack.config.js
+++ b/browser-extension/webpack.config.js
@@ -4,7 +4,7 @@ const path = require('path');
module.exports = {
entry: {
- background: ['./src/background.js'],
+ background: ['./src/background'],
app: ['./src/app/index.js']
},
output: {
@@ -32,7 +32,7 @@ module.exports = {
options: {
modules: {
mode: 'local',
- localIdentName: '[path][name]__[local]--[hash:base64:5]',
+ localIdentName: '[name]__[local]--[hash:base64:5]',
},
/* importLoaders: 1,
sourceMap: true,