From 268f9a7d067cf11078384a9f0a1d6ecce4b6d55f Mon Sep 17 00:00:00 2001 From: Arkadiusz Wieczorek Date: Wed, 19 Jan 2022 13:12:28 +0100 Subject: [PATCH] Add nav --- assets/icons/mail.svg | 3 + assets/icons/settings.svg | 3 + assets/icons/short_left.svg | 3 + assets/icons/trash_full.svg | 3 + report-window/email-template-1.tsx | 433 ++++++------ report-window/email-template-2-controls.tsx | 319 ++++----- report-window/email-template-2.tsx | 719 ++++++++++---------- report-window/report-window.html | 26 +- request-cluster.ts | 332 ++++----- sidebar/global.scss | 4 +- sidebar/sidebar.scss | 36 + sidebar/sidebar.tsx | 57 +- sidebar/stolen-data.tsx | 173 ++--- 13 files changed, 1134 insertions(+), 977 deletions(-) create mode 100644 assets/icons/mail.svg create mode 100644 assets/icons/settings.svg create mode 100644 assets/icons/short_left.svg create mode 100644 assets/icons/trash_full.svg diff --git a/assets/icons/mail.svg b/assets/icons/mail.svg new file mode 100644 index 0000000..4e6fadd --- /dev/null +++ b/assets/icons/mail.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/settings.svg b/assets/icons/settings.svg new file mode 100644 index 0000000..6aa67ab --- /dev/null +++ b/assets/icons/settings.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/short_left.svg b/assets/icons/short_left.svg new file mode 100644 index 0000000..e5bb90b --- /dev/null +++ b/assets/icons/short_left.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/trash_full.svg b/assets/icons/trash_full.svg new file mode 100644 index 0000000..b8cf79a --- /dev/null +++ b/assets/icons/trash_full.svg @@ -0,0 +1,3 @@ + + + diff --git a/report-window/email-template-1.tsx b/report-window/email-template-1.tsx index df0fb0f..5bfabd3 100644 --- a/report-window/email-template-1.tsx +++ b/report-window/email-template-1.tsx @@ -1,215 +1,232 @@ -import React from "react"; -import { useState } from "react"; -import { RequestCluster } from "../request-cluster"; -import { StolenDataEntry } from "../stolen-data-entry"; -import { getDate, toBase64 } from "../util"; -import DomainSummary from "./domain-summary"; +import React from 'react'; +import { useState } from 'react'; +import { RequestCluster } from '../request-cluster'; +import { StolenDataEntry } from '../stolen-data-entry'; +import { getDate, toBase64 } from '../util'; +import DomainSummary from './domain-summary'; -type PopupState = "not_clicked" | "clicked_but_no_reject_all"; +type PopupState = 'not_clicked' | 'clicked_but_no_reject_all'; export default function EmailTemplate1({ - entries, - clusters, + entries, + clusters, }: { - entries: StolenDataEntry[]; - clusters: Record; - version: number; + entries: StolenDataEntry[]; + clusters: Record; + version: number; }): JSX.Element { - const [popupState, setPopupState] = useState("not_clicked"); - const [acceptAllName, setAcceptAllName] = useState( - "Zaakceptuj wszystkie" - ); - const [popupScreenshotBase64, setPopupScreenshotBase64] = - useState(null); + const [popupState, setPopupState] = useState('not_clicked'); + const [acceptAllName, setAcceptAllName] = useState( + 'Zaakceptuj wszystkie' + ); + const [popupScreenshotBase64, setPopupScreenshotBase64] = + useState(null); - return ( -
- - - {popupState === "clicked_but_no_reject_all" ? ( - <> -
- - setAcceptAllName(e.target.value), - }} - /> -
-
- - { - setPopupScreenshotBase64(await toBase64(e.target.files[0])); - }, - }} - /> -
- - ) : null} -

- Dzień dobry, w dniu {getDate()} odwiedziłem stronę{" "} - {entries[0].request.originalURL}. Strona ta wysłała moje dane osobowe do - podmiotów trzecich - bez mojej zgody.{" "} -

-
    - {Object.values(clusters) - .filter((cluster) => cluster.hasMarks()) - .map((cluster) => ( - - ))} -
-

- {" "} - Dane te zostały wysłane przez Państwa stronę - a mówiąc dokładniej, - przez zamieszczone przez Państwa na tej stronie skrypty. -

- {popupState === "not_clicked" ? ( -

- Nastąpiło to, zanim zdążyłem w ogóle przeczytać treść wyskakującego - okienka ze zgodami i zanim miałem szansę wyrazić sprzeciw takiemu - przetwarzaniu danych osobowych. -

- ) : null} - {popupState === "clicked_but_no_reject_all" ? ( -

- O ile po wejściu na stronę wcisnąłem w wyskakującym okienku przycisk „ - {acceptAllName}”, o tyle nie stanowi to według mnie ważnej w świetle - RODO zgody, gdyż brakowało w tym okienku równie łatwo osiągalnego - przycisku, którego kliknięcie skutkowałoby zasygnalizowaniem braku - mojej zgody na takie przetwarzanie moich danych. Mówiąc wprost - - wyrażenie „zgody” było łatwiejsze niż jej niewyrażenie. Niewyrażenie - zgody wiąże się z negatywną konsekwencją konieczności przechodzenia - przez dodatkowe kroki w wyskakującym okienku. Zatem tak otrzymana - przez Państwo moja „zgoda” nie jest poprawną podstawą prawną do - przetwarzania moich danych osobowych, gdyż nie spełnia warunku - dobrowolności wspomnianego w Art. 4. pkt 11{" "} - - rozporządzenia Parlamentu Europejskiego i Rady (UE) 2016/679 z dnia - 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych w związku z - przetwarzaniem danych osobowych i w sprawie swobodnego przepływu - takich danych oraz uchylenia dyrektywy 95/46/WE - - .{} -

- ) : null} -

- Udokumentowałem to na zrzutach ekranu z mojej przeglądarki internetowej, - które to zrzuty przesyłam w załączeniu. -

-

- Wiem, że nie wszystkie rodzaje przetwarzania danych wymagają zgody - użytkownika. W kontekście stron internetowych z wymienionych w Art. 6. - pkt 1. RODO mogą mieć zastosowanie albo „zgoda” (Art. 6. pkt 1. lit. - a)), albo niezbędność tego przetwarzania do wykonania umowy (Art. 6. pkt - 1. lit. b)), albo uzasadniony interes (Art. 6. pkt 1. lit. f)). Wiem - też, że każda z tych podstaw prawnych ma moc dopiero po spełnieniu - określonych warunków. -

-

- Nie widzę ważnej podstawy prawnej legalizującej procesy przetwarzania - moich danych osobowych, jakie wymieniłem powyżej (na pewno nie jest to - przetwarzanie konieczne do wyświetlenia strony z technicznego punktu - widzenia). Jeżeli takie przesłanki legalizujące jednak występują, proszę - o ich wskazanie, - - {" "} - dla każdego z celów i podmiotów z osobna - - . -

-

- Jeżeli wskazaną przez Państwa przesłanką legalizującą dany element - procesu przetwarzania danych osobowych przez Państwa stronę jest Art 6. - pkt 1 lit. a) RODO (zgoda), na mocy Art. 7 pkt 1 RODO proszę o - wykazanie, że udzieliłem Państwu zgodę na takie przetwarzanie moich - danych osobowych zanim to przetwarzanie nastąpiło, oraz że ta zgoda jest - ważna w świetle RODO (odnosząc się w szczególności do art. 7 ust. 3 - RODO). Z góry zaznaczam, że „ustawienia przeglądarki” nie stanowią - ważnej w świetle RODO zgody. -

-

