/*******************************************************************************

    
    Cloud Firewall - a browser extension/addon that allows users to block connections 
    to sites, pages and web resources (images, videos, etc) hosted in major cloud services
    if the user wishes to do so.
    Copyright (C) 2019 Niklas Poslovski
    Copyright (C) 2019 Gokulakrishna Sudharsan

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Home: https://notabug.org/nipos/cloud-firewall
*/
chrome.runtime.onInstalled.addListener(onInstalledfn);
var storageArea = chrome.storage.local;
var settingsToggles = {};
var siteExceptions = {};
//In first version release of this addon, I make an intentional choice not to persist this setting
// and allow it to reset to false every time browser restarts. This way user can choose to toggle OFF or
// ON on the block switch for each cloud provider.
settingsToggles.google = false;
settingsToggles.amazon = false;
settingsToggles.facebook = false;
settingsToggles.apple = false;
settingsToggles.microsoft = false;
settingsToggles.cloudflare = false;
settingsToggles.notInList = false; //always
var log = {};
log.enabled = false;
//console.log(resp.shouldPersistRules);
var languages = ['de','en'];
var helplink;
var privacylink;
if(languages.includes(browser.i18n.getUILanguage())) helplink = 'help.' + browser.i18n.getUILanguage() + '.html';
else helplink = 'help.en.html';

function getSettingStates() {
browser.storage.local.get(["settingsToggles","siteExceptions"],function(obj) {
if(!obj.settingsToggles) obj.settingsToggles = {};
for(let company in settingsToggles) {
if(company === "notInList") continue;
if(obj.settingsToggles.hasOwnProperty(company) && typeof obj.settingsToggles[company] !== undefined) settingsToggles[company] = obj.settingsToggles[company];
}
if(obj.siteExceptions) siteExceptions = obj.siteExceptions;
else siteExceptions = {};
if(log.enabled) console.log("Cloud Firewall: Settings Toggle state : "+JSON.stringify(settingsToggles));
setupRequestListener();
});
}

getSettingStates();

var shouldStoreCache = true;

var counts = {};
counts.apple = 0;
counts.google = 0;
counts.facebook = 0;
counts.amazon = 0;
counts.microsoft = 0;
counts.notInList = 0;
counts.cloudflare = 0;

var temp_IP_array = [];
var cache = {};
cache.google = {};
cache.amazon = {};
cache.facebook = {};
cache.microsoft = {};
cache.apple = {};
cache.google.hosts = [];
cache.amazon.hosts = [];
cache.facebook.hosts = [];
cache.microsoft.hosts = [];
cache.apple.hosts = [];
cache.cloudflare = {};
cache.cloudflare.hosts = [];
cache.notInList = {};
cache.notInList.hosts = [];

chrome.storage.local.get({ counts: {} }, function(obj) {
  if (!!obj.counts && obj.counts.hasOwnProperty("apple")) {
    Object.assign(counts, obj.counts);
    for (let company in counts) {
      if (!counts[company]) {
        counts[company] = 0;
      }
    }
  }
});

function isInKnownhostnames(hostname, company) {
  let result = false;
  for (let el of knownbig5domains[company]) {
    if(hostname == el || hostname.includes("."+el)) {
result = true;
      break;
    }
  }
  return result;
}

function checkIPisinRange(addresses, whichCompany) {
  //  var a = performance.now()
  var result = {};
  result.shouldCancel = false;
  result.whichCompany = "notInList";
  var toLookup = "";
  //looking up both addresses take much time, let's look up first one for now in this version
  toLookup = addresses[0];

  var parsed_addr = ipaddr.process(toLookup);
  var addressType = parsed_addr.kind();
  // for (var address of addresses) {
  if (
    check_many_cidrs(
      parsed_addr,
      addressType,
      addressranges[whichCompany][addressType]
    )
  ) {
    result.shouldCancel = true;
    counts[whichCompany] += 1;
    result.whichCompany = whichCompany;
  }
  // }
  //console.log((performance.now() - a)/1000)
  //console.log(result);
  return result;
}
var timetaken = [];

var isDecentralEyesUserOption = false;
chrome.storage.local.get({ isDecentralEyesUserOption: false }, function(obj) {
  isDecentralEyesUserOption = obj.isDecentralEyesUserOption;
});
/*function showPerTabCount(tabId, counts) {
  var details = { tabId: tabId, text: String(counts.google) };
  browser.browserAction.setBadgeText(details);

  //For Android Firefox, icon is not shown but title is shown in menu entry.
  // So set the title with current tab count
  let title = "(" + counts.google + ")";
  details.title = title;
  browser.browserAction.setTitle(details);
}*/

chrome.tabs.onRemoved.addListener(handleRemoved);

//Only for firefox, see issue #2
function handleRemoved(tabId, removeInfo) {
  if (log.enabled) {
    console.log(countsforBadgeText);
  }

  countsforBadgeText = countsforBadgeText.filter(function(o) {
    //console.log(o);
    let TabNo = o.tabIdMainFrameUrl;
    if (!TabNo) {
      TabNo = -1;
    }
    return TabNo !== tabId;
  });
  if (log.enabled) {
    console.log(countsforBadgeText);
  }
}

function getMainframeUrlfromResource(details,hostonly=false) {
  //console.log(JSON.stringify(details));
  let mainframeUrl = "";
  if (!!details.frameId && details.frameId > 0) {
    let index = details.frameAncestors.findIndex(el => el.frameId === 0);
    mainframeUrl = details.frameAncestors[index].url;
    /* if(log.enabled){
    console.log(mainframeUrl + " from frameAncestors");}
  */
  } else {
    mainframeUrl = details.documentUrl;
  }
  /*        if(log.enabled){
    console.log(mainframeUrl + " from documentUrl");}
  }
*/
if(hostonly) mainframeUrl = µBlock.URI.hostnameFromURI(mainframeUrl);
else mainframeUrl = µBlock.URI.hostnameFromURI(mainframeUrl) + µBlock.URI.pathFromURI(mainframeUrl);
  /* if (log.enabled) {
    console.log("webrequest details object is .. " + JSON.stringify(details));
    console.log("mainframeUrl identified from this object is " + mainframeUrl);
  }*/
  return mainframeUrl;
}

