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