- Jeżeli wskazaną przez Państwa przesłanką legalizującą dany element - procesu przetwarzania danych osobowych przez Państwa stronę jest Art 6. - pkt 1 lit. b) RODO (niezbędność takiego przetwarzania do wykonania - umowy), proszę o wskazanie, w jaki sposób ta konieczność zachodzi, oraz - co sprawia, że Państwa zdaniem nie można wykonać umowy związanej z - wyświetleniem Państwa strony bez przekazywania identyfikatora - internetowego z plików Cookies lub historii przeglądania w nagłówku - Referer do wskazanych podmiotów trzecich. -

-

- Jeżeli wskazaną przez Państwa przesłanką legalizującą dany element - procesu przetwarzania danych osobowych przez Państwa stronę jest Art 6. - pkt 1 lit. f) RODO (uzasadniony interes), proszę o wskazanie, jaki to - jest konkretny interes (prosze o bardziej dokładny opis - niż np. tylko "marketing"), oraz o wynik testu równowagi pomiędzy - Państwa interesem a moimi podstawowymi wolnościami i prawami - ze - wskazaniem tego, co sprawia, że w Państwa ocenie Państwa uzasadniony - interes przeważa moje prawa i interesy w kontekście wspomnianych powyżej - procesów przetwarzania danych. Proszę też pamiętać, że aby w ramach - danego celu przetwarzania powołać się na prawnie uzasadniony interes, - powinni mi Państo umożliwić wyrażenie sprzeciwu wobec przetwarzania - moich danych w tym celu przed rozpoczęciem przetwarzania - zob.{" "} - - Wytyczne 8/2020 Europejskiej Rady Ochrony Danych dotyczące - targetowania użytkowników mediów społecznościowych - -

-

- Niniejszym zwracam się także z żądaniem ujawnienia tożsamości podmiotów, - które są właścicielami wyżej wymienionych domen, abym mógł zapoznać się - z ich politykami prywatności i zwrócić się do tych podmiotów o usunięcie - z ich baz wysłanych przez Państwa stronę moich danych. -

-

- Proszę też o wysłanie kopii danych zebranych na mój temat i wysłanych do - wyżej wymienionych podmiotów. -

-

- W odpowiedzi proszę się nie powoływać na IAB Europe i ich rzekomą renomę - w tworzeniu rozwiązań zgodnych z RODO. IAB chroni interes reklamodawców, - a nie Użytkowników, i ich rozwiązania (np. TCF) są{" "} - - notorycznie niezgodne z RODO i pozbawione szacunku dla Użytkowników - - . -

-

- Apeluję także o wprowadzenie stosownych zmian na stronie tak, aby nie - pozostawiać cienia wątpliwości odnośnie tego, na mocy jakiej przesłanki - legalizującej dane są przetwarzane przez wspomniane podmioty trzecie, - lub tak, aby te dane po prostu nie były wysyłane. Pomoże to zachować - prywatność innym użytkownikom Państwa strony. Polecam Państwa uwadze - oficjalne wytyczne EROD dotyczące zgody w kontekście RODO: - https://edpb.europa.eu/sites/default/files/files/file1/edpb_guidelines_202005_consent_pl.pdf - ). Aby na przykład zapobiec automatycznemu wysyłaniu historii - przeglądania do podmiotów trzecich przez Państwa stronę, można po prostu - ustawić odpowiednio treść nagłówka{" "} - - Referrer-Policy{" "} - - . -

-
- ); + return ( +
+ + + {popupState === 'clicked_but_no_reject_all' ? ( + <> +
+ + + setAcceptAllName(e.target.value), + }} + /> +
+
+ + { + setPopupScreenshotBase64( + await toBase64(e.target.files[0]) + ); + }, + }} + /> +
+ + ) : null} +

+ Dzień dobry, w dniu {getDate()} odwiedziłem stronę{' '} + {entries[0].request.originalURL}. Strona ta wysłała moje dane + osobowe do podmiotów trzecich - bez mojej zgody.{' '} +

+
    + {Object.values(clusters) + .filter((cluster) => cluster.hasMarks()) + .map((cluster) => ( + + ))} +
+

+ {' '} + Dane te zostały wysłane przez Państwa stronę - a mówiąc + dokładniej, przez zamieszczone przez Państwa na tej stronie + skrypty. +

+ {popupState === 'not_clicked' ? ( +

+ Nastąpiło to, zanim zdążyłem w ogóle przeczytać treść + wyskakującego okienka ze zgodami i zanim miałem szansę + wyrazić sprzeciw takiemu przetwarzaniu danych osobowych. +

+ ) : null} + {popupState === 'clicked_but_no_reject_all' ? ( +

+ O ile po wejściu na stronę wcisnąłem w wyskakującym okienku + przycisk „{acceptAllName}”, o tyle nie stanowi to według + mnie ważnej w świetle RODO zgody, gdyż brakowało w tym + okienku równie łatwo osiągalnego przycisku, którego + kliknięcie skutkowałoby zasygnalizowaniem braku mojej zgody + na takie przetwarzanie moich danych. Mówiąc wprost - + wyrażenie „zgody” było łatwiejsze niż jej niewyrażenie. + Niewyrażenie zgody wiąże się z negatywną konsekwencją + konieczności przechodzenia przez dodatkowe kroki w + wyskakującym okienku. Zatem tak otrzymana przez Państwo moja + „zgoda” nie jest poprawną podstawą prawną do przetwarzania + moich danych osobowych, gdyż nie spełnia warunku + dobrowolności wspomnianego w Art. 4. pkt 11{' '} + + rozporządzenia Parlamentu Europejskiego i Rady (UE) + 2016/679 z dnia 27 kwietnia 2016 r. w sprawie ochrony + osób fizycznych w związku z przetwarzaniem danych + osobowych i w sprawie swobodnego przepływu takich danych + oraz uchylenia dyrektywy 95/46/WE + + .{} +

+ ) : null} +

+ Udokumentowałem to na zrzutach ekranu z mojej przeglądarki + internetowej, które to zrzuty przesyłam w załączeniu. +

+

+ Wiem, że nie wszystkie rodzaje przetwarzania danych wymagają + zgody użytkownika. W kontekście stron internetowych z + wymienionych w Art. 6. pkt 1. RODO mogą mieć zastosowanie albo + „zgoda” (Art. 6. pkt 1. lit. a)), albo niezbędność tego + przetwarzania do wykonania umowy (Art. 6. pkt 1. lit. b)), albo + uzasadniony interes (Art. 6. pkt 1. lit. f)). Wiem też, że każda + z tych podstaw prawnych ma moc dopiero po spełnieniu określonych + warunków. +

+

+ Nie widzę ważnej podstawy prawnej legalizującej procesy + przetwarzania moich danych osobowych, jakie wymieniłem powyżej + (na pewno nie jest to przetwarzanie konieczne do wyświetlenia + strony z technicznego punktu widzenia). Jeżeli takie przesłanki + legalizujące jednak występują, proszę o ich wskazanie, + + {' '} + dla każdego z celów i podmiotów z osobna + + . +

+

+ Jeżeli wskazaną przez Państwa przesłanką legalizującą dany + element procesu przetwarzania danych osobowych przez Państwa + stronę jest Art 6. pkt 1 lit. a) RODO (zgoda), na mocy Art. 7 + pkt 1 RODO proszę o wykazanie, że udzieliłem Państwu zgodę na + takie przetwarzanie moich danych osobowych zanim to + przetwarzanie nastąpiło, oraz że ta zgoda jest ważna w świetle + RODO (odnosząc się w szczególności do art. 7 ust. 3 RODO). Z + góry zaznaczam, że „ustawienia przeglądarki” nie stanowią ważnej + w świetle RODO zgody. +

+

