@openreplay/tracker 16.2.0 → 16.2.1
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 +211 -67
- package/dist/cjs/entry.js.map +1 -1
- package/dist/cjs/index.js +211 -67
- 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/lib/entry.js +211 -67
- package/dist/lib/entry.js.map +1 -1
- package/dist/lib/index.js +211 -67
- 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/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/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -4697,11 +4697,52 @@ class IFrameOffsets {
|
|
|
4697
4697
|
|
|
4698
4698
|
var InlineCssMode;
|
|
4699
4699
|
(function (InlineCssMode) {
|
|
4700
|
-
|
|
4701
|
-
InlineCssMode[InlineCssMode["
|
|
4702
|
-
|
|
4703
|
-
InlineCssMode[InlineCssMode["
|
|
4700
|
+
/** default behavior -- will parse and cache the css file on backend */
|
|
4701
|
+
InlineCssMode[InlineCssMode["Disabled"] = 0] = "Disabled";
|
|
4702
|
+
/** will attempt to record the linked css file as AdoptedStyleSheet object */
|
|
4703
|
+
InlineCssMode[InlineCssMode["Inline"] = 1] = "Inline";
|
|
4704
|
+
/** will fetch the file, then simulated AdoptedStyleSheets behavior programmaticaly for the replay */
|
|
4705
|
+
InlineCssMode[InlineCssMode["InlineFetched"] = 2] = "InlineFetched";
|
|
4706
|
+
/** will fetch the file, then save it as plain css inside <style> node */
|
|
4707
|
+
InlineCssMode[InlineCssMode["PlainFetched"] = 3] = "PlainFetched";
|
|
4704
4708
|
})(InlineCssMode || (InlineCssMode = {}));
|
|
4709
|
+
function getInlineOptions(mode) {
|
|
4710
|
+
switch (mode) {
|
|
4711
|
+
case InlineCssMode.Inline:
|
|
4712
|
+
return {
|
|
4713
|
+
inlineRemoteCss: true,
|
|
4714
|
+
inlinerOptions: {
|
|
4715
|
+
forceFetch: false,
|
|
4716
|
+
forcePlain: false,
|
|
4717
|
+
},
|
|
4718
|
+
};
|
|
4719
|
+
case InlineCssMode.InlineFetched:
|
|
4720
|
+
return {
|
|
4721
|
+
inlineRemoteCss: true,
|
|
4722
|
+
inlinerOptions: {
|
|
4723
|
+
forceFetch: true,
|
|
4724
|
+
forcePlain: false,
|
|
4725
|
+
},
|
|
4726
|
+
};
|
|
4727
|
+
case InlineCssMode.PlainFetched:
|
|
4728
|
+
return {
|
|
4729
|
+
inlineRemoteCss: true,
|
|
4730
|
+
inlinerOptions: {
|
|
4731
|
+
forceFetch: true,
|
|
4732
|
+
forcePlain: true,
|
|
4733
|
+
},
|
|
4734
|
+
};
|
|
4735
|
+
case InlineCssMode.Disabled:
|
|
4736
|
+
default:
|
|
4737
|
+
return {
|
|
4738
|
+
inlineRemoteCss: false,
|
|
4739
|
+
inlinerOptions: {
|
|
4740
|
+
forceFetch: false,
|
|
4741
|
+
forcePlain: false,
|
|
4742
|
+
},
|
|
4743
|
+
};
|
|
4744
|
+
}
|
|
4745
|
+
}
|
|
4705
4746
|
const attachShadowNativeFn = IN_BROWSER ? Element.prototype.attachShadow : () => new ShadowRoot();
|
|
4706
4747
|
class TopObserver extends Observer {
|
|
4707
4748
|
constructor(params) {
|
|
@@ -4710,7 +4751,11 @@ class TopObserver extends Observer {
|
|
|
4710
4751
|
disableSprites: false,
|
|
4711
4752
|
inlineCss: 0,
|
|
4712
4753
|
}, params.options);
|
|
4713
|
-
|
|
4754
|
+
const observerOptions = {
|
|
4755
|
+
disableSprites: opts.disableSprites,
|
|
4756
|
+
...getInlineOptions(opts.inlineCss)
|
|
4757
|
+
};
|
|
4758
|
+
super(params.app, true, observerOptions);
|
|
4714
4759
|
this.iframeOffsets = new IFrameOffsets();
|
|
4715
4760
|
this.contextCallbacks = [];
|
|
4716
4761
|
// Attached once per Tracker instance
|
|
@@ -5130,43 +5175,6 @@ function getTimezone() {
|
|
|
5130
5175
|
return `UTC${sign}${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
|
|
5131
5176
|
}
|
|
5132
5177
|
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
5178
|
const proto = {
|
|
5171
5179
|
// ask if there are any tabs alive
|
|
5172
5180
|
ask: 'never-gonna-give-you-up',
|
|
@@ -5198,7 +5206,7 @@ class App {
|
|
|
5198
5206
|
this.stopCallbacks = [];
|
|
5199
5207
|
this.commitCallbacks = [];
|
|
5200
5208
|
this.activityState = ActivityState.NotActive;
|
|
5201
|
-
this.version = '16.2.
|
|
5209
|
+
this.version = '16.2.1'; // TODO: version compatability check inside each plugin.
|
|
5202
5210
|
this.socketMode = false;
|
|
5203
5211
|
this.compressionThreshold = 24 * 1000;
|
|
5204
5212
|
this.bc = null;
|
|
@@ -5521,19 +5529,6 @@ class App {
|
|
|
5521
5529
|
this.onUxtCb = [];
|
|
5522
5530
|
this.contextId = Math.random().toString(36).slice(2);
|
|
5523
5531
|
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
5532
|
this.networkOptions = options.network;
|
|
5538
5533
|
const defaultOptions = {
|
|
5539
5534
|
revID: '',
|
|
@@ -5548,13 +5543,10 @@ class App {
|
|
|
5548
5543
|
__is_snippet: false,
|
|
5549
5544
|
__debug_report_edp: null,
|
|
5550
5545
|
__debug__: LogLevel.Silent,
|
|
5551
|
-
__save_canvas_locally: false,
|
|
5552
5546
|
localStorage: null,
|
|
5553
5547
|
sessionStorage: null,
|
|
5554
5548
|
forceSingleTab: false,
|
|
5555
5549
|
assistSocketHost: '',
|
|
5556
|
-
fixedCanvasScaling: false,
|
|
5557
|
-
disableCanvas: false,
|
|
5558
5550
|
captureIFrames: true,
|
|
5559
5551
|
obscureTextEmails: false,
|
|
5560
5552
|
obscureTextNumbers: false,
|
|
@@ -5592,7 +5584,7 @@ class App {
|
|
|
5592
5584
|
forceNgOff: Boolean(options.forceNgOff),
|
|
5593
5585
|
maintainer: this.options.nodes?.maintainer,
|
|
5594
5586
|
});
|
|
5595
|
-
this.observer = new TopObserver({ app: this, options
|
|
5587
|
+
this.observer = new TopObserver({ app: this, options });
|
|
5596
5588
|
this.ticker = new Ticker(this);
|
|
5597
5589
|
this.ticker.attach(() => this.commit());
|
|
5598
5590
|
this.debug = new Logger(this.options.__debug__);
|
|
@@ -8355,6 +8347,152 @@ function isObject(thing) {
|
|
|
8355
8347
|
return thing !== null && typeof thing === 'object';
|
|
8356
8348
|
}
|
|
8357
8349
|
|
|
8350
|
+
const sensitiveParams = new Set([
|
|
8351
|
+
"password",
|
|
8352
|
+
"pass",
|
|
8353
|
+
"pwd",
|
|
8354
|
+
"mdp",
|
|
8355
|
+
"token",
|
|
8356
|
+
"bearer",
|
|
8357
|
+
"jwt",
|
|
8358
|
+
"api_key",
|
|
8359
|
+
"api-key",
|
|
8360
|
+
"apiKey",
|
|
8361
|
+
"secret",
|
|
8362
|
+
"ssn",
|
|
8363
|
+
"zip",
|
|
8364
|
+
"zipcode",
|
|
8365
|
+
"x-api-key",
|
|
8366
|
+
"www-authenticate",
|
|
8367
|
+
"x-csrf-token",
|
|
8368
|
+
"x-requested-with",
|
|
8369
|
+
"x-forwarded-for",
|
|
8370
|
+
"x-real-ip",
|
|
8371
|
+
"cookie",
|
|
8372
|
+
"authorization",
|
|
8373
|
+
"auth",
|
|
8374
|
+
"proxy-authorization",
|
|
8375
|
+
"set-cookie",
|
|
8376
|
+
"account_key",
|
|
8377
|
+
]);
|
|
8378
|
+
function numDigits(x) {
|
|
8379
|
+
return (Math.log10((x ^ (x >> 31)) - (x >> 31)) | 0) + 1;
|
|
8380
|
+
}
|
|
8381
|
+
function obscure(value) {
|
|
8382
|
+
if (typeof value === "number") {
|
|
8383
|
+
const digits = numDigits(value);
|
|
8384
|
+
return "9".repeat(digits);
|
|
8385
|
+
}
|
|
8386
|
+
if (typeof value === "string") {
|
|
8387
|
+
return value.replace(/[^\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff\s]/g, '*');
|
|
8388
|
+
}
|
|
8389
|
+
return value;
|
|
8390
|
+
}
|
|
8391
|
+
function filterHeaders(headers) {
|
|
8392
|
+
const filteredHeaders = {};
|
|
8393
|
+
if (Array.isArray(headers)) {
|
|
8394
|
+
headers.forEach(({ name, value }) => {
|
|
8395
|
+
if (sensitiveParams.has(name.toLowerCase())) {
|
|
8396
|
+
filteredHeaders[name] = obscure(value);
|
|
8397
|
+
}
|
|
8398
|
+
else {
|
|
8399
|
+
filteredHeaders[name] = value;
|
|
8400
|
+
}
|
|
8401
|
+
});
|
|
8402
|
+
}
|
|
8403
|
+
else {
|
|
8404
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
8405
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8406
|
+
filteredHeaders[key] = obscure(value);
|
|
8407
|
+
}
|
|
8408
|
+
else {
|
|
8409
|
+
filteredHeaders[key] = value;
|
|
8410
|
+
}
|
|
8411
|
+
}
|
|
8412
|
+
}
|
|
8413
|
+
return filteredHeaders;
|
|
8414
|
+
}
|
|
8415
|
+
function filterBody(body) {
|
|
8416
|
+
if (!body) {
|
|
8417
|
+
return body;
|
|
8418
|
+
}
|
|
8419
|
+
let parsedBody;
|
|
8420
|
+
let isJSON = false;
|
|
8421
|
+
try {
|
|
8422
|
+
parsedBody = JSON.parse(body);
|
|
8423
|
+
isJSON = true;
|
|
8424
|
+
}
|
|
8425
|
+
catch (e) {
|
|
8426
|
+
// not json
|
|
8427
|
+
}
|
|
8428
|
+
if (isJSON) {
|
|
8429
|
+
obscureSensitiveData(parsedBody);
|
|
8430
|
+
return JSON.stringify(parsedBody);
|
|
8431
|
+
}
|
|
8432
|
+
else {
|
|
8433
|
+
const isUrlSearch = typeof body === "string" && body.includes("?") && body.includes("=");
|
|
8434
|
+
if (isUrlSearch) {
|
|
8435
|
+
try {
|
|
8436
|
+
const params = new URLSearchParams(body);
|
|
8437
|
+
for (const key of params.keys()) {
|
|
8438
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8439
|
+
const value = obscure(params.get(key));
|
|
8440
|
+
params.set(key, value);
|
|
8441
|
+
}
|
|
8442
|
+
}
|
|
8443
|
+
return params.toString();
|
|
8444
|
+
}
|
|
8445
|
+
catch (e) {
|
|
8446
|
+
// not url query ?
|
|
8447
|
+
return body;
|
|
8448
|
+
}
|
|
8449
|
+
}
|
|
8450
|
+
else {
|
|
8451
|
+
// not json or url query
|
|
8452
|
+
return body;
|
|
8453
|
+
}
|
|
8454
|
+
}
|
|
8455
|
+
}
|
|
8456
|
+
function sanitizeObject(obj) {
|
|
8457
|
+
obscureSensitiveData(obj);
|
|
8458
|
+
return obj;
|
|
8459
|
+
}
|
|
8460
|
+
function obscureSensitiveData(obj) {
|
|
8461
|
+
if (Array.isArray(obj)) {
|
|
8462
|
+
obj.forEach(obscureSensitiveData);
|
|
8463
|
+
}
|
|
8464
|
+
else if (obj && typeof obj === "object") {
|
|
8465
|
+
for (const key in obj) {
|
|
8466
|
+
if (Object.hasOwn(obj, key)) {
|
|
8467
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8468
|
+
obj[key] = obscure(obj[key]);
|
|
8469
|
+
}
|
|
8470
|
+
else if (obj[key] !== null && typeof obj[key] === "object") {
|
|
8471
|
+
obscureSensitiveData(obj[key]);
|
|
8472
|
+
}
|
|
8473
|
+
}
|
|
8474
|
+
}
|
|
8475
|
+
}
|
|
8476
|
+
}
|
|
8477
|
+
function tryFilterUrl(url) {
|
|
8478
|
+
if (!url)
|
|
8479
|
+
return "";
|
|
8480
|
+
try {
|
|
8481
|
+
const urlObj = new URL(url);
|
|
8482
|
+
if (urlObj.searchParams) {
|
|
8483
|
+
for (const key of urlObj.searchParams.keys()) {
|
|
8484
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8485
|
+
urlObj.searchParams.set(key, "******");
|
|
8486
|
+
}
|
|
8487
|
+
}
|
|
8488
|
+
}
|
|
8489
|
+
return urlObj.toString();
|
|
8490
|
+
}
|
|
8491
|
+
catch (e) {
|
|
8492
|
+
return url;
|
|
8493
|
+
}
|
|
8494
|
+
}
|
|
8495
|
+
|
|
8358
8496
|
/**
|
|
8359
8497
|
* I know we're not using most of the information from this class
|
|
8360
8498
|
* but it can be useful in the future if we will decide to display more stuff in our ui
|
|
@@ -8386,13 +8524,18 @@ class NetworkMessage {
|
|
|
8386
8524
|
}
|
|
8387
8525
|
getMessage() {
|
|
8388
8526
|
const { reqHs, resHs } = this.writeHeaders();
|
|
8527
|
+
const reqBody = this.method === 'GET'
|
|
8528
|
+
? JSON.stringify(sanitizeObject(this.getData)) : filterBody(this.requestData);
|
|
8389
8529
|
const request = {
|
|
8390
|
-
headers: reqHs,
|
|
8391
|
-
body:
|
|
8530
|
+
headers: filterHeaders(reqHs),
|
|
8531
|
+
body: reqBody,
|
|
8532
|
+
};
|
|
8533
|
+
const response = {
|
|
8534
|
+
headers: filterHeaders(resHs),
|
|
8535
|
+
body: filterBody(this.response)
|
|
8392
8536
|
};
|
|
8393
|
-
const response = { headers: resHs, body: this.response };
|
|
8394
8537
|
const messageInfo = this.sanitize({
|
|
8395
|
-
url: this.url,
|
|
8538
|
+
url: tryFilterUrl(this.url),
|
|
8396
8539
|
method: this.method,
|
|
8397
8540
|
status: this.status,
|
|
8398
8541
|
request,
|
|
@@ -8708,9 +8851,10 @@ class ResponseProxyHandler {
|
|
|
8708
8851
|
if (typeof this.resp.body.getReader !== 'function') {
|
|
8709
8852
|
return;
|
|
8710
8853
|
}
|
|
8711
|
-
const
|
|
8854
|
+
const clonedResp = this.resp.clone();
|
|
8855
|
+
const _getReader = clonedResp.body.getReader;
|
|
8712
8856
|
// @ts-ignore
|
|
8713
|
-
|
|
8857
|
+
clonedResp.body.getReader = () => {
|
|
8714
8858
|
const reader = _getReader.apply(this.resp.body);
|
|
8715
8859
|
// when readyState is already 4,
|
|
8716
8860
|
// it's not a chunked stream, or it had already been read.
|
|
@@ -9552,7 +9696,7 @@ class API {
|
|
|
9552
9696
|
this.signalStartIssue = (reason, missingApi) => {
|
|
9553
9697
|
const doNotTrack = this.checkDoNotTrack();
|
|
9554
9698
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
9555
|
-
trackerVersion: '16.2.
|
|
9699
|
+
trackerVersion: '16.2.1',
|
|
9556
9700
|
projectKey: this.options.projectKey,
|
|
9557
9701
|
doNotTrack,
|
|
9558
9702
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|