Compare commits
2 Commits
c86a3e2c23
...
416a6aa340
Author | SHA1 | Date | |
---|---|---|---|
416a6aa340 | |||
e1d97f0411 |
@ -25,6 +25,7 @@ export default function EmailContent({
|
|||||||
downloadFiles: Function;
|
downloadFiles: Function;
|
||||||
user_role: string;
|
user_role: string;
|
||||||
}) {
|
}) {
|
||||||
|
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(
|
||||||
@ -39,10 +40,12 @@ export default function EmailContent({
|
|||||||
function copyTextToClipboard() {
|
function copyTextToClipboard() {
|
||||||
// Should be changed in the future to Clipboard API (https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/write#browser_compatibility)
|
// Should be changed in the future to Clipboard API (https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/write#browser_compatibility)
|
||||||
let r = document.createRange();
|
let r = document.createRange();
|
||||||
r.selectNode(document.querySelector('.mail-container__content'));
|
const container = document.querySelector('.mail-container__content');
|
||||||
window.getSelection().addRange(r);
|
if (!container) return;
|
||||||
|
r.selectNode(container);
|
||||||
|
window.getSelection()?.addRange(r);
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
window.getSelection().removeAllRanges();
|
window.getSelection()?.removeAllRanges();
|
||||||
setCopy(true);
|
setCopy(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +122,10 @@ function generateHostPage(
|
|||||||
defaultValueExpression:
|
defaultValueExpression:
|
||||||
index == 0
|
index == 0
|
||||||
? 'marketing'
|
? 'marketing'
|
||||||
: `{${f('legitimate_interest_description', previous_cluster)}}`,
|
: `{${f(
|
||||||
|
'legitimate_interest_description',
|
||||||
|
previous_cluster || undefined
|
||||||
|
)}}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'radiogroup',
|
type: 'radiogroup',
|
||||||
|
@ -16,7 +16,9 @@ function handleNewFile(
|
|||||||
);
|
);
|
||||||
setFiltered(new Blob([JSON.stringify(content)], { type: 'application/json' }));
|
setFiltered(new Blob([JSON.stringify(content)], { type: 'application/json' }));
|
||||||
});
|
});
|
||||||
reader.readAsText(element.files[0]);
|
const file = element?.files?.[0];
|
||||||
|
if (!file) throw new Error('file empty?');
|
||||||
|
reader.readAsText(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateFakeHAR(entries: StolenDataEntry[]) {
|
function generateFakeHAR(entries: StolenDataEntry[]) {
|
||||||
@ -80,8 +82,11 @@ export default function HARConverter({ entries }: { entries: StolenDataEntry[] }
|
|||||||
type="file"
|
type="file"
|
||||||
accept=".har"
|
accept=".har"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setFilename(e.target.files[0].name);
|
const file = e.target?.files?.[0];
|
||||||
handleNewFile(e.target, entries, setFiltered);
|
if (file) {
|
||||||
|
setFilename(file.name);
|
||||||
|
handleNewFile(e.target, entries, setFiltered);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{(filtered && (
|
{(filtered && (
|
||||||
@ -100,7 +105,7 @@ export default function HARConverter({ entries }: { entries: StolenDataEntry[] }
|
|||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
download={`${getshorthost(
|
download={`${getshorthost(
|
||||||
entries[0].request.originalURL
|
entries[0].request.origin
|
||||||
)}-${new Date().toJSON()}-trimmed.har`}
|
)}-${new Date().toJSON()}-trimmed.har`}
|
||||||
>
|
>
|
||||||
Pobierz "zredukowany" HAR
|
Pobierz "zredukowany" HAR
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
import { RequestCluster } from '../../../request-cluster';
|
|
||||||
import { ExplainerKey } from '../explainers';
|
|
||||||
import { ParsedAnswers, ParsedHostAnswers } from '../parse-answers';
|
|
||||||
import { v } from '../verbs';
|
|
||||||
import { Problem } from './problem';
|
|
||||||
|
|
||||||
type UnlawfulDataClassification = 'no_purpose';
|
|
||||||
|
|
||||||
export function classifyUnlawfulData(
|
|
||||||
hostAnswers: ParsedHostAnswers,
|
|
||||||
cluster: RequestCluster
|
|
||||||
): UnlawfulDataClassification {
|
|
||||||
if (hostAnswers.present == 'not_mentioned' && hostAnswers.was_processing_necessary == 'no') {
|
|
||||||
return 'no_purpose';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UnlawfulData extends Problem {
|
|
||||||
static qualifies(answers: ParsedAnswers, clusters: RequestCluster[]): boolean {}
|
|
||||||
getEmailContent() {
|
|
||||||
const _ = (key: string) => v(key, this.answers.zaimek);
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<h2>Przetwarzanie danych osobowych bez ważnej podsawy prawnej</h2>
|
|
||||||
<p>
|
|
||||||
{_('Moje')} dane osobowe zostały ujawnione podmiotom, które są właścicielami
|
|
||||||
domen:
|
|
||||||
</p>
|
|
||||||
{this.getRangeDescription()}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
getNecessaryExplainers() {
|
|
||||||
return [] as ExplainerKey[];
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,16 +21,21 @@ function Report() {
|
|||||||
try {
|
try {
|
||||||
const url = new URL(document.location.toString());
|
const url = new URL(document.location.toString());
|
||||||
const origin = url.searchParams.get('origin');
|
const origin = url.searchParams.get('origin');
|
||||||
|
if (!origin) {
|
||||||
|
return <div>Błąd: brak parametru "origin"</div>;
|
||||||
|
}
|
||||||
const [counter] = useEmitter(getMemory());
|
const [counter] = useEmitter(getMemory());
|
||||||
|
const rawAnswers = url.searchParams.get('answers');
|
||||||
const [answers, setAnswers] = React.useState<ParsedAnswers>(
|
const [answers, setAnswers] = React.useState<ParsedAnswers>(
|
||||||
url.searchParams.get('answers') ? JSON.parse(url.searchParams.get('answers')) : null
|
rawAnswers ? JSON.parse(rawAnswers) : null
|
||||||
);
|
);
|
||||||
const [mode, setMode] = React.useState(url.searchParams.get('mode') || 'survey');
|
const [mode, setMode] = React.useState(url.searchParams.get('mode') || 'survey');
|
||||||
const [scrRequestPath, setScrRequestPath] = React.useState('');
|
const [scrRequestPath, setScrRequestPath] = React.useState('');
|
||||||
|
|
||||||
const clusters = getMemory().getClustersForOrigin(origin);
|
const clusters = getMemory().getClustersForOrigin(origin || '');
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
if (!origin) return;
|
||||||
const url = new URL(document.location.toString());
|
const url = new URL(document.location.toString());
|
||||||
url.searchParams.set('origin', origin);
|
url.searchParams.set('origin', origin);
|
||||||
url.searchParams.set('answers', JSON.stringify(answers));
|
url.searchParams.set('answers', JSON.stringify(answers));
|
||||||
@ -38,8 +43,12 @@ function Report() {
|
|||||||
history.pushState({}, 'Rentgen', url.toString());
|
history.pushState({}, 'Rentgen', url.toString());
|
||||||
}, [mode, answers, origin]);
|
}, [mode, answers, origin]);
|
||||||
const visited_url = Object.values(clusters)
|
const visited_url = Object.values(clusters)
|
||||||
.find((cluster) => cluster.getMarkedRequests().length > 0)
|
.sort((a, b) => (a.lastModified > b.lastModified ? -1 : 1))
|
||||||
?.getMarkedRequests()[0].originalURL;
|
.find((cluster) => !!cluster.lastFullUrl)?.lastFullUrl;
|
||||||
|
|
||||||
|
if (!visited_url) {
|
||||||
|
return <div>Wczytywanie...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
const result = (
|
const result = (
|
||||||
<div {...{ 'data-version': counter }}>
|
<div {...{ 'data-version': counter }}>
|
||||||
|
@ -66,7 +66,7 @@ export default function ScreenshotGenerator({
|
|||||||
}) {
|
}) {
|
||||||
const [mode, setMode] = React.useState<string>('idle');
|
const [mode, setMode] = React.useState<string>('idle');
|
||||||
const [images, setImages] = React.useState<Screenshot[]>([]);
|
const [images, setImages] = React.useState<Screenshot[]>([]);
|
||||||
const [taskId, setTaskId] = React.useState<string>(null);
|
const [taskId, setTaskId] = React.useState<string | null>(null);
|
||||||
const [output, setOutput] = React.useState<any>({});
|
const [output, setOutput] = React.useState<any>({});
|
||||||
|
|
||||||
async function subscribeTask(path: string): Promise<screenshotTask> {
|
async function subscribeTask(path: string): Promise<screenshotTask> {
|
||||||
@ -75,8 +75,8 @@ export default function ScreenshotGenerator({
|
|||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
response = await (await pollTask(path)).json();
|
response = await (await pollTask(path)).json();
|
||||||
setImages((response as screenshotTask)?.images);
|
setImages((response as screenshotTask)?.images);
|
||||||
document.querySelector('.images').scrollTo({
|
document.querySelector('.images')?.scrollTo({
|
||||||
top: document.querySelector('.images').scrollHeight,
|
top: document.querySelector('.images')?.scrollHeight,
|
||||||
behavior: 'smooth',
|
behavior: 'smooth',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,8 @@ import verbs, { v } from './verbs';
|
|||||||
export default function useSurvey(
|
export default function useSurvey(
|
||||||
clusters: RequestCluster[],
|
clusters: RequestCluster[],
|
||||||
{ onComplete }: { onComplete: (sender: { data: RawAnswers }) => void }
|
{ onComplete }: { onComplete: (sender: { data: RawAnswers }) => void }
|
||||||
): Survey.ReactSurveyModel {
|
): Survey.ReactSurveyModel | null {
|
||||||
const [survey, setSurvey] = React.useState<Survey.Model>(null);
|
const [survey, setSurvey] = React.useState<Survey.Model | null>(null);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const model = generateSurveyQuestions(clusters);
|
const model = generateSurveyQuestions(clusters);
|
||||||
const survey = new Survey.Model(model);
|
const survey = new Survey.Model(model);
|
||||||
|
@ -1,20 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import Options from '../../options';
|
|
||||||
import { StolenData } from './stolen-data';
|
|
||||||
import { getshorthost, useEmitter } from '../../util';
|
|
||||||
import { getMemory } from '../../memory';
|
import { getMemory } from '../../memory';
|
||||||
|
import Options from '../../options';
|
||||||
async function getCurrentTab() {
|
import { useEmitter } from '../../util';
|
||||||
const [tab] = await browser.tabs.query({
|
|
||||||
active: true,
|
|
||||||
windowId: browser.windows.WINDOW_ID_CURRENT,
|
|
||||||
});
|
|
||||||
return tab;
|
|
||||||
}
|
|
||||||
|
|
||||||
import './../../styles/global.scss';
|
import './../../styles/global.scss';
|
||||||
import './sidebar.scss';
|
import './sidebar.scss';
|
||||||
|
import { StolenData } from './stolen-data';
|
||||||
|
|
||||||
const Sidebar = () => {
|
const Sidebar = () => {
|
||||||
const url = new URL(document.location.toString());
|
const url = new URL(document.location.toString());
|
||||||
@ -28,8 +20,8 @@ const Sidebar = () => {
|
|||||||
const [cookiesOnly, setCookiesOnly] = React.useState<boolean>(false);
|
const [cookiesOnly, setCookiesOnly] = React.useState<boolean>(false);
|
||||||
const [stolenDataView, setStolenDataView] = React.useState<boolean>(true);
|
const [stolenDataView, setStolenDataView] = React.useState<boolean>(true);
|
||||||
const [cookiesOrOriginOnly, setCookiesOrOriginOnly] = React.useState<boolean>(false);
|
const [cookiesOrOriginOnly, setCookiesOrOriginOnly] = React.useState<boolean>(false);
|
||||||
const [eventCounts, setEventCounts] = useEmitter(getMemory());
|
const [eventCounts] = useEmitter(getMemory());
|
||||||
const [marksOccurrence, setMarksOccurrence] = React.useState<boolean>(false);
|
const [_, setMarksOccurrence] = React.useState<boolean>(false);
|
||||||
const [infoDataDialogAck, setInfoDataDialogAck] = React.useState<boolean>(
|
const [infoDataDialogAck, setInfoDataDialogAck] = React.useState<boolean>(
|
||||||
localStorage.getItem('infoDataDialogAck') === null
|
localStorage.getItem('infoDataDialogAck') === null
|
||||||
? true
|
? true
|
||||||
@ -53,6 +45,7 @@ const Sidebar = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
if (!origin) return;
|
||||||
for (const cluster of Object.values(getMemory().getClustersForOrigin(origin))) {
|
for (const cluster of Object.values(getMemory().getClustersForOrigin(origin))) {
|
||||||
if (cluster.hasMarks()) {
|
if (cluster.hasMarks()) {
|
||||||
return setMarksOccurrence(true);
|
return setMarksOccurrence(true);
|
||||||
@ -62,6 +55,7 @@ const Sidebar = () => {
|
|||||||
return setMarksOccurrence(false);
|
return setMarksOccurrence(false);
|
||||||
}, [eventCounts['*']]);
|
}, [eventCounts['*']]);
|
||||||
|
|
||||||
|
if (!origin) return <div>Błąd: Brak parametru "origin"</div>;
|
||||||
return (
|
return (
|
||||||
<div className="sidebar">
|
<div className="sidebar">
|
||||||
<header className="header">
|
<header className="header">
|
||||||
@ -204,7 +198,7 @@ const Sidebar = () => {
|
|||||||
<StolenData
|
<StolenData
|
||||||
origin={origin}
|
origin={origin}
|
||||||
eventCounts={eventCounts}
|
eventCounts={eventCounts}
|
||||||
minValueLength={minValueLength}
|
minValueLength={minValueLength === null ? 7 : minValueLength}
|
||||||
cookiesOnly={cookiesOnly}
|
cookiesOnly={cookiesOnly}
|
||||||
cookiesOrOriginOnly={cookiesOrOriginOnly}
|
cookiesOrOriginOnly={cookiesOrOriginOnly}
|
||||||
detailsVisibility={detailsVisibility}
|
detailsVisibility={detailsVisibility}
|
||||||
@ -212,7 +206,7 @@ const Sidebar = () => {
|
|||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Options
|
<Options
|
||||||
minValueLength={minValueLength}
|
minValueLength={minValueLength === null ? 7 : minValueLength}
|
||||||
setMinValueLength={setMinValueLength}
|
setMinValueLength={setMinValueLength}
|
||||||
cookiesOnly={cookiesOnly}
|
cookiesOnly={cookiesOnly}
|
||||||
setCookiesOnly={setCookiesOnly}
|
setCookiesOnly={setCookiesOnly}
|
||||||
|
@ -14,7 +14,7 @@ export function StolenData({
|
|||||||
detailsVisibility,
|
detailsVisibility,
|
||||||
}: {
|
}: {
|
||||||
origin: string;
|
origin: string;
|
||||||
eventCounts: Record<string, number>;
|
eventCounts: Record<string, number | undefined>;
|
||||||
minValueLength: number;
|
minValueLength: number;
|
||||||
cookiesOnly: boolean;
|
cookiesOnly: boolean;
|
||||||
cookiesOrOriginOnly: boolean;
|
cookiesOrOriginOnly: boolean;
|
||||||
@ -43,7 +43,7 @@ export function StolenData({
|
|||||||
origin={origin}
|
origin={origin}
|
||||||
shorthost={cluster.id}
|
shorthost={cluster.id}
|
||||||
key={cluster.id + origin}
|
key={cluster.id + origin}
|
||||||
refreshToken={eventCounts[cluster.id]}
|
refreshToken={eventCounts[cluster.id] || 0}
|
||||||
minValueLength={minValueLength}
|
minValueLength={minValueLength}
|
||||||
cookiesOnly={cookiesOnly}
|
cookiesOnly={cookiesOnly}
|
||||||
cookiesOrOriginOnly={cookiesOrOriginOnly}
|
cookiesOrOriginOnly={cookiesOrOriginOnly}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { Tab } from '../../util';
|
||||||
|
|
||||||
export default function TabDropdown({
|
export default function TabDropdown({
|
||||||
setPickedTab,
|
setPickedTab,
|
||||||
@ -7,7 +8,7 @@ export default function TabDropdown({
|
|||||||
setPickedTab: (tab_id: number) => void;
|
setPickedTab: (tab_id: number) => void;
|
||||||
pickedTab: number;
|
pickedTab: number;
|
||||||
}) {
|
}) {
|
||||||
const [tabs, setTabs] = React.useState([]);
|
const [tabs, setTabs] = React.useState<Tab[]>([]);
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
browser.tabs.query({ currentWindow: true }).then(setTabs);
|
browser.tabs.query({ currentWindow: true }).then(setTabs);
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -16,10 +16,9 @@ import './toolbar.scss';
|
|||||||
|
|
||||||
const Toolbar = () => {
|
const Toolbar = () => {
|
||||||
const [origin, setOrigin] = React.useState<string | null>(null);
|
const [origin, setOrigin] = React.useState<string | null>(null);
|
||||||
const [stolenDataView, setStolenDataView] = React.useState<boolean>(true);
|
const [eventCounts] = useEmitter(getMemory());
|
||||||
const [eventCounts, setEventCounts] = useEmitter(getMemory());
|
|
||||||
const [cookieDomainCopy, setCookieDomainCopy] = React.useState<string | null>(null);
|
const [cookieDomainCopy, setCookieDomainCopy] = React.useState<string | null>(null);
|
||||||
const [marksOccurrence, setMarksOccurrence] = React.useState<boolean>(false);
|
const [_, setMarksOccurrence] = React.useState<boolean>(false);
|
||||||
const [exposedOriginDomainCopy, setExposedOriginDomainCopy] = React.useState<string | null>(
|
const [exposedOriginDomainCopy, setExposedOriginDomainCopy] = React.useState<string | null>(
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
@ -32,7 +31,7 @@ const Toolbar = () => {
|
|||||||
const listener = async () => {
|
const listener = async () => {
|
||||||
const tab = await getCurrentTab();
|
const tab = await getCurrentTab();
|
||||||
|
|
||||||
if (tab !== undefined) {
|
if (tab !== undefined && tab.url) {
|
||||||
const url = new URL(tab.url);
|
const url = new URL(tab.url);
|
||||||
if (url.origin.startsWith('moz-extension')) {
|
if (url.origin.startsWith('moz-extension')) {
|
||||||
return;
|
return;
|
||||||
@ -51,6 +50,7 @@ const Toolbar = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
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())
|
||||||
.map((cluster) => cluster.id);
|
.map((cluster) => cluster.id);
|
||||||
@ -58,27 +58,32 @@ const Toolbar = () => {
|
|||||||
|
|
||||||
switch (exposedOriginDomains.length) {
|
switch (exposedOriginDomains.length) {
|
||||||
case 0:
|
case 0:
|
||||||
return null;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
return setExposedOriginDomainCopy(`${exposedOriginDomains[0]}.`);
|
setExposedOriginDomainCopy(`${exposedOriginDomains[0]}.`);
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
return setExposedOriginDomainCopy(
|
setExposedOriginDomainCopy(
|
||||||
`${exposedOriginDomains[0]} oraz ${exposedOriginDomains[1]}.`
|
`${exposedOriginDomains[0]} oraz ${exposedOriginDomains[1]}.`
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
return setExposedOriginDomainCopy(
|
setExposedOriginDomainCopy(
|
||||||
`${exposedOriginDomains[0]}, ${exposedOriginDomains[1]} oraz ${exposedOriginDomains[2]}.`
|
`${exposedOriginDomains[0]}, ${exposedOriginDomains[1]} oraz ${exposedOriginDomains[2]}.`
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return setExposedOriginDomainCopy(
|
setExposedOriginDomainCopy(
|
||||||
`${exposedOriginDomains[0]}, ${exposedOriginDomains[1]} (i ${
|
`${exposedOriginDomains[0]}, ${exposedOriginDomains[1]} (i ${
|
||||||
exposedOriginDomains.length - 2 < 2 ? 2 : exposedOriginDomains.length - 2
|
exposedOriginDomains.length - 2 < 2 ? 2 : exposedOriginDomains.length - 2
|
||||||
} innych).`
|
} innych).`
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}, [eventCounts['*'], origin]);
|
}, [eventCounts['*'], origin]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
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())
|
||||||
.map((cluster) => cluster.id);
|
.map((cluster) => cluster.id);
|
||||||
@ -86,25 +91,30 @@ const Toolbar = () => {
|
|||||||
|
|
||||||
switch (cookieDomains.length) {
|
switch (cookieDomains.length) {
|
||||||
case 0:
|
case 0:
|
||||||
return null;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
return setCookieDomainCopy(`${cookieDomains[0]}.`);
|
setCookieDomainCopy(`${cookieDomains[0]}.`);
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
return setCookieDomainCopy(`${cookieDomains[0]} oraz ${cookieDomains[1]}.`);
|
setCookieDomainCopy(`${cookieDomains[0]} oraz ${cookieDomains[1]}.`);
|
||||||
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
return setCookieDomainCopy(
|
setCookieDomainCopy(
|
||||||
`${cookieDomains[0]}, ${cookieDomains[1]} oraz ${cookieDomains[2]}.`
|
`${cookieDomains[0]}, ${cookieDomains[1]} oraz ${cookieDomains[2]}.`
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return setCookieDomainCopy(
|
setCookieDomainCopy(
|
||||||
`${cookieDomains[0]}, ${cookieDomains[1]} (i ${
|
`${cookieDomains[0]}, ${cookieDomains[1]} (i ${
|
||||||
cookieDomains.length - 2 < 2 ? 2 : cookieDomains.length - 2
|
cookieDomains.length - 2 < 2 ? 2 : cookieDomains.length - 2
|
||||||
} innych).`
|
} innych).`
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}, [eventCounts['*'], origin]);
|
}, [eventCounts['*'], origin]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
if (!origin) return;
|
||||||
for (const cluster of Object.values(getMemory().getClustersForOrigin(origin))) {
|
for (const cluster of Object.values(getMemory().getClustersForOrigin(origin))) {
|
||||||
if (cluster.hasMarks()) {
|
if (cluster.hasMarks()) {
|
||||||
return setMarksOccurrence(true);
|
return setMarksOccurrence(true);
|
||||||
@ -115,12 +125,17 @@ const Toolbar = () => {
|
|||||||
}, [eventCounts['*']]);
|
}, [eventCounts['*']]);
|
||||||
|
|
||||||
function autoMark() {
|
function autoMark() {
|
||||||
|
if (!origin) return;
|
||||||
for (const cluster of Object.values(getMemory().getClustersForOrigin(origin))) {
|
for (const cluster of Object.values(getMemory().getClustersForOrigin(origin))) {
|
||||||
cluster.autoMark();
|
cluster.autoMark();
|
||||||
}
|
}
|
||||||
return setMarksOccurrence(true);
|
return setMarksOccurrence(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!origin) {
|
||||||
|
return <div>Wczytywanie...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="toolbar">
|
<div className="toolbar">
|
||||||
<header className="header">
|
<header className="header">
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
'use strict';
|
||||||
import { StolenDataEntry } from './stolen-data-entry';
|
import { StolenDataEntry } from './stolen-data-entry';
|
||||||
import {
|
import {
|
||||||
flattenObjectEntries,
|
flattenObjectEntries,
|
||||||
@ -75,12 +76,13 @@ export default class ExtendedRequest {
|
|||||||
public tabId: number;
|
public tabId: number;
|
||||||
public url: string;
|
public url: string;
|
||||||
public shorthost: string;
|
public shorthost: string;
|
||||||
public requestHeaders: Request['requestHeaders'] = [];
|
public requestHeaders: { name: string; value?: string; binaryValue?: number[] }[] = [];
|
||||||
public originalURL: string;
|
|
||||||
public origin: string;
|
public origin: string;
|
||||||
public initialized = false;
|
public initialized = false;
|
||||||
public stolenData: StolenDataEntry[];
|
public stolenData: StolenDataEntry[] = [];
|
||||||
public originalPathname: string;
|
public originalURL: string | null = null; // sometimes we can only establish that the given request applied to a certain origin, not a full URL from the address bar - in case of service workers, for example. Hence the null
|
||||||
|
public originalPathname: string | null = null; // same as above
|
||||||
|
public originalHost: string;
|
||||||
public requestBody: RequestBody;
|
public requestBody: RequestBody;
|
||||||
|
|
||||||
static by_id = {} as Record<string, ExtendedRequest>;
|
static by_id = {} as Record<string, ExtendedRequest>;
|
||||||
@ -95,59 +97,57 @@ export default class ExtendedRequest {
|
|||||||
|
|
||||||
this.data = Object.assign({}, data);
|
this.data = Object.assign({}, data);
|
||||||
(this.data as any).frameAncestors = [
|
(this.data as any).frameAncestors = [
|
||||||
...(data as any).frameAncestors.map((e: any) => ({ url: e.url })),
|
...((data as any)?.frameAncestors?.map((e: any) => ({ url: e.url })) || []),
|
||||||
];
|
]; // making a copy?
|
||||||
}
|
|
||||||
|
|
||||||
addHeaders(headers: Request['requestHeaders']) {
|
// console.log('→→→',(this.data as any).frameAncestors, (data as any).frameAncestors);
|
||||||
this.requestHeaders = headers;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
await this.cacheOrigin();
|
|
||||||
this.initialized = true;
|
|
||||||
this.stolenData = this.getAllStolenData();
|
|
||||||
}
|
|
||||||
|
|
||||||
async cacheOrigin(): Promise<void> {
|
|
||||||
let url: string;
|
let url: string;
|
||||||
|
let is_full_url = true;
|
||||||
if (this.data.type === 'main_frame') {
|
if (this.data.type === 'main_frame') {
|
||||||
url = this.data.url;
|
url = this.data.url;
|
||||||
} else if (this.data.originUrl) {
|
} else if (this.data.frameId === 0 && this.data.documentUrl) {
|
||||||
url = this.data.originUrl;
|
url = this.data.documentUrl;
|
||||||
|
if (this.data.tabId == -1) {
|
||||||
|
//a service worker?
|
||||||
|
is_full_url = false;
|
||||||
|
}
|
||||||
} 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
|
||||||
) {
|
) {
|
||||||
url = (this.data as any).frameAncestors[0].url || '';
|
url = (this.data as any).frameAncestors[0].url || '';
|
||||||
} else {
|
} else {
|
||||||
const headers = Object.fromEntries(
|
url = this.data.documentUrl || this.data.originUrl;
|
||||||
this.requestHeaders.map(({ name, value }) => [name, value])
|
|
||||||
);
|
|
||||||
if (headers.Referer) {
|
|
||||||
url = headers.Referer;
|
|
||||||
} else {
|
|
||||||
url = this.data.url;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.originalURL = url;
|
this.originalURL = is_full_url ? url : null;
|
||||||
this.origin = new URL(url).origin;
|
this.origin = new URL(url).origin;
|
||||||
this.originalPathname = new URL(url).pathname;
|
|
||||||
|
this.originalHost = new URL(url).host;
|
||||||
|
this.originalPathname = is_full_url ? new URL(url).pathname : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
addHeaders(headers: Request['requestHeaders']) {
|
||||||
|
this.requestHeaders = headers || [];
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
init() {
|
||||||
|
this.initialized = true;
|
||||||
|
this.stolenData = this.getAllStolenData();
|
||||||
}
|
}
|
||||||
|
|
||||||
isThirdParty() {
|
isThirdParty() {
|
||||||
const request_url = new URL(this.data.url);
|
const request_url = new URL(this.data.url);
|
||||||
const origin_url = new URL(this.originalURL);
|
if (request_url.host.includes(this.originalHost)) {
|
||||||
if (request_url.host.includes(origin_url.host)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (getshorthost(request_url.host) == getshorthost(origin_url.host)) {
|
if (getshorthost(request_url.host) == getshorthost(this.originalHost)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
request_url.origin != origin_url.origin ||
|
request_url.origin != this.origin ||
|
||||||
(this.data as any).urlClassification.thirdParty.length > 0
|
(this.data as any).urlClassification.thirdParty.length > 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -159,9 +159,8 @@ export default class ExtendedRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exposesOrigin() {
|
exposesOrigin() {
|
||||||
const url = new URL(this.originalURL);
|
const host = this.originalHost;
|
||||||
const host = url.host;
|
const path = this.originalPathname || '/';
|
||||||
const path = url.pathname;
|
|
||||||
const shorthost = getshorthost(host);
|
const shorthost = getshorthost(host);
|
||||||
if (this.getReferer().includes(shorthost)) {
|
if (this.getReferer().includes(shorthost)) {
|
||||||
return true;
|
return true;
|
||||||
@ -213,7 +212,10 @@ export default class ExtendedRequest {
|
|||||||
if ((Array.isArray(value) && value.length === 1 && !value[0]) || !value) {
|
if ((Array.isArray(value) && value.length === 1 && !value[0]) || !value) {
|
||||||
return ['requestBody', key];
|
return ['requestBody', key];
|
||||||
} else if (!Array.isArray(value)) {
|
} else if (!Array.isArray(value)) {
|
||||||
return ['raw', String.fromCharCode.apply(null, new Uint8Array(value.bytes))];
|
return [
|
||||||
|
'raw',
|
||||||
|
String.fromCharCode.apply(null, Array.from(new Uint8Array(value.bytes))),
|
||||||
|
];
|
||||||
} else {
|
} else {
|
||||||
return [key, value || ''];
|
return [key, value || ''];
|
||||||
}
|
}
|
||||||
@ -232,7 +234,7 @@ export default class ExtendedRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCookie(): string {
|
getCookie(): string {
|
||||||
return this.requestHeaders.find((h) => h.name == 'Cookie')?.value;
|
return this.requestHeaders.find((h) => h.name == 'Cookie')?.value || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
getPathParams(): StolenDataEntry[] {
|
getPathParams(): StolenDataEntry[] {
|
||||||
@ -255,8 +257,8 @@ export default class ExtendedRequest {
|
|||||||
getQueryParams(): StolenDataEntry[] {
|
getQueryParams(): StolenDataEntry[] {
|
||||||
const url = new URL(this.data.url);
|
const url = new URL(this.data.url);
|
||||||
return flattenObjectEntries(
|
return flattenObjectEntries(
|
||||||
Array.from((url.searchParams as any).entries())
|
(Array.from((url.searchParams as any).entries()) as [string, string][])
|
||||||
.map(([key, value]) => [key, value || ''])
|
.map(([key, value]: [string, string]) => [key, value || ''])
|
||||||
.map(([key, value]) => {
|
.map(([key, value]) => {
|
||||||
return [key, StolenDataEntry.parseValue(safeDecodeURIComponent(value))];
|
return [key, StolenDataEntry.parseValue(safeDecodeURIComponent(value))];
|
||||||
})
|
})
|
||||||
@ -279,7 +281,7 @@ export default class ExtendedRequest {
|
|||||||
.map((header) => {
|
.map((header) => {
|
||||||
return [
|
return [
|
||||||
header.name,
|
header.name,
|
||||||
StolenDataEntry.parseValue(safeDecodeURIComponent(header.value)),
|
StolenDataEntry.parseValue(safeDecodeURIComponent(header.value || '')),
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
).map(([key, value]) => new StolenDataEntry(this, 'header', key, value));
|
).map(([key, value]) => new StolenDataEntry(this, 'header', key, value));
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import ExtendedRequest from './extended-request';
|
import ExtendedRequest from './extended-request';
|
||||||
import { getshorthost, makeThrottle } from './util';
|
import { getshorthost } from './util';
|
||||||
import { RequestCluster } from './request-cluster';
|
import { RequestCluster } from './request-cluster';
|
||||||
import { SaferEmitter } from './safer-emitter';
|
import { SaferEmitter } from './safer-emitter';
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ export default class Memory extends SaferEmitter {
|
|||||||
|
|
||||||
emit(eventName: string, data = 'any'): boolean {
|
emit(eventName: string, data = 'any'): boolean {
|
||||||
setTimeout(() => super.emit(eventName, data), 0);
|
setTimeout(() => super.emit(eventName, data), 0);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
getClustersForOrigin(origin: string): Record<string, RequestCluster> {
|
getClustersForOrigin(origin: string): Record<string, RequestCluster> {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { EventEmitter } from 'events';
|
|
||||||
import ExtendedRequest from './extended-request';
|
import ExtendedRequest from './extended-request';
|
||||||
import { SaferEmitter } from './safer-emitter';
|
import { SaferEmitter } from './safer-emitter';
|
||||||
import { Sources, StolenDataEntry } from './stolen-data-entry';
|
import { Sources, StolenDataEntry } from './stolen-data-entry';
|
||||||
@ -10,13 +9,20 @@ const source_priority: Array<Sources> = ['cookie', 'pathname', 'queryparams', 'h
|
|||||||
export class RequestCluster extends SaferEmitter {
|
export class RequestCluster extends SaferEmitter {
|
||||||
public requests: ExtendedRequest[] = [];
|
public requests: ExtendedRequest[] = [];
|
||||||
public representativeStolenData: StolenDataEntry[] = [];
|
public representativeStolenData: StolenDataEntry[] = [];
|
||||||
public expanded: boolean;
|
public expanded: boolean = false;
|
||||||
|
public lastModified: number = 0;
|
||||||
|
public lastFullUrl: string | null = null;
|
||||||
constructor(public id: string) {
|
constructor(public id: string) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
add(request: ExtendedRequest) {
|
add(request: ExtendedRequest) {
|
||||||
this.requests.push(request);
|
this.requests.push(request);
|
||||||
this.emit('change');
|
this.emit('change');
|
||||||
|
this.lastModified = Date.now();
|
||||||
|
if (request.originalURL) {
|
||||||
|
this.lastFullUrl = request.originalURL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleExpanded(state: boolean) {
|
toggleExpanded(state: boolean) {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { EventEmitter } from 'events';
|
|
||||||
import ExtendedRequest, { HAREntry } from './extended-request';
|
import ExtendedRequest, { HAREntry } from './extended-request';
|
||||||
import { SaferEmitter } from './safer-emitter';
|
import { SaferEmitter } from './safer-emitter';
|
||||||
|
|
||||||
@ -59,11 +58,10 @@ export class StolenDataEntry extends SaferEmitter {
|
|||||||
getPriority() {
|
getPriority() {
|
||||||
let priority = 0;
|
let priority = 0;
|
||||||
priority += Math.min(this.value.length, 50);
|
priority += Math.min(this.value.length, 50);
|
||||||
const url = new URL(this.request.originalURL);
|
if (this.value.includes(this.request.originalHost)) {
|
||||||
if (this.value.includes(url.host)) {
|
|
||||||
priority += 100;
|
priority += 100;
|
||||||
}
|
}
|
||||||
if (this.value.includes(url.pathname)) {
|
if (this.request.originalPathname && this.value.includes(this.request.originalPathname)) {
|
||||||
priority += 100;
|
priority += 100;
|
||||||
}
|
}
|
||||||
if (this.source === 'cookie') {
|
if (this.source === 'cookie') {
|
||||||
@ -133,7 +131,7 @@ export class StolenDataEntry extends SaferEmitter {
|
|||||||
} else if (value === null) {
|
} else if (value === null) {
|
||||||
return 'null';
|
return 'null';
|
||||||
} else {
|
} else {
|
||||||
return value.toString();
|
return (value as any).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,10 +236,14 @@ export class StolenDataEntry extends SaferEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
exposesPath() {
|
exposesPath() {
|
||||||
|
const pathname = this.request.originalPathname;
|
||||||
|
if (pathname === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
this.request.originalPathname !== '/' &&
|
this.request.originalPathname !== '/' &&
|
||||||
[this.value, safeDecodeURIComponent(this.value)].some((haystack) =>
|
[this.value, safeDecodeURIComponent(this.value)].some((haystack) =>
|
||||||
haystack.includes(this.request.originalPathname)
|
haystack.includes(pathname)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
"typeRoots": ["node_modules/@types", "node_modules/web-ext-types"],
|
"typeRoots": ["node_modules/@types", "node_modules/web-ext-types"],
|
||||||
"target": "es2019",
|
"target": "es2019",
|
||||||
"outDir": "lib",
|
"outDir": "lib",
|
||||||
"skipLibCheck": true
|
"skipLibCheck": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"strict": true,
|
||||||
|
"alwaysStrict": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
util.ts
29
util.ts
@ -36,7 +36,11 @@ export function getshorthost(host: string) {
|
|||||||
.replace(/^.*:\/\//, '')
|
.replace(/^.*:\/\//, '')
|
||||||
.replace(/\/.*$/, '')
|
.replace(/\/.*$/, '')
|
||||||
.split('.');
|
.split('.');
|
||||||
let lookback = !['co', 'com'].includes(parts.at(-2)) ? -2 : -3;
|
const second_last = parts.at(-2);
|
||||||
|
if (!second_last) {
|
||||||
|
throw new Error('url too short?');
|
||||||
|
}
|
||||||
|
let lookback = !['co', 'com'].includes(second_last) ? -2 : -3;
|
||||||
if (parts.at(-2) == 'doubleclick' || parts.at(-2) == 'google') {
|
if (parts.at(-2) == 'doubleclick' || parts.at(-2) == 'google') {
|
||||||
lookback = -4; // to distinguish between google ads and stats
|
lookback = -4; // to distinguish between google ads and stats
|
||||||
} else if (parts.at(-2) == 'google') {
|
} else if (parts.at(-2) == 'google') {
|
||||||
@ -89,7 +93,7 @@ export async function getTabByID(id: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function parseToObject(str: unknown): Record<string | symbol, unknown> {
|
export function parseToObject(str: unknown): Record<string | symbol, unknown> {
|
||||||
let result: Record<string | symbol, unknown>;
|
let result: Record<string | symbol, unknown> = {};
|
||||||
let original_string: string;
|
let original_string: string;
|
||||||
if (typeof str === 'string') {
|
if (typeof str === 'string') {
|
||||||
original_string = str;
|
original_string = str;
|
||||||
@ -97,6 +101,8 @@ export function parseToObject(str: unknown): Record<string | symbol, unknown> {
|
|||||||
} else if (typeof str == 'object') {
|
} else if (typeof str == 'object') {
|
||||||
result = str as Record<string | symbol, unknown>;
|
result = str as Record<string | symbol, unknown>;
|
||||||
original_string = (result[Symbol.for('originalString')] as string) || JSON.stringify(str);
|
original_string = (result[Symbol.for('originalString')] as string) || JSON.stringify(str);
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
result[Symbol.for('originalString')] = original_string;
|
result[Symbol.for('originalString')] = original_string;
|
||||||
return result;
|
return result;
|
||||||
@ -149,9 +155,13 @@ export function getDate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function toBase64(file: File): Promise<string> {
|
export function toBase64(file: File): Promise<string> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve, reject) => {
|
||||||
const FR = new FileReader();
|
const FR = new FileReader();
|
||||||
FR.addEventListener('load', (e) => {
|
FR.addEventListener('load', (e) => {
|
||||||
|
const target = e.target;
|
||||||
|
if (!target) {
|
||||||
|
return reject('File missing?');
|
||||||
|
}
|
||||||
resolve(e.target.result as string);
|
resolve(e.target.result as string);
|
||||||
});
|
});
|
||||||
FR.readAsDataURL(file);
|
FR.readAsDataURL(file);
|
||||||
@ -199,7 +209,8 @@ export function isBase64JSON(s: unknown): s is string {
|
|||||||
|
|
||||||
export function flattenObject(
|
export function flattenObject(
|
||||||
obj: unknown,
|
obj: unknown,
|
||||||
parser: (to_parse: unknown) => string | Record<string, unknown> = (id) => id.toString(),
|
parser: (to_parse: { toString: () => string }) => string | Record<string, unknown> = (id) =>
|
||||||
|
id.toString(),
|
||||||
key = '',
|
key = '',
|
||||||
ret = [] as [string, string][],
|
ret = [] as [string, string][],
|
||||||
parsed = false
|
parsed = false
|
||||||
@ -220,7 +231,12 @@ export function flattenObject(
|
|||||||
flattenObject(value, parser, prefix + subkey, ret);
|
flattenObject(value, parser, prefix + subkey, ret);
|
||||||
}
|
}
|
||||||
} else if (!parsed) {
|
} else if (!parsed) {
|
||||||
flattenObject(parser(obj), parser, key, ret, true);
|
try {
|
||||||
|
flattenObject(parser(obj as { toString: () => string }), parser, key, ret, true);
|
||||||
|
} catch (e) {
|
||||||
|
//emergency case, mostly for just type safety
|
||||||
|
ret.push([key, JSON.stringify(obj)]);
|
||||||
|
}
|
||||||
} else if (typeof obj === 'string') {
|
} else if (typeof obj === 'string') {
|
||||||
ret.push([key, obj]);
|
ret.push([key, obj]);
|
||||||
} else {
|
} else {
|
||||||
@ -231,7 +247,8 @@ export function flattenObject(
|
|||||||
|
|
||||||
export function flattenObjectEntries(
|
export function flattenObjectEntries(
|
||||||
entries: [string, unknown][],
|
entries: [string, unknown][],
|
||||||
parser: (to_parse: unknown) => string | Record<string, unknown> = (id) => id.toString()
|
parser: (to_parse: { toString: () => string }) => string | Record<string, unknown> = (id) =>
|
||||||
|
id.toString()
|
||||||
): [string, string][] {
|
): [string, string][] {
|
||||||
return flattenObject(Object.fromEntries(entries), parser);
|
return flattenObject(Object.fromEntries(entries), parser);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user