/*function setBadgeTextForExcludedSite(tabId) {
  chrome.tabs.get(tabId, function(tab) {
    browser.browserAction.setBadgeBackgroundColor({
      color: "SlateBlue",
      tabId: tabId
    });
    browser.browserAction.setBadgeText({
      tabId: tabId,
      text: "!"
    });
  });
}*/

//This is the actual function that gets called for each request and must
//decide whether or not we want to allow or block based on IP or prior cache, if user chooses to block a cloud
// First check in cache. If not found in cache, resolve DNS to IP
// and check if the IP is present in known list of IP address ranges in data/CIDRblocks.js
async function requestListener(details) {
  /*//We only allow GET request to be dropped.  
  if (details.method != 'GET') {
    counts.notInList+=1; return {};
  }*/
  //console.log('Checking: ' + details.url);
  settingsToggles.notInList = false; //always
  var a = performance.now();
  if (!details.url.includes(".")) {
    if (log.enabled) {
      timetaken.push({
        time: (performance.now() - a) / 1000,
        domain: details.url,
        shouldCancel: false,
        url: details.url,
        whichCloud: "Not a valid URL"
      });
    }
    //showPerTabCount(details.tabId);

    //counts.notInList += 1;
    return {};
  }

  // URITools is taken from the fantastic UblockOrigin addon. Credit to @Gorhill and UBO contributors.
  // Taken from https://github.com/gorhill/uBlock/blob/master/src/js/µBlock.URI.js
  // Do check it out and install UblockOrigin for safe browsing.
  var hostname = µBlock.URI.hostnameFromURI(details.url);
  var page = getMainframeUrlfromResource(details,true);
if(page == "") page = hostname;
        let page_a = page.split(".");
        if (page_a.length > 1) {
          let len = page_a.length;
          page = page_a[len - 2] + "." + page_a[len - 1];
        }

  if (!hostname) {
    if (log.enabled) {
      timetaken.push({
        time: (performance.now() - a) / 1000,
        domain: details.url,
        shouldCancel: false,
        url: details.url,
        whichCloud: "Not a valid Hostname"
      });
    }
    // showPerTabCount(details.tabId);

    return {};
  }

  if (
    isDecentralEyesUserOption &&
    details.method === "GET" &&
    isSupportedByDecentraleyes(hostname)
  ) {
    if (log.enabled) {
      console.log(
        "Decentraleyes option enabled and supported hostname for Decentraleyes : " +
          hostname
      );
      console.log(
        "Allowing this URL so Decentraleyes can provide it from local : " +
          details.url
      );
      console.log(
        "You may wish to enable `Block CDN requests not supported by Decentraleyes` setting in that addon`"
      );
    }
    // showPerTabCount(details.tabId);

    return {};
  }

  var isMainFrame =
    details.type === "main_frame" && details.tabId > -1 ? true : false;
  var idAndUrl, badgeindex;

  idAndUrl = details.tabId; //+ ":=CF=:" + mainframeHostname + mainframeUrl;
  //console.log(idAndUrl);
  /*if (!idAndUrl.endsWith("/")) {
    idAndUrl = idAndUrl + "/";
  }*/
  badgeindex = countsforBadgeText.findIndex(
    x => x.tabIdMainFrameUrl === idAndUrl
  );
  if (isMainFrame && details.tabId > -1) {
    let hostname = µBlock.URI.hostnameFromURI(details.url);
    let arr = hostname.split(".");
    let mainframeDomainname = hostname;
    if (arr.length > 1) {
      mainframeDomainname = arr[arr.length - 2] + "." + arr[arr.length - 1];
    }
    let empty = {
      google: 0,
      apple: 0,
      facebook: 0,
      amazon: 0,
      cloudflare: 0,
      microsoft: 0,
      notInList: 0
    };
    let arrObj = JSON.parse(JSON.stringify(perPageURLsObj));
    if (badgeindex > -1) {
      countsforBadgeText[badgeindex].perTabCounts = empty;
      countsforBadgeText[badgeindex].lastMainFrameInTabID = details.url;
      countsforBadgeText[
        badgeindex
      ].isCFDisabled = excludedDomains.includes(mainframeDomainname);
      countsforBadgeText[badgeindex].blockedUrls = arrObj;
    } else {
      let arr = countsforBadgeText.push({
        tabIdMainFrameUrl: idAndUrl,
        perTabCounts: empty,
        lastMainFrameInTabID: details.url,
        isCFDisabled: excludedDomains.includes(mainframeDomainname),
        blockedUrls: arrObj
      });
      badgeindex = arr - 1;
    }
  }

  /* let mainframeUrl = isMainFrame
    ? µBlock.URI.hostnameFromURI(details.url) + µBlock.URI.pathFromURI(details.url)
    : getMainframeUrlfromResource(details);
  let mainframeHostname = µBlock.URI.hostnameFromURI("https://" + mainframeUrl);
  let arr = mainframeHostname.split(".");
  let mainframeDomainname = mainframeHostname;
  if (arr.length > 0) {
    mainframeDomainname = arr[arr.length - 2] + "." + arr[arr.length - 1];
  //console.log({ mainframeDomainname });
  mainframeDomainname = getHashedDomainName(mainframeDomainname);
  let isDomainExcluded = excludedDomainsHashes.includes(mainframeDomainname); 
  */
  /* if (isDomainExcluded && isMainFrame) {
    setBadgeTextForExcludedSite(details.tabId);
  }*/

  if (badgeindex > -1 && countsforBadgeText[badgeindex].isCFDisabled) {
    // console.log("is excluded");
    return {};
  }

  //console.log(hostname)
  var shouldCancel = false;
  var resultfromknown = false;
  for (let el of some_nonbig5domains) {
    if (hostname == el || hostname.includes("."+el)) {
      if (log.enabled) {
        timetaken.push({
          time: (performance.now() - a) / 1000,
          domain: hostname,
          shouldCancel: false,
          url: details.url,
          whichCloud: "Not in the known top 5 Cloud services"
        });
      }
      resultfromknown = true;
      break;
    }
  }
  if (resultfromknown) {
    // showPerTabCount(details.tabId);

    //counts.notInList += 1;
    return {};
  }
  var hostsfound = false;
  for (let company in knownbig5domains) {
var shouldblock = false;
if(siteExceptions.hasOwnProperty(page)) {
if(siteExceptions[page][company]) shouldblock = true;
}
else if(settingsToggles[company]) shouldblock = true;
    if(shouldblock) {
      if (isInKnownhostnames(hostname, company)) {
        //        counts[company] += 1;
        if (log.enabled) {
          timetaken.push({
            time: (performance.now() - a) / 1000,
            domain: hostname,
            shouldCancel: true,
            url: details.url,
            whichCloud: company
          });
        }
        if (isMainFrame && notificationsEnabled) {
          let displayname = hostname.replace("www.", "");
          let msg =
			displayname +
            browser.i18n.getMessage('urlwasblocked') +
            company[0].toUpperCase() +
            company.slice(1) +
			browser.i18n.getMessage('urlwasblockedtwo');
          showNotifications(msg);
        }
        counts[company] += 1;
        resultfromknown = true;
        if (badgeindex > -1 && !!countsforBadgeText[badgeindex]) {
          /*      console.log(company);
      console.log(details.documentUrl + "===" + details.url);
      console.log(countsforBadgeText)
      console.log(details)
      */

          try {
            countsforBadgeText[badgeindex]["perTabCounts"][company] += 1;
            countsforBadgeText[badgeindex]["blockedUrls"][company][
              details.type
            ].push(details.url);
          } catch (e) {
            if (log.enabled) {
              console.log(
                "issue with storing blockedURL in pertabstats object"
              );
            }
          }
          //commented the below so we can set counts on icon only after tab load is complete.
          // i.e to avoid multiple calls to setBadge count on icon.
          setPerTabCount(
            details.tabId,
            countsforBadgeText[badgeindex].perTabCounts
          );
        }

        break;
      }
    }
  }

  if (resultfromknown) {
    return { cancel: true };
  }
  let result = {};
  result.whichCompany = "not in known cloud services list";
  /*for (let company in cache) {
    if (cache[company]["hosts"].includes(hostname)) { //Support for better caching required
      hostsfound = true;
      result.whichCompany = company;
console.log("cache check");
console.log(page);
console.log(siteExceptions);
var shouldblock = false;
if(siteExceptions.hasOwnProperty(page)) {
if(siteExceptions[page][company]) shouldblock = true;
}
else if(settingsToggles[company]) shouldblock = true;
      if (shouldblock) {
        counts[company] += 1;
        shouldCancel = true;
      } else {
        shouldCancel = false;
      }
console.log(shouldCancel);
      break;
    }
  }*/
if(siteExceptions.hasOwnProperty(page)) {
hostsfound = false;
shouldCancel = false;
}
else {
  for (let company in cache) {
    if (cache[company]["hosts"].includes(hostname)) {
      hostsfound = true;
      result.whichCompany = company;

      if (settingsToggles[company]) {
        counts[company] += 1;
        shouldCancel = true;
      } else {
        shouldCancel = false;
      }
      break;
    }
  }
}

  /*console.log({hostsfound})
    console.log({shouldCancel})*/

  if (hostsfound && shouldCancel) {
    if (log.enabled) {
      timetaken.push({
        time: (performance.now() - a) / 1000,
        domain: hostname,
        shouldCancel: true,
        url: details.url,
        whichCloud: result.whichCompany
      });
    }
    if (isMainFrame && notificationsEnabled) {
      let displayname = hostname.replace("www.", "");

      let msg =
		displayname +
		browser.i18n.getMessage('urlwasblocked') +
		result.whichCompany[0].toUpperCase() +
		result.whichCompany.slice(1) +
		browser.i18n.getMessage('urlwasblockedtwo');
      showNotifications(msg);
    }
    // showPerTabCount(details.tabId);
    if (badgeindex > -1 && !!countsforBadgeText[badgeindex]) {
      /*console.log(result.whichCompany);
      console.log(details.documentUrl + "===" + details.url);
      console.log(countsforBadgeText)
      console.log(details)
      */
      try {
        countsforBadgeText[badgeindex]["perTabCounts"][
          result.whichCompany
        ] += 1;
        countsforBadgeText[badgeindex]["blockedUrls"][result.whichCompany][
          details.type
        ].push(details.url);
      } catch (e) {
        if (log.enabled) {
          console.log("issue with storing blockedURL in pertabstats object");
        }
      }
      //commented the below so we can set counts on icon only after tab load is complete.
      // i.e to avoid multiple calls to setBadge count on icon.

      setPerTabCount(
        details.tabId,
        countsforBadgeText[badgeindex].perTabCounts
      );
    }
    return { cancel: true };
  }
  if (hostsfound && !shouldCancel) {
    if (log.enabled) {
      timetaken.push({
        time: (performance.now() - a) / 1000,
        domain: hostname,
        shouldCancel: false,
        url: details.url,
        whichCloud: result.whichCompany
      });
    }
    // showPerTabCount(details.tabId);

    //counts.notInList += 1;
    return {};
  }

  // now let's resolve since we dont have it in cache
  var dns = {};
  dns.addresses = [];
  try {
    dns = await browser.dns.resolve(hostname);
  } catch (e) {
    if (log.enabled) {
      timetaken.push({
        time: (performance.now() - a) / 1000,
        domain: hostname,
        shouldCancel: false,
        url: "DNS resolution failed on " + details.url,
        whichCloud: "DNS resolve failed"
      });
    }
    //showPerTabCount(details.tabId);

    //if dns not able to resolve, don't proceed.
    //counts.notInList += 1;
    return {};
  }

  //If user has hosts file that has huge list of blocked domains (ads, trackers etc),
  // they usually point it to 0.0.0.0 or 127.0.0.1
  // We can return such cases right away. Good for the user that they use this method!
  if (
    !!dns.addresses &&
    dns.addresses.length > 0 &&
    (dns.addresses[0] === "0.0.0.0" || dns.addresses[0] === "127.0.0.1")
  ) {
    //showPerTabCount(details.tabId);

    //counts.notInList += 1;
    return {};
  }
  if (!dns.addresses || !dns.addresses[0]) {
    //showPerTabCount(details.tabId);

    //counts.notInList += 1;
    return {};
  }
  //console.log(dns.addresses);
if(siteExceptions.hasOwnProperty(page)) {
for(let i in siteExceptions[page]) {
if(siteExceptions[page][i]) {
result = checkIPisinRange(dns.addresses,i);
if(result.shouldCancel) break;
}
}
}
else {
for(let i in settingsToggles) {
if(i === "notInList") continue;
if(settingsToggles[i]) {
result = checkIPisinRange(dns.addresses,i);
//if(result.shouldCancel) break;
}
}
}
  /*  var obj = {
    host: hostnameSha256_Base64,
    shouldCancel: result.shouldCancel,
    company: result.whichCompany
  };*/

  //TODO need to make all "Not in known list" as "notInList" so we can checking like below.

  if (
    result.whichCompany === "notInList" ||
    result.whichCompany.toLowerCase().includes("not")
  ) {
    temp_IP_array.push({
      ip: dns.addresses[0],
      hosthash: hostname
    });
  }

  // just add to notinlist now and we will send to worker to adjust company search if
  //if some cloud is allowed from UI toggle switches

  for (let el in cache) {
    // need to make all "Not in known list" as "notInList"
    if (el.toLowerCase().includes("not")) {
      el = "notInList";
    }
    if (result.whichCompany === el) {
      // we check cache size because addon storage area is 5mb for every addon and we don't want to fill it up
      // even in "cache storage disabled" mode from settings page, this helps avoid making cache object "in memory" too big.
      if (approxCacheSizeKb < 4700) {
        cache[el]["hosts"].push(hostname);
      }
    }
  }

  if (result.shouldCancel) {
    if (log.enabled) {
      timetaken.push({
        time: (performance.now() - a) / 1000,
        domain: hostname,
        shouldCancel: true,
        url: details.url,
        whichCloud: result.whichCompany
      });
    }
    if (isMainFrame && notificationsEnabled) {
      let displayname = hostname.replace("www.", "");

      let msg =
        displayname +
		browser.i18n.getMessage('urlwasblocked') +
		result.whichCompany[0].toUpperCase() +
		result.whichCompany.slice(1) +
		browser.i18n.getMessage('urlwasblockedtwo');
      showNotifications(msg);
    }
    //console.log(counts);

    //console.log("Cancelling this url because " + i + " is blocked and DNS resolved IP is " + dns.addresses +  " for the URL " + details.url)
    /// showPerTabCount(details.tabId);
    if (badgeindex > -1 && !!countsforBadgeText[badgeindex]) {
      /*  console.log(result.whichCompany);
      console.log(details.documentUrl + "===" + details.url);
      console.log(countsforBadgeText)
      console.log(details)*/
      //      console.log(countsforBadgeText)
      try {
        countsforBadgeText[badgeindex]["perTabCounts"][
          result.whichCompany
        ] += 1;
        //commented the below so we can set counts on icon only after tab load is complete.
        // i.e to avoid multiple calls to setBadge count on icon.
        countsforBadgeText[badgeindex]["blockedUrls"][result.whichCompany][
          details.type
        ].push(details.url);
      } catch (e) {
        if (log.enabled) {
          console.log("issue with storing blockedURL in pertabstats object");
        }
      }
      setPerTabCount(
        details.tabId,
        countsforBadgeText[badgeindex].perTabCounts
      );
    }

    return { cancel: true };
  }
  if (log.enabled) {
    timetaken.push({
      time: (performance.now() - a) / 1000,
      domain: hostname,
      shouldCancel: false,
      url: details.url,
      whichCloud: "Not in known list"
    });
  }
  //showPerTabCount(details.tabId);

  // counts.notInList += 1;
  return {};
}

