Compare commits

...

6 Commits

20 changed files with 259 additions and 81 deletions

View File

@ -2,18 +2,15 @@ import { RequestCluster } from '../../request-cluster';
import { ParsedAnswers } from './parse-answers'; import { ParsedAnswers } from './parse-answers';
import NoInformationAtAllProblem from './problems/no-information-at-all'; import NoInformationAtAllProblem from './problems/no-information-at-all';
import { Problem } from './problems/problem'; import { Problem } from './problems/problem';
import { TransferOutsideEU } from './problems/transfer-outside-eu';
import { UnknownLegalBasis } from './problems/unknown-legal-basis';
import { UnlawfulCookieAccess } from './problems/unlawful-cookies'; import { UnlawfulCookieAccess } from './problems/unlawful-cookies';
export default function deduceProblems( export default function deduceProblems(
answers: ParsedAnswers, answers: ParsedAnswers,
clusters: Record<string, RequestCluster> clusters: Record<string, RequestCluster>
): Problem[] { ): Problem[] {
const problems = []; return [NoInformationAtAllProblem, UnlawfulCookieAccess, UnknownLegalBasis, TransferOutsideEU]
if (answers.popup_type === 'none') { .map((c) => new c(answers, clusters))
problems.push(new NoInformationAtAllProblem(answers, clusters)); .filter((p) => p.qualifies());
}
if (UnlawfulCookieAccess.qualifies(answers, Object.values(clusters))) {
problems.push(new UnlawfulCookieAccess(answers, clusters));
}
return problems;
} }

View File

