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