+ Jeżeli wskazaną przez Państwa przesłanką legalizującą dany + element procesu przetwarzania danych osobowych przez Państwa + stronę jest Art 6. pkt 1 lit. b) RODO (niezbędność takiego + przetwarzania do wykonania umowy), proszę o wskazanie, w jaki + sposób ta konieczność zachodzi, oraz co sprawia, że Państwa + zdaniem nie można wykonać umowy związanej z wyświetleniem + Państwa strony bez przekazywania identyfikatora internetowego z + plików Cookies lub historii przeglądania w nagłówku Referer do + wskazanych podmiotów trzecich. +

+

+ Jeżeli wskazaną przez Państwa przesłanką legalizującą dany + element procesu przetwarzania danych osobowych przez Państwa + stronę jest Art 6. pkt 1 lit. f) RODO (uzasadniony interes), + proszę o wskazanie, jaki to jest{' '} + konkretny interes (prosze o bardziej dokładny + opis niż np. tylko "marketing"), oraz o wynik testu równowagi + pomiędzy Państwa interesem a moimi podstawowymi wolnościami i + prawami - ze wskazaniem tego, co sprawia, że w Państwa ocenie + Państwa uzasadniony interes przeważa moje prawa i interesy w + kontekście wspomnianych powyżej procesów przetwarzania danych. + Proszę też pamiętać, że aby w ramach danego celu przetwarzania + powołać się na prawnie uzasadniony interes, powinni mi Państo + umożliwić wyrażenie sprzeciwu wobec przetwarzania moich danych w + tym celu przed rozpoczęciem przetwarzania - zob.{' '} + + Wytyczne 8/2020 Europejskiej Rady Ochrony Danych dotyczące + targetowania użytkowników mediów społecznościowych + +

+

+ Niniejszym zwracam się także z żądaniem ujawnienia tożsamości + podmiotów, które są właścicielami wyżej wymienionych domen, abym + mógł zapoznać się z ich politykami prywatności i zwrócić się do + tych podmiotów o usunięcie z ich baz wysłanych przez Państwa + stronę moich danych. +

+

+ Proszę też o wysłanie kopii danych zebranych na mój temat i + wysłanych do wyżej wymienionych podmiotów. +

+

+ W odpowiedzi proszę się nie powoływać na IAB Europe i ich + rzekomą renomę w tworzeniu rozwiązań zgodnych z RODO. IAB chroni + interes reklamodawców, a nie Użytkowników, i ich rozwiązania + (np. TCF) są{' '} + + notorycznie niezgodne z RODO i pozbawione szacunku dla + Użytkowników + + . +

+

+ Apeluję także o wprowadzenie stosownych zmian na stronie tak, + aby nie pozostawiać cienia wątpliwości odnośnie tego, na mocy + jakiej przesłanki legalizującej dane są przetwarzane przez + wspomniane podmioty trzecie, lub tak, aby te dane po prostu nie + były wysyłane. Pomoże to zachować prywatność innym użytkownikom + Państwa strony. Polecam Państwa uwadze oficjalne wytyczne EROD + dotyczące zgody w kontekście RODO: + https://edpb.europa.eu/sites/default/files/files/file1/edpb_guidelines_202005_consent_pl.pdf + ). Aby na przykład zapobiec automatycznemu wysyłaniu historii + przeglądania do podmiotów trzecich przez Państwa stronę, można + po prostu ustawić odpowiednio treść nagłówka{' '} + + Referrer-Policy{' '} + + . +

