Compare commits

..

No commits in common. "3eb5dc6f9de174d49913061083833ad699855ee4" and "a84a8f8c1031e4e7070d3fae5b615f5af1adae2a" have entirely different histories.

7 changed files with 63 additions and 172 deletions

View File

@ -8,7 +8,7 @@ export default class Memory extends EventEmitter {
private throttle = makeThrottle(200); private throttle = makeThrottle(200);
async register(request: ExtendedRequest) { async register(request: ExtendedRequest) {
await request.init(); await request.init();
// console.log("registering request for", request.origin); console.log("registering request for", request.origin);
if (!request.isThirdParty()) { if (!request.isThirdParty()) {
return; return;
} }

View File

@ -15,13 +15,6 @@ const emailSources: Record<Sources, string> = {
queryparams: "jako część adresu URL (query-params)", queryparams: "jako część adresu URL (query-params)",
}; };
const source_priority: Array<Sources> = [
"cookie",
"pathname",
"queryparams",
"header",
];
export default function DomainSummary({ export default function DomainSummary({
cluster, cluster,
}: { }: {
@ -34,37 +27,13 @@ export default function DomainSummary({
<li>Mój adres IP</li> <li>Mój adres IP</li>
{cluster {cluster
.getMarks() .getMarks()
.sort((markA, markB) => { .sort((markA, markB) =>
if (markA.entry.value > markB.entry.value) { markA.entry.value > markB.entry.value ? -1 : 1
return -1; )
} else if (markA.entry.value > markB.entry.value) {
return 1;
} else {
const indexA = source_priority.indexOf(markA.source);
const indexB = source_priority.indexOf(markB.source);
if (indexA < indexB) {
return -1;
} else if (indexA > indexB) {
return 1;
} else {
return markA.name > markB.name ? -1 : 1;
}
}
})
.filter((_, index, array) => {
if (index == 0) {
return true;
}
if (array[index].valuePreview === array[index - 1].valuePreview) {
return false;
} else {
return true;
}
})
.map((mark) => ( .map((mark) => (
<li> <li>
{emailClassifications[mark.classification]}{" "} {emailClassifications[mark.classification]}{" "}
{emailSources[mark.source]} (nazwa: <code>{mark.name}</code>,{" "} {emailSources[mark.source]} (nazwa: {mark.name},{" "}
{mark.key ? ( {mark.key ? (
<> <>
pozycja <code>{mark.key}</code>, pozycja <code>{mark.key}</code>,

View File

@ -59,7 +59,7 @@ function Report() {
> >
{mark.valuePreview} {mark.valuePreview}
{/* always gonna have {/* always gonna have
one key, because unwrapEntry is called above */} one key, because unwrapEntry is calle above */}
</td> </td>
<td> <td>
<select <select
@ -67,6 +67,7 @@ function Report() {
onChange={(e) => { onChange={(e) => {
mark.classification = e.target mark.classification = e.target
.value as keyof typeof Classifications; .value as keyof typeof Classifications;
console.log("changed classification!");
refresh(); refresh();
}} }}
> >

View File

@ -17,9 +17,7 @@ const Sidebar = () => {
const [origin, setOrigin] = useState<string | null>(null); const [origin, setOrigin] = useState<string | null>(null);
const [minValueLength, setMinValueLength] = useState<number | null>(7); const [minValueLength, setMinValueLength] = useState<number | null>(7);
const [cookiesOnly, setCookiesOnly] = useState<boolean>(false); const [cookiesOnly, setCookiesOnly] = useState<boolean>(false);
const [cookiesOrOriginOnly, setCookiesOrOriginOnly] = useState<boolean>( const [cookiesOrOriginOnly, setCookiesOrOriginOnly] = useState<boolean>(true);
false
);
const [counter, setCounter] = useEmitter(getMemory()); const [counter, setCounter] = useEmitter(getMemory());
useEffect(() => { useEffect(() => {

View File

@ -1,15 +1,8 @@
import React from "react"; import React from "react";
import { getMemory } from "../memory"; import { getMemory } from "../memory";
import { RequestCluster } from "../request-cluster"; import { MergedStolenDataEntry, Sources } from "../stolen-data-entry";
import {
MergedStolenDataEntry,
Sources,
StolenDataEntry,
} from "../stolen-data-entry";
import { hyphenate, useEmitter } from "../util"; import { hyphenate } from "../util";
const MAX_STRING_VALUE_LENGTH = 100;
function StolenDataValueTable({ function StolenDataValueTable({
entry, entry,
@ -21,29 +14,24 @@ function StolenDataValueTable({
return ( return (
<table> <table>
<tbody> <tbody>
{Object.keys(entry.getParsedValues(prefixKey)[0]).map((key) => { {Object.keys(entry.getParsedValues(prefixKey)[0]).map((key) => (
const subkey = `${prefixKey}.${key}`;
return (
<tr key={`${prefixKey}.${key}`}> <tr key={`${prefixKey}.${key}`}>
<th <th
onClick={(e) => { onClick={(e) => {
entry.toggleMark(subkey); entry.toggleMark(prefixKey);
e.stopPropagation(); e.stopPropagation();
}} }}
style={{
border: entry.hasMark(subkey)
? "2px solid red"
: "2px solid transparent",
}}
> >
{hyphenate(key)} {hyphenate(key)}
</th> </th>
<td> <td>
<StolenDataValue entry={entry} prefixKey={subkey} /> <StolenDataValue
entry={entry}
prefixKey={`${prefixKey}.${key}`}
/>
</td> </td>
</tr> </tr>
); ))}
})}
</tbody> </tbody>
</table> </table>
); );
@ -56,24 +44,14 @@ function StolenDataValue({
entry: MergedStolenDataEntry; entry: MergedStolenDataEntry;
prefixKey?: string; prefixKey?: string;
}) { }) {
const [version] = useEmitter(entry);
const value = entry.getParsedValues(prefixKey)[0]; const value = entry.getParsedValues(prefixKey)[0];
let body = null; let body = null;
if (!value) { if (!value) {
body = <></>; body = <></>;
} else if (typeof value === "string") { } else if (typeof value === "string") {
const content = entry.getParsedValues(prefixKey)[0] as string;
body = ( body = (
<div <div style={{ border: entry.hasMark(prefixKey) ? "2px solid red" : "" }}>
style={{ {entry.getParsedValues(prefixKey)[0] as string}
border: entry.hasMark(prefixKey)
? "2px solid red"
: "2px solid transparent",
}}
data-version={version}
>
{content.slice(0, MAX_STRING_VALUE_LENGTH)}{" "}
{content.length > MAX_STRING_VALUE_LENGTH ? "(...)" : ""}
</div> </div>
); );
} else { } else {
@ -92,45 +70,6 @@ function StolenDataValue({
); );
} }
const icons: Record<Sources, string> = {
cookie: "🍪",
pathname: "🛣",
queryparams: "🅿",
header: "H",
};
function StolenDataRow({
entry,
cluster,
}: {
entry: MergedStolenDataEntry;
cluster: RequestCluster;
}) {
const [version] = useEmitter(entry);
return (
<tr
key={origin + cluster.id + entry.getUniqueKey()}
data-key={origin + cluster.id + entry.getUniqueKey()}
data-version={version}
>
<th
style={{
width: "100px",
overflowWrap: "anywhere",
border: entry.hasMark("") ? "2px solid red" : "2px solid transparent",
}}
onClick={() => entry.toggleMark("")}
>
{entry.getNames().map(hyphenate).join(", ")}
</th>
<td>{entry.getSources().map((source) => icons[source])}</td>
<td style={{ wordWrap: "anywhere" as any }}>
<StolenDataValue entry={entry} />
</td>
</tr>
);
}
export default function StolenDataCluster({ export default function StolenDataCluster({
origin, origin,
shorthost, shorthost,
@ -146,6 +85,12 @@ export default function StolenDataCluster({
cookiesOrOriginOnly: boolean; cookiesOrOriginOnly: boolean;
}) { }) {
const cluster = getMemory().getClustersForOrigin(origin)[shorthost]; const cluster = getMemory().getClustersForOrigin(origin)[shorthost];
const icons: Record<Sources, string> = {
cookie: "🍪",
pathname: "🛣",
queryparams: "🅿",
header: "H",
};
return ( return (
<div> <div>
<h2> <h2>
@ -169,13 +114,25 @@ export default function StolenDataCluster({
{cluster {cluster
.getStolenData({ minValueLength, cookiesOnly, cookiesOrOriginOnly }) .getStolenData({ minValueLength, cookiesOnly, cookiesOrOriginOnly })
.map((entry) => ( .map((entry) => (
<StolenDataRow <tr
{...{ key={origin + cluster.id + entry.getUniqueKey()}
entry, data-key={origin + cluster.id + entry.getUniqueKey()}
cluster, >
key: origin + cluster.id + entry.getUniqueKey(), <th
style={{
width: "100px",
overflowWrap: "anywhere",
border: entry.hasMark("") ? "2px solid red" : "",
}} }}
/> onClick={() => entry.addMark("")}
>
{entry.getNames().map(hyphenate).join(", ")}
</th>
<td>{entry.getSources().map((source) => icons[source])}</td>
<td style={{ wordWrap: "anywhere" as any }}>
<StolenDataValue entry={entry} />
</td>
</tr>
))} ))}
</tbody> </tbody>
</table> </table>

View File

@ -1,7 +1,7 @@
import { TCModel } from "@iabtcf/core"; import { TCModel } from "@iabtcf/core";
import { EventEmitter } from "events";
import ExtendedRequest, { HAREntry } from "./extended-request"; import ExtendedRequest, { HAREntry } from "./extended-request";
import Mark from "./mark"; import Mark from "./mark";
import { getMemory } from "./memory";
import { import {
getshorthost, getshorthost,
isJSONObject, isJSONObject,
@ -29,7 +29,7 @@ const id = (function* id() {
} }
})(); })();
export class StolenDataEntry extends EventEmitter { export class StolenDataEntry {
public isIAB = false; public isIAB = false;
public iab: TCModel | null = null; public iab: TCModel | null = null;
public id: number; public id: number;
@ -47,7 +47,6 @@ export class StolenDataEntry extends EventEmitter {
// // console.log(this.iab); // // console.log(this.iab);
// this.isIAB = true; // this.isIAB = true;
// } catch (e) {} // } catch (e) {}
super();
this.id = id.next().value as number; this.id = id.next().value as number;
this.classification = this.classify(); this.classification = this.classify();
} }
@ -82,26 +81,8 @@ export class StolenDataEntry extends EventEmitter {
return object; return object;
} else if (isURL(value)) { } else if (isURL(value)) {
const url = new URL(value); const url = new URL(value);
let hash = url.hash;
if (hash.includes("=")) {
//facebook sometimes includes querystring-encoded data into the hash... attempt to parse it
try {
hash = Object.fromEntries(
hash
.slice(1)
.split("&")
.map((kv) => kv.split("="))
);
} catch (e) {
// failed to parse as query string
console.log(
"Failed attempt to parse hash location as query string, probably safe to ignore:",
e
);
}
}
const object = { const object = {
[Symbol.for("originalURL")]: value, // so it doesn't appear raw in the table but can be easily retrieved later [Symbol.for("originalURL")]: value,
host: url.host, host: url.host,
path: url.pathname, path: url.pathname,
...Object.fromEntries( ...Object.fromEntries(
@ -109,7 +90,6 @@ export class StolenDataEntry extends EventEmitter {
entries: () => Iterable<[string, string]>; entries: () => Iterable<[string, string]>;
}).entries() }).entries()
), ),
...(hash === "" ? {} : typeof hash === "string" ? { hash } : hash),
}; };
return object; return object;
} else { } else {
@ -128,7 +108,7 @@ export class StolenDataEntry extends EventEmitter {
addMark(key: string) { addMark(key: string) {
this.marks.push(new Mark(this, key)); this.marks.push(new Mark(this, key));
this.emit("change"); getMemory().emit("change", true); // to trigger rerender
} }
hasMark(key?: string) { hasMark(key?: string) {
@ -141,7 +121,7 @@ export class StolenDataEntry extends EventEmitter {
removeMark(key: string) { removeMark(key: string) {
this.marks = this.marks.filter((mark) => mark.key != key); this.marks = this.marks.filter((mark) => mark.key != key);
this.emit("change"); getMemory().emit("change"); // to trigger rerender
} }
toggleMark(key: string) { toggleMark(key: string) {
@ -183,7 +163,7 @@ export class StolenDataEntry extends EventEmitter {
getValuePreview(key = ""): string { getValuePreview(key = ""): string {
const value = this.getParsedValue(key); const value = this.getParsedValue(key);
const str = value.toString(); const str = value.toString();
if (typeof value !== "object" && this.classification == "id") { if (this.classification == "id") {
return ( return (
str.slice(0, Math.min(str.length / 3, ID_PREVIEW_MAX_LENGTH)) + "(...)" str.slice(0, Math.min(str.length / 3, ID_PREVIEW_MAX_LENGTH)) + "(...)"
); );
@ -195,9 +175,8 @@ export class StolenDataEntry extends EventEmitter {
} }
} }
export class MergedStolenDataEntry extends EventEmitter { export class MergedStolenDataEntry {
constructor(public entries: StolenDataEntry[]) { constructor(public entries: StolenDataEntry[]) {
super();
const all_marks = unique( const all_marks = unique(
entries.map((entry) => entry.marks).reduce(reduceConcat, []) entries.map((entry) => entry.marks).reduce(reduceConcat, [])
); );
@ -207,20 +186,6 @@ export class MergedStolenDataEntry extends EventEmitter {
// getMemory().emit("change"); // to trigger render // getMemory().emit("change"); // to trigger render
} }
on(event: string, listener: () => void) {
for (const entry of this.entries) {
entry.on(event, listener);
}
return this;
}
removeListener(event: string, listener: () => void) {
for (const entry of this.entries) {
entry.removeListener(event, listener);
}
return this;
}
hasValue(value: string) { hasValue(value: string) {
return this.entries.some((entry) => entry.value === value); return this.entries.some((entry) => entry.value === value);
} }

View File

@ -1,5 +1,6 @@
import { EventEmitter } from "events"; import { EventEmitter } from "events";
import { Dispatch, SetStateAction, useEffect, useState } from "react"; import { Dispatch, SetStateAction, useEffect, useState } from "react";
import Memory from "./memory";
export type Unpromisify<T> = T extends Promise<infer R> ? R : T; export type Unpromisify<T> = T extends Promise<infer R> ? R : T;
export type Unarray<T> = T extends Array<infer R> ? R : T; export type Unarray<T> = T extends Array<infer R> ? R : T;