@openreplay/tracker 16.2.0 → 16.2.2-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/entry.js +312 -102
- package/dist/cjs/entry.js.map +1 -1
- package/dist/cjs/index.js +312 -102
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/main/app/index.d.ts +2 -9
- package/dist/cjs/main/app/observer/observer.d.ts +1 -1
- package/dist/cjs/main/app/observer/top_observer.d.ts +9 -5
- package/dist/cjs/main/index.d.ts +1 -0
- package/dist/cjs/main/modules/cssrules.d.ts +3 -1
- package/dist/lib/entry.js +312 -102
- package/dist/lib/entry.js.map +1 -1
- package/dist/lib/index.js +312 -102
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/main/app/index.d.ts +2 -9
- package/dist/lib/main/app/observer/observer.d.ts +1 -1
- package/dist/lib/main/app/observer/top_observer.d.ts +9 -5
- package/dist/lib/main/index.d.ts +1 -0
- package/dist/lib/main/modules/cssrules.d.ts +3 -1
- package/dist/types/main/app/index.d.ts +2 -9
- package/dist/types/main/app/observer/observer.d.ts +1 -1
- package/dist/types/main/app/observer/top_observer.d.ts +9 -5
- package/dist/types/main/index.d.ts +1 -0
- package/dist/types/main/modules/cssrules.d.ts +3 -1
- package/package.json +1 -1
package/dist/cjs/entry.js
CHANGED
|
@@ -4046,6 +4046,7 @@ function ConstructedStyleSheets (app) {
|
|
|
4046
4046
|
return replace.call(this, text).then((sheet) => {
|
|
4047
4047
|
const sheetID = styleSheetIDMap.get(this);
|
|
4048
4048
|
if (sheetID) {
|
|
4049
|
+
console.log('replace');
|
|
4049
4050
|
app.send(AdoptedSSReplaceURLBased(sheetID, text, app.getBaseHref()));
|
|
4050
4051
|
}
|
|
4051
4052
|
return sheet;
|
|
@@ -4055,6 +4056,7 @@ function ConstructedStyleSheets (app) {
|
|
|
4055
4056
|
context.CSSStyleSheet.prototype.replaceSync = function (text) {
|
|
4056
4057
|
const sheetID = styleSheetIDMap.get(this);
|
|
4057
4058
|
if (sheetID) {
|
|
4059
|
+
console.log('replaceSync');
|
|
4058
4060
|
app.send(AdoptedSSReplaceURLBased(sheetID, text, app.getBaseHref()));
|
|
4059
4061
|
}
|
|
4060
4062
|
return replaceSync.call(this, text);
|
|
@@ -4697,11 +4699,52 @@ class IFrameOffsets {
|
|
|
4697
4699
|
|
|
4698
4700
|
var InlineCssMode;
|
|
4699
4701
|
(function (InlineCssMode) {
|
|
4700
|
-
|
|
4701
|
-
InlineCssMode[InlineCssMode["
|
|
4702
|
-
|
|
4703
|
-
InlineCssMode[InlineCssMode["
|
|
4702
|
+
/** default behavior -- will parse and cache the css file on backend */
|
|
4703
|
+
InlineCssMode[InlineCssMode["Disabled"] = 0] = "Disabled";
|
|
4704
|
+
/** will attempt to record the linked css file as AdoptedStyleSheet object */
|
|
4705
|
+
InlineCssMode[InlineCssMode["Inline"] = 1] = "Inline";
|
|
4706
|
+
/** will fetch the file, then simulated AdoptedStyleSheets behavior programmaticaly for the replay */
|
|
4707
|
+
InlineCssMode[InlineCssMode["InlineFetched"] = 2] = "InlineFetched";
|
|
4708
|
+
/** will fetch the file, then save it as plain css inside <style> node */
|
|
4709
|
+
InlineCssMode[InlineCssMode["PlainFetched"] = 3] = "PlainFetched";
|
|
4704
4710
|
})(InlineCssMode || (InlineCssMode = {}));
|
|
4711
|
+
function getInlineOptions(mode) {
|
|
4712
|
+
switch (mode) {
|
|
4713
|
+
case InlineCssMode.Inline:
|
|
4714
|
+
return {
|
|
4715
|
+
inlineRemoteCss: true,
|
|
4716
|
+
inlinerOptions: {
|
|
4717
|
+
forceFetch: false,
|
|
4718
|
+
forcePlain: false,
|
|
4719
|
+
},
|
|
4720
|
+
};
|
|
4721
|
+
case InlineCssMode.InlineFetched:
|
|
4722
|
+
return {
|
|
4723
|
+
inlineRemoteCss: true,
|
|
4724
|
+
inlinerOptions: {
|
|
4725
|
+
forceFetch: true,
|
|
4726
|
+
forcePlain: false,
|
|
4727
|
+
},
|
|
4728
|
+
};
|
|
4729
|
+
case InlineCssMode.PlainFetched:
|
|
4730
|
+
return {
|
|
4731
|
+
inlineRemoteCss: true,
|
|
4732
|
+
inlinerOptions: {
|
|
4733
|
+
forceFetch: true,
|
|
4734
|
+
forcePlain: true,
|
|
4735
|
+
},
|
|
4736
|
+
};
|
|
4737
|
+
case InlineCssMode.Disabled:
|
|
4738
|
+
default:
|
|
4739
|
+
return {
|
|
4740
|
+
inlineRemoteCss: false,
|
|
4741
|
+
inlinerOptions: {
|
|
4742
|
+
forceFetch: false,
|
|
4743
|
+
forcePlain: false,
|
|
4744
|
+
},
|
|
4745
|
+
};
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4705
4748
|
const attachShadowNativeFn = IN_BROWSER ? Element.prototype.attachShadow : () => new ShadowRoot();
|
|
4706
4749
|
class TopObserver extends Observer {
|
|
4707
4750
|
constructor(params) {
|
|
@@ -4710,7 +4753,11 @@ class TopObserver extends Observer {
|
|
|
4710
4753
|
disableSprites: false,
|
|
4711
4754
|
inlineCss: 0,
|
|
4712
4755
|
}, params.options);
|
|
4713
|
-
|
|
4756
|
+
const observerOptions = {
|
|
4757
|
+
disableSprites: opts.disableSprites,
|
|
4758
|
+
...getInlineOptions(opts.inlineCss)
|
|
4759
|
+
};
|
|
4760
|
+
super(params.app, true, observerOptions);
|
|
4714
4761
|
this.iframeOffsets = new IFrameOffsets();
|
|
4715
4762
|
this.contextCallbacks = [];
|
|
4716
4763
|
// Attached once per Tracker instance
|
|
@@ -5130,43 +5177,6 @@ function getTimezone() {
|
|
|
5130
5177
|
return `UTC${sign}${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
|
|
5131
5178
|
}
|
|
5132
5179
|
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
|
|
5133
|
-
function getInlineOptions(mode) {
|
|
5134
|
-
switch (mode) {
|
|
5135
|
-
case InlineCssMode.RemoteOnly:
|
|
5136
|
-
return {
|
|
5137
|
-
inlineRemoteCss: true,
|
|
5138
|
-
inlinerOptions: {
|
|
5139
|
-
forceFetch: false,
|
|
5140
|
-
forcePlain: false,
|
|
5141
|
-
},
|
|
5142
|
-
};
|
|
5143
|
-
case InlineCssMode.RemoteWithForceFetch:
|
|
5144
|
-
return {
|
|
5145
|
-
inlineRemoteCss: true,
|
|
5146
|
-
inlinerOptions: {
|
|
5147
|
-
forceFetch: true,
|
|
5148
|
-
forcePlain: false,
|
|
5149
|
-
},
|
|
5150
|
-
};
|
|
5151
|
-
case InlineCssMode.All:
|
|
5152
|
-
return {
|
|
5153
|
-
inlineRemoteCss: true,
|
|
5154
|
-
inlinerOptions: {
|
|
5155
|
-
forceFetch: true,
|
|
5156
|
-
forcePlain: true,
|
|
5157
|
-
},
|
|
5158
|
-
};
|
|
5159
|
-
case InlineCssMode.None:
|
|
5160
|
-
default:
|
|
5161
|
-
return {
|
|
5162
|
-
inlineRemoteCss: false,
|
|
5163
|
-
inlinerOptions: {
|
|
5164
|
-
forceFetch: false,
|
|
5165
|
-
forcePlain: false,
|
|
5166
|
-
},
|
|
5167
|
-
};
|
|
5168
|
-
}
|
|
5169
|
-
}
|
|
5170
5180
|
const proto = {
|
|
5171
5181
|
// ask if there are any tabs alive
|
|
5172
5182
|
ask: 'never-gonna-give-you-up',
|
|
@@ -5198,7 +5208,7 @@ class App {
|
|
|
5198
5208
|
this.stopCallbacks = [];
|
|
5199
5209
|
this.commitCallbacks = [];
|
|
5200
5210
|
this.activityState = ActivityState.NotActive;
|
|
5201
|
-
this.version = '16.2.
|
|
5211
|
+
this.version = '16.2.2-beta.19'; // TODO: version compatability check inside each plugin.
|
|
5202
5212
|
this.socketMode = false;
|
|
5203
5213
|
this.compressionThreshold = 24 * 1000;
|
|
5204
5214
|
this.bc = null;
|
|
@@ -5521,19 +5531,6 @@ class App {
|
|
|
5521
5531
|
this.onUxtCb = [];
|
|
5522
5532
|
this.contextId = Math.random().toString(36).slice(2);
|
|
5523
5533
|
this.projectKey = projectKey;
|
|
5524
|
-
this.inlineCss = getInlineOptions(options.inlineCss ?? 0);
|
|
5525
|
-
if (Object.keys(options).findIndex((k) => ['fixedCanvasScaling', 'disableCanvas'].includes(k)) !==
|
|
5526
|
-
-1) {
|
|
5527
|
-
console.warn('Openreplay: canvas options are moving to separate key "canvas" in next update. Please update your configuration.');
|
|
5528
|
-
options = {
|
|
5529
|
-
...options,
|
|
5530
|
-
canvas: {
|
|
5531
|
-
__save_canvas_locally: options.__save_canvas_locally,
|
|
5532
|
-
fixedCanvasScaling: options.fixedCanvasScaling,
|
|
5533
|
-
disableCanvas: options.disableCanvas,
|
|
5534
|
-
},
|
|
5535
|
-
};
|
|
5536
|
-
}
|
|
5537
5534
|
this.networkOptions = options.network;
|
|
5538
5535
|
const defaultOptions = {
|
|
5539
5536
|
revID: '',
|
|
@@ -5548,13 +5545,10 @@ class App {
|
|
|
5548
5545
|
__is_snippet: false,
|
|
5549
5546
|
__debug_report_edp: null,
|
|
5550
5547
|
__debug__: LogLevel.Silent,
|
|
5551
|
-
__save_canvas_locally: false,
|
|
5552
5548
|
localStorage: null,
|
|
5553
5549
|
sessionStorage: null,
|
|
5554
5550
|
forceSingleTab: false,
|
|
5555
5551
|
assistSocketHost: '',
|
|
5556
|
-
fixedCanvasScaling: false,
|
|
5557
|
-
disableCanvas: false,
|
|
5558
5552
|
captureIFrames: true,
|
|
5559
5553
|
obscureTextEmails: false,
|
|
5560
5554
|
obscureTextNumbers: false,
|
|
@@ -5592,7 +5586,7 @@ class App {
|
|
|
5592
5586
|
forceNgOff: Boolean(options.forceNgOff),
|
|
5593
5587
|
maintainer: this.options.nodes?.maintainer,
|
|
5594
5588
|
});
|
|
5595
|
-
this.observer = new TopObserver({ app: this, options
|
|
5589
|
+
this.observer = new TopObserver({ app: this, options });
|
|
5596
5590
|
this.ticker = new Ticker(this);
|
|
5597
5591
|
this.ticker.attach(() => this.commit());
|
|
5598
5592
|
this.debug = new Logger(this.options.__debug__);
|
|
@@ -8049,60 +8043,107 @@ function Viewport (app) {
|
|
|
8049
8043
|
app.ticker.attach(sendSetViewportSize, 5, false);
|
|
8050
8044
|
}
|
|
8051
8045
|
|
|
8052
|
-
function CSSRules (app) {
|
|
8053
|
-
if (app === null)
|
|
8046
|
+
function CSSRules (app, opts) {
|
|
8047
|
+
if (app === null)
|
|
8054
8048
|
return;
|
|
8055
|
-
}
|
|
8056
8049
|
if (!window.CSSStyleSheet) {
|
|
8057
8050
|
app.send(TechnicalInfo('no_stylesheet_prototype_in_window', ''));
|
|
8058
8051
|
return;
|
|
8059
8052
|
}
|
|
8053
|
+
// Track CSS rule snapshots by sheetID:index
|
|
8054
|
+
const ruleSnapshots = new Map();
|
|
8055
|
+
let checkInterval = null;
|
|
8056
|
+
const checkIntervalMs = opts.checkCssInterval || 200; // Check every 200ms
|
|
8057
|
+
// Check all rules for changes
|
|
8058
|
+
function checkRuleChanges() {
|
|
8059
|
+
for (let i = 0; i < document.styleSheets.length; i++) {
|
|
8060
|
+
try {
|
|
8061
|
+
const sheet = document.styleSheets[i];
|
|
8062
|
+
const sheetID = styleSheetIDMap.get(sheet);
|
|
8063
|
+
if (!sheetID)
|
|
8064
|
+
continue;
|
|
8065
|
+
// Check each rule in the sheet
|
|
8066
|
+
for (let j = 0; j < sheet.cssRules.length; j++) {
|
|
8067
|
+
try {
|
|
8068
|
+
const rule = sheet.cssRules[j];
|
|
8069
|
+
const key = `${sheetID}:${j}`;
|
|
8070
|
+
const newText = rule.cssText;
|
|
8071
|
+
const oldText = ruleSnapshots.get(key);
|
|
8072
|
+
if (oldText !== newText) {
|
|
8073
|
+
// Rule is new or changed
|
|
8074
|
+
if (oldText !== undefined) {
|
|
8075
|
+
// Rule changed - send update
|
|
8076
|
+
app.send(AdoptedSSDeleteRule(sheetID, j));
|
|
8077
|
+
app.send(AdoptedSSInsertRuleURLBased(sheetID, newText, j, app.getBaseHref()));
|
|
8078
|
+
}
|
|
8079
|
+
else {
|
|
8080
|
+
// Rule added - send insert
|
|
8081
|
+
app.send(AdoptedSSInsertRuleURLBased(sheetID, newText, j, app.getBaseHref()));
|
|
8082
|
+
}
|
|
8083
|
+
ruleSnapshots.set(key, newText);
|
|
8084
|
+
}
|
|
8085
|
+
}
|
|
8086
|
+
catch (e) {
|
|
8087
|
+
/* Skip inaccessible rules */
|
|
8088
|
+
}
|
|
8089
|
+
}
|
|
8090
|
+
// Check for deleted rules
|
|
8091
|
+
const keysToCheck = Array.from(ruleSnapshots.keys()).filter((key) => key.startsWith(`${sheetID}:`));
|
|
8092
|
+
for (const key of keysToCheck) {
|
|
8093
|
+
const index = parseInt(key.split(':')[1], 10);
|
|
8094
|
+
if (index >= sheet.cssRules.length) {
|
|
8095
|
+
ruleSnapshots.delete(key);
|
|
8096
|
+
}
|
|
8097
|
+
}
|
|
8098
|
+
}
|
|
8099
|
+
catch (e) {
|
|
8100
|
+
/* Skip inaccessible sheets */
|
|
8101
|
+
}
|
|
8102
|
+
}
|
|
8103
|
+
}
|
|
8104
|
+
// Standard API hooks
|
|
8060
8105
|
const sendInsertDeleteRule = app.safe((sheet, index, rule) => {
|
|
8061
8106
|
const sheetID = styleSheetIDMap.get(sheet);
|
|
8062
|
-
if (!sheetID)
|
|
8063
|
-
// OK-case. Sheet haven't been registered yet. Rules will be sent on registration.
|
|
8107
|
+
if (!sheetID)
|
|
8064
8108
|
return;
|
|
8065
|
-
}
|
|
8066
8109
|
if (typeof rule === 'string') {
|
|
8067
8110
|
app.send(AdoptedSSInsertRuleURLBased(sheetID, rule, index, app.getBaseHref()));
|
|
8111
|
+
ruleSnapshots.set(`${sheetID}:${index}`, rule);
|
|
8068
8112
|
}
|
|
8069
8113
|
else {
|
|
8070
8114
|
app.send(AdoptedSSDeleteRule(sheetID, index));
|
|
8115
|
+
ruleSnapshots.delete(`${sheetID}:${index}`);
|
|
8071
8116
|
}
|
|
8072
8117
|
});
|
|
8073
|
-
// TODO: proper rule insertion/removal (how?)
|
|
8074
8118
|
const sendReplaceGroupingRule = app.safe((rule) => {
|
|
8075
8119
|
let topmostRule = rule;
|
|
8076
|
-
while (topmostRule.parentRule)
|
|
8120
|
+
while (topmostRule.parentRule)
|
|
8077
8121
|
topmostRule = topmostRule.parentRule;
|
|
8078
|
-
}
|
|
8079
8122
|
const sheet = topmostRule.parentStyleSheet;
|
|
8080
|
-
if (!sheet)
|
|
8081
|
-
app.debug.warn('No parent StyleSheet found for', topmostRule, rule);
|
|
8123
|
+
if (!sheet)
|
|
8082
8124
|
return;
|
|
8083
|
-
}
|
|
8084
8125
|
const sheetID = styleSheetIDMap.get(sheet);
|
|
8085
|
-
if (!sheetID)
|
|
8086
|
-
app.debug.warn('No sheedID found for', sheet, styleSheetIDMap);
|
|
8126
|
+
if (!sheetID)
|
|
8087
8127
|
return;
|
|
8088
|
-
}
|
|
8089
8128
|
const cssText = topmostRule.cssText;
|
|
8090
|
-
const
|
|
8091
|
-
const idx = Array.from(ruleList).indexOf(topmostRule);
|
|
8129
|
+
const idx = Array.from(sheet.cssRules).indexOf(topmostRule);
|
|
8092
8130
|
if (idx >= 0) {
|
|
8093
8131
|
app.send(AdoptedSSInsertRuleURLBased(sheetID, cssText, idx, app.getBaseHref()));
|
|
8094
|
-
app.send(AdoptedSSDeleteRule(sheetID, idx + 1));
|
|
8095
|
-
|
|
8096
|
-
else {
|
|
8097
|
-
app.debug.warn('Rule index not found in', sheet, topmostRule);
|
|
8132
|
+
app.send(AdoptedSSDeleteRule(sheetID, idx + 1));
|
|
8133
|
+
ruleSnapshots.set(`${sheetID}:${idx}`, cssText);
|
|
8098
8134
|
}
|
|
8099
8135
|
});
|
|
8136
|
+
// Patch prototype methods
|
|
8100
8137
|
const patchContext = app.safe((context) => {
|
|
8138
|
+
if (context.__css_tracking_patched__)
|
|
8139
|
+
return;
|
|
8140
|
+
context.__css_tracking_patched__ = true;
|
|
8101
8141
|
const { insertRule, deleteRule } = context.CSSStyleSheet.prototype;
|
|
8102
8142
|
const { insertRule: groupInsertRule, deleteRule: groupDeleteRule } = context.CSSGroupingRule.prototype;
|
|
8103
8143
|
context.CSSStyleSheet.prototype.insertRule = function (rule, index = 0) {
|
|
8104
|
-
|
|
8105
|
-
|
|
8144
|
+
const result = insertRule.call(this, rule, index);
|
|
8145
|
+
sendInsertDeleteRule(this, result, rule);
|
|
8146
|
+
return result;
|
|
8106
8147
|
};
|
|
8107
8148
|
context.CSSStyleSheet.prototype.deleteRule = function (index) {
|
|
8108
8149
|
sendInsertDeleteRule(this, index);
|
|
@@ -8113,33 +8154,50 @@ function CSSRules (app) {
|
|
|
8113
8154
|
sendReplaceGroupingRule(this);
|
|
8114
8155
|
return result;
|
|
8115
8156
|
};
|
|
8116
|
-
context.CSSGroupingRule.prototype.deleteRule = function (index
|
|
8157
|
+
context.CSSGroupingRule.prototype.deleteRule = function (index) {
|
|
8117
8158
|
const result = groupDeleteRule.call(this, index);
|
|
8118
8159
|
sendReplaceGroupingRule(this);
|
|
8119
8160
|
return result;
|
|
8120
8161
|
};
|
|
8121
8162
|
});
|
|
8163
|
+
// Apply patches
|
|
8122
8164
|
patchContext(window);
|
|
8123
8165
|
app.observer.attachContextCallback(patchContext);
|
|
8166
|
+
// Track style nodes
|
|
8124
8167
|
app.nodes.attachNodeCallback((node) => {
|
|
8125
|
-
if (!hasTag(node, 'style') || !node.sheet)
|
|
8168
|
+
if (!hasTag(node, 'style') || !node.sheet)
|
|
8169
|
+
return;
|
|
8170
|
+
if (node.textContent !== null && node.textContent.trim().length > 0)
|
|
8126
8171
|
return;
|
|
8127
|
-
}
|
|
8128
|
-
if (node.textContent !== null && node.textContent.trim().length > 0) {
|
|
8129
|
-
return; // Non-virtual styles captured by the observer as a text
|
|
8130
|
-
}
|
|
8131
8172
|
const nodeID = app.nodes.getID(node);
|
|
8132
|
-
if (!nodeID)
|
|
8173
|
+
if (!nodeID)
|
|
8133
8174
|
return;
|
|
8134
|
-
}
|
|
8135
8175
|
const sheet = node.sheet;
|
|
8136
8176
|
const sheetID = nextID();
|
|
8137
8177
|
styleSheetIDMap.set(sheet, sheetID);
|
|
8138
8178
|
app.send(AdoptedSSAddOwner(sheetID, nodeID));
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8179
|
+
for (let i = 0; i < sheet.cssRules.length; i++) {
|
|
8180
|
+
try {
|
|
8181
|
+
sendInsertDeleteRule(sheet, i, sheet.cssRules[i].cssText);
|
|
8182
|
+
}
|
|
8183
|
+
catch (e) {
|
|
8184
|
+
// Skip inaccessible rules
|
|
8185
|
+
}
|
|
8186
|
+
}
|
|
8187
|
+
});
|
|
8188
|
+
// Start checking and setup cleanup
|
|
8189
|
+
function startChecking() {
|
|
8190
|
+
if (checkInterval)
|
|
8191
|
+
return;
|
|
8192
|
+
checkInterval = window.setInterval(checkRuleChanges, checkIntervalMs);
|
|
8193
|
+
}
|
|
8194
|
+
setTimeout(startChecking, 50);
|
|
8195
|
+
app.attachStopCallback(() => {
|
|
8196
|
+
if (checkInterval) {
|
|
8197
|
+
clearInterval(checkInterval);
|
|
8198
|
+
checkInterval = null;
|
|
8142
8199
|
}
|
|
8200
|
+
ruleSnapshots.clear();
|
|
8143
8201
|
});
|
|
8144
8202
|
}
|
|
8145
8203
|
|
|
@@ -8355,6 +8413,152 @@ function isObject(thing) {
|
|
|
8355
8413
|
return thing !== null && typeof thing === 'object';
|
|
8356
8414
|
}
|
|
8357
8415
|
|
|
8416
|
+
const sensitiveParams = new Set([
|
|
8417
|
+
"password",
|
|
8418
|
+
"pass",
|
|
8419
|
+
"pwd",
|
|
8420
|
+
"mdp",
|
|
8421
|
+
"token",
|
|
8422
|
+
"bearer",
|
|
8423
|
+
"jwt",
|
|
8424
|
+
"api_key",
|
|
8425
|
+
"api-key",
|
|
8426
|
+
"apiKey",
|
|
8427
|
+
"secret",
|
|
8428
|
+
"ssn",
|
|
8429
|
+
"zip",
|
|
8430
|
+
"zipcode",
|
|
8431
|
+
"x-api-key",
|
|
8432
|
+
"www-authenticate",
|
|
8433
|
+
"x-csrf-token",
|
|
8434
|
+
"x-requested-with",
|
|
8435
|
+
"x-forwarded-for",
|
|
8436
|
+
"x-real-ip",
|
|
8437
|
+
"cookie",
|
|
8438
|
+
"authorization",
|
|
8439
|
+
"auth",
|
|
8440
|
+
"proxy-authorization",
|
|
8441
|
+
"set-cookie",
|
|
8442
|
+
"account_key",
|
|
8443
|
+
]);
|
|
8444
|
+
function numDigits(x) {
|
|
8445
|
+
return (Math.log10((x ^ (x >> 31)) - (x >> 31)) | 0) + 1;
|
|
8446
|
+
}
|
|
8447
|
+
function obscure(value) {
|
|
8448
|
+
if (typeof value === "number") {
|
|
8449
|
+
const digits = numDigits(value);
|
|
8450
|
+
return "9".repeat(digits);
|
|
8451
|
+
}
|
|
8452
|
+
if (typeof value === "string") {
|
|
8453
|
+
return value.replace(/[^\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff\s]/g, '*');
|
|
8454
|
+
}
|
|
8455
|
+
return value;
|
|
8456
|
+
}
|
|
8457
|
+
function filterHeaders(headers) {
|
|
8458
|
+
const filteredHeaders = {};
|
|
8459
|
+
if (Array.isArray(headers)) {
|
|
8460
|
+
headers.forEach(({ name, value }) => {
|
|
8461
|
+
if (sensitiveParams.has(name.toLowerCase())) {
|
|
8462
|
+
filteredHeaders[name] = obscure(value);
|
|
8463
|
+
}
|
|
8464
|
+
else {
|
|
8465
|
+
filteredHeaders[name] = value;
|
|
8466
|
+
}
|
|
8467
|
+
});
|
|
8468
|
+
}
|
|
8469
|
+
else {
|
|
8470
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
8471
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8472
|
+
filteredHeaders[key] = obscure(value);
|
|
8473
|
+
}
|
|
8474
|
+
else {
|
|
8475
|
+
filteredHeaders[key] = value;
|
|
8476
|
+
}
|
|
8477
|
+
}
|
|
8478
|
+
}
|
|
8479
|
+
return filteredHeaders;
|
|
8480
|
+
}
|
|
8481
|
+
function filterBody(body) {
|
|
8482
|
+
if (!body) {
|
|
8483
|
+
return body;
|
|
8484
|
+
}
|
|
8485
|
+
let parsedBody;
|
|
8486
|
+
let isJSON = false;
|
|
8487
|
+
try {
|
|
8488
|
+
parsedBody = JSON.parse(body);
|
|
8489
|
+
isJSON = true;
|
|
8490
|
+
}
|
|
8491
|
+
catch (e) {
|
|
8492
|
+
// not json
|
|
8493
|
+
}
|
|
8494
|
+
if (isJSON) {
|
|
8495
|
+
obscureSensitiveData(parsedBody);
|
|
8496
|
+
return JSON.stringify(parsedBody);
|
|
8497
|
+
}
|
|
8498
|
+
else {
|
|
8499
|
+
const isUrlSearch = typeof body === "string" && body.includes("?") && body.includes("=");
|
|
8500
|
+
if (isUrlSearch) {
|
|
8501
|
+
try {
|
|
8502
|
+
const params = new URLSearchParams(body);
|
|
8503
|
+
for (const key of params.keys()) {
|
|
8504
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8505
|
+
const value = obscure(params.get(key));
|
|
8506
|
+
params.set(key, value);
|
|
8507
|
+
}
|
|
8508
|
+
}
|
|
8509
|
+
return params.toString();
|
|
8510
|
+
}
|
|
8511
|
+
catch (e) {
|
|
8512
|
+
// not url query ?
|
|
8513
|
+
return body;
|
|
8514
|
+
}
|
|
8515
|
+
}
|
|
8516
|
+
else {
|
|
8517
|
+
// not json or url query
|
|
8518
|
+
return body;
|
|
8519
|
+
}
|
|
8520
|
+
}
|
|
8521
|
+
}
|
|
8522
|
+
function sanitizeObject(obj) {
|
|
8523
|
+
obscureSensitiveData(obj);
|
|
8524
|
+
return obj;
|
|
8525
|
+
}
|
|
8526
|
+
function obscureSensitiveData(obj) {
|
|
8527
|
+
if (Array.isArray(obj)) {
|
|
8528
|
+
obj.forEach(obscureSensitiveData);
|
|
8529
|
+
}
|
|
8530
|
+
else if (obj && typeof obj === "object") {
|
|
8531
|
+
for (const key in obj) {
|
|
8532
|
+
if (Object.hasOwn(obj, key)) {
|
|
8533
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8534
|
+
obj[key] = obscure(obj[key]);
|
|
8535
|
+
}
|
|
8536
|
+
else if (obj[key] !== null && typeof obj[key] === "object") {
|
|
8537
|
+
obscureSensitiveData(obj[key]);
|
|
8538
|
+
}
|
|
8539
|
+
}
|
|
8540
|
+
}
|
|
8541
|
+
}
|
|
8542
|
+
}
|
|
8543
|
+
function tryFilterUrl(url) {
|
|
8544
|
+
if (!url)
|
|
8545
|
+
return "";
|
|
8546
|
+
try {
|
|
8547
|
+
const urlObj = new URL(url);
|
|
8548
|
+
if (urlObj.searchParams) {
|
|
8549
|
+
for (const key of urlObj.searchParams.keys()) {
|
|
8550
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8551
|
+
urlObj.searchParams.set(key, "******");
|
|
8552
|
+
}
|
|
8553
|
+
}
|
|
8554
|
+
}
|
|
8555
|
+
return urlObj.toString();
|
|
8556
|
+
}
|
|
8557
|
+
catch (e) {
|
|
8558
|
+
return url;
|
|
8559
|
+
}
|
|
8560
|
+
}
|
|
8561
|
+
|
|
8358
8562
|
/**
|
|
8359
8563
|
* I know we're not using most of the information from this class
|
|
8360
8564
|
* but it can be useful in the future if we will decide to display more stuff in our ui
|
|
@@ -8386,13 +8590,18 @@ class NetworkMessage {
|
|
|
8386
8590
|
}
|
|
8387
8591
|
getMessage() {
|
|
8388
8592
|
const { reqHs, resHs } = this.writeHeaders();
|
|
8593
|
+
const reqBody = this.method === 'GET'
|
|
8594
|
+
? JSON.stringify(sanitizeObject(this.getData)) : filterBody(this.requestData);
|
|
8389
8595
|
const request = {
|
|
8390
|
-
headers: reqHs,
|
|
8391
|
-
body:
|
|
8596
|
+
headers: filterHeaders(reqHs),
|
|
8597
|
+
body: reqBody,
|
|
8598
|
+
};
|
|
8599
|
+
const response = {
|
|
8600
|
+
headers: filterHeaders(resHs),
|
|
8601
|
+
body: filterBody(this.response)
|
|
8392
8602
|
};
|
|
8393
|
-
const response = { headers: resHs, body: this.response };
|
|
8394
8603
|
const messageInfo = this.sanitize({
|
|
8395
|
-
url: this.url,
|
|
8604
|
+
url: tryFilterUrl(this.url),
|
|
8396
8605
|
method: this.method,
|
|
8397
8606
|
status: this.status,
|
|
8398
8607
|
request,
|
|
@@ -8708,9 +8917,10 @@ class ResponseProxyHandler {
|
|
|
8708
8917
|
if (typeof this.resp.body.getReader !== 'function') {
|
|
8709
8918
|
return;
|
|
8710
8919
|
}
|
|
8711
|
-
const
|
|
8920
|
+
const clonedResp = this.resp.clone();
|
|
8921
|
+
const _getReader = clonedResp.body.getReader;
|
|
8712
8922
|
// @ts-ignore
|
|
8713
|
-
|
|
8923
|
+
clonedResp.body.getReader = () => {
|
|
8714
8924
|
const reader = _getReader.apply(this.resp.body);
|
|
8715
8925
|
// when readyState is already 4,
|
|
8716
8926
|
// it's not a chunked stream, or it had already been read.
|
|
@@ -9552,7 +9762,7 @@ class API {
|
|
|
9552
9762
|
this.signalStartIssue = (reason, missingApi) => {
|
|
9553
9763
|
const doNotTrack = this.checkDoNotTrack();
|
|
9554
9764
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
9555
|
-
trackerVersion: '16.2.
|
|
9765
|
+
trackerVersion: '16.2.2-beta.19',
|
|
9556
9766
|
projectKey: this.options.projectKey,
|
|
9557
9767
|
doNotTrack,
|
|
9558
9768
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|
|
@@ -9651,7 +9861,7 @@ class API {
|
|
|
9651
9861
|
Mouse(app, options.mouse);
|
|
9652
9862
|
// inside iframe, we ignore viewport scroll
|
|
9653
9863
|
Scroll(app, this.crossdomainMode);
|
|
9654
|
-
CSSRules(app);
|
|
9864
|
+
CSSRules(app, options);
|
|
9655
9865
|
ConstructedStyleSheets(app);
|
|
9656
9866
|
Console(app, options);
|
|
9657
9867
|
Exception(app, options);
|