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));
+}