setInterval(storeToDisk, 4 * 60 * 1000);
//setInterval(testReset, 5 * 1000);
/*
function funccrypto() {
  var k = encrypttest(20000, cache);
  console.log(k.data);
}
//setInterval(testReset, 30*1000);
//setInterval(testhash, 1000);

function testhash() {
  let md = forge.md.sha256.create();
  md.update("Test string for sha25633 as base64 . com .org.in");
  let buffer = md.digest();
  hostnameSha256_Base64 = forge.util.encode64(buffer.getBytes());
  console.log({ hostnameSha256_Base64 });
}
function testReset() {
  if (!!cache) {
    cache = {};
    counts = {};
    console.log("for testing, reset cache and calling handleStartup");
    handleStartup();
  }
} */

function showNotifications(msg) {
  chrome.notifications.create({
    type: "basic",
    title: "Cloud Firewall",
    message: msg,
    iconUrl: "images/shield32.png"
  });
}

function dedupCache() {
  for (let el in cache) {
    if (cache[el]["hosts"].length > 0) {
      cache[el]["hosts"] = Array.from(new Set(cache[el]["hosts"]));
    }
  }
}
var approxCacheSizeKb = 0;
async function storeToDisk() {
  if (log.enabled) {
    console.log(counts);
    console.table(timetaken);
  }
  timetaken = [];

  /*if (!cache) {
    await handleStartup();
  }*/
  // await window.crypto.subtle.digest('SHA-1', new TextEncoder().encode(hostname));

  dedupCache();
  approxCacheSizeKb = JSON.stringify(cache).length / 1000;

  // the below if condition to ensure this object won't inflate.
  // This is just a precaution.. as tab.OnRemoved Listener will take care of cleaning up this object
  // .. when the user closes a tab . Having the below just to ensure it won't grow too big.
  if (countsforBadgeText.length > 50) {
    countsforBadgeText = [];
    countsforBadgeText.push({
      tabIdMainFrameUrl: -100,
      perTabCounts: counts,
      lastMainFrameInTabID: "http://example.com/full/path",
      isCFDisabled: false
    });
  }
  //encryptCache("paswrod");
  //console.log(k)

  // console.log(JSON.stringify(cache));
  await browser.storage.local.set({ counts: counts });
  let items = await browser.storage.local.get();
  //console.log(items)
  storageUsed = JSON.stringify(items).length / 1000;
  if (log.enabled) {
    console.log(storageUsed + " kb storage used");
  }

  /*       let compressedCache = LZString.compressToUTF16(JSON.stringify(cache));

  await browser.storage.local.set({ cache: compressedCache });
*/

  //var cache = await encryptRecent(cache);
  // await browser.storage.local.set({ cache: cache });

  if (temp_IP_array.length > 0) {
    let updateWorker = new Worker(
      chrome.extension.getURL("js/background/workerForCacheUpdate.js")
    );
    temp_IP_array = temp_IP_array.filter(
      (el, index, self) =>
        index === self.findIndex(t => t.hosthash === el.hosthash)
    );
    //         console.log(JSON.stringify(cache));

    updateWorker.postMessage([cache, settingsToggles, temp_IP_array]);
    temp_IP_array = [];
    updateWorker.onmessage = function(e) {
      cache = e.data.workerResult;
      if (log.enabled) {
        console.log(JSON.stringify(cache));
      }

      //storageUsed now has total kilobytes in storage, Addons are allowed 5MB storage.
      if (shouldStoreCache && storageUsed < 4700) {
        if (log.enabled) {
          console.log(
            "Cloud Firewall caching enabled, storing to local storage"
          );
        }

        let compressedCache = LZString.compressToUTF16(JSON.stringify(cache));
        browser.storage.local.set({ cache: compressedCache }, () => {
          if (log.enabled) {
            console.log("updated cache received from worker and saved to disk");
          }
        });
      } else {
        if (log.enabled) {
          console.log(
            "Cloud Firewall either cache is disabled or storage size reached 4.7MB, max allocated storage per addon is 5mb. Use settings page to clear cache"
          );
        }
      }
      updateWorker.terminate();
    };
  }
}

