Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@webblackbox/recorder

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@webblackbox/recorder - npm Package Compare versions

Comparing version
0.4.5
to
0.5.0
+259
-11
dist/index.js

@@ -141,3 +141,6 @@ // src/action-span.ts

// src/normalizer.ts
import { extractRequestIdFromPayload } from "@webblackbox/protocol";
import {
extractRequestIdFromPayload,
sanitizeUrlForPrivacy
} from "@webblackbox/protocol";
var CDP_EVENT_MAP = {

@@ -181,2 +184,3 @@ "Network.requestWillBeSent": "network.request",

vitals: "perf.vitals",
privacyViolation: "privacy.violation",
localStorageOp: "storage.local.op",

@@ -307,3 +311,3 @@ localStorageSnapshot: "storage.local.snapshot",

const method = (asString(payload?.method) ?? "GET").toUpperCase();
const url = asString(payload?.url) ?? "unknown://request";
const url = sanitizeUrlForPrivacy(asString(payload?.url) ?? "unknown://request");
const reqId = readRequestId(payload) ?? buildFallbackReqId(method, url);

@@ -322,3 +326,4 @@ return stripUndefined({

const url = asString(payload?.url);
const reqId = readRequestId(payload) ?? buildFallbackReqId(method ?? "GET", url ?? "unknown://request");
const sanitizedUrl = url ? sanitizeUrlForPrivacy(url) : void 0;
const reqId = readRequestId(payload) ?? buildFallbackReqId(method ?? "GET", sanitizedUrl ?? "unknown://request");
return stripUndefined({

@@ -328,3 +333,3 @@ reqId,

method: method ? method.toUpperCase() : void 0,
url,
url: sanitizedUrl,
status: asFiniteNumber(payload?.status) ?? void 0,

@@ -338,3 +343,3 @@ statusText: asString(payload?.statusText) ?? void 0,

redirected: asBoolean(payload?.redirected),
responseUrl: asString(payload?.responseUrl) ?? void 0,
responseUrl: sanitizeOptionalUrl(asString(payload?.responseUrl)),
failed: asBoolean(payload?.failed)

@@ -346,3 +351,4 @@ });

const url = asString(payload?.url);
const reqId = readRequestId(payload) ?? buildFallbackReqId(method ?? "GET", url ?? "unknown://request");
const sanitizedUrl = url ? sanitizeUrlForPrivacy(url) : void 0;
const reqId = readRequestId(payload) ?? buildFallbackReqId(method ?? "GET", sanitizedUrl ?? "unknown://request");
return stripUndefined({

@@ -352,3 +358,3 @@ reqId,

method: method ? method.toUpperCase() : void 0,
url,
url: sanitizedUrl,
duration: asFiniteNumber(payload?.duration) ?? void 0,

@@ -360,3 +366,3 @@ message: asString(payload?.message) ?? void 0,

function normalizeContentNetworkBodyPayload(payload) {
const reqId = readRequestId(payload) ?? buildFallbackReqId("GET", asString(payload?.url) ?? "unknown://request");
const reqId = readRequestId(payload) ?? buildFallbackReqId("GET", sanitizeOptionalUrl(asString(payload?.url)) ?? "unknown://request");
return stripUndefined({

@@ -478,3 +484,3 @@ reqId,

}
const url = asString(frame.url) ?? "(anonymous)";
const url = sanitizeOptionalUrl(asString(frame.url)) ?? "(anonymous)";
const line = asFiniteNumber(frame.lineNumber);

@@ -535,2 +541,5 @@ const col = asFiniteNumber(frame.columnNumber);

}
function sanitizeOptionalUrl(value) {
return value ? sanitizeUrlForPrivacy(value) : void 0;
}
function compactText(value, maxLength) {

@@ -558,2 +567,5 @@ return value.length > maxLength ? `${value.slice(0, Math.max(0, maxLength - 3))}...` : value;

}
if (rawType === "privacyViolation") {
return "privacy.violation";
}
if (rawType === "cdp.network.body") {

@@ -763,2 +775,3 @@ return "network.body";

import {
DEFAULT_CAPTURE_POLICY,
EventIdFactory

@@ -768,2 +781,3 @@ } from "@webblackbox/protocol";

// src/redaction.ts
import { sanitizeUrlForPrivacy as sanitizeUrlForPrivacy2 } from "@webblackbox/protocol";
var REDACTED = "[REDACTED]";

@@ -848,2 +862,10 @@ var SHA_256_K = [

const normalizedKey = key.toLowerCase();
if (isUrlLikeField(normalizedKey) && typeof value === "string") {
output[key] = sanitizeUrlForPrivacy2(value);
continue;
}
if (normalizedKey === "selector" && typeof value === "string") {
output[key] = profile.hashSensitiveValues ? `selector:${hashValue(value).slice(0, 12)}` : "[REDACTED_SELECTOR]";
continue;
}
if (profile.redactHeaders.includes(normalizedKey) || isSensitiveKey(normalizedKey, profile)) {

@@ -991,2 +1013,5 @@ output[key] = profile.hashSensitiveValues && typeof value === "string" ? hashValue(value) : REDACTED;

}
function isUrlLikeField(key) {
return key === "url" || key === "href" || key === "responseurl" || key === "documenturl" || key === "requesturl" || key.endsWith("url");
}
function containsSensitivePattern(value, profile) {

@@ -1152,2 +1177,13 @@ const lowered = value.toLowerCase();

const redactedPayload = redactPayload(normalized.payload, this.config.redaction);
const privacy = classifyPrivacy(
normalized.eventType,
redactedPayload,
this.config.capturePolicy
);
const violation = evaluateCapturePolicy(
normalized.eventType,
redactedPayload,
privacy,
this.config.capturePolicy
);
const event = {

@@ -1163,5 +1199,10 @@ v: 1,

mono: nextRawEvent.mono,
type: normalized.eventType,
type: violation ? "privacy.violation" : normalized.eventType,
id: this.idFactory.next(),
data: redactedPayload
privacy: violation ? {
category: "system",
sensitivity: "medium",
redacted: true
} : privacy,
data: violation ?? redactedPayload
};

@@ -1240,2 +1281,209 @@ const actionLinkedEvent = this.actionSpanTracker.assign(event);

}
function classifyPrivacy(eventType, payload, policy) {
const effectivePolicy = policy ?? DEFAULT_CAPTURE_POLICY;
const category = classifyCategory(eventType);
const sensitivity = classifySensitivity(eventType);
return {
category,
sensitivity,
redacted: isRedactedByPolicy(eventType, category, effectivePolicy) || hasRedactionSignal(payload)
};
}
function evaluateCapturePolicy(eventType, payload, privacy, policy) {
if (eventType === "privacy.violation") {
return null;
}
if (!policy) {
return createPrivacyViolation(eventType, privacy, "missing-capture-policy", "missing");
}
const reason = findPolicyViolationReason(eventType, payload, policy);
if (!reason) {
return null;
}
return createPrivacyViolation(eventType, privacy, reason, policy.mode);
}
function createPrivacyViolation(eventType, privacy, reason, policyMode) {
return {
blockedType: eventType,
category: privacy.category,
sensitivity: privacy.sensitivity,
reason,
policyMode,
redacted: true
};
}
function findPolicyViolationReason(eventType, payload, policy) {
if (eventType === "screen.screenshot" && policy.categories.screenshots === "off") {
return "screenshots-disabled";
}
if (eventType === "network.body" && policy.categories.network !== "body-allowlist") {
return "network-body-disabled";
}
if (eventType === "dom.snapshot") {
if (policy.categories.dom === "off") {
return "dom-disabled";
}
if (policy.categories.dom !== "allow" && hasBlobReference(payload)) {
return "dom-raw-snapshot-disabled";
}
}
if (eventType.startsWith("dom.") && policy.categories.dom === "off") {
return "dom-disabled";
}
if (eventType === "user.input") {
if (policy.categories.inputs === "none") {
return "inputs-disabled";
}
if (policy.categories.inputs === "length-only" && hasRawInputValue(payload)) {
return "raw-input-value-disabled";
}
}
if (eventType.startsWith("console.") || eventType.startsWith("error.")) {
if (policy.categories.console === "off") {
return "console-disabled";
}
if (policy.categories.console === "metadata" && hasConsoleTextPayload(payload)) {
return "console-payload-disabled";
}
}
if (eventType.startsWith("storage.")) {
if (isStorageDisabledByPolicy(eventType, policy)) {
return "storage-disabled";
}
if (isStorageCountsOnlyByPolicy(eventType, policy) && hasStorageDetail(payload)) {
return "storage-detail-disabled";
}
}
if (eventType === "perf.heap.snapshot" && (policy.categories.heapProfiles !== "lab-only" || policy.mode !== "lab")) {
return "heap-profile-disabled";
}
if ((eventType === "perf.trace" || eventType === "perf.cpu.profile") && policy.categories.cdp !== "full") {
return "cdp-profile-disabled";
}
return null;
}
function classifyCategory(eventType) {
if (eventType === "user.input") {
return "inputs";
}
if (eventType.startsWith("user.")) {
return "actions";
}
if (eventType.startsWith("dom.")) {
return "dom";
}
if (eventType.startsWith("screen.")) {
return "screenshots";
}
if (eventType.startsWith("console.") || eventType.startsWith("error.")) {
return "console";
}
if (eventType.startsWith("network.")) {
return "network";
}
if (eventType.startsWith("storage.")) {
return "storage";
}
if (eventType.startsWith("perf.")) {
return "performance";
}
return "system";
}
function classifySensitivity(eventType) {
if (eventType === "privacy.violation") {
return "medium";
}
if (eventType === "user.input" || eventType === "dom.snapshot" || eventType === "network.body" || eventType === "screen.screenshot" || eventType.startsWith("storage.")) {
return "high";
}
if (eventType.startsWith("dom.") || eventType.startsWith("console.") || eventType.startsWith("error.") || eventType.startsWith("network.")) {
return "medium";
}
return "low";
}
function isRedactedByPolicy(eventType, category, policy) {
switch (category) {
case "actions":
return policy.categories.actions !== "allow";
case "inputs":
return policy.categories.inputs !== "allow";
case "dom":
return policy.categories.dom !== "allow";
case "screenshots":
return policy.categories.screenshots !== "allow";
case "console":
return policy.categories.console !== "allow";
case "network":
return eventType === "network.body" ? policy.categories.network !== "body-allowlist" : policy.categories.network === "metadata";
case "storage":
if (eventType.startsWith("storage.cookie.")) {
return policy.categories.cookies !== "names-only";
}
if (eventType.startsWith("storage.idb.")) {
return policy.categories.indexedDb !== "names-only";
}
return policy.categories.storage !== "allow";
case "performance":
case "system":
return false;
}
}
function isStorageDisabledByPolicy(eventType, policy) {
if (eventType.startsWith("storage.cookie.")) {
return policy.categories.cookies === "off";
}
if (eventType.startsWith("storage.idb.")) {
return policy.categories.indexedDb === "off";
}
return policy.categories.storage === "off";
}
function isStorageCountsOnlyByPolicy(eventType, policy) {
if (eventType.startsWith("storage.cookie.")) {
return policy.categories.cookies === "count-only";
}
if (eventType.startsWith("storage.idb.")) {
return policy.categories.indexedDb === "counts-only";
}
return policy.categories.storage === "counts-only";
}
function hasBlobReference(payload) {
const row = asRecord3(payload);
if (!row) {
return false;
}
return typeof row.contentHash === "string" || typeof row.hash === "string";
}
function hasRawInputValue(payload) {
const row = asRecord3(payload);
if (!row) {
return false;
}
return typeof row.value === "string" || typeof row.text === "string";
}
function hasConsoleTextPayload(payload) {
const row = asRecord3(payload);
if (!row) {
return false;
}
const args = row.args;
return typeof row.text === "string" && row.text.length > 0 || typeof row.message === "string" && row.message.length > 0 || typeof row.stack === "string" && row.stack.length > 0 || Array.isArray(args) && args.length > 0;
}
function hasStorageDetail(payload) {
const row = asRecord3(payload);
if (!row) {
return false;
}
return hasBlobReference(row) || typeof row.key === "string" || Array.isArray(row.names) || Array.isArray(row.databaseNames) || asRecord3(row.entries) !== null;
}
function hasRedactionSignal(payload) {
const row = asRecord3(payload);
if (!row) {
return false;
}
const target = row.target;
return row.redacted === true || row.valueRedacted === true || row.selectorRedacted === true || target !== null && typeof target === "object" && !Array.isArray(target) && target.selectorRedacted === true;
}
function asRecord3(value) {
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
}
export {

@@ -1242,0 +1490,0 @@ ActionSpanTracker,

+2
-2
{
"name": "@webblackbox/recorder",
"description": "Browser event recorder and normalization engine for WebBlackbox capture pipelines.",
"version": "0.4.5",
"version": "0.5.0",
"type": "module",

@@ -41,3 +41,3 @@ "main": "./dist/index.js",

"dependencies": {
"@webblackbox/protocol": "0.4.5"
"@webblackbox/protocol": "0.5.0"
},

@@ -44,0 +44,0 @@ "scripts": {