Generating screenshots

This commit is contained in:
Arkadiusz Wieczorek 2022-05-22 16:49:24 +02:00
parent 24da4a34dd
commit 7a2122089e
6 changed files with 201 additions and 81 deletions

View File

@ -15,7 +15,7 @@
}
&__content {
height: 75vh;
height: 70vh;
overflow-y: scroll;
padding: 1rem 2rem;
color: $black-color;

View File

@ -5,6 +5,7 @@ import { Explainers } from './explainers';
import { ParsedAnswers } from './parse-answers';
import { v } from './verbs';
import './email-content.scss';
import { Fragment } from 'react';
declare var PLUGIN_NAME: string;
declare var PLUGIN_URL: string;
@ -28,40 +29,48 @@ export default function EmailContent({
)
).map((explainer_key) => Explainers[explainer_key]);
return (
<div className="mail-container">
<div className="mail-container__header">
<div className="mail-container__header--control">
<button>Kopiuj</button>
<Fragment>
<h1>Treść maila</h1>
<p>
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Iure dolore, pariatur ab
eius expedita maxime alias esse quis possimus rem aliquid dicta laudantium rerum
libero enim cumque. Aperiam, enim aliquid.
</p>
<div className="mail-container">
<div className="mail-container__header">
<div className="mail-container__header--control">
<button>Kopiuj</button>
</div>
</div>
</div>
{/* <pre>{JSON.stringify(answers, null, 3)}</pre> */}
<article className="mail-container__content">
<p>Dzień dobry,</p>
<p>
w dniu {getDate()} {_('odwiedziłem')} stronę {visited_url}. Po podejrzeniu ruchu
sieciowego generowanego przez stronę za pomocą wtyczki{' '}
<a href={PLUGIN_URL}>{PLUGIN_NAME}</a> w przeglądarce Firefox {_('mam')} pytania
dotyczące przetwarzania {_('moich')} danych osobowych, na które nie{' '}
{_('znalazłem')} odpowiedzi nigdzie na Państwa stronie.
</p>
{problems.map((problem) => problem.getEmailContent())}
{explainers.map((explainer) => explainer(answers.zaimek))}
<h2>Państwa rola jako współadministratora danych osobowych</h2>
<p>
{_('Zwracam')} Państwa uwagę na fakt, że w myśl{' '}
<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">
treści wyroku TSUE w sprawie C-40/17
</a>{' '}
poprzez wysyłanie moich danych w wyżej opisanym zakresie stają się Państwo
współadministratorem moich danych osobowych, dlatego ciąży na Państwu obowiązek
odpowiedzi na moje pytania na mocy Art. 12 i 13 Rozporządzenia 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, dalej: RODO).
</p>
</article>
</div>
{/* <pre>{JSON.stringify(answers, null, 3)}</pre> */}
<article className="mail-container__content">
<p>Dzień dobry,</p>
<p>
w dniu {getDate()} {_('odwiedziłem')} stronę {visited_url}. Po podejrzeniu
ruchu sieciowego generowanego przez stronę za pomocą wtyczki{' '}
<a href={PLUGIN_URL}>{PLUGIN_NAME}</a> w przeglądarce Firefox {_('mam')}{' '}
pytania dotyczące przetwarzania {_('moich')} danych osobowych, na które nie{' '}
{_('znalazłem')} odpowiedzi nigdzie na Państwa stronie.
</p>
{problems.map((problem) => problem.getEmailContent())}
{explainers.map((explainer) => explainer(answers.zaimek))}
<h2>Państwa rola jako współadministratora danych osobowych</h2>
<p>
{_('Zwracam')} Państwa uwagę na fakt, że w myśl{' '}
<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">
treści wyroku TSUE w sprawie C-40/17
</a>{' '}
poprzez wysyłanie moich danych w wyżej opisanym zakresie stają się Państwo
współadministratorem moich danych osobowych, dlatego ciąży na Państwu
obowiązek odpowiedzi na moje pytania na mocy Art. 12 i 13 Rozporządzenia
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, dalej: RODO).
</p>
</article>
</div>
</Fragment>
);
}

