Compare commits

..

1 Commits

5 changed files with 93 additions and 100 deletions

View File

@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import browserAPI, { Tab } from '../../lib/browser-api'; import { Tab } from '../../util';
export default function TabDropdown({ export default function TabDropdown({
setPickedTab, setPickedTab,
@ -10,7 +10,7 @@ export default function TabDropdown({
}) { }) {
const [tabs, setTabs] = React.useState<Tab[]>([]); const [tabs, setTabs] = React.useState<Tab[]>([]);
React.useEffect(() => { React.useEffect(() => {
browserAPI.tabs.query({ currentWindow: true }).then(setTabs); browser.tabs.query({ currentWindow: true }).then(setTabs);
}, []); }, []);
return ( return (
<select <select

View File

@ -1,18 +1,20 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { useEmitter } from '../../util';
import { getMemory } from '../../memory'; import { getMemory } from '../../memory';
import { useEmitter, getshorthost } from '../../util';
import browserAPI from '../../lib/browser-api';
async function getCurrentTab() { async function getCurrentTab() {
const [tab] = await browserAPI.tabs.query({ const [tab] = await browser.tabs.query({
active: true, active: true,
windowId: browserAPI.windows.WINDOW_ID_CURRENT, windowId: browser.windows.WINDOW_ID_CURRENT,
}); });
return tab; return tab;
} }
function isDomainHighlySuspicious(domain: string) { import './../../styles/global.scss';
import './toolbar.scss';
function isDomainHighlySuspicious(domain: string): boolean {
return ( return (
domain.includes('facebook') || domain.includes('facebook') ||
domain.includes('twitter') || domain.includes('twitter') ||
@ -25,19 +27,19 @@ const Toolbar = () => {
const [origin, setOrigin] = React.useState<string | null>(null); const [origin, setOrigin] = React.useState<string | null>(null);
const [eventCounts] = useEmitter(getMemory()); const [eventCounts] = useEmitter(getMemory());
const [cookieDomainCopy, setCookieDomainCopy] = React.useState<string | null>(null); const [cookieDomainCopy, setCookieDomainCopy] = React.useState<string | null>(null);
const [_, setMarksOccurrence] = React.useState(false); const [_, setMarksOccurrence] = React.useState<boolean>(false);
const [exposedOriginDomainCopy, setExposedOriginDomainCopy] = React.useState<string | null>( const [exposedOriginDomainCopy, setExposedOriginDomainCopy] = React.useState<string | null>(
null null
); );
const first_sentence_cookie = const first_sentence_cookie = 'Strona dokonała zapisu i odczytu plików Cookie dla domen ';
'Strona dokonała zapisu i odczytu plików Cookie dla domen ';
const first_sentence_history = const first_sentence_history =
'Część informacji o Twojej historii przeglądania została wysłana do '; 'Część informacji o Twojej historii przeglądania została wysłana do ';
React.useEffect(() => { React.useEffect(() => {
const listener = async () => { const listener = async () => {
const tab = await getCurrentTab(); const tab = await getCurrentTab();
if (tab !== undefined && tab.url) { if (tab !== undefined && tab.url) {
const url = new URL(tab.url); const url = new URL(tab.url);
if (url.origin.startsWith('moz-extension')) { if (url.origin.startsWith('moz-extension')) {
@ -48,27 +50,26 @@ const Toolbar = () => {
console.warn('Out of the tab scope'); console.warn('Out of the tab scope');
} }
}; };
browserAPI.tabs.onUpdated.addListener(listener);
browser.tabs.onUpdated.addListener(listener);
listener(); listener();
return () => { return () => {
browserAPI.tabs.onUpdated.removeListener(listener); browser.tabs.onUpdated.removeListener(listener);
}; };
}); });
React.useEffect(() => { React.useEffect(() => {
if (!origin) return; if (!origin) return;
const exposedOriginDomains = Object.values(getMemory().getClustersForOrigin(origin)) const exposedOriginDomains = Object.values(getMemory().getClustersForOrigin(origin))
.filter((cluster) => cluster.exposesOrigin()) .filter((cluster) => cluster.exposesOrigin())
.sort((cluster1, cluster2) => .sort((cluster1, cluster2) =>
isDomainHighlySuspicious(cluster1.id) isDomainHighlySuspicious(cluster1.id)
? -1 ? -1
: isDomainHighlySuspicious(cluster2.id) : isDomainHighlySuspicious(cluster2.id)
? 1 ? 1
: 0 : 0
) )
.map((cluster) => cluster.id); .map((cluster) => cluster.id);
setExposedOriginDomainCopy(''); setExposedOriginDomainCopy('');
switch (exposedOriginDomains.length) { switch (exposedOriginDomains.length) {
@ -99,18 +100,16 @@ const Toolbar = () => {
React.useEffect(() => { React.useEffect(() => {
if (!origin) return; if (!origin) return;
const cookieDomains = Object.values(getMemory().getClustersForOrigin(origin)) const cookieDomains = Object.values(getMemory().getClustersForOrigin(origin))
.filter((cluster) => cluster.hasCookies()) .filter((cluster) => cluster.hasCookies())
.sort((cluster1, cluster2) => .sort((cluster1, cluster2) =>
isDomainHighlySuspicious(cluster1.id) isDomainHighlySuspicious(cluster1.id)
? -1 ? -1
: isDomainHighlySuspicious(cluster2.id) : isDomainHighlySuspicious(cluster2.id)
? 1 ? 1
: 0 : 0
) )
.map((cluster) => cluster.id); .map((cluster) => cluster.id);
setCookieDomainCopy(''); setCookieDomainCopy('');
switch (cookieDomains.length) { switch (cookieDomains.length) {
@ -129,7 +128,7 @@ const Toolbar = () => {
break; break;
default: default:
setCookieDomainCopy( setCookieDomainCopy(
`${cookieDomains[0]}, ${cookieDomains[1]} (i ${ `${cookieDomains[0]}, ${cookieDomains[1]} (i ${
cookieDomains.length - 2 < 2 ? 2 : cookieDomains.length - 2 cookieDomains.length - 2 < 2 ? 2 : cookieDomains.length - 2
} innych).` } innych).`
); );
@ -137,37 +136,44 @@ const Toolbar = () => {
} }
}, [eventCounts['*'], origin]); }, [eventCounts['*'], origin]);
const autoMark = () => { React.useEffect(() => {
Object.values(getMemory().getClustersForOrigin(origin || '')).forEach((cluster) => if (!origin) return;
cluster.autoMark() for (const cluster of Object.values(getMemory().getClustersForOrigin(origin))) {
); if (cluster.hasMarks()) {
setMarksOccurrence(true); return setMarksOccurrence(true);
}; }
}
return setMarksOccurrence(false);
}, [eventCounts['*']]);
function autoMark() {
if (!origin) return;
for (const cluster of Object.values(getMemory().getClustersForOrigin(origin))) {
cluster.autoMark();
}
return setMarksOccurrence(true);
}
return ( return (
<div className="toolbar"> <div className="toolbar">
<header className={origin ? 'header' : 'header header--no-page'}> <header className={origin ? 'header' : 'header header--no-page'}>
<img src="../../assets/icon-addon.svg" height="24" /> <img src="../../assets/icon-addon.svg" height={32}></img>
<div className="webpage-metadata"> <div className="webpage-metadata">
{origin ? ( {origin ? (
<div className="webpage-metadata--hyperlink">{origin}</div> <>
<span>Analiza strony</span>
<span className="webpage-metadata--hyperlink">{origin}</span>
</>
) : ( ) : (
<div>Rentgen - wtyczka do przeglądania</div> <span>Przejdź do wybranej strony internetowej</span>
)} )}
</div> </div>
{origin ? ( {origin ? (
<button
onClick={() => {
window.close();
}}
>
<img src="../../assets/icons/x_thick.svg" width="12" height="12" />
</button>
) : (
<a href="https://internet-czas-dzialac.pl"> <a href="https://internet-czas-dzialac.pl">
<img src="/assets/icons/info_circle_outline.svg" width="20" height="20" /> <img src="/assets/icons/info_circle_outline.svg" width="20" height="20" />
</a> </a>
)} ) : null}
</header> </header>
{origin ? ( {origin ? (
@ -177,22 +183,30 @@ const Toolbar = () => {
<div className="counters-wrapper"> <div className="counters-wrapper">
<div className="counters"> <div className="counters">
<div className="counter counter--cookies"> <div className="counter counter--cookies">
<img src="/assets/icons/cookie.svg#color" width="24" height="24" /> <img
src="/assets/icons/cookie.svg#color"
width="24"
height="24"
/>
<span data-event={`${eventCounts['*']}`}> <span data-event={`${eventCounts['*']}`}>
{ {
Object.values(getMemory().getClustersForOrigin(origin)).filter( Object.values(
(cluster) => cluster.hasCookies() getMemory().getClustersForOrigin(origin)
).length ).filter((cluster) => cluster.hasCookies()).length
} }
</span> </span>
</div> </div>
<div className="counter counter--browser-history"> <div className="counter counter--browser-history">
<img src="/assets/icons/warning.svg#color" width="24" height="24" /> <img
src="/assets/icons/warning.svg#color"
width="24"
height="24"
/>
<span data-event={`${eventCounts['*']}`}> <span data-event={`${eventCounts['*']}`}>
{ {
Object.values(getMemory().getClustersForOrigin(origin)).filter( Object.values(
(cluster) => cluster.exposesOrigin() getMemory().getClustersForOrigin(origin)
).length ).filter((cluster) => cluster.exposesOrigin()).length
} }
</span> </span>
</div> </div>
@ -233,9 +247,9 @@ const Toolbar = () => {
<Fragment> <Fragment>
<section className="about"> <section className="about">
<p> <p>
Takie przetwarzanie danych może być niezgodne z&nbsp;prawem. Takie przetwarzanie danych może być niezgodne z prawem. Przejdź
Przejdź do analizy aby pomóc ustalić, czy ta strona nie narusza do analizy aby pomóc ustalić, czy ta strona nie narusza RODO lub
RODO lub ustawy Prawo Komunikacji Elektronicznej. ustawy Prawo Komunikacji Elektronicznej.
</p> </p>
</section> </section>
<section className="actions"> <section className="actions">
@ -247,7 +261,7 @@ const Toolbar = () => {
`/components/sidebar/sidebar.html?origin=${origin}`, `/components/sidebar/sidebar.html?origin=${origin}`,
'new_tab' 'new_tab'
); );
window.close(); window.close(); // close toolbar popup
}} }}
> >
Przejdź do analizy Przejdź do analizy

View File

@ -8,33 +8,6 @@
* - memory.ts: browserAction.*, webRequest.*, cookies.*, extension.* * - memory.ts: browserAction.*, webRequest.*, cookies.*, extension.*
*/ */
// Import full Request type from util.ts
export type Request = {
cookieStoreId?: string;
documentUrl?: string;
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;
url: string;
urlClassification?: { firstParty: string[]; thirdParty: string[] };
};
// === Tab API (util.ts, tab-dropdown.tsx, toolbar.tsx) === // === Tab API (util.ts, tab-dropdown.tsx, toolbar.tsx) ===
export interface Tab { export interface Tab {
id?: number; // util.ts: tab.id, tab-dropdown.tsx: tab.id id?: number; // util.ts: tab.id, tab-dropdown.tsx: tab.id
@ -64,11 +37,23 @@ export interface BadgeColorDetails {
} }
// === WebRequest API (memory.ts) === // === WebRequest API (memory.ts) ===
export interface RequestDetails {
requestId: string; // memory.ts: request.requestId
requestHeaders?: RequestHeader[]; // memory.ts: request.requestHeaders
// Note: ExtendedRequest konstruktor używa więcej pól,
// ale tu skupiamy się na tym co bezpośrednio używa browser API
}
export interface RequestHeader {
name: string;
value?: string;
}
export interface RequestFilter { export interface RequestFilter {
urls: string[]; // memory.ts: { urls: ['<all_urls>'] } urls: string[]; // memory.ts: { urls: ['<all_urls>'] }
} }
export type RequestListener = (details: Request) => void; export type RequestListener = (details: RequestDetails) => void;
// === Cookies API (memory.ts) === // === Cookies API (memory.ts) ===
export interface Cookie { export interface Cookie {

View File

@ -2,11 +2,10 @@ import ExtendedRequest from './extended-request';
import { getshorthost } from './util'; import { getshorthost } from './util';
import { RequestCluster } from './request-cluster'; import { RequestCluster } from './request-cluster';
import { SaferEmitter } from './safer-emitter'; import { SaferEmitter } from './safer-emitter';
import browserAPI from './lib/browser-api';
function setDomainsCount(counter: number, tabId: number) { function setDomainsCount(counter: number, tabId: number) {
browserAPI.badge.setBadgeText({ text: counter < 0 ? '0' : counter.toString(), tabId }); browser.browserAction.setBadgeText({ text: counter < 0 ? '0' : counter.toString(), tabId });
browserAPI.badge.setTitle({ browser.browserAction.setTitle({
title: 'Rentgen', title: 'Rentgen',
tabId, tabId,
}); });
@ -33,8 +32,8 @@ export default class Memory extends SaferEmitter {
Object.values(this.getClustersForOrigin(request.origin)).some((cluster) => Object.values(this.getClustersForOrigin(request.origin)).some((cluster) =>
cluster.hasCookies() cluster.hasCookies()
) )
? browserAPI.badge.setBadgeBackgroundColor({ color: '#ff726b' }) ? browser.browserAction.setBadgeBackgroundColor({ color: '#ff726b' })
: browserAPI.badge.setBadgeBackgroundColor({ color: '#ffb900' }); : browser.browserAction.setBadgeBackgroundColor({ color: '#ffb900' });
if (request.tabId >= 0) { if (request.tabId >= 0) {
setDomainsCount( setDomainsCount(
@ -47,14 +46,14 @@ export default class Memory extends SaferEmitter {
constructor() { constructor() {
super(); super();
browserAPI.webRequest.onBeforeRequest.addListener( browser.webRequest.onBeforeRequest.addListener(
async (request) => { async (request) => {
new ExtendedRequest(request); new ExtendedRequest(request);
}, },
{ urls: ['<all_urls>'] }, { urls: ['<all_urls>'] },
['requestBody'] ['requestBody']
); );
browserAPI.webRequest.onBeforeSendHeaders.addListener( browser.webRequest.onBeforeSendHeaders.addListener(
async (request) => { async (request) => {
const extendedRequest = ExtendedRequest.by_id[request.requestId].addHeaders( const extendedRequest = ExtendedRequest.by_id[request.requestId].addHeaders(
request.requestHeaders || [] request.requestHeaders || []
@ -77,9 +76,9 @@ export default class Memory extends SaferEmitter {
async removeCookiesFor(origin: string, shorthost?: string): Promise<void> { async removeCookiesFor(origin: string, shorthost?: string): Promise<void> {
if (shorthost) { if (shorthost) {
const cookies = await browserAPI.cookies.getAll({ domain: shorthost }); const cookies = await browser.cookies.getAll({ domain: shorthost });
for (const cookie of cookies) { for (const cookie of cookies) {
await browserAPI.cookies.remove({ await browser.cookies.remove({
name: cookie.name, name: cookie.name,
url: `https://${cookie.domain}`, url: `https://${cookie.domain}`,
}); });
@ -107,9 +106,5 @@ export function init() {
} }
export function getMemory(): Memory { export function getMemory(): Memory {
const backgroundPage = browserAPI.extension.getBackgroundPage(); return (browser.extension.getBackgroundPage().window as any).memory as Memory;
if (!backgroundPage) {
throw new Error('Background page not available');
}
return (backgroundPage.window as any).memory as Memory;
} }

View File

@ -1,12 +1,11 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import React from 'react'; import React from 'react';
import { DataLocation, Sources } from './stolen-data-entry'; import { DataLocation, Sources } from './stolen-data-entry';
import browserAPI from './lib/browser-api';
export type Unpromisify<T> = T extends Promise<infer R> ? R : T; export type Unpromisify<T> = T extends Promise<infer R> ? R : T;
export type Unarray<T> = T extends Array<infer R> ? R : T; export type Unarray<T> = T extends Array<infer R> ? R : T;
export type Tab = Unarray<Unpromisify<ReturnType<typeof browserAPI.tabs.query>>>; export type Tab = Unarray<Unpromisify<ReturnType<typeof browser.tabs.query>>>;
export type Request = { export type Request = {
cookieStoreId?: string; 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. 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.
@ -90,7 +89,7 @@ export function parseCookie(cookie: string): Record<string, string> {
} }
export async function getTabByID(id: number) { export async function getTabByID(id: number) {
const tabs = await browserAPI.tabs.query({ currentWindow: true }); const tabs = await browser.tabs.query({ currentWindow: true });
return tabs.find((tab) => tab.id == id); return tabs.find((tab) => tab.id == id);
} }