@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/index.js CHANGED
@@ -4697,11 +4697,52 @@ class IFrameOffsets {
4697
4697
 
4698
4698
  var InlineCssMode;
4699
4699
  (function (InlineCssMode) {
4700
- InlineCssMode[InlineCssMode["None"] = 0] = "None";
4701
- InlineCssMode[InlineCssMode["RemoteOnly"] = 1] = "RemoteOnly";
4702
- InlineCssMode[InlineCssMode["RemoteWithForceFetch"] = 2] = "RemoteWithForceFetch";
4703
- InlineCssMode[InlineCssMode["All"] = 3] = "All";
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
- super(params.app, true, opts);
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.0'; // TODO: version compatability check inside each plugin.
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: { ...options, ...this.inlineCss } });
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: this.method === 'GET' ? JSON.stringify(this.getData) : this.requestData,
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 _getReader = this.resp.body.getReader;
8854
+ const clonedResp = this.resp.clone();
8855
+ const _getReader = clonedResp.body.getReader;
8712
8856
  // @ts-ignore
8713
- this.resp.body.getReader = () => {
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.0',
9699
+ trackerVersion: '16.2.1',
9556
9700
  projectKey: this.options.projectKey,
9557
9701
  doNotTrack,
9558
9702
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,