var notificationsEnabled = true;
function updateNotifications() {
  chrome.storage.local.get({ notificationsEnabled: true }, function(obj) {
    notificationsEnabled = obj.notificationsEnabled;
  });
}
updateNotifications();
//Monitor changes in data, and setup everything again.
//This could probably be optimized to not do everything on every change
//but why bother?
function monitorChanges(changes, namespace) {
  if (changes.disabled) {
    if (changes.disabled.newValue == true) {
      console.log("Disabling Cloud Firewall, removing listener");
      chrome.webRequest.onBeforeRequest.removeListener(requestListener);
    } else {
      console.log("Enabling Cloud Firewall, setting up listener");
      setupRequestListener();
    }
  }

  if (changes.logging) {
    console.log("Cloud Firewall Logging settings have changed, updating...");
    updateLogging();
  }

  if (changes.notificationsEnabled) {
    updateNotifications();
  }

  if (changes.settingsToggles || changes.siteExceptions) {
    getSettingStates();
  }

  if (changes.isDecentralEyesUserOption) {
    isDecentralEyesUserOption = changes.isDecentralEyesUserOption.newValue;
  }

  if (changes.cacheType) {
    console.log(
      "Cloud Firewall ShouldCache? setting changed to " +
        changes.cacheType.newValue
    );
    if (changes.cacheType.newValue) {
      shouldStoreCache = true;
    } else {
      shouldStoreCache = false;
      resetCache(false);
    }
  }
}

