Modifying content security policy

This commit is contained in:
Manoj Vivek 2019-08-09 15:06:14 +05:30
parent 4008e1811c
commit 7d4c6e926e
6 changed files with 76 additions and 4 deletions

View file

@ -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",

View file

@ -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",

View file

@ -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: ["<all_urls>"],
types: ["main_frame", "sub_frame"]
},
['blocking', 'responseHeaders']
);

View file

@ -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('; ');
}

View file

@ -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}`);
});
});
});

View file

@ -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,