Skip to content
Snippets Groups Projects
state-manager.js 5.45 KiB
Newer Older
/**
 * State Manager
 * Belongs to Decentraleyes.
 *
 * @author      Thomas Rientjes
 * @since       2017-03-10
 * @license     MPL 2.0
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 */

'use strict';

/**
 * State Manager
 */

var stateManager = {};

/**
 * Constants
 */

const BLOCKING_ACTION = 'blocking';
const HOST_PREFIX = '*://';
const HOST_SUFFIX = '/*';
const JAVASCRIPT_REQUEST_TYPE = 'script';
const REQUEST_HEADERS = 'requestHeaders';
const XML_HTTP_REQUEST_TYPE = 'xmlhttprequest';

/**
 * Public Methods
 */

stateManager.registerInjection = function (tabIdentifier, injection) {

    let injectionIdentifier, registeredTab, injectionCount;

    injectionIdentifier = injection.source + injection.path + injection.version;
    registeredTab = stateManager.tabs[tabIdentifier];

    registeredTab.injections[injectionIdentifier] = injection;
    injectionCount = Object.keys(registeredTab.injections).length || 0;

    if (injectionCount > 0) {

        chrome.browserAction.setBadgeText({
            tabId: tabIdentifier,
            text: injectionCount.toString()
        });

    } else {

        chrome.browserAction.setBadgeText({
            tabId: tabIdentifier,
            text: ''
        });
    }

    if (isNaN(interceptor.amountInjected)) {

        chrome.storage.local.get('amountInjected', function (items) {

            interceptor.amountInjected = items.amountInjected;

            chrome.storage.local.set({
                'amountInjected': ++interceptor.amountInjected
            });
        });

    } else {

        chrome.storage.local.set({
            'amountInjected': ++interceptor.amountInjected
        });
    }
};

stateManager.addDomainToWhitelist = function (domain) {

    return new Promise((resolve) => {

        let whitelistedDomains = requestAnalyzer.whitelistedDomains;
        whitelistedDomains[domain] = true;

        chrome.storage.local.set({whitelistedDomains}, resolve);
    });
};

stateManager.deleteDomainFromWhitelist = function (domain) {

    return new Promise((resolve) => {

        let whitelistedDomains = requestAnalyzer.whitelistedDomains;
        delete whitelistedDomains[domain];

        chrome.storage.local.set({whitelistedDomains}, resolve);
    });
};

/**
 * Private Methods
 */

stateManager._createTab = function (tab) {

    let tabIdentifier, requestFilters;

    tabIdentifier = tab.id;

    stateManager.tabs[tabIdentifier] = {
        'injections': {}
    };

    requestFilters = {

        'tabId': tabIdentifier,
        'types': stateManager.validTypes,
        'urls': stateManager.validHosts
    };

    chrome.webRequest.onBeforeRequest.addListener(function (requestDetails) {

        return new Promise((resolve) => {

            browser.tabs.get(tabIdentifier).then(function (tab) {
                resolve(interceptor.handleRequest(requestDetails, tabIdentifier, tab));
            });
        });

    }, requestFilters, [BLOCKING_ACTION]);
};

stateManager._removeTab = function (tabIdentifier) {
    delete stateManager.tabs[tabIdentifier];
};

stateManager._updateTab = function (details) {

    let tabIdentifier, frameIdentifier;

    tabIdentifier = details.tabId;
    frameIdentifier = details.frameId;

    if (tabIdentifier === -1 || frameIdentifier !== 0) {
        return;
    }

    chrome.browserAction.setBadgeText({
        tabId: tabIdentifier,
        text: ''
    });

    if (stateManager.tabs[tabIdentifier]) {
        stateManager.tabs[tabIdentifier].injections = {};
    }
};

/**
 * Initializations
 */

stateManager.requests = {};
stateManager.tabs = {};

stateManager.validTypes = [

    JAVASCRIPT_REQUEST_TYPE,
    XML_HTTP_REQUEST_TYPE
];

stateManager.validHosts = [];

for (let mapping in mappings) {

    if (!mappings.hasOwnProperty(mapping)) {
        continue;
    }

    let supportedHost = HOST_PREFIX + mapping + HOST_SUFFIX;
    stateManager.validHosts.push(supportedHost);
}

chrome.tabs.query({}, function (tabs) {
    tabs.forEach(stateManager._createTab);
});

/**
 * Event Handlers
 */

chrome.tabs.onCreated.addListener(stateManager._createTab);
chrome.tabs.onRemoved.addListener(stateManager._removeTab);

chrome.webNavigation.onCommitted.addListener(stateManager._updateTab, {
    url: [{urlContains: ':'}]
});

chrome.webRequest.onErrorOccurred.addListener(function (requestDetails) {

    if (stateManager.requests[requestDetails.requestId]) {
        delete stateManager.requests[requestDetails.requestId];
    }

}, {'urls': ['*://*/*']});

chrome.webRequest.onBeforeRedirect.addListener(function (requestDetails) {

    let knownRequest = stateManager.requests[requestDetails.requestId];

    if (knownRequest) {

        stateManager.registerInjection(knownRequest.tabIdentifier, knownRequest.targetDetails);
        delete stateManager.requests[requestDetails.requestId];
    }

}, {'urls': ['*://*/*']});

chrome.webRequest.onBeforeSendHeaders.addListener(function (requestDetails) {

    for (let i = 0; i < requestDetails.requestHeaders.length; ++i) {

        if (requestDetails.requestHeaders[i].name === 'Origin') {
            requestDetails.requestHeaders.splice(i, 1);
        } else if (requestDetails.requestHeaders[i].name === 'Referer') {
            requestDetails.requestHeaders.splice(i, 1);
        }
    }

    return {requestHeaders: requestDetails.requestHeaders};

}, {urls: stateManager.validHosts}, [BLOCKING_ACTION, REQUEST_HEADERS]);