diff --git a/sidebar/stolen-data-cluster.tsx b/sidebar/stolen-data-cluster.tsx index 35521c2..23c13f9 100644 --- a/sidebar/stolen-data-cluster.tsx +++ b/sidebar/stolen-data-cluster.tsx @@ -1,11 +1,7 @@ import React from "react"; import { getMemory } from "../memory"; import { RequestCluster } from "../request-cluster"; -import { - MergedStolenDataEntry, - Sources, - StolenDataEntry, -} from "../stolen-data-entry"; +import { MergedStolenDataEntry, Sources } from "../stolen-data-entry"; import { hyphenate, useEmitter } from "../util"; @@ -19,33 +15,42 @@ function StolenDataValueTable({ prefixKey: string; }) { return ( - - - {Object.keys(entry.getParsedValues(prefixKey)[0]).map((key) => { - const subkey = `${prefixKey}.${key}`; - return ( - - - - - ); - })} - -
{ - entry.toggleMark(subkey); - e.stopPropagation(); - }} - style={{ - border: entry.hasMark(subkey) - ? "2px solid red" - : "2px solid transparent", - }} - > - {hyphenate(key)} - - -
+
+ {entry.getDecodingsApplied().includes("base64") ? ( + + "base64" + + ) : ( + "" + )} + + + {Object.keys(entry.getParsedValues(prefixKey)[0]).map((key) => { + const subkey = `${prefixKey}.${key}`; + return ( + + + + + ); + })} + +
{ + entry.toggleMark(subkey); + e.stopPropagation(); + }} + style={{ + border: entry.hasMark(subkey) + ? "2px solid red" + : "2px solid transparent", + }} + > + {hyphenate(key)} + + +
+
); } diff --git a/stolen-data-entry.ts b/stolen-data-entry.ts index 3b6b2b1..59af733 100644 --- a/stolen-data-entry.ts +++ b/stolen-data-entry.ts @@ -2,8 +2,10 @@ import { TCModel } from "@iabtcf/core"; import { EventEmitter } from "events"; import ExtendedRequest, { HAREntry } from "./extended-request"; import Mark from "./mark"; + import { getshorthost, + isBase64JSON, isJSONObject, isURL, parseToObject, @@ -29,12 +31,15 @@ const id = (function* id() { } })(); +export type DecodingSchema = "base64"; + export class StolenDataEntry extends EventEmitter { public isIAB = false; public iab: TCModel | null = null; public id: number; public marks: Mark[] = []; public classification: keyof typeof Classifications; + public decoding_applied: DecodingSchema = null; constructor( public request: ExtendedRequest, @@ -50,6 +55,10 @@ export class StolenDataEntry extends EventEmitter { super(); this.id = id.next().value as number; this.classification = this.classify(); + if (isBase64JSON(value)) { + this.value = atob(value); + this.decoding_applied = "base64"; + } } getPriority() { @@ -291,4 +300,8 @@ export class MergedStolenDataEntry extends EventEmitter { toggleMark(key: string): void { this.entries.forEach((entry) => entry.toggleMark(key)); } + + getDecodingsApplied(): DecodingSchema[] { + return unique(this.entries.map((entry) => entry.decoding_applied)); + } } diff --git a/util.ts b/util.ts index 4033755..07b0870 100644 --- a/util.ts +++ b/util.ts @@ -171,3 +171,15 @@ export function isSameURL(url1: string, url2: string): boolean { url2 = url2.replace(/^https?:\/\//, "").replace(/\/$/, ""); return url1 === url2; } + +export function isBase64(s: string): boolean { + try { + atob(s); + return true; + } catch (e) {} + return false; +} + +export function isBase64JSON(s: unknown): s is string { + return typeof s === "string" && isBase64(s) && isJSONObject(atob(s)); +}