@ -19,6 +19,7 @@ export default function EmailContent({
visited_url: string; visited_url: string;
clusters: Record<string, RequestCluster>; clusters: Record<string, RequestCluster>;
}) { }) {
console.log('rendering email!', answers);
const _ = (key: string) => v(key, answers.zaimek); const _ = (key: string) => v(key, answers.zaimek);
const problems = deduceProblems(answers, clusters); const problems = deduceProblems(answers, clusters);
const explainers = Array.from( const explainers = Array.from(

View File

@ -1,4 +1,6 @@
export type ExplainerKey = 'cookies_are_pii'; // various explainers that could be related to multiple problems. They are gathered here and added at the end of the email to avoid pasting them multiple times
export type ExplainerKey = 'cookies_are_pii' | 'responsibility_for_third_parties';
export const Explainers: Record<ExplainerKey, (zaimek_index: 0 | 1 | 2 | 3) => JSX.Element> = { export const Explainers: Record<ExplainerKey, (zaimek_index: 0 | 1 | 2 | 3) => JSX.Element> = {
cookies_are_pii: () => ( cookies_are_pii: () => (
@ -11,4 +13,18 @@ export const Explainers: Record<ExplainerKey, (zaimek_index: 0 | 1 | 2 | 3) => J
</p> </p>
</> </>
), ),
responsibility_for_third_parties: () => (
<>
<h2>Administrator strony ponosi odpowiedzialność za skrypty podmiotów trzecich</h2>
<p>
W wypadku, gdy ujawnienie czy dostęp do danych osobowych zostało dokonane przez
skrypty podmiotów trzecich (np. Google, Facebook, itp), których autorem nie jest
Administrator strony, Administrator wciąż jest odpowiedzialny za procesy
przetwarzania danych osobowych, jakie realizują te skrypty - w myśl treści{' '}
<a href="https://curia.europa.eu/juris/document/document.jsf?text=&docid=216555&pageIndex=0&doclang=PL&mode=lst&dir=&occ=first&part=1&cid=1254905">
wyroku TSUE w sprawie C-40/17
</a>
</p>
</>
),
}; };

View File

@ -1,26 +1,30 @@
import { RequestCluster } from '../../request-cluster';
function generateHostPage( function generateHostPage(
host: string, cluster: RequestCluster,
index: number, index: number,
all_hosts: string[] all_clusters: RequestCluster[]
): { title: string; elements: any[]; visibleIf: string } { ): { title: string; elements: any[]; visibleIf?: string } {
function f(name: string, h = host) { function f(name: string, c = cluster) {
return `${h.replace(/\./g, '_')}|${name}`; return `${c.id.replace(/\./g, '_')}|${name}`;
} }
const previous_host: string | null = index > 0 ? all_hosts[index - 1] : null; const previous_cluster: RequestCluster | null = index > 0 ? all_clusters[index - 1] : null;
function defaultValue(name: string) { function defaultValue(name: string) {
if (!previous_host) { if (!previous_cluster) {
return {}; return {};
} }
return { defaultValueExpression: `{${f(name, previous_host)}}` }; return { defaultValueExpression: `{${f(name, previous_cluster)}}` };
} }
const domain = cluster.id;
const danych = cluster.getDataTypeDescription();
return { return {
title: host, title: cluster.id,
elements: [ elements: [
{ {
type: 'radiogroup', type: 'radiogroup',
name: f('present'), name: f('present'),
isRequired: true, isRequired: true,
title: `Cel ujawnienia danych właścicielowi domeny ${host}`, title: `Cel ujawnienia danych (${danych}) właścicielowi domeny ${domain}`,
...defaultValue('present'), ...defaultValue('present'),
visibleIf: '{popup_type} != "none"', visibleIf: '{popup_type} != "none"',
choices: [ choices: [
@ -56,10 +60,10 @@ function generateHostPage(
'present' 'present'
)}} != "not_mentioned" and {${f('present')}} != "not_before_making_a_choice"`, )}} != "not_mentioned" and {${f('present')}} != "not_before_making_a_choice"`,
choices: [ choices: [
{ value: 'consent', text: 'to zgoda.' }, { value: 'consent', text: 'to zgoda (art. 6 ust. 1 lit. a RODO).' },
{ {
value: 'legitimate_interest', value: 'legitimate_interest',
text: 'to uzasadniony interes.', text: 'to uzasadniony interes (art. 6 ust. 1 lit. f RODO).',
}, },
{ value: 'not_mentioned', text: 'nie jest wskazana nigdzie na stronie.' }, { value: 'not_mentioned', text: 'nie jest wskazana nigdzie na stronie.' },
], ],
@ -76,7 +80,7 @@ function generateHostPage(
choices: [ choices: [
{ {
value: 'claims_consent_but_sends_before_consent', value: 'claims_consent_but_sends_before_consent',
text: `Strona wysłała {moje} dane do ${host} zanim {wyraziłem} na to zgodę`, text: `Strona wysłała {moje} dane do ${domain} zanim {wyraziłem} na to zgodę`,
}, },
{ {
value: 'claims_consent_but_there_was_no_easy_refuse', value: 'claims_consent_but_there_was_no_easy_refuse',
@ -111,18 +115,18 @@ function generateHostPage(
}, },
{ {
type: 'text', type: 'text',
title: `Jak administrator opisał to, na czym polega uzasadniony interes w kontekście ${host}?`, title: `Jak administrator opisał to, na czym polega uzasadniony interes w kontekście ${domain}?`,
name: f('legitimate_interest_description'), name: f('legitimate_interest_description'),
visibleIf: `{${f('legitimate_interest_activity_specified')}} = 'vague'`, visibleIf: `{${f('legitimate_interest_activity_specified')}} = 'vague'`,
placeholder: 'marketing', placeholder: 'marketing',
defaultValueExpression: defaultValueExpression:
index == 0 index == 0
? 'marketing' ? 'marketing'
: `{${f('legitimate_interest_description', previous_host)}}`, : `{${f('legitimate_interest_description', previous_cluster)}}`,
}, },
{ {
type: 'radiogroup', type: 'radiogroup',
title: `Czy domena ${host} należy do podmiotu spoza Europy (np. Google, Facebook)?`, title: `Czy domena ${domain} należy do podmiotu spoza Europy (np. Google, Facebook)?`,
name: f('outside_eu'), name: f('outside_eu'),
...defaultValue('outside_eu'), ...defaultValue('outside_eu'),
visibleIf: `{${f('legitimate_interest_activity_specified')}} = "precise" or {${f( visibleIf: `{${f('legitimate_interest_activity_specified')}} = "precise" or {${f(
@ -137,7 +141,7 @@ function generateHostPage(
}, },
{ {
type: 'radiogroup', type: 'radiogroup',
title: `Czy w {Twojej} ocenie wysłanie {Twoich} danych do właściciela domeny ${host} było konieczne do świadczenia zażądanej przez {Ciebie} usługi drogą elektroniczną?`, title: `Czy w {Twojej} ocenie ujawnienie {Twoich} danych (${danych}) właścicielowi domeny ${domain} było konieczne do świadczenia zażądanej przez {Ciebie} usługi drogą elektroniczną?`,
name: f('was_processing_necessary'), name: f('was_processing_necessary'),
isRequired: true, isRequired: true,
...defaultValue('was_processing_necessary'), ...defaultValue('was_processing_necessary'),
@ -154,7 +158,7 @@ function generateHostPage(
}; };
} }
export default function generateSurveyQuestions(hosts: string[]) { export default function generateSurveyQuestions(clusters: RequestCluster[]) {
return { return {
showQuestionNumbers: 'off', showQuestionNumbers: 'off',
showProgressBar: 'top', showProgressBar: 'top',
@ -393,7 +397,7 @@ export default function generateSurveyQuestions(hosts: string[]) {
}, },
], ],
}, },
...hosts.map(generateHostPage), ...clusters.map(generateHostPage),
], ],
}; };
} }

View File

@ -50,6 +50,7 @@ export function parseAnswers({
mentions_passive_consent, mentions_passive_consent,
rejection_is_hard, rejection_is_hard,
administrator_identity_available_before_choice, administrator_identity_available_before_choice,
popup_action,
...rest ...rest
}: RawAnswers): ParsedAnswers { }: RawAnswers): ParsedAnswers {
return { return {
@ -62,6 +63,7 @@ export function parseAnswers({
mentions_passive_consent, mentions_passive_consent,
rejection_is_hard, rejection_is_hard,
administrator_identity_available_before_choice, administrator_identity_available_before_choice,
popup_action,
hosts: parseHostAnswers(rest), hosts: parseHostAnswers(rest),
} as ParsedAnswers; } as ParsedAnswers;
} }

View File

@ -3,6 +3,9 @@ import { v } from '../verbs';
import { Problem } from './problem'; import { Problem } from './problem';
export default class NoInformationAtAllProblem extends Problem { export default class NoInformationAtAllProblem extends Problem {
qualifies() {
return this.answers.popup_type === 'none';
}
getEmailContent() { getEmailContent() {
const _ = (word: string) => v(word, this.answers.zaimek); const _ = (word: string) => v(word, this.answers.zaimek);
return ( return (
@ -39,6 +42,7 @@ export default class NoInformationAtAllProblem extends Problem {
}) })
) { ) {
explainers.push('cookies_are_pii'); explainers.push('cookies_are_pii');
explainers.push('responsibility_for_third_parties');
} }
return explainers; return explainers;
} }

View File

@ -19,6 +19,7 @@ export abstract class Problem {
abstract getEmailContent(): JSX.Element; abstract getEmailContent(): JSX.Element;
abstract getNecessaryExplainers(): ExplainerKey[]; abstract getNecessaryExplainers(): ExplainerKey[];
abstract qualifies(): boolean;
getMarkedClusters() { getMarkedClusters() {
return Object.values(this.clusters).filter((c) => c.hasMarks()); return Object.values(this.clusters).filter((c) => c.hasMarks());

View File

@ -0,0 +1,63 @@
import { RequestCluster } from '../../../request-cluster';
import { ExplainerKey } from '../explainers';
import { v } from '../verbs';
import { Problem } from './problem';
export class TransferOutsideEU extends Problem {
getNecessaryExplainers(): ExplainerKey[] {
return [];
}
qualifies(): boolean {
return Object.values(this.answers.hosts).some(
(hostAnswers) => hostAnswers.outside_eu == 'yes'
);
}
getRelatedClusters(): RequestCluster[] {
return Object.entries(this.answers.hosts)
.filter(([_, hostAnswers]) => hostAnswers.outside_eu == 'yes')
.map(([id]) => this.clusters[id]);
}
getEmailContent() {
const clusters = this.getRelatedClusters();
const _ = (key: string) => v(key, this.answers.zaimek);
return (
<>
<h2>Transfer danych osobowych poza Europejski Obszar Gospodarczy</h2>
<p>
Państwa strona przetworzyła {_('moje')} dane osobowe poprzez przesłanie danych
do:
</p>
<ul>
{clusters.map((cluster) => (
<li key={cluster.id}>
Właściciela domeny <strong>{cluster.id}</strong>: (w zakresie:{' '}
{cluster.getDataTypeDescription('mojej')});
</li>
))}
</ul>
<p>
Według {_('mojej')} najlepszej wiedzy, każdy z tych podmiotów utrzymuje swoje
serwery poza Europejskim Obszarem Gospodarczym. Zatem Państwa strona przesłała
{_('moje')} dane osobowe poza EOG. Jeżeli tak jest, to takie przetwarzanie
danych jest niezgodne z prawem, gdyż dane trafiają do krajów, które nie
gwarantują ochrony danych w stopniu, jakiego wymaga RODO, a tzw. Tarcza
Prywatności została unieważniona w 2020r. Zob.{' '}
<a href="https://panoptykon.org/noyb-skargi-schrems-ii">
artykuł Fundacji Panoptykon w tej sprawie
</a>
.
</p>
<p>
{_('Zwracam')} się zatem do Państwa z pytaniem:{' '}
<strong>
czy wyżej wymienione podmioty, którym Państwa strona ujawniła moje dane
osobowe, przechowują moje dane poza EOG?
</strong>
</p>
</>
);
}
}

View File

@ -0,0 +1,73 @@
import { RequestCluster } from '../../../request-cluster';
import { ExplainerKey } from '../explainers';
import { ParsedHostAnswers } from '../parse-answers';
import { v } from '../verbs';
import { Problem } from './problem';
const testCluster: (cluster: RequestCluster, answers: ParsedHostAnswers | undefined) => boolean = (
cluster,
hostAnswers
) => {
if (!hostAnswers) {
return false;
}
if (cluster.hasMarkedCookies()) {
/* if it has cookies, it will be picked up by the UnlawfulCookieAccess problem, and that one
is pretty detailed, so no need to mention it here. */
return false;
}
return hostAnswers.legal_basis_type == 'not_mentioned';
};
export class UnknownLegalBasis extends Problem {
getNecessaryExplainers(): ExplainerKey[] {
return ['responsibility_for_third_parties'];
}
qualifies(): boolean {
return Object.values(this.clusters).some((cluster) =>
testCluster(cluster, this.answers.hosts[cluster.id])
);
}
getRelatedClusters() {
return Object.values(this.clusters).filter((cluster) =>
testCluster(cluster, this.answers.hosts[cluster.id])
);
}
getEmailContent() {
const clusters = this.getRelatedClusters();
const _ = (key: string) => v(key, this.answers.zaimek);
return (
<>
<h2>Przetwarzanie danych osobowych bez podania podstawy prawnej</h2>
<p>Państwa strona przetworzyła {_('moje')} dane osobowe poprzez ujawnienie:</p>
<ul>
{clusters.map((cluster) => (
<li key={cluster.id}>
Właścicielowi domeny <strong>{cluster.id}</strong>:{' '}
{cluster.getDataTypeDescription('mojej')}
</li>
))}
</ul>
<p>
{_('Moja')} historia przeglądania stanowi {_('moje')} dane osobowe. Zgodnie z
treścią Artykułu 13 p. 1 lit. c){' '}
<a href="https://eur-lex.europa.eu/legal-content/PL/TXT/HTML/?uri=CELEX:32016R0679&qid=1632163985520&from=PL#d1e1822-1-1">
RODO
</a>
, aby przetwarzać dane osobowe, trzeba poinformować osobę, której dane dotyczą,
o tym, jaka jest podstawa prawna takiego przetwarzania danych.
</p>
<p>
Zwracam się zatem z pytaniem:{' '}
<strong>
jakie były podstawy prawne ujawnienia moich danych każdemu z wyżej
wymienionych podmiotów przez Państwa stronę?
</strong>
</p>
</>
);
}
}

View File

@ -1,25 +1,23 @@
import { RequestCluster } from '../../../request-cluster';
import { wordlist } from '../../../util'; import { wordlist } from '../../../util';
import { ExplainerKey } from '../explainers'; import { ExplainerKey } from '../explainers';
import { ParsedAnswers } from '../parse-answers';
import { v } from '../verbs'; import { v } from '../verbs';
import { Problem } from './problem'; import { Problem } from './problem';
export class UnlawfulCookieAccess extends Problem { export class UnlawfulCookieAccess extends Problem {
getNecessaryExplainers(): ExplainerKey[] { getNecessaryExplainers(): ExplainerKey[] {
return []; return ['cookies_are_pii', 'responsibility_for_third_parties'];
} }
static qualifies(answers: ParsedAnswers, clusters: RequestCluster[]): boolean { qualifies(): boolean {
// są cookiesy, nie było zgody, nie są konieczne do działania strony // są cookiesy, nie było zgody, nie są konieczne do działania strony
const cookie_clusters = Object.values(clusters).filter((c) => c.hasMarkedCookies()); const cookie_clusters = Object.values(this.clusters).filter((c) => c.hasMarkedCookies());
return cookie_clusters.some((cluster) => { return cookie_clusters.some((cluster) => {
const hostAnswers = answers.hosts[cluster.id]; const hostAnswers = this.answers.hosts[cluster.id];
return ( return (
(hostAnswers.present == 'not_mentioned' || (hostAnswers.present == 'not_mentioned' ||
hostAnswers.present == 'not_before_making_a_choice' || hostAnswers.present == 'not_before_making_a_choice' ||
['none', 'closed_popup', 'deny_all'].includes(answers.popup_action) || ['none', 'closed_popup', 'deny_all'].includes(this.answers.popup_action) ||
answers.popup_type === 'none') && this.answers.popup_type === 'none') &&
hostAnswers.was_processing_necessary != 'yes' hostAnswers.was_processing_necessary != 'yes'
); );
}); });
@ -76,7 +74,8 @@ export class UnlawfulCookieAccess extends Problem {
<li> <li>
Użytkownik wyraził zgodę na takie przetwarzanie danych <em>po</em> tym, jak Użytkownik wyraził zgodę na takie przetwarzanie danych <em>po</em> tym, jak
został poinformowany bezpośrednio o celu uzyskania dostępu do tej został poinformowany bezpośrednio o celu uzyskania dostępu do tej
informacji; informacji. Zgodnie z Art. 174 ustawy Prawo Telekomunikacyjne, taka zgoda
musiałaby spełniać warunki zgody ustalone przez RODO;
</li> </li>
<li> <li>
Dostęp do treści plików cookies jest konieczny do dostarczania usługi Dostęp do treści plików cookies jest konieczny do dostarczania usługi
@ -163,9 +162,12 @@ export class UnlawfulCookieAccess extends Problem {
'' ''
)} )}
<p> <p>
{_('Proszę')} o wskazanie, czy być może stosowali Państwo inną podstawę prawną {_('Proszę')} o wskazanie,{' '}
do takiego przetwarzania {_('moich')} danych osobowych, czy przetwarzali je <strong>
państwo bez ważnej podstawy prawnej? czy być może stosowali Państwo inną podstawę prawną do takiego przetwarzania{' '}
{_('moich')} danych osobowych, czy przetwarzali je państwo bez ważnej
podstawy prawnej?
</strong>
</p> </p>
{maybe_unnecessary_hosts.length > 1 ? ( {maybe_unnecessary_hosts.length > 1 ? (
<p> <p>

View File

@ -1,15 +1,16 @@
import * as Survey from 'survey-react'; import * as Survey from 'survey-react';
import { RequestCluster } from '../../request-cluster';
import RawAnswers from './raw-answers'; import RawAnswers from './raw-answers';
import useSurvey from './use-survey'; import useSurvey from './use-survey';
export default function Questions({ export default function Questions({
hosts, clusters,
onComplete, onComplete,
}: { }: {
hosts: string[]; clusters: RequestCluster[];
onComplete: (data: RawAnswers) => void; onComplete: (data: RawAnswers) => void;
}) { }) {
const survey = useSurvey(hosts, { const survey = useSurvey(clusters, {
onComplete: (sender) => onComplete(sender.data), onComplete: (sender) => onComplete(sender.data),
}); });
if (!survey) { if (!survey) {

View File

@ -35,9 +35,9 @@ function Report() {
<div {...{ 'data-version': counter }}> <div {...{ 'data-version': counter }}>
{mode === 'survey' ? ( {mode === 'survey' ? (
<Questions <Questions
hosts={Object.values(clusters) clusters={Object.values(clusters).filter(
.filter((cluster) => cluster.getMarkedRequests().length > 0) (cluster) => cluster.getMarkedRequests().length > 0
.map((cluster) => cluster.id)} )}
onComplete={(answers) => { onComplete={(answers) => {
setAnswers(parseAnswers(answers)); setAnswers(parseAnswers(answers));
setMode('screenshots'); setMode('screenshots');

View File

@ -1,16 +1,17 @@
import * as React from 'react'; import * as React from 'react';
import * as Survey from 'survey-react'; import * as Survey from 'survey-react';
import { RequestCluster } from '../../request-cluster';
import generateSurveyQuestions from './generate-survey-questions'; import generateSurveyQuestions from './generate-survey-questions';
import RawAnswers from './raw-answers'; import RawAnswers from './raw-answers';
import verbs, { v } from './verbs'; import verbs, { v } from './verbs';
export default function useSurvey( export default function useSurvey(
hosts: string[], clusters: RequestCluster[],
{ onComplete }: { onComplete: (sender: { data: RawAnswers }) => void } { onComplete }: { onComplete: (sender: { data: RawAnswers }) => void }
): Survey.ReactSurveyModel { ): Survey.ReactSurveyModel {
const [survey, setSurvey] = React.useState<Survey.Model>(null); const [survey, setSurvey] = React.useState<Survey.Model>(null);
React.useEffect(() => { React.useEffect(() => {
const model = generateSurveyQuestions(hosts); const model = generateSurveyQuestions(clusters);
console.log(model); console.log(model);
const survey = new Survey.Model(model); const survey = new Survey.Model(model);
survey.onProcessTextValue.add(function ( survey.onProcessTextValue.add(function (

View File

@ -8,6 +8,7 @@ const words = {
mnie: ['mnie', 'mnie', 'mnie', 'nas'], mnie: ['mnie', 'mnie', 'mnie', 'nas'],
moich: ['moich', 'moich', 'moich', 'naszych'], moich: ['moich', 'moich', 'moich', 'naszych'],
moje: ['moje', 'moje', 'moje', 'nasze'], moje: ['moje', 'moje', 'moje', 'nasze'],
moja: ['moja', 'moja', 'moja', 'nasza'],
mojej: ['mojej', 'mojej', 'mojej', 'naszej'], mojej: ['mojej', 'mojej', 'mojej', 'naszej'],
muszę: ['muszę', 'muszę', 'muszę', 'musimy'], muszę: ['muszę', 'muszę', 'muszę', 'musimy'],
odkliknąłeś: ['odkliknąłeś', 'odkliknęłaś', 'odklikęłoś', 'odkliknęliście'], odkliknąłeś: ['odkliknąłeś', 'odkliknęłaś', 'odklikęłoś', 'odkliknęliście'],

View File

@ -145,16 +145,6 @@ const Toolbar = () => {
<section className="summary"> <section className="summary">
<div className="counters-wrapper"> <div className="counters-wrapper">
<div className="counters"> <div className="counters">
<div className="counter counter--browser-history">
<img src="/assets/icons/warning.svg#color" width="24" height="24" />
<span data-event={`${eventCounts['*']}`}>
{
Object.values(getMemory().getClustersForOrigin(origin)).filter(
(cluster) => cluster.exposesOrigin()
).length
}
</span>
</div>
<div className="counter counter--cookies"> <div className="counter counter--cookies">
<img src="/assets/icons/cookie.svg#color" width="24" height="24" /> <img src="/assets/icons/cookie.svg#color" width="24" height="24" />
<span data-event={`${eventCounts['*']}`}> <span data-event={`${eventCounts['*']}`}>
@ -165,6 +155,16 @@ const Toolbar = () => {
} }
</span> </span>
</div> </div>
<div className="counter counter--browser-history">
<img src="/assets/icons/warning.svg#color" width="24" height="24" />
<span data-event={`${eventCounts['*']}`}>
{
Object.values(getMemory().getClustersForOrigin(origin)).filter(
(cluster) => cluster.exposesOrigin()
).length
}
</span>
</div>
</div> </div>
<div className="big-counter" data-event={`${eventCounts['*']}`}> <div className="big-counter" data-event={`${eventCounts['*']}`}>
{Object.values(getMemory().getClustersForOrigin(origin)).length} {Object.values(getMemory().getClustersForOrigin(origin)).length}
@ -174,18 +174,6 @@ const Toolbar = () => {
</section> </section>
<section className="details"> <section className="details">
{exposedOriginDomainCopy ? (
<p
data-event={`${eventCounts['*']}`}
title={Object.values(getMemory().getClustersForOrigin(origin))
.filter((cluster) => cluster.exposesOrigin())
.map((domain) => domain.id)
.join(', ')}
>
{first_sentence_cookie}
<strong>{exposedOriginDomainCopy}</strong>
</p>
) : null}
{cookieDomainCopy ? ( {cookieDomainCopy ? (
<p <p
data-event={`${eventCounts['*']}`} data-event={`${eventCounts['*']}`}
@ -194,10 +182,22 @@ const Toolbar = () => {
.map((domain) => domain.id) .map((domain) => domain.id)
.join(', ')} .join(', ')}
> >
{first_sentence_history} {first_sentence_cookie}
<strong>{cookieDomainCopy}</strong> <strong>{cookieDomainCopy}</strong>
</p> </p>
) : null} ) : null}
{exposedOriginDomainCopy ? (
<p
data-event={`${eventCounts['*']}`}
title={Object.values(getMemory().getClustersForOrigin(origin))
.filter((cluster) => cluster.exposesOrigin())
.map((domain) => domain.id)
.join(', ')}
>
{first_sentence_history}
<strong>{exposedOriginDomainCopy}</strong>
</p>
) : null}
</section> </section>
{exposedOriginDomainCopy || cookieDomainCopy ? ( {exposedOriginDomainCopy || cookieDomainCopy ? (

View File

@ -117,9 +117,10 @@ export default class ExtendedRequest {
async cacheOrigin(): Promise<void> { async cacheOrigin(): Promise<void> {
let url: string; let url: string;
if (this.data.tabId && this.data.tabId >= 0) { if (this.data.type === 'main_frame') {
const tab = await browser.tabs.get(this.data.tabId); url = this.data.url;
url = tab.url; } else if (this.data.originUrl) {
url = this.data.originUrl;
} else if ( } else if (
(this.data as any)?.frameAncestors && (this.data as any)?.frameAncestors &&
(this.data as any).frameAncestors[0] !== undefined (this.data as any).frameAncestors[0] !== undefined

View File

@ -3,7 +3,7 @@ import { getshorthost, makeThrottle } from './util';
import { RequestCluster } from './request-cluster'; import { RequestCluster } from './request-cluster';
import { SaferEmitter } from './safer-emitter'; import { SaferEmitter } from './safer-emitter';
function setDomainsNumber(counter: number, tabId: number) { function setDomainsCount(counter: number, tabId: number) {
browser.browserAction.setBadgeText({ text: counter < 0 ? '0' : counter.toString(), tabId }); browser.browserAction.setBadgeText({ text: counter < 0 ? '0' : counter.toString(), tabId });
browser.browserAction.setTitle({ browser.browserAction.setTitle({
title: 'Rentgen', title: 'Rentgen',
@ -35,10 +35,12 @@ export default class Memory extends SaferEmitter {
? browser.browserAction.setBadgeBackgroundColor({ color: '#ff726b' }) ? browser.browserAction.setBadgeBackgroundColor({ color: '#ff726b' })
: browser.browserAction.setBadgeBackgroundColor({ color: '#ffb900' }); : browser.browserAction.setBadgeBackgroundColor({ color: '#ffb900' });
setDomainsNumber( if (request.tabId >= 0) {
Object.values(this.getClustersForOrigin(request.origin)).length, setDomainsCount(
request.tabId Object.values(this.getClustersForOrigin(request.origin)).length,
); request.tabId
);
}
} }
constructor() { constructor() {

1
package-lock.json generated
View File

@ -5,7 +5,6 @@
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "rentgen",
"version": "0.0.3", "version": "0.0.3",
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"dependencies": { "dependencies": {

View File

@ -182,4 +182,15 @@ export class RequestCluster extends SaferEmitter {
entry.unmark(); entry.unmark();
}); });
} }
getDataTypeDescription(noun = 'Twojej') {
let types_of_data: string[] = [];
if (this.exposesOrigin()) {
types_of_data.push(`część ${noun} historii przeglądania`);
}
if (this.hasMarkedCookies()) {
types_of_data.push('unikalne ID z cookies');
}
return types_of_data.join(', ');
}
} }

View File

@ -48,7 +48,6 @@ export class SaferEmitter extends EventEmitter {
Reflect.apply(listener, this, args); Reflect.apply(listener, this, args);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
debugger;
} }
}); });
} }