View File

@ -1,6 +1,7 @@
@import './../../styles/colors.scss';
* {
box-sizing: border-box;
font-family: 'OpenSans' !important;
}
@ -44,10 +45,8 @@ h3 {
align-items: center;
max-height: 3.5rem;
min-height: 3.5rem;
// border-bottom: 1px solid $light-grey;
position: sticky;
top: 0;
// background: #ffffff;
z-index: 1;
.webpage-metadata {
@ -75,7 +74,6 @@ h3 {
background-color: transparent;
.sv_p_root {
& > .sv_row:nth-child(2n) {
// background-color: hsl(217.5, 7.8%, 96%);
background-color: #fff;
}
@ -84,7 +82,6 @@ h3 {
}
& > .sv_row {
// border-bottom: 1px solid #d1d1d1;
border-bottom: none;
background-color: #fff;
box-shadow: rgba(12, 12, 13, 0.1) 0px 1px 4px 0px;

View File

@ -19,21 +19,6 @@ function Report() {
);
const [mode, setMode] = React.useState(url.searchParams.get('mode') || 'survey');
const clusters = getMemory().getClustersForOrigin(origin);
/* const [entries, setEntries] = React.useState<StolenDataEntry[]>([]); */
/* React.useEffect(() => {
* setEntries(
* Object.values(clusters)
* .map((cluster) => {
* cluster.calculateRepresentativeStolenData();
* return cluster.representativeStolenData;
* })
* .reduce(reduceConcat, [])
* .filter((entry) => entry.isMarked)
* );
* }, []); */
/* if (entries.length == 0) {
* return <>Wczytywanie...</>;
* } */
React.useEffect(() => {
const url = new URL(document.location.toString());
@ -62,7 +47,9 @@ function Report() {
''
)}
{mode === 'screenshots' ? (
<ScreenshotGenerator {...{ visited_url, clusters }} />
<ScreenshotGenerator
{...{ visited_url, clusters, setReportWindowMode: setMode }}
/>
) : (
''
)}

View File

@ -0,0 +1,66 @@
@import './../../styles/colors.scss';
.images {
display: flex;
grid-gap: 1rem;
flex-wrap: wrap;
margin: 2rem 0;
}
.browser {
height: 9.667rem;
width: 16rem;
font-weight: 800 !important;
// box-shadow: rgba(12, 12, 13, 0.1) 0px 1px 4px 0px;
color: $disabled-grey !important;
border: 1px solid $disabled-grey;
background-image: linear-gradient(to bottom, $icd-rentgen-color 20%, #fff 20%, #fff 100%);
animation: xray 2s cubic-bezier(0, 1.43, 0.39, 1.43) infinite;
&--filled {
background-size: contain;
background-position-y: 18px;
animation: none;
.browser__header {
background-color: #fff;
}
}
@keyframes xray {
to {
background-position-y: 11.1rem;
}
}
&__header {
height: 1.667rem;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 0.5rem;
font-size: 1.25rem;
border-bottom: 1px solid $disabled-grey;
&--address-bar {
border: 1px solid $disabled-grey;
height: 1rem;
width: 10rem;
font-size: 0.667rem;
font-weight: 400;
padding-left: 0.25rem;
color: #000;
}
&--controls {
padding-bottom: 0.25rem;
font-weight: 900;
}
}
&__content {
height: 7.667rem;
}
}

View File

@ -2,6 +2,21 @@ import React, { Fragment } from 'react';
import { RequestCluster } from '../../request-cluster';
import './screenshot-generator.scss';
enum taskState {
WAITING = 'waiting',
RUNNING = 'running',
FINISHED = 'finished',
}
interface screenshotTask {
url: string;
domains: string[];
id: string;
status: taskState;
output: string;
files: string[];
}
function createTaskEndpoint(visited_url: string, domains: string[]) {
return `http://65.108.60.135:3000/api/requests?url=${visited_url}${domains.reduce(
(prev: string, curr: string) => prev + '&domains[]=' + curr,
@ -13,39 +28,45 @@ function createTask(visited_url: string, domains: string[]) {
return fetch(createTaskEndpoint(visited_url, domains), { method: 'POST' });
}
async function subscribe(path: string) {
let request = await fetch(path, { method: 'GET' });
const response = await request.json();
if (response.status === 'running' || response.status === 'waiting') {
console.debug(response.status);
await new Promise((resolve) => setTimeout(resolve, 1000));
await subscribe(path);
} else if (response.status === 'finished') {
console.log('response', response);
return response;
}
function pollTask(path: string): Promise<Response> {
return fetch(path, { method: 'GET' });
}
export default function ScreenshotGenerator({
visited_url,
clusters,
setReportWindowMode,
}: {
visited_url: string;
clusters: Record<string, RequestCluster>;
setReportWindowMode: Function;
}) {
const [isLoading, setLoading] = React.useState<boolean>(false);
const [output, setOutput] = React.useState<string[]>([]);
const [mode, setMode] = React.useState<string>('idle');
const [images, setImages] = React.useState<string[]>([]);
const [taskId, setTaskId] = React.useState<string>(null);
async function subscribeTask(path: string): Promise<screenshotTask> {
let response = { status: taskState.WAITING };
while (response.status === taskState.WAITING || response.status === taskState.RUNNING) {
await new Promise((resolve) => setTimeout(resolve, 1000));
response = await (await pollTask(path)).json();
setImages((response as screenshotTask)?.files);
}
if (response.status === taskState.FINISHED) {
setMode('finished');
}
return response as screenshotTask;
}
return (
<div className="generator-container">
{!isLoading ? (
{mode === 'idle' ? (
<Fragment>
<h1>Przygotowanie zrzutów ekranów</h1>
<p>
Dla potwierdzenia przechwyconych danych, warto załączyć zrzuty ekranów
narzędzi deweloperskich do maila dla administratora oraz Urzędzu Ochrony
narzędzi deweloperskich do maila dla administratora oraz Urzędu Ochrony
Danych Osobowych.
</p>
<p>
@ -54,30 +75,70 @@ export default function ScreenshotGenerator({
Ciebie.
</p>
<button>Pomiń</button>
<button
className="sv_prev_btn"
onClick={() => {
setReportWindowMode('preview');
}}
>
Pomiń
</button>
<button
className="sv_next_btn"
onClick={async () => {
setLoading(true);
setMode('in_progress');
const task = await createTask(visited_url, Object.keys(clusters));
const response = await subscribe(task.url);
setOutput(response.files);
const urlArr = task.url.split('/');
setTaskId(urlArr[urlArr.length - 1]);
const response = await subscribeTask(task.url);
setImages(response.files);
console.log('output', response);
}}
>
Wygeneruj
</button>
</Fragment>
) : (
) : null}
{mode === 'in_progress' || mode === 'finished' ? (
<Fragment>
<h1>Przygotowujemy zrzuty ekranów</h1>
<pre>{createTaskEndpoint(visited_url, Object.keys(clusters))}</pre>
<div className="images">
{images.map((filename: string) => {
return (
<div
className="browser browser--filled"
style={{
backgroundImage: `url(http://65.108.60.135:3000/static/${taskId}/${filename})`,
}}
>
<div className="browser__header">
<div className="browser__header--address-bar">
{filename}
</div>
<div className="browser__header--controls">···</div>
</div>
<div className="browser__content"></div>
</div>
);
})}
{JSON.stringify(output)}
<button>In progress</button>
{mode === 'in_progress' ? (
<div className="browser">
<div className="browser__header">
<div className="browser__header--address-bar"></div>
<div className="browser__header--controls">···</div>
</div>
<div className="browser__content"></div>
</div>
) : null}
</div>
{mode === 'finished' ? (
<button className="sv_next_btn">Pobierz zrzuty ekranów</button>
) : null}
</Fragment>
)}
) : null}
</div>
);
}