Compare commits
No commits in common. "develop" and "fix-checkbox" have entirely different histories.
develop
...
fix-checkb
127
README.md
127
README.md
|
@ -1,70 +1,8 @@
|
||||||
<h1 style="display: flex; align-items: center;"><img src="./assets/icon-addon-2048.png" alt="Rentgen logo" style="margin-right: 1rem;" width="48"/> Rentgen</h1>
|
<h1 style="display: flex; align-items: center;"><img src="./assets/icon-addon-2048.png" alt="Rentgen logo" style="margin-right: 1rem;" width="48"/> Rentgen</h1>
|
||||||
|
|
||||||
<strong>Rentgen</strong> is an add-on prepared for Firefox-based browsers. This extension will automatically visualize all the data that a given website ~~steals~~ sends to third parties.
|
|
||||||
|
|
||||||
Note: At the moment, we support Polish language because this extension generates mail content that is dedicated to Polish website owners. In further versions of this add-on, we will add other languages as well.
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
|
|
||||||
- analysis of web traffic generated by the visited website;
|
|
||||||
- visualization of data transmitted to third parties by the visited site (user's browsing history and cookies);
|
|
||||||
- preparation of screenshots of development tools as evidence of data transmitted to third parties;
|
|
||||||
- assisting in the evaluation of potential work areas for compliance with GDPR;
|
|
||||||
- generating a report or email content that can be sent to an administrator and Personal Data Protection Office in Poland.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Firefox: https://addons.mozilla.org/en-US/firefox/addon/rentgen/
|
|
||||||
|
|
||||||
## How to build and run Rentgen on your own
|
|
||||||
|
|
||||||
### Pre-requirements
|
|
||||||
|
|
||||||
- OS: Linux x86_64
|
|
||||||
- Node.js: 16.x version
|
|
||||||
- npm: 7.x version or higher
|
|
||||||
|
|
||||||
### Build steps
|
|
||||||
|
|
||||||
1. Pull repository or download a zip package
|
|
||||||
2. Go to the root directory of the pulled repository
|
|
||||||
3. Run command: `npm install`
|
|
||||||
4. Run command: `npm run build`
|
|
||||||
5. Run command: `npm run create-package`
|
|
||||||
6. Go to the `web-ext-artifacts` directory
|
|
||||||
7. You will find a zip archive: `rentgen-x-x-x.zip` (`x-x-x` means add-on version)
|
|
||||||
|
|
||||||
### Run steps
|
|
||||||
|
|
||||||
1. Run Firefox and go to `about:debugging`
|
|
||||||
2. Click _This Firefox_ tab
|
|
||||||
3. Click _Load Temporary Add-on..._ button
|
|
||||||
4. Pick the zip archive from last step of build process.
|
|
||||||
|
|
||||||
## Issue tracker
|
|
||||||
|
|
||||||
If you find a problem, please send us an email: kontakt@internet-czas-dzialac.pl
|
|
||||||
|
|
||||||
We don't receive issues on Microsoft Github.
|
|
||||||
|
|
||||||
Each issue will be reviewed and moved to an internal issues list of our Gitea instance: https://git.internet-czas-dzialac.pl/icd/rentgen/issues. We use Gitea and most likely in the future with the federalization of Gitea, we will be able to let users in to report issues directly from the Gitea site.
|
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
|
|
||||||
<img src="./assets/screenshots/image-14.png" />
|
|
||||||
<img src="./assets/screenshots/image-15.png" />
|
|
||||||
<img src="./assets/screenshots/3a.png" />
|
|
||||||
<img src="./assets/screenshots/3b.png" />
|
|
||||||
<img src="./assets/screenshots/4a.png" />
|
|
||||||
<img src="./assets/screenshots/4b.png" />
|
|
||||||
<img src="./assets/screenshots/5a.png" />
|
|
||||||
<img src="./assets/screenshots/5b.png" />
|
|
||||||
<img src="./assets/screenshots/2022-07-14_21-04.png" />
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<strong>Rentgen</strong> to wtyczka dla przeglądarek opartych o Firefoxa, która automatycznie wizualizuje, jakie dane zostały ~~wykradzione~~ wysłane do podmiotów trzecich przez odwiedzane strony. Wtyczka obrazuje ilość skryptów śledzących na stronie internetowej i pomaga w sformułowaniu maila do administratora strony, który może być podstawą do skargi RODO w Urzędzie Ochrony Danych Osobowych.
|
<strong>Rentgen</strong> to wtyczka dla przeglądarek opartych o Firefoxa, która automatycznie wizualizuje, jakie dane zostały ~~wykradzione~~ wysłane do podmiotów trzecich przez odwiedzane strony. Wtyczka obrazuje ilość skryptów śledzących na stronie internetowej i pomaga w sformułowaniu maila do administratora strony, który może być podstawą do skargi RODO w Urzędzie Ochrony Danych Osobowych.
|
||||||
|
|
||||||
|
|
||||||
**Funkcje Rentgena:**
|
**Funkcje Rentgena:**
|
||||||
|
|
||||||
- analiza ruchu sieciowego generowanego przez stronę internetową;
|
- analiza ruchu sieciowego generowanego przez stronę internetową;
|
||||||
|
@ -73,10 +11,6 @@ Each issue will be reviewed and moved to an internal issues list of our Gitea in
|
||||||
- pomoc w oszacowaniu potencjalnych obszarów roboczych względem zgodności z RODO;
|
- pomoc w oszacowaniu potencjalnych obszarów roboczych względem zgodności z RODO;
|
||||||
- generowanie raportu lub treści maila, którą można wysłać do administratora oraz Urzędu Ochrony Danych Osobowych.
|
- generowanie raportu lub treści maila, którą można wysłać do administratora oraz Urzędu Ochrony Danych Osobowych.
|
||||||
|
|
||||||
## Instalacja
|
|
||||||
|
|
||||||
Firefox: https://addons.mozilla.org/pl/firefox/addon/rentgen/
|
|
||||||
|
|
||||||
## Jak zbudować i uruchomić Rentgena ze źródeł
|
## Jak zbudować i uruchomić Rentgena ze źródeł
|
||||||
|
|
||||||
### Wymagania wstępne
|
### Wymagania wstępne
|
||||||
|
@ -104,7 +38,7 @@ Firefox: https://addons.mozilla.org/pl/firefox/addon/rentgen/
|
||||||
|
|
||||||
## Zgłaszanie błędów
|
## Zgłaszanie błędów
|
||||||
|
|
||||||
Jeżeli znajdziesz jakieś problem, napisz do nas maila: kontakt@internet-czas-dzialac.pl
|
Link do issue trackera na naszej instancji Discourse: https://forum.internet-czas-dzialac.pl/c/rentgen-issue-tracker
|
||||||
|
|
||||||
Nie przyjmujemy zgłoszeń na platformie Microsoft Github.
|
Nie przyjmujemy zgłoszeń na platformie Microsoft Github.
|
||||||
|
|
||||||
|
@ -112,3 +46,60 @@ Każdy problem zostanie sprawdzony i przeniesiony na wewnętrzną listę problem
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## English description 🇬🇧
|
||||||
|
|
||||||
|
<strong>Rentgen</strong> is an add-on prepared for Firefox-based browsers. This extension will automatically visualize all the data that a given website ~~steals~~ sends to third parties.
|
||||||
|
|
||||||
|
Note: At the moment, we support Polish language because this extension generates mail content that is dedicated to Polish website owners. In further versions of this add-on, we will add other languages as well.
|
||||||
|
|
||||||
|
**Features:**
|
||||||
|
|
||||||
|
- analysis of web traffic generated by the visited website;
|
||||||
|
- visualization of data transmitted to third parties by the visited site (user's browsing history and cookies);
|
||||||
|
- preparation of screenshots of development tools as evidence of data transmitted to third parties;
|
||||||
|
- assisting in the evaluation of potential work areas for compliance with GDPR;
|
||||||
|
- generating a report or email content that can be sent to an administrator and Personal Data Protection Office in Poland.
|
||||||
|
|
||||||
|
## How to build and run Rentgen on your own
|
||||||
|
|
||||||
|
### Pre-requirements
|
||||||
|
|
||||||
|
- OS: Linux x86_64
|
||||||
|
- Node.js: 16.x version
|
||||||
|
- npm: 7.x version or higher
|
||||||
|
|
||||||
|
### Build steps
|
||||||
|
|
||||||
|
1. Pull repository or download a zip package
|
||||||
|
2. Go to the root directory of the pulled repository
|
||||||
|
3. Run command: `npm install`
|
||||||
|
4. Run command: `npm run build`
|
||||||
|
5. Run command: `npm run create-package`
|
||||||
|
6. Go to the `web-ext-artifacts` directory
|
||||||
|
7. You will find a zip archive: `rentgen-x-x-x.zip` (`x-x-x` means add-on version)
|
||||||
|
|
||||||
|
### Run steps
|
||||||
|
|
||||||
|
1. Run Firefox and go to `about:debugging`
|
||||||
|
2. Click _This Firefox_ tab
|
||||||
|
3. Click _Load Temporary Add-on..._ button
|
||||||
|
4. Pick the zip archive from last step of build process.
|
||||||
|
|
||||||
|
## Issue tracker
|
||||||
|
|
||||||
|
Link to issue tracker on our Discourse instance: https://forum.internet-czas-dzialac.pl/c/rentgen-issue-tracker
|
||||||
|
|
||||||
|
Each issue will be reviewed and moved to an internal issues list of our Gitea instance: https://git.internet-czas-dzialac.pl/icd/rentgen/issues. We use Gitea and most likely in the future with the federalization of Gitea, we will be able to let users in to report issues directly from the Gitea site.
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
<img src="./assets/screenshots/image-14.png" />
|
||||||
|
<img src="./assets/screenshots/image-15.png" />
|
||||||
|
<img src="./assets/screenshots/3a.png" />
|
||||||
|
<img src="./assets/screenshots/3b.png" />
|
||||||
|
<img src="./assets/screenshots/4a.png" />
|
||||||
|
<img src="./assets/screenshots/4b.png" />
|
||||||
|
<img src="./assets/screenshots/5a.png" />
|
||||||
|
<img src="./assets/screenshots/5b.png" />
|
||||||
|
<img src="./assets/screenshots/2022-07-14_21-04.png" />
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import { Problem } from './problems/problem';
|
||||||
import { TransferOutsideEU } from './problems/transfer-outside-eu';
|
import { TransferOutsideEU } from './problems/transfer-outside-eu';
|
||||||
import { UnknownIdentity } from './problems/unknown-identity';
|
import { UnknownIdentity } from './problems/unknown-identity';
|
||||||
import { UnknownLegalBasis } from './problems/unknown-legal-basis';
|
import { UnknownLegalBasis } from './problems/unknown-legal-basis';
|
||||||
import { UnknownPurposes } from './problems/unknown-purpose';
|
|
||||||
import { UnlawfulCookieAccess } from './problems/unlawful-cookies';
|
import { UnlawfulCookieAccess } from './problems/unlawful-cookies';
|
||||||
|
|
||||||
export default function deduceProblems(
|
export default function deduceProblems(
|
||||||
|
@ -14,7 +13,6 @@ export default function deduceProblems(
|
||||||
): Problem[] {
|
): Problem[] {
|
||||||
return [
|
return [
|
||||||
NoInformationAtAllProblem,
|
NoInformationAtAllProblem,
|
||||||
UnknownPurposes,
|
|
||||||
UnlawfulCookieAccess,
|
UnlawfulCookieAccess,
|
||||||
UnknownLegalBasis,
|
UnknownLegalBasis,
|
||||||
UnknownIdentity,
|
UnknownIdentity,
|
||||||
|
|
|
@ -7,8 +7,6 @@ import './email-content.scss';
|
||||||
import { Fragment, useState } from 'react';
|
import { Fragment, useState } from 'react';
|
||||||
import emailIntro from './email-intro';
|
import emailIntro from './email-intro';
|
||||||
import { reportIntro } from './report-intro';
|
import { reportIntro } from './report-intro';
|
||||||
import { downloadText } from '../../util';
|
|
||||||
import { getFakeClusterData } from './fake-clusters';
|
|
||||||
|
|
||||||
const SS_URL = 'http://65.108.60.135:3000';
|
const SS_URL = 'http://65.108.60.135:3000';
|
||||||
|
|
||||||
|
@ -138,23 +136,6 @@ export default function EmailContent({
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="diag-toolbox">
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
onClick={() =>
|
|
||||||
downloadText(
|
|
||||||
'diag.json',
|
|
||||||
JSON.stringify({
|
|
||||||
answers,
|
|
||||||
fake_clusters_data: getFakeClusterData(clusters),
|
|
||||||
visited_url,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Pobierz plik diagnostyczny
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,49 +9,7 @@ export const Explainers: Record<ExplainerKey, (zaimek_index: 0 | 1 | 2 | 3) => J
|
||||||
<p>
|
<p>
|
||||||
Sztucznie wygenerowane identyfikatory przechowywane w plikach Cookies stanowią dane
|
Sztucznie wygenerowane identyfikatory przechowywane w plikach Cookies stanowią dane
|
||||||
osobowe. Wskazuje na to wprost Art. 4. pkt 1. RODO, wymieniając „identyfikator
|
osobowe. Wskazuje na to wprost Art. 4. pkt 1. RODO, wymieniając „identyfikator
|
||||||
internetowy” i „numer identyfikacyjny” jako przykłady danych osobowych. Losowe
|
internetowy” i „numer identyfikacyjny” jako przykłady danych osobowych.
|
||||||
przypisane identyfikatory mogą nie zawierać imienia i nazwiska osoby, której
|
|
||||||
dotyczą, ani nie prowadzić wprost do ich ustalenia, ale pozwalają odróżnić jedną,
|
|
||||||
daną konkretną osobę, od innych.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Por. komentarz z D. Lubasz [w:] Ochrona Danych Osobowych [red.] D. Lubasz, Warszawa
|
|
||||||
2020 r., str. 81:
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<em>
|
|
||||||
Zidentyfikowaną osobą fizyczną jest osoba, której tożsamość jest ustalona -
|
|
||||||
bezpośrednio i natychmiast, czyli taka, którą bezpośrednio można wskazać,
|
|
||||||
wyodrębnić lub wyróżnić z określonej zbiorowości.{' '}
|
|
||||||
<strong>Nie musi to natomiast polegać na podaniu jej imienia nazwiska</strong>.
|
|
||||||
Konstatacja ta jest zwłaszcza istotna w środowisku cyfrowym, w którym
|
|
||||||
identyfikacja sprowadza się do oznaczenia danego użytkownika w celu wywierania
|
|
||||||
na niego określonego wpływu. (...) Możliwą do zidentyfikowania jest osoba,
|
|
||||||
której tożsamość dopiero administrator może ustalić -{' '}
|
|
||||||
<strong>niezależnie od tego, czy to zrobi, czy nie</strong>.
|
|
||||||
</em>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Podobnie za{' '}
|
|
||||||
<em>
|
|
||||||
P. Litwiński [w:] Rozporządzenie UE w sprawie ochrony osób fizycznych w związku
|
|
||||||
z przetwarzaniem danych osobowych i w sprawie swobodnego przepływu takich
|
|
||||||
danych, Komentarz [red.] P. Litwiński, Warszawa 2018 r.
|
|
||||||
</em>
|
|
||||||
:
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<em>
|
|
||||||
Jak zwrócono uwagę w nauce prawa, identyfikacja osoby powinna być rozumiana jako
|
|
||||||
możliwość „fizycznego” wskazania tejże osoby, nie zaś jako ustalenie
|
|
||||||
podstawowych danych tej osoby (...). Analogicznie,{' '}
|
|
||||||
<em>identyfikacja osoby nie wymaga znajomości jej imienia lub nazwiska</em>,
|
|
||||||
wymaga natomiast znajomości pewnych unikalnych cech tej osoby, które odróżniają
|
|
||||||
ją od innych osób (...). W ten sam sposób należy więc rozumieć zwrot „można
|
|
||||||
zidentyfikować” - nie tylko jako możliwość odniesienia konkretnej informacji do
|
|
||||||
konkretnej osoby, lecz także jako możliwość wskazania tej osoby, rozumianego
|
|
||||||
jako faktyczne wyodrębnienie jej spośród innych osób.
|
|
||||||
</em>
|
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
// good for diagnostic purposes
|
|
||||||
|
|
||||||
import { RequestCluster } from '../../request-cluster';
|
|
||||||
import { DataLocation } from '../../stolen-data-entry';
|
|
||||||
|
|
||||||
export type FakeRequestClusterData = {
|
|
||||||
id: string;
|
|
||||||
hasCookies: boolean;
|
|
||||||
hasMarkedCookies: boolean;
|
|
||||||
hasMarks: boolean;
|
|
||||||
exposesOriginWhere: DataLocation[];
|
|
||||||
exposesOrigin: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function getFakeClusterData(
|
|
||||||
clusters: Record<string, RequestCluster>
|
|
||||||
): Record<string, FakeRequestClusterData> {
|
|
||||||
return Object.fromEntries(
|
|
||||||
Object.entries(clusters).map(([key, cluster]) => [key, cluster.makeDataForFake()])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function makeFakeClusters(
|
|
||||||
fake_clusters_data: Record<string, FakeRequestClusterData>
|
|
||||||
): Record<string, FakeCluster> {
|
|
||||||
return Object.fromEntries(
|
|
||||||
Object.entries(fake_clusters_data).map(([key, cluster_data]) => [
|
|
||||||
key,
|
|
||||||
new FakeCluster(cluster_data),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FakeCluster extends RequestCluster {
|
|
||||||
constructor(public data: FakeRequestClusterData) {
|
|
||||||
super(data.id);
|
|
||||||
|
|
||||||
for (const key of [
|
|
||||||
'hasCookies',
|
|
||||||
'hasMarkedCookies',
|
|
||||||
'hasMarks',
|
|
||||||
'exposesOriginWhere',
|
|
||||||
'exposesOrigin',
|
|
||||||
]) {
|
|
||||||
//@ts-ignore
|
|
||||||
this[key] = () => {
|
|
||||||
//@ts-ignore
|
|
||||||
return this.data[key];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hasCookies() {
|
|
||||||
return this.data.hasCookies;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -44,7 +44,7 @@ export default class NoInformationAtAllProblem extends Problem {
|
||||||
<li>Jaki jest cel takiego przetwarzania danych przez Państwa stronę?</li>
|
<li>Jaki jest cel takiego przetwarzania danych przez Państwa stronę?</li>
|
||||||
<li>
|
<li>
|
||||||
Jaka jest podstawa prawna takiego przetwarzania{' '}
|
Jaka jest podstawa prawna takiego przetwarzania{' '}
|
||||||
{mode == 'email' ? _('moich') : ''} danych osobowych
|
{mode == 'email' ? _('moich') : ''} danych osobowych $
|
||||||
{mode == 'report' ? 'użytkowników końcowych' : ''} przez Państwa stronę?
|
{mode == 'report' ? 'użytkowników końcowych' : ''} przez Państwa stronę?
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -5,8 +5,7 @@ import { Problem } from './problem';
|
||||||
|
|
||||||
export class TransferOutsideEU extends Problem {
|
export class TransferOutsideEU extends Problem {
|
||||||
getNecessaryExplainers(): ExplainerKey[] {
|
getNecessaryExplainers(): ExplainerKey[] {
|
||||||
const has_cookies = this.getRelatedClusters().some((cluster) => cluster.hasCookies());
|
return [];
|
||||||
return has_cookies ? ['cookies_are_pii'] : [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qualifies(): boolean {
|
qualifies(): boolean {
|
||||||
|
|
|
@ -19,8 +19,7 @@ export class UnknownIdentity extends Problem {
|
||||||
{mode == 'email' ? (
|
{mode == 'email' ? (
|
||||||
<p>
|
<p>
|
||||||
Na Państwa stronie nie {_('znalazłem')} sposobu na poznanie tożsamości
|
Na Państwa stronie nie {_('znalazłem')} sposobu na poznanie tożsamości
|
||||||
administratora strony <strong>przed</strong> podjęciem wyboru dotyczącego
|
administratora strony przed podjęciem wyboru dotyc
|
||||||
przetwarzania danych mnie dotyczących.
|
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p>Na stronie brakuje sposobu na poznanie tożsamości administratora strony.</p>
|
<p>Na stronie brakuje sposobu na poznanie tożsamości administratora strony.</p>
|
||||||
|
|
|
@ -21,11 +21,7 @@ const testCluster: (cluster: RequestCluster, answers: ParsedHostAnswers | undefi
|
||||||
|
|
||||||
export class UnknownLegalBasis extends Problem {
|
export class UnknownLegalBasis extends Problem {
|
||||||
getNecessaryExplainers(): ExplainerKey[] {
|
getNecessaryExplainers(): ExplainerKey[] {
|
||||||
const has_cookies = this.getRelatedClusters().some((cluster) => cluster.hasCookies());
|
return ['responsibility_for_third_parties'];
|
||||||
return [
|
|
||||||
'responsibility_for_third_parties',
|
|
||||||
...(has_cookies ? ['cookies_are_pii' as ExplainerKey] : []),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qualifies(): boolean {
|
qualifies(): boolean {
|
||||||
|
@ -74,7 +70,7 @@ export class UnknownLegalBasis extends Problem {
|
||||||
Na stronie nie znajdują się informacje o tym, jaka jest podstawa prawna
|
Na stronie nie znajdują się informacje o tym, jaka jest podstawa prawna
|
||||||
takiego przetwarzania danych osobowych, jakimi jest część historii
|
takiego przetwarzania danych osobowych, jakimi jest część historii
|
||||||
przeglądania. Zgodnie z treścią Artykułu 13. p. 1 lit. c) RODO, aby
|
przeglądania. Zgodnie z treścią Artykułu 13. p. 1 lit. c) RODO, aby
|
||||||
przetwarzać dane osobowe, trzeba poinformować osobę, której dane dotyczą, o
|
przetwarzać dane osobowe, trzeba poinformować osobę, któ©ej dane dotyczą, o
|
||||||
tym, jak ajest podstaw aprawna takiego przetwarzania danych.
|
tym, jak ajest podstaw aprawna takiego przetwarzania danych.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
import { RequestCluster } from '../../../request-cluster';
|
|
||||||
import { dataLocationToText, wordlist } from '../../../util';
|
|
||||||
import { ExplainerKey } from '../explainers';
|
|
||||||
import { v } from '../verbs';
|
|
||||||
import { Problem } from './problem';
|
|
||||||
|
|
||||||
export class UnknownPurposes extends Problem {
|
|
||||||
getNecessaryExplainers(): ExplainerKey[] {
|
|
||||||
const has_cookies = this.getAffectedClusters().some((cluster) => cluster.hasCookies());
|
|
||||||
if (has_cookies) {
|
|
||||||
return ['cookies_are_pii'];
|
|
||||||
} else {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
isHostAffected(host: string) {
|
|
||||||
const answers = this.answers.hosts[host];
|
|
||||||
if (!answers) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
['not_mentioned', 'not_before_making_a_choice'].includes(answers.present) &&
|
|
||||||
['no', 'not_sure'].includes(answers.was_processing_necessary) &&
|
|
||||||
(this.clusters[host].hasCookies() || this.clusters[host].exposesOrigin())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
qualifies(): boolean {
|
|
||||||
return Object.keys(this.answers.hosts).some((host) => this.isHostAffected(host));
|
|
||||||
}
|
|
||||||
|
|
||||||
getAffectedClusters(): RequestCluster[] {
|
|
||||||
return Object.keys(this.answers.hosts)
|
|
||||||
.filter((host) => this.isHostAffected(host))
|
|
||||||
.map((host) => this.clusters[host]);
|
|
||||||
}
|
|
||||||
|
|
||||||
getEmailContent({ mode, tone }: { mode: 'email' | 'report'; tone: 'official' | 'polite' }) {
|
|
||||||
const _ = (key: string) => v(key, this.answers.zaimek);
|
|
||||||
const affected_clusters = this.getAffectedClusters();
|
|
||||||
const has_history = affected_clusters.some((cluster) => cluster.exposesOrigin());
|
|
||||||
const has_cookies = affected_clusters.some((cluster) => cluster.hasCookies());
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h2>Cele przetwarzania danych</h2>
|
|
||||||
<p>
|
|
||||||
Państwa strona{' '}
|
|
||||||
{mode == 'email'
|
|
||||||
? `ujawniła dane ${_('mnie')} dotyczące`
|
|
||||||
: 'ujawnia dane dotyczące użytkowników'}{' '}
|
|
||||||
w zakresie{' '}
|
|
||||||
{wordlist([
|
|
||||||
...(has_cookies ? ['treści plików cookies'] : []),
|
|
||||||
...(has_history
|
|
||||||
? [
|
|
||||||
mode === 'email'
|
|
||||||
? `części ${_('mojej')} historii przeglądania`
|
|
||||||
: `części historii przeglądania`,
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
])}{' '}
|
|
||||||
podmiotom, które są właścicielami nastepujących domen:
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
{affected_clusters.map((cluster, index) => {
|
|
||||||
const locations = cluster.exposesOriginWhere();
|
|
||||||
return (
|
|
||||||
<li>
|
|
||||||
<strong>{cluster.id}</strong>:{' '}
|
|
||||||
{wordlist([
|
|
||||||
...(cluster.hasCookies() ? ['treść plików cookies'] : []),
|
|
||||||
...(cluster.exposesOrigin()
|
|
||||||
? [
|
|
||||||
(mode === 'email'
|
|
||||||
? `część ${_('mojej')} historii przeglądania`
|
|
||||||
: `część historii przeglądania użytkownika`) +
|
|
||||||
' (' +
|
|
||||||
wordlist(
|
|
||||||
locations.map((l) => dataLocationToText(l))
|
|
||||||
) +
|
|
||||||
')',
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
])}
|
|
||||||
{index === affected_clusters.length - 1 ? '.' : ';'}
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
{mode === 'email' ? (
|
|
||||||
tone === 'official' ? (
|
|
||||||
<p>
|
|
||||||
Proszę o wskazanie, jakie są cele takiego przetwarzania danych, które
|
|
||||||
mnie dotyczą.
|
|
||||||
</p>
|
|
||||||
) : (
|
|
||||||
<p>
|
|
||||||
Apeluję o umieszczenie informacji na temat na Państwa stronie, aby jej
|
|
||||||
użytkownicy mogli podejmować w pełni świadome wybory dotyczące
|
|
||||||
przetwarzania danych ich dotyczących.
|
|
||||||
</p>
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<p>
|
|
||||||
<strong>Zalecenie</strong>: warto dodać informacje o tym, jakie są cele
|
|
||||||
ujawniania wyżej opisanych danych wyżej opisanym podmiotom trzecim.
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,17 +5,6 @@
|
||||||
font-family: 'OpenSans' !important;
|
font-family: 'OpenSans' !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#app {
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-flow: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main-section {
|
|
||||||
flex-grow: 1;
|
|
||||||
margin-bottom: 20px; // to contain diag section
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
html {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
@ -300,9 +289,3 @@ h1 {
|
||||||
color: $ultra-black-color;
|
color: $ultra-black-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.diag-toolbox {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 10px;
|
|
||||||
left: 10px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -110,7 +110,7 @@ function Report() {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<section id="main-section">{result}</section>
|
<section>{result}</section>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -38,7 +38,7 @@ interface screenshotTask {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTaskEndpoint(visited_url: string, domains: string[]) {
|
function createTaskEndpoint(visited_url: string, domains: string[]) {
|
||||||
return `${SS_URL}/api/requests?url=${encodeURIComponent(visited_url)}${domains.reduce(
|
return `${SS_URL}/api/requests?url=${visited_url}${domains.reduce(
|
||||||
(prev: string, curr: string) => prev + '&domains[]=' + curr,
|
(prev: string, curr: string) => prev + '&domains[]=' + curr,
|
||||||
''
|
''
|
||||||
)}`;
|
)}`;
|
||||||
|
|
|
@ -7,15 +7,6 @@
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
|
|
||||||
&__header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.icon.cookie-data {
|
|
||||||
margin-left: 0.25rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.domain-checkbox {
|
.domain-checkbox {
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
width: 0.875rem;
|
width: 0.875rem;
|
||||||
|
|
|
@ -2,10 +2,12 @@ import React from 'react';
|
||||||
import { getMemory } from '../../memory';
|
import { getMemory } from '../../memory';
|
||||||
import { StolenDataEntry } from '../../stolen-data-entry';
|
import { StolenDataEntry } from '../../stolen-data-entry';
|
||||||
|
|
||||||
import { useEmitter } from '../../util';
|
import { maskString, useEmitter } from '../../util';
|
||||||
|
|
||||||
import './stolen-data-cluster.scss';
|
import './stolen-data-cluster.scss';
|
||||||
|
|
||||||
|
const MAX_STRING_VALUE_LENGTH = 100;
|
||||||
|
|
||||||
function StolenDataValue({ entry }: { entry: StolenDataEntry; prefixKey?: string }) {
|
function StolenDataValue({ entry }: { entry: StolenDataEntry; prefixKey?: string }) {
|
||||||
const [version] = useEmitter(entry);
|
const [version] = useEmitter(entry);
|
||||||
let body = null;
|
let body = null;
|
||||||
|
@ -41,16 +43,13 @@ function StolenDataRow({ entry }: { entry: StolenDataEntry }) {
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={entry.isMarked}
|
checked={entry.isMarked}
|
||||||
id={entry.id.toString()}
|
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
entry.toggleMark();
|
entry.toggleMark();
|
||||||
getMemory().emit('change', entry.request.shorthost);
|
getMemory().emit('change', entry.request.shorthost);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<th title={`Nazwa: ${entry.name}\nŹródło: ${entry.source}`}>
|
<th title={`Nazwa: ${entry.name}\nŹródło: ${entry.source}`}>{entry.name}</th>
|
||||||
<label htmlFor={entry.id.toString()}>{entry.name}</label>
|
|
||||||
</th>
|
|
||||||
<td className="icons">
|
<td className="icons">
|
||||||
{entry.source === 'cookie' ? (
|
{entry.source === 'cookie' ? (
|
||||||
<span title="Dane przechowywane w Cookies">
|
<span title="Dane przechowywane w Cookies">
|
||||||
|
@ -104,11 +103,13 @@ export default function StolenDataCluster({
|
||||||
shorthost,
|
shorthost,
|
||||||
minValueLength,
|
minValueLength,
|
||||||
cookiesOnly,
|
cookiesOnly,
|
||||||
|
refreshToken,
|
||||||
cookiesOrOriginOnly,
|
cookiesOrOriginOnly,
|
||||||
detailsVisibility,
|
detailsVisibility,
|
||||||
}: {
|
}: {
|
||||||
origin: string;
|
origin: string;
|
||||||
shorthost: string;
|
shorthost: string;
|
||||||
|
refreshToken: number;
|
||||||
minValueLength: number;
|
minValueLength: number;
|
||||||
cookiesOnly: boolean;
|
cookiesOnly: boolean;
|
||||||
cookiesOrOriginOnly: boolean;
|
cookiesOrOriginOnly: boolean;
|
||||||
|
@ -121,34 +122,20 @@ export default function StolenDataCluster({
|
||||||
return (
|
return (
|
||||||
<div className="stolen-data-cluster-container">
|
<div className="stolen-data-cluster-container">
|
||||||
<header className="domains-container">
|
<header className="domains-container">
|
||||||
<div className="domains-container__header">
|
<div>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="domain-checkbox"
|
className="domain-checkbox"
|
||||||
data-version={version}
|
data-version={version}
|
||||||
checked={cluster.hasMarks()}
|
checked={cluster.hasMarks()}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
console.log('Clicked checkbox!', {
|
|
||||||
cluster_id: cluster.id,
|
|
||||||
has_marks: cluster.hasMarks(),
|
|
||||||
});
|
|
||||||
cluster.hasMarks() ? cluster.undoMark() : cluster.autoMark();
|
cluster.hasMarks() ? cluster.undoMark() : cluster.autoMark();
|
||||||
getMemory().emit('change', cluster.id);
|
getMemory().emit('change', cluster.id);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<a className="domain" href={'https://' + cluster.id} target="_blank">
|
<a className="domain" href={'https://' + cluster.id} target="_blank">
|
||||||
{cluster.id}
|
{cluster.id}
|
||||||
</a>{' '}
|
</a>
|
||||||
{cluster.hasCookies() ? (
|
|
||||||
<img
|
|
||||||
src="/assets/icons/cookie.svg"
|
|
||||||
height={16}
|
|
||||||
width={16}
|
|
||||||
className="icon cookie-data"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="subdomains-container">
|
<div className="subdomains-container">
|
||||||
{fullHosts.map((host, index) => (
|
{fullHosts.map((host, index) => (
|
||||||
|
|
|
@ -14,15 +14,6 @@ async function getCurrentTab() {
|
||||||
import './../../styles/global.scss';
|
import './../../styles/global.scss';
|
||||||
import './toolbar.scss';
|
import './toolbar.scss';
|
||||||
|
|
||||||
function isDomainHighlySuspicious(domain: string): boolean {
|
|
||||||
return (
|
|
||||||
domain.includes('facebook') ||
|
|
||||||
domain.includes('twitter') ||
|
|
||||||
domain.includes('linkedin') ||
|
|
||||||
false
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Toolbar = () => {
|
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());
|
||||||
|
@ -62,13 +53,6 @@ const Toolbar = () => {
|
||||||
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) =>
|
|
||||||
isDomainHighlySuspicious(cluster1.id)
|
|
||||||
? -1
|
|
||||||
: isDomainHighlySuspicious(cluster2.id)
|
|
||||||
? 1
|
|
||||||
: 0
|
|
||||||
)
|
|
||||||
.map((cluster) => cluster.id);
|
.map((cluster) => cluster.id);
|
||||||
setExposedOriginDomainCopy('');
|
setExposedOriginDomainCopy('');
|
||||||
|
|
||||||
|
@ -102,13 +86,6 @@ const Toolbar = () => {
|
||||||
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) =>
|
|
||||||
isDomainHighlySuspicious(cluster1.id)
|
|
||||||
? -1
|
|
||||||
: isDomainHighlySuspicious(cluster2.id)
|
|
||||||
? 1
|
|
||||||
: 0
|
|
||||||
)
|
|
||||||
.map((cluster) => cluster.id);
|
.map((cluster) => cluster.id);
|
||||||
setCookieDomainCopy('');
|
setCookieDomainCopy('');
|
||||||
|
|
||||||
|
|
13
diag.html
13
diag.html
|
@ -1,13 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>RENTGEN DIAG</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
</body>
|
|
||||||
<script src="/node_modules/react/umd/react.production.min.js"></script>
|
|
||||||
<script src="/node_modules/react-dom/umd/react-dom.production.min.js"></script>
|
|
||||||
<script src="/node_modules/survey-react/survey.react.min.js"></script>
|
|
||||||
<script src="./lib/diag.js"></script>
|
|
||||||
</html>
|
|
65
diag.tsx
65
diag.tsx
|
@ -1,65 +0,0 @@
|
||||||
import React, { Fragment } from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import EmailContent from './components/report-window/email-content';
|
|
||||||
|
|
||||||
import { makeFakeClusters } from './components/report-window/fake-clusters';
|
|
||||||
|
|
||||||
class ErrorBoundary extends React.Component<any, { hasError: boolean; error: any }> {
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
this.state = { hasError: false, error: null };
|
|
||||||
}
|
|
||||||
|
|
||||||
static getDerivedStateFromError(error: any) {
|
|
||||||
return { hasError: true, error };
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (this.state.hasError) {
|
|
||||||
return <h1>Something went wrong.</h1>;
|
|
||||||
}
|
|
||||||
return this.props.children;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function Diag() {
|
|
||||||
const [json, setjson] = React.useState(
|
|
||||||
JSON.stringify({ answers: { hosts: {} }, visited_url: '', fake_clusters_data: {} })
|
|
||||||
);
|
|
||||||
const { answers, visited_url, fake_clusters_data } = JSON.parse(json);
|
|
||||||
const fake_clusters = makeFakeClusters(fake_clusters_data);
|
|
||||||
return (
|
|
||||||
<div style={{ display: 'grid', gridTemplateColumns: '50% 50%', minHeight: '100vh' }}>
|
|
||||||
<div>
|
|
||||||
<textarea
|
|
||||||
style={{ width: 'calc(100% - 50px)', height: '100%' }}
|
|
||||||
value={json}
|
|
||||||
onChange={(e) => {
|
|
||||||
setjson(e.target.value);
|
|
||||||
}}
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<EmailContent
|
|
||||||
{...{
|
|
||||||
answers,
|
|
||||||
visited_url,
|
|
||||||
clusters: fake_clusters,
|
|
||||||
scrRequestPath: '/screenshots',
|
|
||||||
downloadFiles: () => {
|
|
||||||
alert('download!');
|
|
||||||
},
|
|
||||||
user_role: 'user',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ReactDOM.render(
|
|
||||||
<ErrorBoundary>
|
|
||||||
<Diag />
|
|
||||||
</ErrorBoundary>,
|
|
||||||
document.getElementById('app')
|
|
||||||
);
|
|
|
@ -48,7 +48,6 @@ esbuild
|
||||||
'components/sidebar/sidebar.tsx',
|
'components/sidebar/sidebar.tsx',
|
||||||
'components/report-window/report-window.tsx',
|
'components/report-window/report-window.tsx',
|
||||||
'background.ts',
|
'background.ts',
|
||||||
'diag.tsx',
|
|
||||||
'styles/global.scss',
|
'styles/global.scss',
|
||||||
'styles/fonts.scss',
|
'styles/fonts.scss',
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
import { DataLocation, StolenDataEntry } from './stolen-data-entry';
|
import { StolenDataEntry } from './stolen-data-entry';
|
||||||
import {
|
import {
|
||||||
flattenObjectEntries,
|
flattenObjectEntries,
|
||||||
getshorthost,
|
getshorthost,
|
||||||
|
@ -164,12 +164,12 @@ export default class ExtendedRequest {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
exposesOriginWhere(): null | DataLocation {
|
exposesOrigin() {
|
||||||
const host = this.originalHost;
|
const host = this.originalHost;
|
||||||
const path = this.originalPathname || '/';
|
const path = this.originalPathname || '/';
|
||||||
const shorthost = getshorthost(host);
|
const shorthost = getshorthost(host);
|
||||||
if (this.getReferer().includes(shorthost)) {
|
if (this.getReferer().includes(shorthost)) {
|
||||||
return { path: this.url, source: 'header', key: 'Referer' };
|
return true;
|
||||||
}
|
}
|
||||||
for (const entry of this.stolenData) {
|
for (const entry of this.stolenData) {
|
||||||
if (
|
if (
|
||||||
|
@ -177,14 +177,10 @@ export default class ExtendedRequest {
|
||||||
entry.value.includes(path) ||
|
entry.value.includes(path) ||
|
||||||
entry.value.includes(shorthost)
|
entry.value.includes(shorthost)
|
||||||
) {
|
) {
|
||||||
return entry.toDataLocation();
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
exposesOrigin() {
|
|
||||||
return this.exposesOriginWhere() !== null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getAllStolenData(): StolenDataEntry[] {
|
private getAllStolenData(): StolenDataEntry[] {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "Rentgen",
|
"name": "Rentgen",
|
||||||
"short_name": "Rentgen",
|
"short_name": "Rentgen",
|
||||||
"version": "0.1.10",
|
"version": "0.1.8",
|
||||||
"author": "Kuba Orlik, Arkadiusz Wieczorek (Internet. Czas działać!)",
|
"author": "Kuba Orlik, Arkadiusz Wieczorek (Internet. Czas działać!)",
|
||||||
"homepage_url": "https://git.internet-czas-dzialac.pl/icd/rentgen",
|
"homepage_url": "https://git.internet-czas-dzialac.pl/icd/rentgen",
|
||||||
"background": {
|
"background": {
|
||||||
|
|
4
package-lock.json
generated
4
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "rentgen",
|
"name": "rentgen",
|
||||||
"version": "0.1.10",
|
"version": "0.1.7",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "rentgen",
|
"name": "rentgen",
|
||||||
"version": "0.1.10",
|
"version": "0.1.7",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iabtcf/core": "^1.3.1",
|
"@iabtcf/core": "^1.3.1",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "rentgen",
|
"name": "rentgen",
|
||||||
"version": "0.1.10",
|
"version": "0.1.8",
|
||||||
"description": "Rentgen is an add-on prepared for Firefox-based browsers. This extension will automatically visualize all the data that a given website sends to third parties.",
|
"description": "Rentgen is an add-on prepared for Firefox-based browsers. This extension will automatically visualize all the data that a given website sends to third parties.",
|
||||||
"main": "esbuild.config.js",
|
"main": "esbuild.config.js",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { FakeRequestClusterData } from './components/report-window/fake-clusters';
|
|
||||||
import ExtendedRequest from './extended-request';
|
import ExtendedRequest from './extended-request';
|
||||||
import { SaferEmitter } from './safer-emitter';
|
import { SaferEmitter } from './safer-emitter';
|
||||||
import { DataLocation, Sources, StolenDataEntry } from './stolen-data-entry';
|
import { Sources, StolenDataEntry } from './stolen-data-entry';
|
||||||
|
|
||||||
import { allSubhosts, isSameURL, reduceConcat, unique } from './util';
|
import { allSubhosts, isSameURL, reduceConcat, unique } from './util';
|
||||||
|
|
||||||
|
@ -172,13 +171,7 @@ export class RequestCluster extends SaferEmitter {
|
||||||
return this.requests.map((request) => request.getMarkedEntries()).reduce(reduceConcat, []);
|
return this.requests.map((request) => request.getMarkedEntries()).reduce(reduceConcat, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
exposesOriginWhere(): DataLocation[] {
|
exposesOrigin() {
|
||||||
return this.requests
|
|
||||||
.map((request) => request.exposesOriginWhere())
|
|
||||||
.filter((l) => l !== null) as DataLocation[];
|
|
||||||
}
|
|
||||||
|
|
||||||
exposesOrigin(): boolean {
|
|
||||||
return this.requests.some((request) => request.exposesOrigin());
|
return this.requests.some((request) => request.exposesOrigin());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,15 +201,4 @@ export class RequestCluster extends SaferEmitter {
|
||||||
}
|
}
|
||||||
return types_of_data.join(', ');
|
return types_of_data.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
makeDataForFake(): FakeRequestClusterData {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
hasCookies: this.hasCookies(),
|
|
||||||
hasMarkedCookies: this.hasMarkedCookies(),
|
|
||||||
hasMarks: this.hasMarks(),
|
|
||||||
exposesOriginWhere: this.exposesOriginWhere(),
|
|
||||||
exposesOrigin: this.exposesOrigin(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,12 +33,6 @@ const id = (function* id() {
|
||||||
|
|
||||||
export type DecodingSchema = 'base64' | 'raw';
|
export type DecodingSchema = 'base64' | 'raw';
|
||||||
|
|
||||||
export type DataLocation = {
|
|
||||||
path: string;
|
|
||||||
source: Sources;
|
|
||||||
key: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class StolenDataEntry extends SaferEmitter {
|
export class StolenDataEntry extends SaferEmitter {
|
||||||
public isIAB = false;
|
public isIAB = false;
|
||||||
public id: number;
|
public id: number;
|
||||||
|
@ -259,12 +253,4 @@ export class StolenDataEntry extends SaferEmitter {
|
||||||
haystack.includes(getshorthost(this.request.origin))
|
haystack.includes(getshorthost(this.request.origin))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
toDataLocation(): DataLocation {
|
|
||||||
return {
|
|
||||||
path: this.request.url,
|
|
||||||
source: this.source,
|
|
||||||
key: this.name,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
36
util.ts
36
util.ts
|
@ -1,6 +1,5 @@
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { DataLocation, Sources } from './stolen-data-entry';
|
|
||||||
|
|
||||||
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;
|
||||||
|
@ -78,7 +77,7 @@ export function useEmitter(
|
||||||
export function parseCookie(cookie: string): Record<string, string> {
|
export function parseCookie(cookie: string): Record<string, string> {
|
||||||
return cookie
|
return cookie
|
||||||
.split(';')
|
.split(';')
|
||||||
.map((l) => [l.slice(0, l.indexOf('=')), l.slice(l.indexOf('=') + 1)])
|
.map((l) => l.split('='))
|
||||||
.reduce(
|
.reduce(
|
||||||
(acc, [key, value]) => ({
|
(acc, [key, value]) => ({
|
||||||
...acc,
|
...acc,
|
||||||
|
@ -284,37 +283,8 @@ export function normalizeForClassname(string: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wordlist(words: string[]) {
|
export function wordlist(words: string[]) {
|
||||||
return Array.from(new Set(words)).reduce(
|
return words.reduce(
|
||||||
(acc, word, i) =>
|
(acc, word, i) => `${acc}${i > 0 ? (i < words.length - 1 ? ',' : ' i') : ''} ${word}`,
|
||||||
`${acc}${
|
|
||||||
i > 0 ? (i < words.length - 1 ? ', ' : Math.random() > 0.5 ? ' i ' : ' oraz ') : ''
|
|
||||||
}${word}`,
|
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const source_to_word: Record<Sources, string> = {
|
|
||||||
cookie: 'plik cookie o nazwie',
|
|
||||||
pathname: 'fragment ścieżki w URL',
|
|
||||||
queryparams: 'query params w URL o nazwie',
|
|
||||||
header: 'nagłówek HTTP',
|
|
||||||
request_body: 'body zapytania HTTP, pod kluczem',
|
|
||||||
};
|
|
||||||
|
|
||||||
export function dataLocationToText(l: DataLocation) {
|
|
||||||
return `${source_to_word[l.source]} ${l.key}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function downloadText(filename: string, text: string) {
|
|
||||||
// https://stackoverflow.com/questions/45831191/generate-and-download-file-from-js
|
|
||||||
var element = document.createElement('a');
|
|
||||||
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
|
||||||
element.setAttribute('download', filename);
|
|
||||||
|
|
||||||
element.style.display = 'none';
|
|
||||||
document.body.appendChild(element);
|
|
||||||
|
|
||||||
element.click();
|
|
||||||
|
|
||||||
document.body.removeChild(element);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user