chrome.runtime.onStartup.addListener(handleStartup);

chrome.storage.onChanged.addListener(monitorChanges);

var isTBB = false;

async function checkIsTorBrowser() {
  isTBB = false;
  try {
    var gettingInfo = await browser.runtime.getBrowserInfo();
    if (
      gettingInfo.hasOwnProperty("isTorBrowser") &&
      !!gettingInfo.isTorBrowser &&
      gettingInfo.isTorBrowser
    ) {
      if (chrome.webRequest.onBeforeRequest.hasListener(requestListener)) {
        chrome.webRequest.onBeforeRequest.removeListener(requestListener);
      }
      console.log("Tor Browser detected.");
      console.log("This addon does NOT yet support Tor Browser.");
      console.log(
        "If you are using this addon in tor browser, you can uninstall this addon"
      );
      console.log(
        "There's an open feature request in project Gitlab issue tracker for TBB support"
      );
      console.log("https://gitlab.com/gkrishnaks/cloud-firewall/issues/18");
      showNotifications(
        browser.i18n.getMessage("torwarning")
      );
      isTBB = true;
    } else {
      isTBB = false;
    }
  } catch (e) {
    isTBB = false;
  }
}
checkIsTorBrowser();
var perPageURLsObj = {};
//Sets up the listener, only if at least one switch is enabled. Otherwise de-register the listener.
function setupRequestListener() {
  /*if (log.enabled) {
    console.log(
      "Cloud Firewall: Checking if we need to setup request listeners"
    );
  }*/

  // Tor browser support is NOT yet available
  // Refer open feature request : https://gitlab.com/gkrishnaks/cloud-firewall/issues/18
  // The below is the SAFE way to detect tor browser.
  // Tor Browser project added the property isTorBrowser to getBrowserInfo to be made available to NoScript addon.
  // Refer the documentation for getBrowserInfo at
  // https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getBrowserInfo#Syntax

  if (isTBB) {
    return;
  }

  let shouldRegisterListener = false;
  for (let company in settingsToggles) {
    if (company.toLowerCase().includes("not")) {
      continue;
    }
    if (settingsToggles[company]) {
      shouldRegisterListener = true;
      break;
    }
  }

  if (
    !shouldRegisterListener &&
    chrome.webRequest.onBeforeRequest.hasListener(requestListener)
  ) {
    console.log(
      "Cloud Firewall: Removed request listener as no block switch is active in popup menu"
    );
    chrome.webRequest.onBeforeRequest.removeListener(requestListener);
    return;
  }

  if (
    shouldRegisterListener &&
    !chrome.webRequest.onBeforeRequest.hasListener(requestListener)
  ) {
    console.log(
      "Cloud Firewall: Setting up request listener as at least one block switch is active in popup menu"
    );
    var types = [];
    for (let val in chrome.webRequest.ResourceType) {
      types.push(chrome.webRequest.ResourceType[val]);
    }

    for (let i in settingsToggles) {
      if (!i.toLowerCase().includes("not")) {
        perPageURLsObj[i] = {};
        for (let type of types) {
          perPageURLsObj[i][type] = [];
        }
      }
    }
    /* Supported types in latest Firefox versions as on March 2019 :
   [
        "image",
        "imageset",
        "main_frame",
        "object",
        "other",
        "script",
        "stylesheet",
        "sub_frame",
        "xmlhttprequest",
        "beacon",
        "csp_report",
        "font",
        "media",
        "object_subrequest",
        "ping",
        "speculative",
        "web_manifest",
        "websocket",
        "xbl",
        "xml_dtd",
        "xslt"
      ] */

    chrome.webRequest.onBeforeRequest.addListener(
      requestListener,
      {
        urls: ["https://*/*", "http://*/*"],
        types: types
      },
      ["blocking"]
    );
  }
}