+
+ ); } diff --git a/report-window/email-template-2-controls.tsx b/report-window/email-template-2-controls.tsx index 23b1e09..804755f 100644 --- a/report-window/email-template-2-controls.tsx +++ b/report-window/email-template-2-controls.tsx @@ -1,163 +1,170 @@ -import React from "react"; -import { Dispatch, SetStateAction } from "react"; -import { toBase64 } from "../util"; -import { EmailTemplate2Config } from "./email-template-2"; +import React from 'react'; +import { Dispatch, SetStateAction } from 'react'; +import { toBase64 } from '../util'; +import { EmailTemplate2Config } from './email-template-2'; export default function EmailTemplate2Controls({ - config, - setConfig, + config, + setConfig, }: { - config: EmailTemplate2Config; - setConfig: Dispatch>; + config: EmailTemplate2Config; + setConfig: Dispatch>; }): JSX.Element { - return ( -
-
- - -
- {config.popup_type !== "none" ? ( + return (
- - { - const popup_screenshot_base64 = await toBase64( - e.target.files[0] - ); - setConfig((v) => ({ - ...v, - popup_screenshot_base64, - })); - }, - }} - /> +
+ + +
+ {config.popup_type !== 'none' ? ( +
+ + { + const popup_screenshot_base64 = await toBase64( + e.target.files[0] + ); + setConfig((v) => ({ + ...v, + popup_screenshot_base64, + })); + }, + }} + /> +
+ ) : ( + '' + )} + {config.popup_type === 'consent' ? ( +
+ + + setConfig((v) => ({ + ...v, + popup_accept_all_text: e.target.value, + })), + }} + /> +
+ ) : ( + '' + )} +
+ + +
+ {config.popup_action === 'closed' ? ( +
+ + + setConfig((v) => ({ + ...v, + popup_closed_how: e.target.value, + })) + } + /> +
+ ) : ( + '' + )} + {config.popup_type !== 'none' ? ( +
+ + setConfig((v) => ({ + ...v, + popup_mentions_passive_consent: + e.target.checked, + })) + } + /> + +
+ ) : ( + '' + )} + {config.popup_mentions_passive_consent ? ( +
+ + + setConfig((v) => ({ + ...v, + popup_passive_consent_text: e.target.value, + })) + } + /> +
+ ) : ( + '' + )}
- ) : ( - "" - )} - {config.popup_type === "consent" ? ( -
- - - setConfig((v) => ({ - ...v, - popup_accept_all_text: e.target.value, - })), - }} - /> -
- ) : ( - "" - )} -
- - -
- {config.popup_action === "closed" ? ( -
- - - setConfig((v) => ({ ...v, popup_closed_how: e.target.value })) - } - /> -
- ) : ( - "" - )} - {config.popup_type !== "none" ? ( -
- - setConfig((v) => ({ - ...v, - popup_mentions_passive_consent: e.target.checked, - })) - } - /> - -
- ) : ( - "" - )} - {config.popup_mentions_passive_consent ? ( -
- - - setConfig((v) => ({ - ...v, - popup_passive_consent_text: e.target.value, - })) - } - /> -
- ) : ( - "" - )} -
- ); + ); } diff --git a/report-window/email-template-2.tsx b/report-window/email-template-2.tsx index eee511d..d071dd7 100644 --- a/report-window/email-template-2.tsx +++ b/report-window/email-template-2.tsx @@ -92,370 +92,397 @@ export default function EmailTemplate2({ return ( <> -

- Dzień dobry, w dniu {getDate()} odwiedziłem stronę {visited_url} - . -

- {config.popup_type === 'none' ? ( +

- Nie ukazał mi się na stronie żaden mechanizm pozyskujący - zgodę na przetwarzanie moich danych osobowych lub - umożliwiający mi wyrażenie sprzeciwu wobec przetwarzania - przez stronę moich danych osobowych w zakresie wykraczającym - poza procesy konieczne do wyświetlenia strony + Dzień dobry, w dniu {getDate()} odwiedziłem stronę{' '} + {visited_url}.

- ) : config.popup_type == 'passive_cookie_banner' ? ( - <> + {config.popup_type === 'none' ? (

- Na stronie była widoczna informacja o plikach Cookie.{' '} + Nie ukazał mi się na stronie żaden mechanizm pozyskujący + zgodę na przetwarzanie moich danych osobowych lub + umożliwiający mi wyrażenie sprzeciwu wobec przetwarzania + przez stronę moich danych osobowych w zakresie + wykraczającym poza procesy konieczne do wyświetlenia + strony

-

- -

- - ) : ( - <> -

- Ukazało mi się okienko z informacjami i pytaniami - dotyczącymi sposobów, w jaki strona przetwarza moje dane - osobowe.{' '} -

-

- -

-

- {config.popup_action === 'ignored' - ? /* HTML */ `Nie kliknąłem żadnego przycisku w tym - okienku. W szczególności nie kliknąłem przycisku - „${config.popup_accept_all_text}”.` - : config.popup_action === 'accepted' - ? `Kliknąłem na widoczną w tym okienku opcję „${config.popup_accept_all_text}”.` - : ''} -

- - )} -

- W tym samym czasie rejestrowałem ruch sieciowy generowany przez - tę stronę za pomocą narzędzi w przeglądarce Firefox. Okazało - się, że Państwa strona wysłała była moje dane osobowe do - następujących podmiotów: -

-
    - {Object.values(clusters) - .filter((cluster) => cluster.hasMarks()) - .map((cluster) => ( - - ))} -
- {config.popup_action === 'ignored' ? ( -

- Dane te zostały wysłane, zanim kliknąłem cokolwiek na tej - stronie. -

- ) : config.popup_action === 'accepted' ? ( -

- Dane te zostały wysłane po tym, jak kliknąłem przycisk „ - {config.popup_accept_all_text}” -

- ) : ( - '' - )} -

- W załączeniu przesyłam część zrzutów ekranu dokumentujących fakt - wysłania tych danych przez Państwa stronę.{' '} -

-

Podstawa prawna

-

- Ustawa Prawo Telekomunikacyjne w art. 173 reguluje warunki, - które musi spełnić administrator strony, aby jego strona mogła - zapisywać i czytać treść plików cookie. Nie reguluje jednak - tego, jakim podmiotom i w jakim zakresie dane mogą być{' '} - ujawniane przez stronę. Tym zajmuje się Rozporządzenie - 2016/679 Parlamentu Europejskiego i Rady (UE) z dnia 27 kwietnia - 2016 r. w sprawie ochrony osób fizycznych w związku z - przetwarzaniem danych osobowych i w sprawie swobodnego przepływu - takich danych oraz uchylenia dyrektywy 95/46/WE (ogólne - rozporządzenie o ochronie danych) – RODO. Zapis/odczyt plików - cookie a ujawnianie ich treści podmiotom trzecim to dwa różne - procesy. Niniejsza wiadomość i pytania w niej zawarte dotyczą - właśnie ujawniania moich danych osobowych (pochodzących - m.in. z Cookies) podmiotom trzecim. -

-

- W kontekście stron internetowych są właściwie dopuszczalne tylko - trzy z sześciu wymienionych w Art. 6 pkt 1 RODO podstaw prawnych - dla przetwarzania danych osobowych: -

-
    -
  1. - „Zgoda” — osoba, której dane dotyczą wyraziła zgodę na - przetwarzanie swoich danych osobowych w jednym lub większej - liczbie określonych celów (Art. 6 pkt 1 lit. a)). -
  2. -
  3. - „Niezbędność” — przetwarzanie jest niezbędne do - wykonania umowy, której stroną jest osoba, której dane - dotyczą, lub do podjęcia działań na żądanie osoby, której - dane dotyczą, przed zawarciem umowy ( - Art. 6 pkt 1 lit. b));{' '} -
  4. -
  5. - „Uzasadniony Interes” — przetwarzanie jest niezbędne - do celów wynikających z prawnie uzasadnionych interesów - realizowanych przez administratora lub przez stronę trzecią, - z wyjątkiem sytuacji, w których nadrzędny charakter wobec - tych interesów mają interesy lub podstawowe prawa i wolności - osoby, której dane dotyczą, wymagające ochrony danych - osobowych, w szczególności gdy osoba, której dane dotyczą, - jest dzieckiem (Art. 6 pkt 1 lit. f) - ); -
  6. -
-

- W przypadku opisywanej przeze mnie mojej wizyty na Państwa - stronie nie ma zastosowania „Zgoda”, gdyż{' '} - {config.popup_action === 'ignored' ? ( + ) : config.popup_type == 'passive_cookie_banner' ? ( <> - nie wyrażałem żadnej zgody na takie przetwarzanie moich - danych - {config.popup_type === 'consent' ? ( - <> - — w szczególności nie kliknąłem przycisku - „{config.popup_accept_all_text}” - - ) : ( - '' - )} - . - - ) : config.popup_action === 'accepted' ? ( - <> - o ile po wejściu na stronę wcisnąłem w wyskakującym - okienku przycisk „{config.popup_accept_all_text}”, o - tyle nie stanowi to według mnie ważnej w świetle RODO - zgody, gdyż brakowało w tym okienku równie łatwo - osiągalnego przycisku, którego kliknięcie skutkowałoby - zasygnalizowaniem braku mojej zgody na takie - przetwarzanie moich danych. Mówiąc wprost — - wyrażenie „zgody” było łatwiejsze niż jej niewyrażenie. - Niewyrażenie zgody wiąże się z negatywną konsekwencją - konieczności przechodzenia przez dodatkowe kroki w - wyskakującym okienku. Zatem tak otrzymana przez Państwo - moja „zgoda” nie jest poprawną podstawą prawną do - przetwarzania moich danych osobowych, gdyż nie spełnia - warunku dobrowolności wspomnianego w motywie (42) RODO. - - ) : config.popup_action === 'closed' ? ( - <> - zamknąłem okienko pytające o zgodę poprzez{' '} - {config.popup_closed_how}. Nie może być to uznane za - zgodę, bo nie spełnia to warunku jednoznaczności - opisanego w motywie (32) Rozporządzenia 2016/679.{' '} +

+ Na stronie była widoczna informacja o plikach + Cookie.{' '} +

+

+ +

) : ( - '' - )}{' '} - Za zgodę nie można też uznać posiadania włączonej obsługi - cookies w przeglądarce (gdyż aby zgoda była ważna, musi być - szczegółowa dla każdego celów z osobna), jakichkolwiek innych - ustawień przeglądarki, ani pasywnych działań z mojej strony (np. - „kontynuowanie korzystania ze strony”) - {config.popup_mentions_passive_consent ? ( <> - {' '} - — nieprawdą więc jest zawarty na Państwa stronie - komunikat „{config.popup_passive_consent_text.trim()}” - (por. paragraf 97.{' '} - - oficjalnych wytycznych EROD dotyczących zgody na - mocy rozporządzenia 2016/679 - - ) +

+ Ukazało mi się okienko z informacjami i pytaniami + dotyczącymi sposobów, w jaki strona przetwarza moje + dane osobowe.{' '} +

+

+ +

+

+ {config.popup_action === 'ignored' + ? /* HTML */ `Nie kliknąłem żadnego przycisku w + tym okienku. W szczególności nie kliknąłem + przycisku „${config.popup_accept_all_text}”.` + : config.popup_action === 'accepted' + ? `Kliknąłem na widoczną w tym okienku opcję „${config.popup_accept_all_text}”.` + : ''} +

- ) : ( - '' )} - . -

-

- W mojej ocenie „Niezbędność“ nie ma zastosowania co do opisanych - powyżej sposobów przetwarzania danych. Nie widzę, co miałoby - sprawiać, aby wysyłanie moich danych osobowych do wspomnianych - powyżej podmiotów trzecich było konieczne do wyświetlenia - Państwa strony na ekranie mojego komputera (zob.{' '} - - Wytyczne 8/2020 EROD dotyczące targetowania użytkowników - mediów społecznościowych - - , par. 49);.{' '} -

-

- Pozostaje zatem „Uzasadniony Interes”. Aby Administrator mógł - używać uzasadnionego interesu jako podstawy prawnej targetowania - użytkowników Sieci, muszą zostać spełnione m.in. następujące - warunki:{' '} -

-
    -
  1. - Administrator danych lub podmiot trzeci, któremu dane są - ujawniane musi{' '} - - faktycznie realizować dany konkretny uzasadniony interes - {' '} - ( - - Wyrok TSUE z dnia 29 lipca 2019 r. w sprawie Fashion ID, - C-40/17, ECLI:EU:C:2019:629 - - , pkt 95.) -
  2. -
  3. - Takie przetwarzanie danych jest konieczne{' '} - dla potrzeb wynikających z danego uzasadnionego interesu ( - - Wyrok TSUE z dnia 29 lipca 2019 r. w sprawie Fashion ID, - C-40/17, ECLI:EU:C:2019:629 - - , pkt 95.) -
  4. -
  5. - Wybrany uzasadniony interes musi mieć pierwszeństwo nad - prawami i wolnościami osoby, której dotyczą przetwarzane - dane ( - - Wyrok TSUE z dnia 29 lipca 2019 r. w sprawie Fashion ID, - C-40/17, ECLI:EU:C:2019:629 - - , pkt 95.) -
  6. -
  7. - Osoby, których dane dotyczą, powinny mieć możliwość - wyrażenia sprzeciwu wobec przetwarzania ich danych do celów - związanych z targetowaniem{' '} - przed rozpoczęciem przetwarzania (zob.{' '} - - Wytyczne 8/2020 EROD dotyczące targetowania użytkowników - mediów społecznościowych - - , par. 54); -
  8. -
- {config.popup_action !== 'accepted' ? (

- Moje dane zostały ujawnione podmiotom trzecim tuż po - włączeniu strony, zatem nie jest spełniony warunek 4. - Apeluję o wdrożenie zmian na stronie, które sprawią, że - dopiero po świadomym niewyrażeniu sprzeciwu przez - użytkownika aktywowane są procesy przetwarzania danych - osobowych, których podstawą prawną jest uzasadniony interes. -

- ) : ( - '' - )} -

- Jeżeli istnieją jednak inne niż uzasadniony interes ważne - podstawy prawne do takiego przetwarzania moich danych osobowych - przez Państwa stronę, proszę o ich wskazanie,{' '} - dla każdego z wymienionych podmiotów z osobna. - (Przypominam, że Art. 173 ustawy Prawo Telekomunikacyjne nie ma - tutaj zastosowania, ponieważ nie pytam o zapis/odczyt plików na - moim komputerze, tylko o ujawnianie moich danych osobowych - podmiotom trzecim). W przeciwnym wypadku, aby ustalić, czy moje - dane były przez Państwa przetwarzane na mocy uzasadnionego - interesu zgodnie z prawem, proszę o wypełnienie następującego - szablonu (lub udzielenie tych samych informacji w innej postaci, - przy zachowaniu zakresu i szczegółowości informacji: -

-
-

- W dniu {getDate()} strona {visited_url}: + W tym samym czasie rejestrowałem ruch sieciowy generowany + przez tę stronę za pomocą narzędzi w przeglądarce Firefox. + Okazało się, że Państwa strona wysłała była moje dane + osobowe do następujących podmiotów:

    {Object.values(clusters) .filter((cluster) => cluster.hasMarks()) .map((cluster) => ( -
  • - ujawniła pańskie dane w zakresie{' '} - - - {' '} - firmie nazwa firmy, - która jest właścicielem domeny{' '} - {cluster.id} i swoją politykę - prywatności publikuje pod adresem{' '} - - adres URL polityki prywatności tej firmy - - . Podstawą prawną takiego przetwarzania danych - przez naszą stronę jest uzasadniony interes:{' '} - - na czym polega ten uzasadniony interes, tzn. - bieżące działania podejmowane przez podmiot - realizujący ten interes lub korzyści dla - podmiotu realizującego ten interes - oczekiwane w bardzo bliskiej przyszłości - {' '} - realizowany przez{' '} - - kogo? jaki podmiot podejmuje wspomniane - działania lub jest beneficjentem - wspomnianych korzyści? - - . Ujawnienie{' '} - temu - podmiotowi przez naszą stronę było konieczne dla - potrzeb wynikających z tego interesu, ponieważ - - uzasadnienie konieczności - - .
    -
  • + ))}
-
-

- Proszę w szczególności zwrócić uwagę na podanie adresów do - polityk prywatności tych firm, abym wiedział, jak skontaktować - się z nimi i wnioskować o usunięcie z ich baz wysłanych przez - Państwa stronę moich danych. ) -

-

- W odpowiedzi proszę się nie powoływać na IAB Europe i ich - rzekomą renomę w tworzeniu rozwiązań zgodnych z RODO. IAB chroni - interes reklamodawców, a nie Użytkowników, i ich rozwiązania - (np. TCF) są{' '} - - notorycznie niezgodne z RODO i pozbawione szacunku dla - Użytkowników - - . -

-

- Apeluję także o wprowadzenie stosownych zmian na stronie tak, - aby nie pozostawiać cienia wątpliwości odnośnie tego, na mocy - jakiej przesłanki legalizującej dane są przetwarzane przez - wspomniane podmioty trzecie, lub tak, aby te dane po prostu nie - były wysyłane. Pomoże to zachować prywatność innym użytkownikom - Państwa strony. Polecam Państwa uwadze - - {' '} - oficjalne wytyczne EROD dotyczące zgody w kontekście RODO - - . Aby na przykład zapobiec automatycznemu wysyłaniu historii - przeglądania do podmiotów trzecich przez Państwa stronę, można - po prostu ustawić odpowiednio treść nagłówka{' '} - - Referrer-Policy{' '} - - . -

+ {config.popup_action === 'ignored' ? ( +

+ Dane te zostały wysłane, zanim kliknąłem cokolwiek na + tej stronie. +

+ ) : config.popup_action === 'accepted' ? ( +

+ Dane te zostały wysłane po tym, jak kliknąłem przycisk „ + {config.popup_accept_all_text}” +

+ ) : ( + '' + )} +

+ W załączeniu przesyłam część zrzutów ekranu dokumentujących + fakt wysłania tych danych przez Państwa stronę.{' '} +

+

Podstawa prawna

+

+ Ustawa Prawo Telekomunikacyjne w art. 173 reguluje warunki, + które musi spełnić administrator strony, aby jego strona + mogła zapisywać i czytać treść plików cookie. Nie reguluje + jednak tego, jakim podmiotom i w jakim zakresie dane mogą + być ujawniane przez stronę. Tym zajmuje się + Rozporządzenie 2016/679 Parlamentu Europejskiego i Rady (UE) + z dnia 27 kwietnia 2016 r. w sprawie ochrony osób fizycznych + w związku z przetwarzaniem danych osobowych i w sprawie + swobodnego przepływu takich danych oraz uchylenia dyrektywy + 95/46/WE (ogólne rozporządzenie o ochronie danych) – RODO. + Zapis/odczyt plików cookie a ujawnianie ich treści podmiotom + trzecim to dwa różne procesy. Niniejsza wiadomość i pytania + w niej zawarte dotyczą właśnie ujawniania moich + danych osobowych (pochodzących m.in. z Cookies) podmiotom + trzecim. +

+

+ W kontekście stron internetowych są właściwie dopuszczalne + tylko trzy z sześciu wymienionych w Art. 6 pkt 1 RODO + podstaw prawnych dla przetwarzania danych osobowych: +

+
    +
  1. + „Zgoda” — osoba, której dane dotyczą wyraziła + zgodę na przetwarzanie swoich danych osobowych w jednym + lub większej liczbie określonych celów ( + Art. 6 pkt 1 lit. a)). +
  2. +
  3. + „Niezbędność” — przetwarzanie jest niezbędne do + wykonania umowy, której stroną jest osoba, której dane + dotyczą, lub do podjęcia działań na żądanie osoby, + której dane dotyczą, przed zawarciem umowy ( + Art. 6 pkt 1 lit. b));{' '} +
  4. +
  5. + „Uzasadniony Interes” — przetwarzanie jest + niezbędne do celów wynikających z prawnie uzasadnionych + interesów realizowanych przez administratora lub przez + stronę trzecią, z wyjątkiem sytuacji, w których + nadrzędny charakter wobec tych interesów mają interesy + lub podstawowe prawa i wolności osoby, której dane + dotyczą, wymagające ochrony danych osobowych, w + szczególności gdy osoba, której dane dotyczą, jest + dzieckiem (Art. 6 pkt 1 lit. f) + ); +
  6. +
