Merge pull request 'Problem: nieznany cel. Dodanie narzędzi diagnostycznych' (#99) from unknown-purpose into develop
Reviewed-on: #99
This commit is contained in:
		
						commit
						1106e86b41
					
				@ -5,6 +5,7 @@ import { Problem } from './problems/problem';
 | 
			
		||||
import { TransferOutsideEU } from './problems/transfer-outside-eu';
 | 
			
		||||
import { UnknownIdentity } from './problems/unknown-identity';
 | 
			
		||||
import { UnknownLegalBasis } from './problems/unknown-legal-basis';
 | 
			
		||||
import { UnknownPurposes } from './problems/unknown-purpose';
 | 
			
		||||
import { UnlawfulCookieAccess } from './problems/unlawful-cookies';
 | 
			
		||||
 | 
			
		||||
export default function deduceProblems(
 | 
			
		||||
@ -13,6 +14,7 @@ export default function deduceProblems(
 | 
			
		||||
): Problem[] {
 | 
			
		||||
    return [
 | 
			
		||||
        NoInformationAtAllProblem,
 | 
			
		||||
        UnknownPurposes,
 | 
			
		||||
        UnlawfulCookieAccess,
 | 
			
		||||
        UnknownLegalBasis,
 | 
			
		||||
        UnknownIdentity,
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@ import './email-content.scss';
 | 
			
		||||
import { Fragment, useState } from 'react';
 | 
			
		||||
import emailIntro from './email-intro';
 | 
			
		||||
import { reportIntro } from './report-intro';
 | 
			
		||||
import { downloadText } from '../../util';
 | 
			
		||||
import { getFakeClusterData } from './fake-clusters';
 | 
			
		||||
 | 
			
		||||
const SS_URL = 'http://65.108.60.135:3000';
 | 
			
		||||
 | 
			
		||||
@ -136,6 +138,23 @@ export default function EmailContent({
 | 
			
		||||
                        </p>
 | 
			
		||||
                    </section>
 | 
			
		||||
                ) : null}
 | 
			
		||||
                <div className="diag-toolbox">
 | 
			
		||||
                    <a
 | 
			
		||||
                        href="#"
 | 
			
		||||
                        onClick={() =>
 | 
			
		||||
                            downloadText(
 | 
			
		||||
                                'diag.json',
 | 
			
		||||
                                JSON.stringify({
 | 
			
		||||
                                    answers,
 | 
			
		||||
                                    fake_clusters_data: getFakeClusterData(clusters),
 | 
			
		||||
                                    visited_url,
 | 
			
		||||
                                })
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    >
 | 
			
		||||
                        Pobierz plik diagnostyczny
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </Fragment>
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										56
									
								
								components/report-window/fake-clusters.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								components/report-window/fake-clusters.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
			
		||||
// good for diagnostic purposes
 | 
			
		||||
 | 
			
		||||
import { RequestCluster } from '../../request-cluster';
 | 
			
		||||
import { DataLocation } from '../../stolen-data-entry';
 | 
			
		||||
 | 
			
		||||
export type FakeRequestClusterData = {
 | 
			
		||||
    id: string;
 | 
			
		||||
    hasCookies: boolean;
 | 
			
		||||
    hasMarkedCookies: boolean;
 | 
			
		||||
    hasMarks: boolean;
 | 
			
		||||
    exposesOriginWhere: DataLocation[];
 | 
			
		||||
    exposesOrigin: boolean;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function getFakeClusterData(
 | 
			
		||||
    clusters: Record<string, RequestCluster>
 | 
			
		||||
): Record<string, FakeRequestClusterData> {
 | 
			
		||||
    return Object.fromEntries(
 | 
			
		||||
        Object.entries(clusters).map(([key, cluster]) => [key, cluster.makeDataForFake()])
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function makeFakeClusters(
 | 
			
		||||
    fake_clusters_data: Record<string, FakeRequestClusterData>
 | 
			
		||||
): Record<string, FakeCluster> {
 | 
			
		||||
    return Object.fromEntries(
 | 
			
		||||
        Object.entries(fake_clusters_data).map(([key, cluster_data]) => [
 | 
			
		||||
            key,
 | 
			
		||||
            new FakeCluster(cluster_data),
 | 
			
		||||
        ])
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class FakeCluster extends RequestCluster {
 | 
			
		||||
    constructor(public data: FakeRequestClusterData) {
 | 
			
		||||
        super(data.id);
 | 
			
		||||
 | 
			
		||||
        for (const key of [
 | 
			
		||||
            'hasCookies',
 | 
			
		||||
            'hasMarkedCookies',
 | 
			
		||||
            'hasMarks',
 | 
			
		||||
            'exposesOriginWhere',
 | 
			
		||||
            'exposesOrigin',
 | 
			
		||||
        ]) {
 | 
			
		||||
            //@ts-ignore
 | 
			
		||||
            this[key] = () => {
 | 
			
		||||
                //@ts-ignore
 | 
			
		||||
                return this.data[key];
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    hasCookies() {
 | 
			
		||||
        return this.data.hasCookies;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								components/report-window/problems/unknown-purpose.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								components/report-window/problems/unknown-purpose.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,109 @@
 | 
			
		||||
import { RequestCluster } from '../../../request-cluster';
 | 
			
		||||
import { dataLocationToText, wordlist } from '../../../util';
 | 
			
		||||
import { ExplainerKey } from '../explainers';
 | 
			
		||||
import { v } from '../verbs';
 | 
			
		||||
import { Problem } from './problem';
 | 
			
		||||
 | 
			
		||||
export class UnknownPurposes extends Problem {
 | 
			
		||||
    getNecessaryExplainers(): ExplainerKey[] {
 | 
			
		||||
        return [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    isHostAffected(host: string) {
 | 
			
		||||
        const answers = this.answers.hosts[host];
 | 
			
		||||
        if (!answers) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return (
 | 
			
		||||
            ['not_mentioned', 'not_before_making_a_choice'].includes(answers.present) &&
 | 
			
		||||
            ['no', 'not_sure'].includes(answers.was_processing_necessary) &&
 | 
			
		||||
            (this.clusters[host].hasCookies() || this.clusters[host].exposesOrigin())
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qualifies(): boolean {
 | 
			
		||||
        return Object.keys(this.answers.hosts).some((host) => this.isHostAffected(host));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getAffectedClusters(): RequestCluster[] {
 | 
			
		||||
        return Object.keys(this.answers.hosts)
 | 
			
		||||
            .filter((host) => this.isHostAffected(host))
 | 
			
		||||
            .map((host) => this.clusters[host]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getEmailContent({ mode, tone }: { mode: 'email' | 'report'; tone: 'official' | 'polite' }) {
 | 
			
		||||
        const _ = (key: string) => v(key, this.answers.zaimek);
 | 
			
		||||
        const affected_clusters = this.getAffectedClusters();
 | 
			
		||||
        const has_history = affected_clusters.some((cluster) => cluster.exposesOrigin());
 | 
			
		||||
        const has_cookies = affected_clusters.some((cluster) => cluster.hasCookies());
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
            <>
 | 
			
		||||
                <h2>Cele przetwarzania danych</h2>
 | 
			
		||||
                <p>
 | 
			
		||||
                    Państwa strona{' '}
 | 
			
		||||
                    {mode == 'email'
 | 
			
		||||
                        ? `ujawniła dane ${_('mnie')} dotyczące`
 | 
			
		||||
                        : 'ujawnia dane dotyczące użytkowników'}{' '}
 | 
			
		||||
                    w zakresie{' '}
 | 
			
		||||
                    {wordlist([
 | 
			
		||||
                        ...(has_cookies ? ['treści plików cookies'] : []),
 | 
			
		||||
                        ...(has_history
 | 
			
		||||
                            ? [
 | 
			
		||||
                                  mode === 'email'
 | 
			
		||||
                                      ? `części ${_('mojej')} historii przeglądania`
 | 
			
		||||
                                      : `części historii przeglądania`,
 | 
			
		||||
                              ]
 | 
			
		||||
                            : []),
 | 
			
		||||
                    ])}{' '}
 | 
			
		||||
                    podmiotom, które są właścicielami nastepujących domen:
 | 
			
		||||
                </p>
 | 
			
		||||
                <ul>
 | 
			
		||||
                    {affected_clusters.map((cluster, index) => {
 | 
			
		||||
                        const locations = cluster.exposesOriginWhere();
 | 
			
		||||
                        return (
 | 
			
		||||
                            <li>
 | 
			
		||||
                                <strong>{cluster.id}</strong>:{' '}
 | 
			
		||||
                                {wordlist([
 | 
			
		||||
                                    ...(cluster.hasCookies() ? ['treść plików cookies'] : []),
 | 
			
		||||
                                    ...(cluster.exposesOrigin()
 | 
			
		||||
                                        ? [
 | 
			
		||||
                                              (mode === 'email'
 | 
			
		||||
                                                  ? `część ${_('mojej')} historii przeglądania`
 | 
			
		||||
                                                  : `część historii przeglądania użytkownika`) +
 | 
			
		||||
                                                  ' (' +
 | 
			
		||||
                                                  wordlist(
 | 
			
		||||
                                                      locations.map((l) => dataLocationToText(l))
 | 
			
		||||
                                                  ) +
 | 
			
		||||
                                                  ')',
 | 
			
		||||
                                          ]
 | 
			
		||||
                                        : []),
 | 
			
		||||
                                ])}
 | 
			
		||||
                                {index === affected_clusters.length - 1 ? '.' : ';'}
 | 
			
		||||
                            </li>
 | 
			
		||||
                        );
 | 
			
		||||
                    })}
 | 
			
		||||
                </ul>
 | 
			
		||||
                {mode === 'email' ? (
 | 
			
		||||
                    tone === 'official' ? (
 | 
			
		||||
                        <p>
 | 
			
		||||
                            Proszę o wskazanie, jakie są cele takiego przetwarzania danych, które
 | 
			
		||||
                            mnie dotyczą.
 | 
			
		||||
                        </p>
 | 
			
		||||
                    ) : (
 | 
			
		||||
                        <p>
 | 
			
		||||
                            Apeluję o umieszczenie informacji na temat na Państwa stronie, aby jej
 | 
			
		||||
                            użytkownicy mogli podejmować w pełni świadome wybory dotyczące
 | 
			
		||||
                            przetwarzania danych ich dotyczących.
 | 
			
		||||
                        </p>
 | 
			
		||||
                    )
 | 
			
		||||
                ) : (
 | 
			
		||||
                    <p>
 | 
			
		||||
                        <strong>Zalecenie</strong>: warto dodać informacje o tym, jakie są cele
 | 
			
		||||
                        ujawniania wyżej opisanych danych wyżej opisanym podmiotom trzecim.
 | 
			
		||||
                    </p>
 | 
			
		||||
                )}
 | 
			
		||||
            </>
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -5,6 +5,17 @@
 | 
			
		||||
    font-family: 'OpenSans' !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#app {
 | 
			
		||||
    min-height: 100vh;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-flow: column;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#main-section {
 | 
			
		||||
    flex-grow: 1;
 | 
			
		||||
    margin-bottom: 20px; // to contain diag section
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
html {
 | 
			
		||||
    font-size: 1rem;
 | 
			
		||||
}
 | 
			
		||||
@ -289,3 +300,9 @@ h1 {
 | 
			
		||||
        color: $ultra-black-color;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.diag-toolbox {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    bottom: 10px;
 | 
			
		||||
    left: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -110,7 +110,7 @@ function Report() {
 | 
			
		||||
                        )}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </header>
 | 
			
		||||
                <section>{result}</section>
 | 
			
		||||
                <section id="main-section">{result}</section>
 | 
			
		||||
            </Fragment>
 | 
			
		||||
        );
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
 | 
			
		||||
@ -104,13 +104,11 @@ export default function StolenDataCluster({
 | 
			
		||||
    shorthost,
 | 
			
		||||
    minValueLength,
 | 
			
		||||
    cookiesOnly,
 | 
			
		||||
    refreshToken,
 | 
			
		||||
    cookiesOrOriginOnly,
 | 
			
		||||
    detailsVisibility,
 | 
			
		||||
}: {
 | 
			
		||||
    origin: string;
 | 
			
		||||
    shorthost: string;
 | 
			
		||||
    refreshToken: number;
 | 
			
		||||
    minValueLength: number;
 | 
			
		||||
    cookiesOnly: boolean;
 | 
			
		||||
    cookiesOrOriginOnly: boolean;
 | 
			
		||||
@ -130,6 +128,10 @@ export default function StolenDataCluster({
 | 
			
		||||
                        data-version={version}
 | 
			
		||||
                        checked={cluster.hasMarks()}
 | 
			
		||||
                        onChange={() => {
 | 
			
		||||
                            console.log('Clicked checkbox!', {
 | 
			
		||||
                                cluster_id: cluster.id,
 | 
			
		||||
                                has_marks: cluster.hasMarks(),
 | 
			
		||||
                            });
 | 
			
		||||
                            cluster.hasMarks() ? cluster.undoMark() : cluster.autoMark();
 | 
			
		||||
                            getMemory().emit('change', cluster.id);
 | 
			
		||||
                        }}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								diag.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								diag.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <title>RENTGEN DIAG</title>
 | 
			
		||||
    </head>
 | 
			
		||||
    <body>
 | 
			
		||||
        <div id="app"></div>
 | 
			
		||||
    </body>
 | 
			
		||||
    <script src="/node_modules/react/umd/react.production.min.js"></script>
 | 
			
		||||
    <script src="/node_modules/react-dom/umd/react-dom.production.min.js"></script>
 | 
			
		||||
    <script src="/node_modules/survey-react/survey.react.min.js"></script>
 | 
			
		||||
    <script src="./lib/diag.js"></script>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										65
									
								
								diag.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								diag.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
			
		||||
import React, { Fragment } from 'react';
 | 
			
		||||
import ReactDOM from 'react-dom';
 | 
			
		||||
import EmailContent from './components/report-window/email-content';
 | 
			
		||||
 | 
			
		||||
import { makeFakeClusters } from './components/report-window/fake-clusters';
 | 
			
		||||
 | 
			
		||||
class ErrorBoundary extends React.Component<any, { hasError: boolean; error: any }> {
 | 
			
		||||
    constructor(props: any) {
 | 
			
		||||
        super(props);
 | 
			
		||||
        this.state = { hasError: false, error: null };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static getDerivedStateFromError(error: any) {
 | 
			
		||||
        return { hasError: true, error };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render() {
 | 
			
		||||
        if (this.state.hasError) {
 | 
			
		||||
            return <h1>Something went wrong.</h1>;
 | 
			
		||||
        }
 | 
			
		||||
        return this.props.children;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function Diag() {
 | 
			
		||||
    const [json, setjson] = React.useState(
 | 
			
		||||
        JSON.stringify({ answers: { hosts: {} }, visited_url: '', fake_clusters_data: {} })
 | 
			
		||||
    );
 | 
			
		||||
    const { answers, visited_url, fake_clusters_data } = JSON.parse(json);
 | 
			
		||||
    const fake_clusters = makeFakeClusters(fake_clusters_data);
 | 
			
		||||
    return (
 | 
			
		||||
        <div style={{ display: 'grid', gridTemplateColumns: '50% 50%', minHeight: '100vh' }}>
 | 
			
		||||
            <div>
 | 
			
		||||
                <textarea
 | 
			
		||||
                    style={{ width: 'calc(100% - 50px)', height: '100%' }}
 | 
			
		||||
                    value={json}
 | 
			
		||||
                    onChange={(e) => {
 | 
			
		||||
                        setjson(e.target.value);
 | 
			
		||||
                    }}
 | 
			
		||||
                ></textarea>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div>
 | 
			
		||||
                <EmailContent
 | 
			
		||||
                    {...{
 | 
			
		||||
                        answers,
 | 
			
		||||
                        visited_url,
 | 
			
		||||
                        clusters: fake_clusters,
 | 
			
		||||
                        scrRequestPath: '/screenshots',
 | 
			
		||||
                        downloadFiles: () => {
 | 
			
		||||
                            alert('download!');
 | 
			
		||||
                        },
 | 
			
		||||
                        user_role: 'user',
 | 
			
		||||
                    }}
 | 
			
		||||
                />
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ReactDOM.render(
 | 
			
		||||
    <ErrorBoundary>
 | 
			
		||||
        <Diag />
 | 
			
		||||
    </ErrorBoundary>,
 | 
			
		||||
    document.getElementById('app')
 | 
			
		||||
);
 | 
			
		||||
@ -48,6 +48,7 @@ esbuild
 | 
			
		||||
            'components/sidebar/sidebar.tsx',
 | 
			
		||||
            'components/report-window/report-window.tsx',
 | 
			
		||||
            'background.ts',
 | 
			
		||||
            'diag.tsx',
 | 
			
		||||
            'styles/global.scss',
 | 
			
		||||
            'styles/fonts.scss',
 | 
			
		||||
        ],
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
import { StolenDataEntry } from './stolen-data-entry';
 | 
			
		||||
import { DataLocation, StolenDataEntry } from './stolen-data-entry';
 | 
			
		||||
import {
 | 
			
		||||
    flattenObjectEntries,
 | 
			
		||||
    getshorthost,
 | 
			
		||||
@ -164,12 +164,12 @@ export default class ExtendedRequest {
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exposesOrigin() {
 | 
			
		||||
    exposesOriginWhere(): null | DataLocation {
 | 
			
		||||
        const host = this.originalHost;
 | 
			
		||||
        const path = this.originalPathname || '/';
 | 
			
		||||
        const shorthost = getshorthost(host);
 | 
			
		||||
        if (this.getReferer().includes(shorthost)) {
 | 
			
		||||
            return true;
 | 
			
		||||
            return { path: this.url, source: 'header', key: 'Referer' };
 | 
			
		||||
        }
 | 
			
		||||
        for (const entry of this.stolenData) {
 | 
			
		||||
            if (
 | 
			
		||||
@ -177,10 +177,14 @@ export default class ExtendedRequest {
 | 
			
		||||
                entry.value.includes(path) ||
 | 
			
		||||
                entry.value.includes(shorthost)
 | 
			
		||||
            ) {
 | 
			
		||||
                return true;
 | 
			
		||||
                return entry.toDataLocation();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exposesOrigin() {
 | 
			
		||||
        return this.exposesOriginWhere() !== null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private getAllStolenData(): StolenDataEntry[] {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
import { FakeRequestClusterData } from './components/report-window/fake-clusters';
 | 
			
		||||
import ExtendedRequest from './extended-request';
 | 
			
		||||
import { SaferEmitter } from './safer-emitter';
 | 
			
		||||
import { Sources, StolenDataEntry } from './stolen-data-entry';
 | 
			
		||||
import { DataLocation, Sources, StolenDataEntry } from './stolen-data-entry';
 | 
			
		||||
 | 
			
		||||
import { allSubhosts, isSameURL, reduceConcat, unique } from './util';
 | 
			
		||||
 | 
			
		||||
@ -171,7 +172,13 @@ export class RequestCluster extends SaferEmitter {
 | 
			
		||||
        return this.requests.map((request) => request.getMarkedEntries()).reduce(reduceConcat, []);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exposesOrigin() {
 | 
			
		||||
    exposesOriginWhere(): DataLocation[] {
 | 
			
		||||
        return this.requests
 | 
			
		||||
            .map((request) => request.exposesOriginWhere())
 | 
			
		||||
            .filter((l) => l !== null) as DataLocation[];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    exposesOrigin(): boolean {
 | 
			
		||||
        return this.requests.some((request) => request.exposesOrigin());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -203,4 +210,15 @@ export class RequestCluster extends SaferEmitter {
 | 
			
		||||
        }
 | 
			
		||||
        return types_of_data.join(', ');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    makeDataForFake(): FakeRequestClusterData {
 | 
			
		||||
        return {
 | 
			
		||||
            id: this.id,
 | 
			
		||||
            hasCookies: this.hasCookies(),
 | 
			
		||||
            hasMarkedCookies: this.hasMarkedCookies(),
 | 
			
		||||
            hasMarks: this.hasMarks(),
 | 
			
		||||
            exposesOriginWhere: this.exposesOriginWhere(),
 | 
			
		||||
            exposesOrigin: this.exposesOrigin(),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,12 @@ const id = (function* id() {
 | 
			
		||||
 | 
			
		||||
export type DecodingSchema = 'base64' | 'raw';
 | 
			
		||||
 | 
			
		||||
export type DataLocation = {
 | 
			
		||||
    path: string;
 | 
			
		||||
    source: Sources;
 | 
			
		||||
    key: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export class StolenDataEntry extends SaferEmitter {
 | 
			
		||||
    public isIAB = false;
 | 
			
		||||
    public id: number;
 | 
			
		||||
@ -253,4 +259,12 @@ export class StolenDataEntry extends SaferEmitter {
 | 
			
		||||
            haystack.includes(getshorthost(this.request.origin))
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    toDataLocation(): DataLocation {
 | 
			
		||||
        return {
 | 
			
		||||
            path: this.request.url,
 | 
			
		||||
            source: this.source,
 | 
			
		||||
            key: this.name,
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										34
									
								
								util.ts
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								util.ts
									
									
									
									
									
								
							@ -1,5 +1,6 @@
 | 
			
		||||
import { EventEmitter } from 'events';
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { DataLocation, Sources } from './stolen-data-entry';
 | 
			
		||||
 | 
			
		||||
export type Unpromisify<T> = T extends Promise<infer R> ? R : T;
 | 
			
		||||
export type Unarray<T> = T extends Array<infer R> ? R : T;
 | 
			
		||||
@ -283,8 +284,37 @@ export function normalizeForClassname(string: string) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function wordlist(words: string[]) {
 | 
			
		||||
    return words.reduce(
 | 
			
		||||
        (acc, word, i) => `${acc}${i > 0 ? (i < words.length - 1 ? ',' : ' i') : ''} ${word}`,
 | 
			
		||||
    return Array.from(new Set(words)).reduce(
 | 
			
		||||
        (acc, word, i) =>
 | 
			
		||||
            `${acc}${
 | 
			
		||||
                i > 0 ? (i < words.length - 1 ? ', ' : Math.random() > 0.5 ? ' i ' : ' oraz ') : ''
 | 
			
		||||
            }${word}`,
 | 
			
		||||
        ''
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const source_to_word: Record<Sources, string> = {
 | 
			
		||||
    cookie: 'plik cookie o nazwie',
 | 
			
		||||
    pathname: 'fragment ścieżki w URL',
 | 
			
		||||
    queryparams: 'query params w URL o nazwie',
 | 
			
		||||
    header: 'nagłówek HTTP',
 | 
			
		||||
    request_body: 'body zapytania HTTP, pod kluczem',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function dataLocationToText(l: DataLocation) {
 | 
			
		||||
    return `${source_to_word[l.source]} ${l.key}`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function downloadText(filename: string, text: string) {
 | 
			
		||||
    // https://stackoverflow.com/questions/45831191/generate-and-download-file-from-js
 | 
			
		||||
    var element = document.createElement('a');
 | 
			
		||||
    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
 | 
			
		||||
    element.setAttribute('download', filename);
 | 
			
		||||
 | 
			
		||||
    element.style.display = 'none';
 | 
			
		||||
    document.body.appendChild(element);
 | 
			
		||||
 | 
			
		||||
    element.click();
 | 
			
		||||
 | 
			
		||||
    document.body.removeChild(element);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user