@openreplay/tracker 15.1.3 → 15.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 +223 -56
- package/dist/cjs/entry.js.map +1 -1
- package/dist/cjs/index.js +223 -56
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/main/index.d.ts +2 -0
- package/dist/cjs/main/modules/viewport.d.ts +5 -1
- package/dist/lib/entry.js +223 -56
- package/dist/lib/entry.js.map +1 -1
- package/dist/lib/index.js +223 -56
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/main/index.d.ts +2 -0
- package/dist/lib/main/modules/viewport.d.ts +5 -1
- package/package.json +1 -1
package/dist/lib/index.js
CHANGED
|
@@ -4629,7 +4629,7 @@ class Session {
|
|
|
4629
4629
|
}
|
|
4630
4630
|
}
|
|
4631
4631
|
|
|
4632
|
-
function wrap(callback, n) {
|
|
4632
|
+
function wrap$1(callback, n) {
|
|
4633
4633
|
let t = 0;
|
|
4634
4634
|
return () => {
|
|
4635
4635
|
if (t++ >= n) {
|
|
@@ -4657,7 +4657,7 @@ class Ticker {
|
|
|
4657
4657
|
if (useSafe) {
|
|
4658
4658
|
callback = this.app.safe(callback);
|
|
4659
4659
|
}
|
|
4660
|
-
this.callbacks.unshift(n ? wrap(callback, n) : callback) - 1;
|
|
4660
|
+
this.callbacks.unshift(n ? wrap$1(callback, n) : callback) - 1;
|
|
4661
4661
|
}
|
|
4662
4662
|
start() {
|
|
4663
4663
|
if (this.timer === null) {
|
|
@@ -4733,7 +4733,7 @@ class App {
|
|
|
4733
4733
|
this.stopCallbacks = [];
|
|
4734
4734
|
this.commitCallbacks = [];
|
|
4735
4735
|
this.activityState = ActivityState.NotActive;
|
|
4736
|
-
this.version = '15.1
|
|
4736
|
+
this.version = '15.2.1'; // TODO: version compatability check inside each plugin.
|
|
4737
4737
|
this.socketMode = false;
|
|
4738
4738
|
this.compressionThreshold = 24 * 1000;
|
|
4739
4739
|
this.bc = null;
|
|
@@ -5371,6 +5371,7 @@ class App {
|
|
|
5371
5371
|
}
|
|
5372
5372
|
}
|
|
5373
5373
|
this.emptyBatchCounter = 0;
|
|
5374
|
+
console.log('messages', this.messages.join(', '));
|
|
5374
5375
|
try {
|
|
5375
5376
|
requestIdleCb(() => {
|
|
5376
5377
|
this.messages.unshift(Timestamp(this.timestamp()), TabData(this.session.getTabId()));
|
|
@@ -7528,15 +7529,19 @@ function Scroll (app, insideIframe) {
|
|
|
7528
7529
|
}, 5, false);
|
|
7529
7530
|
}
|
|
7530
7531
|
|
|
7531
|
-
function Viewport (app) {
|
|
7532
|
+
function Viewport (app, options) {
|
|
7532
7533
|
let url, width, height;
|
|
7533
7534
|
let navigationStart;
|
|
7534
7535
|
let referrer = document.referrer;
|
|
7536
|
+
const urlSanitizer = options?.urlSanitizer || ((u) => u);
|
|
7537
|
+
const titleSanitizer = options?.titleSanitizer || ((t) => t);
|
|
7535
7538
|
const sendSetPageLocation = app.safe(() => {
|
|
7536
7539
|
const { URL } = document;
|
|
7537
7540
|
if (URL !== url) {
|
|
7538
7541
|
url = URL;
|
|
7539
|
-
|
|
7542
|
+
const sanitizedURL = urlSanitizer(url);
|
|
7543
|
+
const title = titleSanitizer(document.title);
|
|
7544
|
+
app.send(SetPageLocation(sanitizedURL, referrer, navigationStart, title));
|
|
7540
7545
|
navigationStart = 0;
|
|
7541
7546
|
referrer = url;
|
|
7542
7547
|
}
|
|
@@ -8005,6 +8010,152 @@ function isObject(thing) {
|
|
|
8005
8010
|
return thing !== null && typeof thing === 'object';
|
|
8006
8011
|
}
|
|
8007
8012
|
|
|
8013
|
+
const sensitiveParams = new Set([
|
|
8014
|
+
"password",
|
|
8015
|
+
"pass",
|
|
8016
|
+
"pwd",
|
|
8017
|
+
"mdp",
|
|
8018
|
+
"token",
|
|
8019
|
+
"bearer",
|
|
8020
|
+
"jwt",
|
|
8021
|
+
"api_key",
|
|
8022
|
+
"api-key",
|
|
8023
|
+
"apiKey",
|
|
8024
|
+
"secret",
|
|
8025
|
+
"ssn",
|
|
8026
|
+
"zip",
|
|
8027
|
+
"zipcode",
|
|
8028
|
+
"x-api-key",
|
|
8029
|
+
"www-authenticate",
|
|
8030
|
+
"x-csrf-token",
|
|
8031
|
+
"x-requested-with",
|
|
8032
|
+
"x-forwarded-for",
|
|
8033
|
+
"x-real-ip",
|
|
8034
|
+
"cookie",
|
|
8035
|
+
"authorization",
|
|
8036
|
+
"auth",
|
|
8037
|
+
"proxy-authorization",
|
|
8038
|
+
"set-cookie",
|
|
8039
|
+
"account_key",
|
|
8040
|
+
]);
|
|
8041
|
+
function numDigits(x) {
|
|
8042
|
+
return (Math.log10((x ^ (x >> 31)) - (x >> 31)) | 0) + 1;
|
|
8043
|
+
}
|
|
8044
|
+
function obscure(value) {
|
|
8045
|
+
if (typeof value === "number") {
|
|
8046
|
+
const digits = numDigits(value);
|
|
8047
|
+
return "9".repeat(digits);
|
|
8048
|
+
}
|
|
8049
|
+
if (typeof value === "string") {
|
|
8050
|
+
return value.replace(/[^\f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff\s]/g, '*');
|
|
8051
|
+
}
|
|
8052
|
+
return value;
|
|
8053
|
+
}
|
|
8054
|
+
function filterHeaders(headers) {
|
|
8055
|
+
const filteredHeaders = {};
|
|
8056
|
+
if (Array.isArray(headers)) {
|
|
8057
|
+
headers.forEach(({ name, value }) => {
|
|
8058
|
+
if (sensitiveParams.has(name.toLowerCase())) {
|
|
8059
|
+
filteredHeaders[name] = obscure(value);
|
|
8060
|
+
}
|
|
8061
|
+
else {
|
|
8062
|
+
filteredHeaders[name] = value;
|
|
8063
|
+
}
|
|
8064
|
+
});
|
|
8065
|
+
}
|
|
8066
|
+
else {
|
|
8067
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
8068
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8069
|
+
filteredHeaders[key] = obscure(value);
|
|
8070
|
+
}
|
|
8071
|
+
else {
|
|
8072
|
+
filteredHeaders[key] = value;
|
|
8073
|
+
}
|
|
8074
|
+
}
|
|
8075
|
+
}
|
|
8076
|
+
return filteredHeaders;
|
|
8077
|
+
}
|
|
8078
|
+
function filterBody(body) {
|
|
8079
|
+
if (!body) {
|
|
8080
|
+
return body;
|
|
8081
|
+
}
|
|
8082
|
+
let parsedBody;
|
|
8083
|
+
let isJSON = false;
|
|
8084
|
+
try {
|
|
8085
|
+
parsedBody = JSON.parse(body);
|
|
8086
|
+
isJSON = true;
|
|
8087
|
+
}
|
|
8088
|
+
catch (e) {
|
|
8089
|
+
// not json
|
|
8090
|
+
}
|
|
8091
|
+
if (isJSON) {
|
|
8092
|
+
obscureSensitiveData(parsedBody);
|
|
8093
|
+
return JSON.stringify(parsedBody);
|
|
8094
|
+
}
|
|
8095
|
+
else {
|
|
8096
|
+
const isUrlSearch = typeof body === "string" && body.includes("?") && body.includes("=");
|
|
8097
|
+
if (isUrlSearch) {
|
|
8098
|
+
try {
|
|
8099
|
+
const params = new URLSearchParams(body);
|
|
8100
|
+
for (const key of params.keys()) {
|
|
8101
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8102
|
+
const value = obscure(params.get(key));
|
|
8103
|
+
params.set(key, value);
|
|
8104
|
+
}
|
|
8105
|
+
}
|
|
8106
|
+
return params.toString();
|
|
8107
|
+
}
|
|
8108
|
+
catch (e) {
|
|
8109
|
+
// not url query ?
|
|
8110
|
+
return body;
|
|
8111
|
+
}
|
|
8112
|
+
}
|
|
8113
|
+
else {
|
|
8114
|
+
// not json or url query
|
|
8115
|
+
return body;
|
|
8116
|
+
}
|
|
8117
|
+
}
|
|
8118
|
+
}
|
|
8119
|
+
function sanitizeObject(obj) {
|
|
8120
|
+
obscureSensitiveData(obj);
|
|
8121
|
+
return obj;
|
|
8122
|
+
}
|
|
8123
|
+
function obscureSensitiveData(obj) {
|
|
8124
|
+
if (Array.isArray(obj)) {
|
|
8125
|
+
obj.forEach(obscureSensitiveData);
|
|
8126
|
+
}
|
|
8127
|
+
else if (obj && typeof obj === "object") {
|
|
8128
|
+
for (const key in obj) {
|
|
8129
|
+
if (Object.hasOwn(obj, key)) {
|
|
8130
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8131
|
+
obj[key] = obscure(obj[key]);
|
|
8132
|
+
}
|
|
8133
|
+
else if (obj[key] !== null && typeof obj[key] === "object") {
|
|
8134
|
+
obscureSensitiveData(obj[key]);
|
|
8135
|
+
}
|
|
8136
|
+
}
|
|
8137
|
+
}
|
|
8138
|
+
}
|
|
8139
|
+
}
|
|
8140
|
+
function tryFilterUrl(url) {
|
|
8141
|
+
if (!url)
|
|
8142
|
+
return "";
|
|
8143
|
+
try {
|
|
8144
|
+
const urlObj = new URL(url);
|
|
8145
|
+
if (urlObj.searchParams) {
|
|
8146
|
+
for (const key of urlObj.searchParams.keys()) {
|
|
8147
|
+
if (sensitiveParams.has(key.toLowerCase())) {
|
|
8148
|
+
urlObj.searchParams.set(key, "******");
|
|
8149
|
+
}
|
|
8150
|
+
}
|
|
8151
|
+
}
|
|
8152
|
+
return urlObj.toString();
|
|
8153
|
+
}
|
|
8154
|
+
catch (e) {
|
|
8155
|
+
return url;
|
|
8156
|
+
}
|
|
8157
|
+
}
|
|
8158
|
+
|
|
8008
8159
|
/**
|
|
8009
8160
|
* I know we're not using most of the information from this class
|
|
8010
8161
|
* but it can be useful in the future if we will decide to display more stuff in our ui
|
|
@@ -8036,13 +8187,18 @@ class NetworkMessage {
|
|
|
8036
8187
|
}
|
|
8037
8188
|
getMessage() {
|
|
8038
8189
|
const { reqHs, resHs } = this.writeHeaders();
|
|
8190
|
+
const reqBody = this.method === 'GET'
|
|
8191
|
+
? JSON.stringify(sanitizeObject(this.getData)) : filterBody(this.requestData);
|
|
8039
8192
|
const request = {
|
|
8040
|
-
headers: reqHs,
|
|
8041
|
-
body:
|
|
8193
|
+
headers: filterHeaders(reqHs),
|
|
8194
|
+
body: reqBody,
|
|
8195
|
+
};
|
|
8196
|
+
const response = {
|
|
8197
|
+
headers: filterHeaders(resHs),
|
|
8198
|
+
body: filterBody(this.response)
|
|
8042
8199
|
};
|
|
8043
|
-
const response = { headers: resHs, body: this.response };
|
|
8044
8200
|
const messageInfo = this.sanitize({
|
|
8045
|
-
url: this.url,
|
|
8201
|
+
url: tryFilterUrl(this.url),
|
|
8046
8202
|
method: this.method,
|
|
8047
8203
|
status: this.status,
|
|
8048
8204
|
request,
|
|
@@ -8128,42 +8284,47 @@ const genStringBody = (body) => {
|
|
|
8128
8284
|
return null;
|
|
8129
8285
|
}
|
|
8130
8286
|
let result;
|
|
8131
|
-
|
|
8132
|
-
if (
|
|
8133
|
-
|
|
8287
|
+
try {
|
|
8288
|
+
if (typeof body === 'string') {
|
|
8289
|
+
if (body[0] === '{' || body[0] === '[') {
|
|
8290
|
+
result = body;
|
|
8291
|
+
}
|
|
8292
|
+
// 'a=1&b=2' => try to parse as query
|
|
8293
|
+
const arr = body.split('&');
|
|
8294
|
+
if (arr.length === 1) {
|
|
8295
|
+
// not a query, parse as original string
|
|
8296
|
+
result = body;
|
|
8297
|
+
}
|
|
8298
|
+
else {
|
|
8299
|
+
// 'a=1&b=2&c' => parse as query
|
|
8300
|
+
result = arr.join(',');
|
|
8301
|
+
}
|
|
8134
8302
|
}
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8303
|
+
else if (isIterable(body)) {
|
|
8304
|
+
// FormData or URLSearchParams or Array
|
|
8305
|
+
const arr = [];
|
|
8306
|
+
for (const [key, value] of body) {
|
|
8307
|
+
arr.push(`${key}=${typeof value === 'string' ? value : '[object Object]'}`);
|
|
8308
|
+
}
|
|
8309
|
+
result = arr.join(',');
|
|
8310
|
+
}
|
|
8311
|
+
else if (body instanceof Blob ||
|
|
8312
|
+
body instanceof ReadableStream ||
|
|
8313
|
+
body instanceof ArrayBuffer) {
|
|
8314
|
+
result = 'byte data';
|
|
8315
|
+
}
|
|
8316
|
+
else if (isPureObject(body)) {
|
|
8317
|
+
// overriding ArrayBufferView which is not convertable to string
|
|
8139
8318
|
result = body;
|
|
8140
8319
|
}
|
|
8141
8320
|
else {
|
|
8142
|
-
|
|
8143
|
-
result = arr.join(',');
|
|
8144
|
-
}
|
|
8145
|
-
}
|
|
8146
|
-
else if (isIterable(body)) {
|
|
8147
|
-
// FormData or URLSearchParams or Array
|
|
8148
|
-
const arr = [];
|
|
8149
|
-
for (const [key, value] of body) {
|
|
8150
|
-
arr.push(`${key}=${typeof value === 'string' ? value : '[object Object]'}`);
|
|
8321
|
+
result = `can't parse body ${typeof body}`;
|
|
8151
8322
|
}
|
|
8152
|
-
result
|
|
8153
|
-
}
|
|
8154
|
-
else if (body instanceof Blob ||
|
|
8155
|
-
body instanceof ReadableStream ||
|
|
8156
|
-
body instanceof ArrayBuffer) {
|
|
8157
|
-
result = 'byte data';
|
|
8323
|
+
return result;
|
|
8158
8324
|
}
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
result = body;
|
|
8325
|
+
catch (_) {
|
|
8326
|
+
return "can't parse body";
|
|
8162
8327
|
}
|
|
8163
|
-
else {
|
|
8164
|
-
result = `can't parse body ${typeof body}`;
|
|
8165
|
-
}
|
|
8166
|
-
return result;
|
|
8167
8328
|
};
|
|
8168
8329
|
const genGetDataByUrl = (url, getData = {}) => {
|
|
8169
8330
|
if (!isPureObject(getData)) {
|
|
@@ -8358,9 +8519,10 @@ class ResponseProxyHandler {
|
|
|
8358
8519
|
if (typeof this.resp.body.getReader !== 'function') {
|
|
8359
8520
|
return;
|
|
8360
8521
|
}
|
|
8361
|
-
const
|
|
8522
|
+
const clonedResp = this.resp.clone();
|
|
8523
|
+
const _getReader = clonedResp.body.getReader;
|
|
8362
8524
|
// @ts-ignore
|
|
8363
|
-
|
|
8525
|
+
clonedResp.body.getReader = () => {
|
|
8364
8526
|
const reader = _getReader.apply(this.resp.body);
|
|
8365
8527
|
// when readyState is already 4,
|
|
8366
8528
|
// it's not a chunked stream, or it had already been read.
|
|
@@ -8805,10 +8967,17 @@ class XHRProxy {
|
|
|
8805
8967
|
}
|
|
8806
8968
|
}
|
|
8807
8969
|
|
|
8808
|
-
const
|
|
8970
|
+
const warn = (api) => {
|
|
8809
8971
|
const str = `Openreplay: Can't find ${api} in global context.`;
|
|
8810
8972
|
console.warn(str);
|
|
8811
8973
|
};
|
|
8974
|
+
const OR_FLAG = Symbol('OpenReplayProxyOriginal');
|
|
8975
|
+
const isProxied = (fn) => !!fn && fn[OR_FLAG] !== undefined;
|
|
8976
|
+
const unwrap = (fn) => isProxied(fn) ? fn[OR_FLAG] : fn;
|
|
8977
|
+
const wrap = (proxy, orig) => {
|
|
8978
|
+
proxy[OR_FLAG] = orig;
|
|
8979
|
+
return proxy;
|
|
8980
|
+
};
|
|
8812
8981
|
/**
|
|
8813
8982
|
* Creates network proxies for XMLHttpRequest, fetch, and sendBeacon to intercept and monitor network requests and
|
|
8814
8983
|
* responses.
|
|
@@ -8842,26 +9011,24 @@ function createNetworkProxy(context, ignoredHeaders, setSessionTokenHeader, sani
|
|
|
8842
9011
|
if (!context)
|
|
8843
9012
|
return;
|
|
8844
9013
|
if (modules.xhr) {
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
9014
|
+
const original = unwrap(context.XMLHttpRequest);
|
|
9015
|
+
if (!original)
|
|
9016
|
+
warn('XMLHttpRequest');
|
|
8848
9017
|
else {
|
|
8849
|
-
|
|
9018
|
+
context.XMLHttpRequest = wrap(XHRProxy.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher), original);
|
|
8850
9019
|
}
|
|
8851
9020
|
}
|
|
8852
9021
|
if (modules.fetch) {
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
9022
|
+
const original = unwrap(context.fetch);
|
|
9023
|
+
if (!original)
|
|
9024
|
+
warn('fetch');
|
|
8856
9025
|
else {
|
|
8857
|
-
|
|
9026
|
+
context.fetch = wrap(FetchProxy.create(ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl, tokenUrlMatcher), original);
|
|
8858
9027
|
}
|
|
8859
9028
|
}
|
|
8860
|
-
if (modules.beacon) {
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
context.navigator.sendBeacon = BeaconProxy.create(origBeacon, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl);
|
|
8864
|
-
}
|
|
9029
|
+
if (modules.beacon && ((_a = context.navigator) === null || _a === void 0 ? void 0 : _a.sendBeacon)) {
|
|
9030
|
+
const original = unwrap(context.navigator.sendBeacon);
|
|
9031
|
+
context.navigator.sendBeacon = wrap(BeaconProxy.create(original, ignoredHeaders, setSessionTokenHeader, sanitize, sendMessage, isServiceUrl), original);
|
|
8865
9032
|
}
|
|
8866
9033
|
}
|
|
8867
9034
|
|
|
@@ -9201,7 +9368,7 @@ class API {
|
|
|
9201
9368
|
this.signalStartIssue = (reason, missingApi) => {
|
|
9202
9369
|
const doNotTrack = this.checkDoNotTrack();
|
|
9203
9370
|
console.log("Tracker couldn't start due to:", JSON.stringify({
|
|
9204
|
-
trackerVersion: '15.1
|
|
9371
|
+
trackerVersion: '15.2.1',
|
|
9205
9372
|
projectKey: this.options.projectKey,
|
|
9206
9373
|
doNotTrack,
|
|
9207
9374
|
reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
|
|
@@ -9289,7 +9456,7 @@ class API {
|
|
|
9289
9456
|
this.app = app;
|
|
9290
9457
|
if (!this.crossdomainMode) {
|
|
9291
9458
|
// no need to send iframe viewport data since its a node for us
|
|
9292
|
-
Viewport(app);
|
|
9459
|
+
Viewport(app, options.urls);
|
|
9293
9460
|
// calculated in main window
|
|
9294
9461
|
Connection(app);
|
|
9295
9462
|
// while we can calculate it here, trying to compute it for all parts is hard
|