maxmilton/trackx-magnet

View on GitHub
src/background.ts

Summary

Maintainability
C
7 hrs
Test Coverage
F
0%
import blocklist from './blocklist.json';

const REPORT_TO_HEADER_VALUE = `{"max_age":1440,"endpoints":[{"url":"${process
  .env.API_ENDPOINT!}/report"}]}`;
const NEL_HEADER_VALUE = '{"max_age":1440,"report_to":"default"}';

const reBlockList = new RegExp(blocklist.join('|'), 'i');

function modifyCSPHeader(header: string): string {
  let newHeader = header;
  const connectSrcIndex = newHeader.indexOf('connect-src');
  const defaultSrcIndex = newHeader.indexOf('default-src');

  if (connectSrcIndex !== -1) {
    // add to existing connect-src directive
    const nextSemiIndex = newHeader.indexOf(';', connectSrcIndex);
    newHeader = `${newHeader.slice(
      0,
      nextSemiIndex === -1 ? undefined : nextSemiIndex,
    )} ${process.env.API_ORIGIN!}${
      nextSemiIndex === -1 ? '' : newHeader.slice(nextSemiIndex)
    }`;
  } else if (defaultSrcIndex !== -1) {
    // add to existing default-src directive
    const nextSemiIndex = newHeader.indexOf(';', defaultSrcIndex);
    newHeader = `${newHeader.slice(
      0,
      nextSemiIndex === -1 ? undefined : nextSemiIndex,
    )} ${process.env.API_ORIGIN!}${
      nextSemiIndex === -1 ? '' : newHeader.slice(nextSemiIndex)
    }`;
  }

  const reportUriIndex = newHeader.indexOf('report-uri');
  if (reportUriIndex === -1) {
    // add new report-uri directive
    newHeader += `; report-uri ${process.env.API_ENDPOINT!}/report;`;
  }

  return newHeader;
}

function modifyReportingEndpointsHeader(header: string): string {
  let newHeader = header;
  const defaultIndex = newHeader.indexOf('default=');

  if (defaultIndex === -1) {
    // add new default endpoint
    newHeader += `, default="${process.env.API_ENDPOINT!}/report"`;
  } else {
    const nextCommaIndex = newHeader.indexOf(',', defaultIndex);

    // replace existing default endpoint
    newHeader = `${newHeader.slice(0, defaultIndex)}default="${process.env
      .API_ENDPOINT!}/report"${
      nextCommaIndex === -1 ? '' : newHeader.slice(nextCommaIndex)
    }`;
  }

  return newHeader;
}

// Modify CSP header if present to allow connecting to the TrackX API
// https://github.com/GoogleChrome/chrome-extensions-samples/blob/e716678b67fd30a5876a552b9665e9f847d6d84b/mv2-archive/extensions/no_cookies/background.js
chrome.webRequest.onHeadersReceived.addListener(
  (details) => {
    const responseHeaders = details.responseHeaders || [];
    let hasReportingEndpoints;
    let hasReportTo;
    let hasNEL;

    for (const header of responseHeaders) {
      switch (header.name) {
        case 'content-security-policy':
        case 'content-security-policy-report-only':
          header.value = modifyCSPHeader(header.value!);
          break;
        case 'reporting-endpoints':
          hasReportingEndpoints = true;
          header.value = modifyReportingEndpointsHeader(header.value!);
          break;
        case 'report-to':
          hasReportTo = true;
          header.value = REPORT_TO_HEADER_VALUE;
          break;
        case 'nel':
          hasNEL = true;
          header.value = NEL_HEADER_VALUE;
          break;
        default:
          break;
      }
    }

    if (!hasReportingEndpoints) {
      responseHeaders.push({
        name: 'reporting-endpoints',
        value: `default="${process.env.API_ENDPOINT!}/report"`,
      });
    }

    if (!hasReportTo) {
      responseHeaders.push({
        name: 'report-to',
        value: REPORT_TO_HEADER_VALUE,
      });
    }

    if (!hasNEL) {
      responseHeaders.push({
        name: 'nel',
        value: NEL_HEADER_VALUE,
      });
    }

    return { responseHeaders };
  },
  { urls: ['<all_urls>'] },
  [
    'blocking',
    'responseHeaders',
    // 'extraHeaders',
  ],
);

chrome.runtime.onMessage.addListener((req, { tab }, reply) => {
  if (req === 'tab' && tab) {
    if (reBlockList.test(`${tab.url!} ${tab.title!}`)) {
      // Empty response when tab data matches a word on the block list
      reply();
    } else {
      reply(tab);
    }
  }
});