+

+ W przypadku opisywanej przeze mnie mojej wizyty na Państwa + stronie nie ma zastosowania „Zgoda”, gdyż{' '} + {config.popup_action === 'ignored' ? ( + <> + nie wyrażałem żadnej zgody na takie przetwarzanie + moich danych + {config.popup_type === 'consent' ? ( + <> + — w szczególności nie kliknąłem + przycisku „{config.popup_accept_all_text}” + + ) : ( + '' + )} + . + + ) : config.popup_action === 'accepted' ? ( + <> + o ile po wejściu na stronę wcisnąłem w wyskakującym + okienku przycisk „{config.popup_accept_all_text}”, o + tyle nie stanowi to według mnie ważnej w świetle + RODO zgody, gdyż brakowało w tym okienku równie + łatwo osiągalnego przycisku, którego kliknięcie + skutkowałoby zasygnalizowaniem braku mojej zgody na + takie przetwarzanie moich danych. Mówiąc wprost + — wyrażenie „zgody” było łatwiejsze niż jej + niewyrażenie. Niewyrażenie zgody wiąże się z + negatywną konsekwencją konieczności przechodzenia + przez dodatkowe kroki w wyskakującym okienku. Zatem + tak otrzymana przez Państwo moja „zgoda” nie jest + poprawną podstawą prawną do przetwarzania moich + danych osobowych, gdyż nie spełnia warunku + dobrowolności wspomnianego w motywie (42) RODO. + + ) : config.popup_action === 'closed' ? ( + <> + zamknąłem okienko pytające o zgodę poprzez{' '} + {config.popup_closed_how}. Nie może być to uznane za + zgodę, bo nie spełnia to warunku jednoznaczności + opisanego w motywie (32) Rozporządzenia 2016/679.{' '} + + ) : ( + '' + )}{' '} + Za zgodę nie można też uznać posiadania włączonej obsługi + cookies w przeglądarce (gdyż aby zgoda była ważna, musi być + szczegółowa dla każdego celów z osobna), jakichkolwiek + innych ustawień przeglądarki, ani pasywnych działań z mojej + strony (np. „kontynuowanie korzystania ze strony”) + {config.popup_mentions_passive_consent ? ( + <> + {' '} + — nieprawdą więc jest zawarty na Państwa + stronie komunikat „ + {config.popup_passive_consent_text.trim()}” (por. + paragraf 97.{' '} + + oficjalnych wytycznych EROD dotyczących zgody na + mocy rozporządzenia 2016/679 + + ) + + ) : ( + '' + )} + . +