var excludedDomains = [];
chrome.storage.local.get({ excludedDomains: [] }, function(obj) {
  excludedDomains = obj.excludedDomains;
});
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  /*function checktabUrl(key, tabid, url) {
       let isTabIdMatch = parseInt(key.split(":=CF=:")[0]) === tabid;
      let isTabIdMatch = key === tabid;

    let URI = µBlock.URI.hostnameFromURI(url) + µBlock.URI.pathFromURI(url);
    let urlMatch = key.split(":=CF=:")[1] === URI;
    return isTabIdMatch; // && urlMatch;
  }*/

  if (log.enabled) {
    console.log("Received background message: " + JSON.stringify(request));
  }
  if (request.type == "appDetails") {
    let a = JSON.stringify(counts);
    // let b = JSON.stringify(settingsToggles);
    let url = request.url;
    let index = countsforBadgeText.findIndex(
      x => x.tabIdMainFrameUrl === request.tabid
    );
    let arrObj = {};
    arrObj.AddressBar_URL = "";
    arrObj.Counts = {};
    arrObj.Resources_Hosted_In_Cloud = {};
    let perPageStats;
    let isCFEnabled = chrome.webRequest.onBeforeRequest.hasListener(
      requestListener
    );
    //    console.log(chrome.webRequest.onBeforeRequest.hasListener(requestListener));
    if (index > -1) {
      perPageStats = countsforBadgeText[index].perTabCounts;
    } else {
      perPageStats = {
        google: 0,
        apple: 0,
        facebook: 0,
        amazon: 0,
        cloudflare: 0,
        microsoft: 0,
        notInList: 0
      };
    }
    let isDomainExcluded = false;
    // console.log(request);
    let domainname = request.domainname;
    let lastMainframeURL = "";

    if (index > -1) {
      lastMainframeURL = countsforBadgeText[index].lastMainFrameInTabID;
      arrObj.AddressBar_URL = lastMainframeURL;
      arrObj.Counts = countsforBadgeText[index].perTabCounts;
      arrObj.Resources_Hosted_In_Cloud = countsforBadgeText[index].blockedUrls;
      let mainframehostname = µBlock.URI.hostnameFromURI(lastMainframeURL);
      let arr = mainframehostname.split(".");
      if (arr.length > 2) {
        let len = arr.length;
        domainname = arr[len - 2] + "." + arr[len - 1];
      } else {
        domainname = mainframehostname;
      }
    }

    isDomainExcluded = excludedDomains.includes(domainname);
    //    console.log(perPageStats);
    let c = {
      logstatus: log.enabled,
      //settingsToggles: b,
      counts: a,
      appDisabled: false,
      appVersion: manifestData.version,
      perPageStats: perPageStats,
      isCFEnabled: isCFEnabled,
      isTorBrowser: isTBB,
      isDomainExcluded: isDomainExcluded,
      lastMainframeDomainName: domainname,
      stringified_blockedUrls: JSON.stringify(arrObj)
    };
    // console.log(c);
    sendResponse(c);
  } else if (request.type == "addToExcludes") {
    //console.log("to exclude " + request.domainname);
    excludedDomains.push(request.domainname);
    chrome.storage.local.set(
      { excludedDomains: excludedDomains},
      () => {
        if (log.enabled) {
          console.log(request.domainname + " is now Excluded");
        }
        sendResponse("Added to Excludes");
      }
    );
  } else if (request.type == "removeFromExcludes") {
    //console.log("to exclude " + request.domainname);
    excludedDomains = excludedDomains.filter(o => {
      return o !== request.domainname;
    });
    chrome.storage.local.set(
      { excludedDomains: excludedDomains },
      () => {
        if (log.enabled) {
          console.log(request.domainname + " is removed from Excludes");
        }
        sendResponse("Removed from Excludes");
      }
    );
  } else if (request.type == "toggleSetting") {
    dedupCache();

    if (log.enabled) {
      console.log(
        "Switching Block" +
          request.company +
          " to " +
          !settingsToggles[request.company]
      );
      console.log("Cache Before rewrite:");
      console.log(JSON.stringify(window.cache));
    }
    // Need to update NotInList cache when user toggles an ALLOW switch to BLOCK. So if it was ALLOW earlier..
    // .. i.e false earlier, call cacheupdate to move the cache entries from notinlist to appropriate cloud hashes for recently visited domains.
    // This is actually also done iun SToreToDisk which runs once every 4 minutes.
    //  But through the below, we can ensure it happens when toggle is switched within a 4 minutes window
    // So pass the current toggle state of the switch was earlier FALSe i.e allow. Skip cache update if going from BLock --> allow.
if(!settingsToggles[request.company] && cache.notInList.hosts.length > 0) callUpdateCacheWorker(settingsToggles);
if(request.domainname) {
browser.storage.local.get("siteExceptions").then(function(data) {
if(request.command && request.command == "resetDefault") {
delete data.siteExceptions[request.domainname];
browser.storage.local.set({siteExceptions:data.siteExceptions});
sendResponse("Removed Exception");
}
else {
if(data.siteExceptions[request.domainname]) data.siteExceptions[request.domainname][request.company] = !data.siteExceptions[request.domainname][request.company];
else {
data.siteExceptions[request.domainname] = new Object;
for(var key in settingsToggles) {
if(key != "notInList") data.siteExceptions[request.domainname][key] = settingsToggles[key];
}
data.siteExceptions[request.domainname][request.company] = !settingsToggles[request.company];
}
browser.storage.local.set({siteExceptions:data.siteExceptions});
sendResponse("toggled "+request.company+" for "+request.domainname);
}
});
}
else {
    settingsToggles[request.company] = !settingsToggles[request.company];
    //console.log(settingsToggles);
    saveToggleStates();
    sendResponse("toggled " + request.company);
}
  } else if (request.type == "doFullReset") {
    var resettype = request.type;
    delete request.type;
    resetCache(false);
  } else if (request.type == "cipherCache") {
    toggleEncryption(request.password);
  } else {
    console.log("Unexpected message: " + JSON.stringify(request));
    return false;
  }

  return true; //This tells the browser to keep sendResponse alive because
  //we're sending the response asynchronously.
});
var log = {};
log.enabled = false;
var manifestData = chrome.runtime.getManifest();

function updateLogging() {
  chrome.storage.local.get({ logging: false }, function(obj) {
    log.enabled = obj.logging;
  });
}
updateLogging();

function saveToggleStates() {
  chrome.storage.local.set({ settingsToggles: settingsToggles });
}

