diff --git a/report-window/har-converter.tsx b/report-window/har-converter.tsx index 2829c5c..300c219 100644 --- a/report-window/har-converter.tsx +++ b/report-window/har-converter.tsx @@ -6,7 +6,7 @@ import { getshorthost, unique } from '../util'; function handleNewFile( element: HTMLInputElement, entries: StolenDataEntry[], - setFiltered: (Blob) => void + setFiltered: (arg0: Blob) => void ): void { const reader = new FileReader(); reader.addEventListener('load', () => { diff --git a/sidebar/sidebar.tsx b/sidebar/sidebar.tsx index 359ebec..17bd11f 100644 --- a/sidebar/sidebar.tsx +++ b/sidebar/sidebar.tsx @@ -2,15 +2,8 @@ import React, { Fragment, useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; import Options from '../options'; import { StolenData } from './stolen-data'; -import { getshorthost, useEmitter } from '../util'; +import { useEmitter } from '../util'; import { getMemory } from '../memory'; -import InfoCircleIcon from '../assets/icons/info_circle_outline.svg'; -import SettingsIcon from '../assets/icons/settings.svg'; -import TrashIcon from '../assets/icons/trash_full.svg'; -import MailIcon from '../assets/icons/mail.svg'; -import ShortLeftIcon from '../assets/icons/short_left.svg'; -import CloseBigIcon from '../assets/icons/close_big.svg'; -import CookiesIcon from '../assets/icons/cookie.svg'; async function getCurrentTab() { const [tab] = await browser.tabs.query({ @@ -110,11 +103,19 @@ const Sidebar = () => { {stolenDataView ? ( - + ) : ( )} @@ -122,7 +123,11 @@ const Sidebar = () => { {stolenDataView ? ( @@ -192,7 +209,11 @@ const Sidebar = () => { ); }} > - + ) : null} diff --git a/sidebar/stolen-data-cluster.tsx b/sidebar/stolen-data-cluster.tsx index 611c845..e40a326 100644 --- a/sidebar/stolen-data-cluster.tsx +++ b/sidebar/stolen-data-cluster.tsx @@ -3,8 +3,6 @@ import { getMemory } from '../memory'; import { StolenDataEntry } from '../stolen-data-entry'; import { maskString, useEmitter } from '../util'; -import CookieIcon from '../assets/icons/cookie.svg'; -import WarningIcon from '../assets/icons/warning.svg'; import './stolen-data-cluster.scss'; @@ -80,7 +78,8 @@ function StolenDataRow({ {entry.source === 'cookie' ? ( - - - - = T extends Promise ? R : T; export type Unarray = T extends Array ? R : T; export type Tab = Unarray>>; export type Request = { - cookieStoreId?: string; - documentUrl?: string; // RL of the document in which the resource will be loaded. For example, if the web page at "https://example.com" contains an image or an iframe, then the documentUrl for the image or iframe will be "https://example.com". For a top-level document, documentUrl is undefined. - frameId: number; - incognito?: boolean; - method: string; - originUrl: string; - parentFrameId: number; - proxyInfo?: { - host: string; - port: number; + cookieStoreId?: string; + documentUrl?: string; // RL of the document in which the resource will be loaded. For example, if the web page at "https://example.com" contains an image or an iframe, then the documentUrl for the image or iframe will be "https://example.com". For a top-level document, documentUrl is undefined. + frameId: number; + incognito?: boolean; + method: string; + originUrl: string; + parentFrameId: number; + proxyInfo?: { + host: string; + port: number; + type: string; + username: string; + proxyDNS: boolean; + failoverTimeout: number; + }; + requestHeaders?: { name: string; value?: string; binaryValue?: number[] }[]; + requestId: string; + tabId: number; + thirdParty?: boolean; + timeStamp: number; type: string; - username: string; - proxyDNS: boolean; - failoverTimeout: number; - }; - requestHeaders?: { name: string; value?: string; binaryValue?: number[] }[]; - requestId: string; - tabId: number; - thirdParty?: boolean; - timeStamp: number; - type: string; - url: string; // the target of the request; - urlClassification?: { firstParty: string[]; thirdParty: string[] }; + url: string; // the target of the request; + urlClassification?: { firstParty: string[]; thirdParty: string[] }; }; export function getshorthost(host: string) { - const parts = host - .replace(/^.*:\/\//, "") - .replace(/\/.*$/, "") - .split("."); - let lookback = !['co','com'].includes(parts.at(-2)) ? -2 : -3; - if (parts.at(-2) == "doubleclick" || parts.at(-2) == "google") { - lookback = -4; // to distinguish between google ads and stats - } else if (parts.at(-2) == "google") { - lookback = -3; // to distinguish various google services - } - return parts.slice(lookback).join("."); + const parts = host + .replace(/^.*:\/\//, '') + .replace(/\/.*$/, '') + .split('.'); + let lookback = !['co', 'com'].includes(parts.at(-2)) ? -2 : -3; + if (parts.at(-2) == 'doubleclick' || parts.at(-2) == 'google') { + lookback = -4; // to distinguish between google ads and stats + } else if (parts.at(-2) == 'google') { + lookback = -3; // to distinguish various google services + } + return parts.slice(lookback).join('.'); } export function useEmitter( - e: EventEmitter + e: EventEmitter ): [number, Dispatch>] { - const [counter, setCounter] = useState(0); - useEffect(() => { - const callback = () => { - setCounter((counter) => counter + 1); - }; - e.on("change", callback); - return () => { - e.removeListener("change", callback); - }; - }, []); - return [counter, setCounter]; + const [counter, setCounter] = useState(0); + useEffect(() => { + const callback = () => { + setCounter((counter) => counter + 1); + }; + e.on('change', callback); + return () => { + e.removeListener('change', callback); + }; + }, []); + return [counter, setCounter]; } export function parseCookie(cookie: string): Record { - return cookie - .split(";") - .map((l) => l.split("=")) - .reduce( - (acc, [key, value]) => ({ - ...acc, - [key]: value, - }), - {} - ); + return cookie + .split(';') + .map((l) => l.split('=')) + .reduce( + (acc, [key, value]) => ({ + ...acc, + [key]: value, + }), + {} + ); } export async function getTabByID(id: number) { - const tabs = await browser.tabs.query({ currentWindow: true }); - return tabs.find((tab) => tab.id == id); + const tabs = await browser.tabs.query({ currentWindow: true }); + return tabs.find((tab) => tab.id == id); } export function parseToObject(str: unknown): Record { - let result: Record; - let original_string: string; - if (typeof str === "string") { - original_string = str; - result = JSON.parse(str); - } else if (typeof str == "object") { - result = str as Record; - original_string = - (result[Symbol.for("originalString")] as string) || JSON.stringify(str); - } - result[Symbol.for("originalString")] = original_string; - return result; + let result: Record; + let original_string: string; + if (typeof str === 'string') { + original_string = str; + result = JSON.parse(str); + } else if (typeof str == 'object') { + result = str as Record; + original_string = + (result[Symbol.for('originalString')] as string) || + JSON.stringify(str); + } + result[Symbol.for('originalString')] = original_string; + return result; } export function isJSONObject( - str: unknown + str: unknown ): str is Record | string | number { - try { - const firstChar = JSON.stringify(parseToObject(str))[0]; - return ["{", "["].includes(firstChar); - } catch (e) { - return false; - } + try { + const firstChar = JSON.stringify(parseToObject(str))[0]; + return ['{', '['].includes(firstChar); + } catch (e) { + return false; + } } export function isURL(str: unknown): str is string { - try { - return !!(typeof str === "string" && new URL(str)); - } catch (e) { - return false; - } + try { + return !!(typeof str === 'string' && new URL(str)); + } catch (e) { + return false; + } } export function hyphenate(str: string): string { - return str.replace(/[_\[A-Z]/g, `${String.fromCharCode(173)}$&`); + return str.replace(/[_\[A-Z]/g, `${String.fromCharCode(173)}$&`); } export function unique(array: T[]): Array { - return Array.from(new Set(array)); + return Array.from(new Set(array)); } export function allSubhosts(host: string) { - const parts = host.split("."); - const result = []; - for (let i = 0; i < parts.length - 2; i++) { - result.push(parts.slice(i).join(".")); - } - return result; + const parts = host.split('.'); + const result = []; + for (let i = 0; i < parts.length - 2; i++) { + result.push(parts.slice(i).join('.')); + } + return result; } export function reduceConcat(a: T[], b: T[]): T[] { - return a.concat(b); + return a.concat(b); } export function getDate() { - const d = new Date(); - return `${d.getFullYear()}-${(d.getMonth() + 1) - .toString() - .padStart(2, "0")}-${d.getDate().toString().padStart(2, "0")}`; + const d = new Date(); + return `${d.getFullYear()}-${(d.getMonth() + 1) + .toString() + .padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`; } export function toBase64(file: File): Promise { - return new Promise((resolve) => { - const FR = new FileReader(); - FR.addEventListener("load", (e) => { - resolve(e.target.result as string); + return new Promise((resolve) => { + const FR = new FileReader(); + FR.addEventListener('load', (e) => { + resolve(e.target.result as string); + }); + FR.readAsDataURL(file); }); - FR.readAsDataURL(file); - }); } export function makeThrottle(interval: number) { - let last_emit = 0; - function emit(callback: () => void) { - if (Date.now() - last_emit > interval) { - callback(); - last_emit = Date.now(); - return true; - } else { - return false; + let last_emit = 0; + function emit(callback: () => void) { + if (Date.now() - last_emit > interval) { + callback(); + last_emit = Date.now(); + return true; + } else { + return false; + } } - } - return function (callback: () => void) { - if (!emit(callback)) { - setTimeout(() => emit(callback), interval); - } - }; + return function (callback: () => void) { + if (!emit(callback)) { + setTimeout(() => emit(callback), interval); + } + }; } export function isSameURL(url1: string, url2: string): boolean { - if (url1 === url2) { - return true; - } - url1 = url1.replace(/^https?:\/\//, "").replace(/\/$/, ""); - url2 = url2.replace(/^https?:\/\//, "").replace(/\/$/, ""); - return url1 === url2; + if (url1 === url2) { + return true; + } + url1 = url1.replace(/^https?:\/\//, '').replace(/\/$/, ''); + url2 = url2.replace(/^https?:\/\//, '').replace(/\/$/, ''); + return url1 === url2; } export function isBase64(s: string): boolean { - try { - atob(s); - return true; - } catch (e) {} - return false; + try { + atob(s); + return true; + } catch (e) {} + return false; } export function isBase64JSON(s: unknown): s is string { - return typeof s === "string" && isBase64(s) && isJSONObject(atob(s)); + return typeof s === 'string' && isBase64(s) && isJSONObject(atob(s)); } export function flattenObject( - obj: unknown, - parser: (to_parse: unknown) => string | Record = (id) => - id.toString(), - key = "", - ret = [], - parsed = false + obj: unknown, + parser: (to_parse: unknown) => string | Record = (id) => + id.toString(), + key = '', + ret = [] as [string, string][], + parsed = false ): [string, string][] { - const prefix = key === "" ? "" : `${key}.`; - if (Array.isArray(obj)) { - if (obj.length == 1) { - flattenObject(obj[0], parser, key, ret); + const prefix = key === '' ? '' : `${key}.`; + if (Array.isArray(obj)) { + if (obj.length == 1) { + flattenObject(obj[0], parser, key, ret); + } else { + for (let i in obj) { + flattenObject(obj[i], parser, prefix + i, ret); + } + } + } else if (typeof obj === 'object') { + for (const [subkey, value] of Object.entries(obj)) { + flattenObject(value, parser, prefix + subkey, ret); + } + } else if (!parsed) { + flattenObject(parser(obj), parser, key, ret, true); + } else if (typeof obj === 'string') { + ret.push([key, obj]); } else { - for (let i in obj) { - flattenObject(obj[i], parser, prefix + i, ret); - } + throw new Error('Something went wrong when parsing ' + obj); } - } else if (typeof obj === "object") { - for (const [subkey, value] of Object.entries(obj)) { - flattenObject(value, parser, prefix + subkey, ret); - } - } else if (!parsed) { - flattenObject(parser(obj), parser, key, ret, true); - } else { - ret.push([key, obj]); - } - return ret; + return ret; } export function flattenObjectEntries( - entries: [string, unknown][], - parser: (to_parse: unknown) => string | Record = (id) => - id.toString() + entries: [string, unknown][], + parser: (to_parse: unknown) => string | Record = (id) => + id.toString() ): [string, string][] { - return flattenObject(Object.fromEntries(entries), parser); + return flattenObject(Object.fromEntries(entries), parser); } export function maskString( - str: string, - max_fraction_remaining: number, - max_chars_total: number + str: string, + max_fraction_remaining: number, + max_chars_total: number ): string { - const amount_of_chars_to_cut = - str.length - Math.min(str.length * max_fraction_remaining, max_chars_total); - if (amount_of_chars_to_cut == 0) { - return str; - } - return ( - str.slice(0, str.length / 2 - amount_of_chars_to_cut / 2) + - "(...)" + - str.slice(str.length / 2 + amount_of_chars_to_cut / 2) - ); + const amount_of_chars_to_cut = + str.length - + Math.min(str.length * max_fraction_remaining, max_chars_total); + if (amount_of_chars_to_cut == 0) { + return str; + } + return ( + str.slice(0, str.length / 2 - amount_of_chars_to_cut / 2) + + '(...)' + + str.slice(str.length / 2 + amount_of_chars_to_cut / 2) + ); } export function safeDecodeURIComponent(s: string) { - try { - return decodeURIComponent(s); - } catch (e) { - return s; - } + try { + return decodeURIComponent(s); + } catch (e) { + return s; + } }