+

+ W mojej ocenie „Niezbędność“ nie ma zastosowania co do + opisanych powyżej sposobów przetwarzania danych. Nie widzę, + co miałoby sprawiać, aby wysyłanie moich danych osobowych do + wspomnianych powyżej podmiotów trzecich było konieczne do + wyświetlenia Państwa strony na ekranie mojego komputera + (zob.{' '} + + Wytyczne 8/2020 EROD dotyczące targetowania użytkowników + mediów społecznościowych + + , par. 49);.{' '} +

+

+ Pozostaje zatem „Uzasadniony Interes”. Aby Administrator + mógł używać uzasadnionego interesu jako podstawy prawnej + targetowania użytkowników Sieci, muszą zostać spełnione + m.in. następujące warunki:{' '} +

+
    +
  1. + Administrator danych lub podmiot trzeci, któremu dane są + ujawniane musi{' '} + + faktycznie realizować dany konkretny uzasadniony + interes + {' '} + ( + + Wyrok TSUE z dnia 29 lipca 2019 r. w sprawie Fashion + ID, C-40/17, ECLI:EU:C:2019:629 + + , pkt 95.) +
  2. +
  3. + Takie przetwarzanie danych jest{' '} + konieczne dla potrzeb wynikających z + danego uzasadnionego interesu ( + + Wyrok TSUE z dnia 29 lipca 2019 r. w sprawie Fashion + ID, C-40/17, ECLI:EU:C:2019:629 + + , pkt 95.) +
  4. +
  5. + Wybrany uzasadniony interes musi mieć pierwszeństwo nad + prawami i wolnościami osoby, której dotyczą przetwarzane + dane ( + + Wyrok TSUE z dnia 29 lipca 2019 r. w sprawie Fashion + ID, C-40/17, ECLI:EU:C:2019:629 + + , pkt 95.) +
  6. +
  7. + Osoby, których dane dotyczą, powinny mieć możliwość + wyrażenia sprzeciwu wobec przetwarzania ich danych do + celów związanych z targetowaniem{' '} + przed rozpoczęciem przetwarzania (zob.{' '} + + Wytyczne 8/2020 EROD dotyczące targetowania + użytkowników mediów społecznościowych + + , par. 54); +
  8. +
+ {config.popup_action !== 'accepted' ? ( +

+ Moje dane zostały ujawnione podmiotom trzecim tuż po + włączeniu strony, zatem nie jest spełniony warunek 4. + Apeluję o wdrożenie zmian na stronie, które sprawią, że + dopiero po świadomym niewyrażeniu sprzeciwu przez + użytkownika aktywowane są procesy przetwarzania danych + osobowych, których podstawą prawną jest uzasadniony + interes. +

+ ) : ( + '' + )} +

+ Jeżeli istnieją jednak inne niż uzasadniony interes ważne + podstawy prawne do takiego przetwarzania moich danych + osobowych przez Państwa stronę, proszę o ich wskazanie,{' '} + dla każdego z wymienionych podmiotów z osobna. + (Przypominam, że Art. 173 ustawy Prawo Telekomunikacyjne nie + ma tutaj zastosowania, ponieważ nie pytam o zapis/odczyt + plików na moim komputerze, tylko o ujawnianie moich danych + osobowych podmiotom trzecim). W przeciwnym wypadku, aby + ustalić, czy moje dane były przez Państwa przetwarzane na + mocy uzasadnionego interesu zgodnie z prawem, proszę o + wypełnienie następującego szablonu (lub udzielenie tych + samych informacji w innej postaci, przy zachowaniu zakresu i + szczegółowości informacji: +

+
+

+ W dniu {getDate()} strona {visited_url}: +

+
    + {Object.values(clusters) + .filter((cluster) => cluster.hasMarks()) + .map((cluster) => ( +
  • + ujawniła pańskie dane w zakresie{' '} + + + {' '} + firmie{' '} + nazwa firmy, + która jest właścicielem domeny{' '} + {cluster.id} i swoją + politykę prywatności publikuje pod adresem{' '} + + adres URL polityki prywatności tej firmy + + . Podstawą prawną takiego przetwarzania + danych przez naszą stronę jest uzasadniony + interes:{' '} + + na czym polega ten uzasadniony interes, + tzn. bieżące działania podejmowane przez + podmiot realizujący ten interes lub + korzyści dla podmiotu realizującego ten + interes oczekiwane w bardzo bliskiej + przyszłości + {' '} + realizowany przez{' '} + + kogo? jaki podmiot podejmuje wspomniane + działania lub jest beneficjentem + wspomnianych korzyści? + + . Ujawnienie{' '} + {' '} + temu podmiotowi przez naszą stronę było + konieczne dla potrzeb wynikających z tego + interesu, ponieważ + + uzasadnienie konieczności + + .
    +
  • + ))} +
+
+

+ Proszę w szczególności zwrócić uwagę na podanie adresów do + polityk prywatności tych firm, abym wiedział, jak + skontaktować się z nimi i wnioskować o usunięcie z ich baz + wysłanych przez Państwa stronę moich danych. ) +