async function resetCache(shouldRemoveCounts) {
  console.log("Cloud Firewall cache reset");
  try {
    await browser.storage.local.set({ cache: "" });
    showNotifications(browser.i18n.getMessage('cachedeleted'));
  } catch (e) {
    console.log("Cloud Firewall: Issue with clearing offline cache");
  }
  // just to test cache is cleared
  chrome.storage.local.get("cache", function(obj) {
    console.log(obj);
  });
  for (let company in cache) {
    cache[company].hosts = [];
  }
  await browser.tabs.reload({ bypassCache: true });
  if (shouldRemoveCounts) {
    for (let company in counts) {
      counts[company] = 0;
    }
  }
}

chrome.storage.local.get(
  {
    disabled: false
  },
  function(obj) {
    if (!obj.disabled) {
      setupRequestListener();
    } else {
      console.log("Cloud Firewall is disabled");
    }
  }
);

var encryptionEnabled = false;
chrome.storage.local.get(
  {
    isCipherCache: false
  },
  function(obj) {
    encryptionEnabled = obj.isCipherCache;
  }
);

async function toggleEncryption(password) {
  encryptionEnabled = !encryptionEnabled;
  await browser.storage.local.set({ isCipherCache: encryptionEnabled });
  if (encryptionEnabled) {
    //encryptCache(password);
  } else {
    //switchOffEncryption(password);
  }
}

//const e = window.crypto.getRandomValues(new Uint32Array(10)).join("");
var storageUsed = 0;
async function handleStartup() {
  console.log("Cloud Firewall starting up");
  storageUsed = 0; //this will be updated  below or also in storeToDisk  function

  chrome.storage.local.get({ shouldPersistRules: true }, function(obj) {
    if (!obj.shouldPersistRules) {
      for (let company in settingsToggles) {
        settingsToggles[company] = false;
        chrome.storage.local.set({ settingsToggles: settingsToggles });
      }
    } else {
      getSettingStates();
    }
  });
browser.storage.local.get("siteExceptions").then(function(data) {
if(!data.siteExceptions) browser.storage.local.set({siteExceptions:new Object});
});
  var count = await browser.storage.local.get("counts");
  if (
    !!count &&
    !!count.counts &&
    !!count.counts.amazon &&
    count.counts.hasOwnProperty("amazon")
  ) {
    //  console.log(count.counts.amazon)
    counts = JSON.parse(JSON.stringify(count.counts));
    if (log.enabled) {
      console.log(counts);
    }
  }
  var store = await browser.storage.local.get({ cache: "" });
  if (store.cache.length > 0) {
    var parsed = JSON.parse(LZString.decompressFromUTF16(store.cache));
    if (!!parsed) {
      //Object.assign(cache , parsed); Assign does shallow copy, let's do manually
      // Adding this because initially  I had 5 clouds from Dhruv Mehrothra anD Kashmir Hill's "Living with the big tech"
      // Now I am trying to add Cloudflare support but users shouldn't lose their cache or counts.
      // Since does not have nesting, so Objects.assign should suffice.
      for (let company in parsed) {
        if (
          !!cache[company] &&
          !!parsed[company] &&
          !!cache[company]["hosts"] &&
          !!parsed[company]["hosts"]
        ) {
          cache[company]["hosts"] = parsed[company]["hosts"];
        }
      }
    }
    if (!!cache && !!parsed) {
      if (log.enabled) {
        console.log(
          LZString.decompressFromUTF16(store.cache).length / 1000 +
            " kb storage plaintext"
        );

        console.log(
          store.cache.length / 1000 + " kb storage compressed with LZString"
        );
        console.log(JSON.stringify(cache));
      }
      let items = await browser.storage.local.get();
      //console.log(items)
      storageUsed = JSON.stringify(items).length / 1000;

      if (log.enabled) {
        console.log(storageUsed + " kb storage space used so far");
      }
    }
  }
  // set logging to OFF when browser starts. User can enable it when needed from Settings page.
  await browser.storage.local.set({ logging: false });
}

async function onInstalledfn(details) {
  if (details.reason === "install") {
    console.log("Cloud Firewall installed");
  }

  if (details.reason === "update") {
    console.log("Cloud Firewall updated");
    //if (!!details.previousVersion && details.previousVersion === "0.0.1.11") {
    //reset cache to empty as we add salt to hostname before hashing this version
    // ... as per suggestion received from an encryption expert I reached out on twitter,
    // .. it's good to have a salt even if we are reusing same salt for subsequent usage as we
    // .. as we need to identify the same hostname the next time it appears based on hash.
    // we will have this cache reset as we work on cache enhancement until we add AES256 support
    if (
      !details.previousVersion.includes("12") &&
      !details.previousVersion.includes("13") &&
      !details.previousVersion.includes("14")
    ) {
      await resetCache(false);
    }
    //}

    //Noticed that counts were reset when addon was updated from 0.0.1 to 0.0.1.1
    // Temporary fix for that below is reuse same code from handlestartup.

    var count = await browser.storage.local.get("counts");
    if (
      !!count &&
      !!count.counts &&
      !!count.counts.amazon &&
      count.counts.hasOwnProperty("amazon")
    ) {
      //  console.log(count.counts.amazon)
      Object.assign(counts, count.counts);
      for (let company in counts) {
        if (!counts[company]) {
          counts[company] = 0;
        }
      }
      //TODO remove this next version. Read above comment.
      if (!count.counts.cloudflare) {
        counts.cloudflare = 0;
        await browser.storage.local.set({ counts: counts });
      }
      if (log.enabled) {
        console.log(counts);
      }
    }
  }

  let a = await browser.storage.local.get({ cache: "" });
  //console.log(JSON.stringify(LZString.decompressFromUTF16(a.cache)));
  /* var bytes = await browser.storage.local.getBytesInUse("cache");
  console.log(bytes.bytesUsed);
  console.log(bytes)*/

  if (!a.cache) {
    await browser.storage.local.set({ cache: "" });
  }
  if (details.temporary) {
    log.enabled = true;
    // console.log(details);
    handleStartup();
  }
  //console.log(await browser.storage.local.get({hostSalt: ""}) )
  if (details.reason === "install") {
    openUrl(chrome.extension.getURL(helplink), true);
  }
  let shouldShowUpdteinfo = true; //change this before every release TODO
  //if (!!details.previousVersion && details.previousVersion === "0.0.1.11") {
  if (details.reason === "update" && shouldShowUpdteinfo) {
    openUrl(chrome.extension.getURL("update.html"), false);
  }
  //}
}

var openUrl = (url, active) => {
  chrome.tabs.query(
    {
      currentWindow: true
    },
    function(tabs) {
      //FIREFOXBUG: Firefox chokes on url:url filter if the url is a moz-extension:// url
      //so we don't use that, doing it the more manual way instead.
      for (var i = 0; i < tabs.length; i++) {
        if (tabs[i].url == url) {
          chrome.tabs.update(
            tabs[i].id,
            {
              active: true,
              url: url
            },
            function(tab) {
              //      close();
            }
          );
          return;
        }
      }

      chrome.tabs.create({
        url: url,
        active: active
      });
      //window.close();
    }
  );
};

function callUpdateCacheWorker(CurrentSettingsState) {
  let workerUpdateCache = new Worker(
    chrome.extension.getURL("js/background/workerForCacheUpdate.js")
  );

  if (temp_IP_array.length > 0) {
    temp_IP_array = temp_IP_array.filter(
      (el, index, self) =>
        index === self.findIndex(t => t.hosthash === el.hosthash)
    );
    //         console.log(JSON.stringify(cache));

    workerUpdateCache.postMessage([cache, CurrentSettingsState, temp_IP_array]);
    temp_IP_array = [];
    workerUpdateCache.onmessage = function(e) {
      cache = e.data.workerResult;
      if (log.enabled) {
        console.log(
          "User toggled setting switch in popup, cache rewrite completed but not stored to disk as it will be taken care by SToreToDisk function once every 4 minutes"
        );
        console.log(JSON.stringify(cache));
      }
      // No need to store cache here, as storetoDisk will do it anyway once every 4 minutes.
      workerUpdateCache.terminate();
    };
  }
}

var countsforBadgeText = [
  {
    tabIdMainFrameUrl: -100,
    perTabCounts: counts,
    lastMainFrameInTabID: "example.com",
    isCFDisabled: false
  }
];

chrome.tabs.onUpdated.addListener(tabUpdateHandler);

function tabUpdateHandler(tabId, changeInfo, tab) {
  if (
    tab.status === "complete" &&
    !tab.url.includes("moz-extension") &&
    !tab.url.includes("about:") &&
    chrome.webRequest.onBeforeRequest.hasListener(requestListener)
  ) {
    let hostname = µBlock.URI.hostnameFromURI(tab.url);
    let tabidUrl = tabId; /*+ ":=CF=:" + hostname + µBlock.URI.pathFromURI(tab.url);
    if (!tabidUrl.endsWith("/")) {
      tabidUrl = tabidUrl + "/";
    }*/
    let index = countsforBadgeText.findIndex(
      x => x.tabIdMainFrameUrl === tabidUrl
    );
    var counts = 0;
    if (index > -1) {
      for (let company in countsforBadgeText[index].perTabCounts) {
        if (company.toLowerCase().includes("not")) {
          continue;
        }
        counts += countsforBadgeText[index].perTabCounts[company];
      }
      let title = "Cloud Firewall ({{badge}})";
      if (countsforBadgeText[index].isCFDisabled) {
        title =
          counts < 1
            ? title.replace("{{badge}}", "✻")
            : title.replace("{{badge}}", counts.toString());
      } else {
        title = title.replace("{{badge}}", counts.toString());
      }

      browser.browserAction.setTitle({
        title: title,
        tabId: tabId
      });
    }

    let domainname = hostname;
    let arr = hostname.split(".");
    if (arr.length > 0) {
      domainname = arr[arr.length - 2] + "." + arr[arr.length - 1];
    }
    if (excludedDomains.includes(domainname) && counts < 1) {
      //      chrome.webRequest.onBeforeRequest.hasListener(requestListener)

      browser.browserAction.setBadgeBackgroundColor({
        color: "SlateBlue",
        tabId: tabId
      });
      browser.browserAction.setBadgeText({
        tabId: tabId,
        text: "✻"
      });
      return;
    }
    if (index > -1) {
      setPerTabCount(tabId, countsforBadgeText[index].perTabCounts);
    }
    //      console.log(tabidUrl);
  }
}

function setPerTabCount(tabId, perTabCounts) {
  chrome.tabs.get(tabId, function(tab) {
    if (!chrome.runtime.lastError) {
      let counts = 0;
      for (let company in perTabCounts) {
        if (company.toLowerCase().includes("not")) {
          continue;
        }
        counts += perTabCounts[company];
      }
      // console.log(counts)
      try {
        if (counts > 0) {
          browser.browserAction.setBadgeBackgroundColor({
            color: [0x66, 0x66, 0x66, 0xff],
            tabId: tabId
          });
          browser.browserAction.setBadgeText({
            tabId: tabId,
            text: String(counts)
          });
        } else {
          browser.browserAction.setBadgeBackgroundColor({
            color: [0, 217, 0, 255],
            tabId: tabId
          });
          browser.browserAction.setBadgeText({ tabId: tabId, text: "0" });
        }
        //For Android Firefox, icon is not shown but title is shown in menu entry.
        // So set the title with current tab count
      } catch (e) {
        if (log.enabled) {
          console.log(
            "Cloud Firewall: Error in setting badge counts, the tab may have got closed prematurely"
          );
        }
      }
    } else {
      if (log.enabled) {
        console.log(
          "Cloud Firewall: Error in setting badge counts, perhaps the tab was closed prematurely"
        );
      }
    }
  });
}

//chrome.tabs.onActivated.addListener(tabOnActivatedListener);
/*
function tabOnActivatedListener(tab) {
  let tabId = tab.tabId;
  chrome.tabs.query(
    {
      active: true,
      currentWindow: true
    },
    function(tabs) {
      if (!!tabs[0].url) {
        let hostname = µBlock.URI.hostnameFromURI(tabs[0].url);
        if (!!hostname) {
          let url = hostname + tabs[0].url.split(hostname)[1];
          if (!url.endsWith("/")) {
            url = url + "/";
            badgeindex = countsforBadgeText.findIndex(
              x => x.tabIdMainFrameUrl === url
            );
            if(!!badgeindex && badgeindex > -1){
            setPerTabCount(tabId, countsforBadgeText[badgeindex].perTabCounts);
          }}
        }
      }
    }
  );
}
*/