+

+ W odpowiedzi proszę się nie powoływać na IAB Europe i ich + rzekomą renomę w tworzeniu rozwiązań zgodnych z RODO. IAB + chroni interes reklamodawców, a nie Użytkowników, i ich + rozwiązania (np. TCF) są{' '} + + notorycznie niezgodne z RODO i pozbawione szacunku dla + Użytkowników + + . +

+

+ Apeluję także o wprowadzenie stosownych zmian na stronie + tak, aby nie pozostawiać cienia wątpliwości odnośnie tego, + na mocy jakiej przesłanki legalizującej dane są przetwarzane + przez wspomniane podmioty trzecie, lub tak, aby te dane po + prostu nie były wysyłane. Pomoże to zachować prywatność + innym użytkownikom Państwa strony. Polecam Państwa uwadze + + {' '} + oficjalne wytyczne EROD dotyczące zgody w kontekście + RODO + + . Aby na przykład zapobiec automatycznemu wysyłaniu historii + przeglądania do podmiotów trzecich przez Państwa stronę, + można po prostu ustawić odpowiednio treść nagłówka{' '} + + Referrer-Policy{' '} + + . +

+
); } diff --git a/report-window/report-window.html b/report-window/report-window.html index 8a59dca..098ce50 100644 --- a/report-window/report-window.html +++ b/report-window/report-window.html @@ -1,16 +1,22 @@ - + + - Wygeneruj maila co zgłoszenia - - -
+ Treść maila do zgłoszenia + + + +
- - + + + \ No newline at end of file diff --git a/request-cluster.ts b/request-cluster.ts index 0caea59..bd4521c 100644 --- a/request-cluster.ts +++ b/request-cluster.ts @@ -1,179 +1,183 @@ -import { EventEmitter } from "events"; -import ExtendedRequest from "./extended-request"; -import { Sources, StolenDataEntry } from "./stolen-data-entry"; +import { EventEmitter } from 'events'; +import ExtendedRequest from './extended-request'; +import { Sources, StolenDataEntry } from './stolen-data-entry'; -import { allSubhosts, isSameURL, reduceConcat, unique } from "./util"; +import { allSubhosts, isSameURL, reduceConcat, unique } from './util'; const source_priority: Array = [ - "cookie", - "pathname", - "queryparams", - "header", + 'cookie', + 'pathname', + 'queryparams', + 'header', ]; export class RequestCluster extends EventEmitter { - public requests: ExtendedRequest[] = []; - public representativeStolenData: StolenDataEntry[] = []; - public expanded: boolean; - constructor(public id: string) { - super(); - } - add(request: ExtendedRequest) { - this.requests.push(request); - this.emit("change"); - } - - toggleExpanded(state: boolean) { - this.expanded = state; - this.emit("change"); - } - - hasCookies() { - for (const request of this.requests) { - if (request.hasCookie()) { - return true; - } + public requests: ExtendedRequest[] = []; + public representativeStolenData: StolenDataEntry[] = []; + public expanded: boolean; + constructor(public id: string) { + super(); } - return false; - } - - calculateRepresentativeStolenData( - filter: { - minValueLength: number; - cookiesOnly: boolean; - cookiesOrOriginOnly: boolean; - } = { minValueLength: 0, cookiesOnly: false, cookiesOrOriginOnly: false } - ): StolenDataEntry[] { - this.representativeStolenData = this.requests - .map((request) => request.stolenData) - - .reduce((a, b) => a.concat(b), []) - .filter((entry) => { - return entry.value.length >= filter.minValueLength; - }) - .filter((entry) => !filter.cookiesOnly || entry.source === "cookie") - .filter( - (entry) => - !filter.cookiesOrOriginOnly || - entry.source === "cookie" || - entry.classification === "history" - ) - .sort((entry1, entry2) => { - if (entry1.value > entry2.value) { - return -1; - } else if (entry1.value < entry2.value) { - return 1; - } else { - const indexA = source_priority.indexOf(entry1.source); - const indexB = source_priority.indexOf(entry2.source); - if (indexA < indexB) { - return -1; - } else if (indexA > indexB) { - return 1; - } else if (entry1.value.length > entry2.value.length) { - return -1; - } else if (entry1.value.length < entry2.value.length) { - return 1; - } else if (entry1.isMarked && !entry2.isMarked) { - return -1; - } else if (!entry1.isMarked && entry2.isMarked) { - return 1; - } else { - return 0; - } - } - }) - .filter((_, index, array) => { - // removing value duplicates - if (index == 0) { - return true; - } - if ( - array[index].getValuePreview() === - array[index - 1].getValuePreview() || - isSameURL(array[index].value, array[index - 1].value) - ) { - return false; - } else { - return true; - } - }) - .sort((entry1, entry2) => { - if (entry1.name < entry2.name) { - return -1; - } else if (entry1.name > entry2.name) { - return 1; - } else { - if (entry1.value.length > entry2.value.length) { - return 1; - } else { - return -1; - } - } - }) - .filter((_, index, array) => { - // removing name duplicates, keeping only the first - which is the longest. Some data loss may occur. - if (index == 0) { - return true; - } - if (array[index].name === array[index - 1].name) { - return false; - } else { - return true; - } - }) - .sort((entry1, entry2) => - entry1.getPriority() > entry2.getPriority() ? -1 : 1 - ); - return this.representativeStolenData; - } - - static sortCompare(a: RequestCluster, b: RequestCluster) { - if (a.hasCookies() == b.hasCookies()) { - if (a.id < b.id) { - return -1; - } else { - return 1; - } - } else { - if (a.hasCookies()) { - return -1; - } else { - return 1; - } + add(request: ExtendedRequest) { + this.requests.push(request); + this.emit('change'); } - } - getMarkedRequests() { - return this.requests.filter((request) => request.hasMark()); - } + toggleExpanded(state: boolean) { + this.expanded = state; + this.emit('change'); + } - getFullHosts() { - return unique( - this.requests - .map((request) => allSubhosts(request.getHost())) - .reduce((a, b) => a.concat(b), []) - ); - } + hasCookies() { + for (const request of this.requests) { + if (request.hasCookie()) { + return true; + } + } + return false; + } - hasMarks() { - return this.requests.some((request) => request.hasMark()); - } + calculateRepresentativeStolenData( + filter: { + minValueLength: number; + cookiesOnly: boolean; + cookiesOrOriginOnly: boolean; + } = { + minValueLength: 0, + cookiesOnly: false, + cookiesOrOriginOnly: false, + } + ): StolenDataEntry[] { + this.representativeStolenData = this.requests + .map((request) => request.stolenData) - getMarkedEntries(): StolenDataEntry[] { - return this.requests - .map((request) => request.getMarkedEntries()) - .reduce(reduceConcat, []); - } + .reduce((a, b) => a.concat(b), []) + .filter((entry) => { + return entry.value.length >= filter.minValueLength; + }) + .filter((entry) => !filter.cookiesOnly || entry.source === 'cookie') + .filter( + (entry) => + !filter.cookiesOrOriginOnly || + entry.source === 'cookie' || + entry.classification === 'history' + ) + .sort((entry1, entry2) => { + if (entry1.value > entry2.value) { + return -1; + } else if (entry1.value < entry2.value) { + return 1; + } else { + const indexA = source_priority.indexOf(entry1.source); + const indexB = source_priority.indexOf(entry2.source); + if (indexA < indexB) { + return -1; + } else if (indexA > indexB) { + return 1; + } else if (entry1.value.length > entry2.value.length) { + return -1; + } else if (entry1.value.length < entry2.value.length) { + return 1; + } else if (entry1.isMarked && !entry2.isMarked) { + return -1; + } else if (!entry1.isMarked && entry2.isMarked) { + return 1; + } else { + return 0; + } + } + }) + .filter((_, index, array) => { + // removing value duplicates + if (index == 0) { + return true; + } + if ( + array[index].getValuePreview() === + array[index - 1].getValuePreview() || + isSameURL(array[index].value, array[index - 1].value) + ) { + return false; + } else { + return true; + } + }) + .sort((entry1, entry2) => { + if (entry1.name < entry2.name) { + return -1; + } else if (entry1.name > entry2.name) { + return 1; + } else { + if (entry1.value.length > entry2.value.length) { + return 1; + } else { + return -1; + } + } + }) + .filter((_, index, array) => { + // removing name duplicates, keeping only the first - which is the longest. Some data loss may occur. + if (index == 0) { + return true; + } + if (array[index].name === array[index - 1].name) { + return false; + } else { + return true; + } + }) + .sort((entry1, entry2) => + entry1.getPriority() > entry2.getPriority() ? -1 : 1 + ); + return this.representativeStolenData; + } - exposesOrigin() { - return this.requests.some((request) => request.exposesOrigin()); - } + static sortCompare(a: RequestCluster, b: RequestCluster) { + if (a.hasCookies() == b.hasCookies()) { + if (a.id < b.id) { + return -1; + } else { + return 1; + } + } else { + if (a.hasCookies()) { + return -1; + } else { + return 1; + } + } + } - autoMark() { - this.calculateRepresentativeStolenData(); - this.representativeStolenData.forEach((entry) => { - entry.autoMark(); - }); - } + getMarkedRequests() { + return this.requests.filter((request) => request.hasMark()); + } + + getFullHosts() { + return unique( + this.requests + .map((request) => allSubhosts(request.getHost())) + .reduce((a, b) => a.concat(b), []) + ); + } + + hasMarks() { + return this.requests.some((request) => request.hasMark()); + } + + getMarkedEntries(): StolenDataEntry[] { + return this.requests + .map((request) => request.getMarkedEntries()) + .reduce(reduceConcat, []); + } + + exposesOrigin() { + return this.requests.some((request) => request.exposesOrigin()); + } + + autoMark() { + this.calculateRepresentativeStolenData(); + this.representativeStolenData.forEach((entry) => { + entry.autoMark(); + }); + } } diff --git a/sidebar/global.scss b/sidebar/global.scss index 32d4233..6beb2ad 100644 --- a/sidebar/global.scss +++ b/sidebar/global.scss @@ -5,10 +5,12 @@ text-rendering: optimizelegibility; font-smooth: auto; -webkit-font-smoothing: auto; + user-select: none; } html { font-size: 1rem; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } button { @@ -38,7 +40,7 @@ select { #app { user-select: text; - padding: 0.5rem 1rem; + padding: 0rem 1rem; display: flex; flex-flow: column; justify-content: flex-start; diff --git a/sidebar/sidebar.scss b/sidebar/sidebar.scss index 1e5ade6..0426511 100644 --- a/sidebar/sidebar.scss +++ b/sidebar/sidebar.scss @@ -4,8 +4,12 @@ header { display: grid; grid-template-columns: 8rem 1fr 1rem; max-height: 4rem; + padding-top: 0.5rem; padding-bottom: 0.5rem; border-bottom: 1px solid $light-grey; + position: sticky; + top: 0; + background: #fff; .webpage-metadata { word-break: break-all; @@ -31,5 +35,37 @@ header { border: none; background: transparent; cursor: pointer; + padding: 0; + } +} + +nav { + padding: 0.25rem 0; + border-bottom: 1px solid $light-grey; + + button { + border: none; + cursor: pointer; + color: $mid-grey; + padding: 0.25rem 0rem; + display: flex; + flex-wrap: nowrap; + line-height: 1rem; + line-height: 1.5rem; + background: #fff; + width: 100%; + + &:hover { + color: #000; + text-decoration: underline; + svg path { + fill: #000; + } + } + + span { + padding-left: 0.5rem; + font-size: 0.875rem; + } } } diff --git a/sidebar/sidebar.tsx b/sidebar/sidebar.tsx index 71bbdc4..319dee7 100644 --- a/sidebar/sidebar.tsx +++ b/sidebar/sidebar.tsx @@ -2,9 +2,14 @@ import React, { Fragment, useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; import Options from '../options'; import { StolenData } from './stolen-data'; -import { useEmitter } from '../util'; +import { getshorthost, useEmitter } from '../util'; import { getMemory } from '../memory'; -import InfoCircle from '../assets/icons/info_circle_outline.svg'; +import { RequestCluster } from '../request-cluster'; +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'; async function getCurrentTab() { const [tab] = await browser.tabs.query({ @@ -64,14 +69,54 @@ const Sidebar = () => { {origin} - - - + {stolenDataView ? ( + + + + ) : ( + + )} diff --git a/sidebar/stolen-data.tsx b/sidebar/stolen-data.tsx index 58c5048..25c7fe1 100644 --- a/sidebar/stolen-data.tsx +++ b/sidebar/stolen-data.tsx @@ -1,93 +1,94 @@ -import React from "react"; -import { RequestCluster } from "../request-cluster"; +import React from 'react'; +import { RequestCluster } from '../request-cluster'; -import StolenDataCluster from "./stolen-data-cluster"; -import { getshorthost } from "../util"; -import { getMemory } from "../memory"; +import StolenDataCluster from './stolen-data-cluster'; +import { getshorthost } from '../util'; +import { getMemory } from '../memory'; export function StolenData({ - origin, - minValueLength, - refreshToken, - refresh, - cookiesOnly, - cookiesOrOriginOnly, + origin, + minValueLength, + refreshToken, + refresh, + cookiesOnly, + cookiesOrOriginOnly, }: { - origin: string; - refreshToken: number; - refresh: () => void; - minValueLength: number; - cookiesOnly: boolean; - cookiesOrOriginOnly: boolean; + origin: string; + refreshToken: number; + refresh: () => void; + minValueLength: number; + cookiesOnly: boolean; + cookiesOrOriginOnly: boolean; }) { - if (!origin) { - return
; - } - const clusters = Object.values(getMemory().getClustersForOrigin(origin)) - .sort(RequestCluster.sortCompare) - .filter((cluster) => !cookiesOnly || cluster.hasCookies()) - .filter( - (cluster) => - !cookiesOrOriginOnly || cluster.hasCookies() || cluster.exposesOrigin() + if (!origin) { + return
; + } + const clusters = Object.values(getMemory().getClustersForOrigin(origin)) + .sort(RequestCluster.sortCompare) + .filter((cluster) => !cookiesOnly || cluster.hasCookies()) + .filter( + (cluster) => + !cookiesOrOriginOnly || + cluster.hasCookies() || + cluster.exposesOrigin() + ); + return ( +
+
+ {/* + */} + + {/* */} + + {clusters.map((cluster) => { + return ( + + ); + })} +
+
); - return ( -
- {" "} -
-

- {origin} - - - - -

- {clusters.map((cluster) => { - return ( - - ); - })} -
-
- ); }