feat(tracker): 3.4.1: uint encoding safety check, log fixes, debug logs

This commit is contained in:
ShiKhu 2021-09-30 21:43:17 +02:00
parent dfe60e5bf3
commit 0fcf9e425a
8 changed files with 50 additions and 29 deletions

View file

@ -1,6 +1,6 @@
{
"name": "@openreplay/tracker",
"version": "3.3.0",
"version": "3.4.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View file

@ -1,7 +1,7 @@
{
"name": "@openreplay/tracker",
"description": "The OpenReplay tracker main package",
"version": "3.4.0",
"version": "3.4.1",
"keywords": [
"logging",
"replay"

View file

@ -1,5 +1,5 @@
import { timestamp, log, warn } from '../utils';
import { Timestamp, TechnicalInfo, PageClose } from '../../messages';
import { Timestamp, PageClose } from '../../messages';
import Message from '../../messages/message';
import Nodes from './nodes';
import Observer from './observer';
@ -24,10 +24,11 @@ export type Options = {
session_pageno_key: string;
local_uuid_key: string;
ingestPoint: string;
resourceBaseHref: string, // resourceHref?
resourceBaseHref: string | null, // resourceHref?
//resourceURLRewriter: (url: string) => string | boolean,
__is_snippet: boolean;
__debug_report_edp: string | null;
__debug_log: boolean;
onStart?: (info: OnStartInfo) => void;
} & ObserverOptions & WebworkerOptions;
@ -67,9 +68,10 @@ export default class App {
session_pageno_key: '__openreplay_pageno',
local_uuid_key: '__openreplay_uuid',
ingestPoint: DEFAULT_INGEST_POINT,
resourceBaseHref: '',
resourceBaseHref: null,
__is_snippet: false,
__debug_report_edp: null,
__debug_log: false,
obscureTextEmails: true,
obscureTextNumbers: false,
captureIFrames: false,
@ -90,10 +92,9 @@ export default class App {
new Blob([`WEBWORKER_BODY`], { type: 'text/javascript' }),
),
);
// this.worker.onerror = e => {
// this.send(new TechnicalInfo("webworker_error", JSON.stringify(e)));
// /* TODO: send report */
// }
this.worker.onerror = e => {
this._debug("webworker_error", e)
}
let lastTs = timestamp();
let fileno = 0;
this.worker.onmessage = ({ data }: MessageEvent) => {
@ -114,11 +115,11 @@ export default class App {
this.attachEventListener(document, 'mouseleave', alertWorker, false, false);
this.attachEventListener(document, 'visibilitychange', alertWorker, false);
} catch (e) {
this.sendDebugReport("worker_start", e);
this._debug("worker_start", e);
}
}
private sendDebugReport(context: string, e: any) {
private _debug(context: string, e: any) {
if(this.options.__debug_report_edp !== null) {
fetch(this.options.__debug_report_edp, {
method: 'POST',
@ -129,6 +130,9 @@ export default class App {
})
});
}
if(this.options.__debug_log) {
warn("OpenReplay errror: ", context, e)
}
}
send(message: Message, urgent = false): void {
@ -160,12 +164,11 @@ export default class App {
try {
fn.apply(this, args);
} catch (e) {
app.send(new TechnicalInfo("error", JSON.stringify({
time: timestamp(),
name: e.name,
message: e.message,
stack: e.stack
})));
this._debug("safe_fn_call", e)
// time: timestamp(),
// name: e.name,
// message: e.message,
// stack: e.stack
}
} as any // TODO: correct typing
}
@ -210,8 +213,10 @@ export default class App {
return this.projectKey
}
getBaseHref(): string {
if (this.options.resourceBaseHref) {
if (typeof this.options.resourceBaseHref === 'string') {
return this.options.resourceBaseHref
} else if (typeof this.options.resourceBaseHref === 'object') {
//switch between types
}
if (document.baseURI) {
return document.baseURI
@ -221,6 +226,12 @@ export default class App {
?.getElementsByTagName("base")[0]
?.getAttribute("href") || location.origin + location.pathname
}
resolveResourceURL(resourceURL: string): string {
const base = new URL(this.getBaseHref())
base.pathname += "/" + new URL(resourceURL).pathname
base.pathname.replace(/\/+/g, "/")
return base.toString()
}
isServiceURL(url: string): boolean {
return url.startsWith(this.options.ingestPoint)
@ -310,7 +321,7 @@ export default class App {
.catch(e => {
this.stop();
warn("OpenReplay was unable to start. ", e)
this.sendDebugReport("session_start", e);
this._debug("session_start", e);
throw e;
})
}

View file

@ -17,7 +17,7 @@ import Scroll from './modules/scroll';
import Viewport from './modules/viewport';
import Longtasks from './modules/longtasks';
import CSSRules from './modules/cssrules';
import { IN_BROWSER, deprecationWarn } from './utils';
import { IN_BROWSER, deprecationWarn, DOCS_HOST } from './utils';
import { Options as AppOptions } from './app';
import { Options as ConsoleOptions } from './modules/console';
@ -41,13 +41,13 @@ const DOCS_SETUP = '/installation/setup-or';
function processOptions(obj: any): obj is Options {
if (obj == null) {
console.error(`OpenReplay: invalid options argument type. Please, check documentation on https://docs.openreplay.com${ DOCS_SETUP }`);
console.error(`OpenReplay: invalid options argument type. Please, check documentation on ${DOCS_HOST}${DOCS_SETUP}`);
return false;
}
if (typeof obj.projectKey !== 'string') {
if (typeof obj.projectKey !== 'number') {
if (typeof obj.projectID !== 'number') { // Back compatability
console.error(`OpenReplay: projectKey is missing or wrong type (string is expected). Please, check https://docs.openreplay.com${ DOCS_SETUP } for more information.`)
console.error(`OpenReplay: projectKey is missing or wrong type (string is expected). Please, check ${DOCS_HOST}${DOCS_SETUP} for more information.`)
return false
} else {
obj.projectKey = obj.projectID.toString();
@ -59,7 +59,7 @@ function processOptions(obj: any): obj is Options {
}
}
if (typeof obj.sessionToken !== 'string' && obj.sessionToken != null) {
console.warn(`OpenReplay: invalid options argument type. Please, check documentation on https://docs.openreplay.com${ DOCS_SETUP }`)
console.warn(`OpenReplay: invalid options argument type. Please, check documentation on ${DOCS_HOST}${DOCS_SETUP}`)
}
return true;
}
@ -70,6 +70,10 @@ export default class API {
if (!IN_BROWSER || !processOptions(options)) {
return;
}
if ((window as any).__OPENREPLAY__) {
console.error("OpenReplay: one tracker instance has been initialised already")
return
}
if (!options.__DISABLE_SECURE_MODE && location.protocol !== 'https:') {
console.error("OpenReplay: Your website must be publicly accessible and running on SSL in order for OpenReplay to properly capture and replay the user session. You can disable this check by setting `__DISABLE_SECURE_MODE` option to `true` if you are testing in localhost. Keep in mind, that asset files on a local machine are not available to the outside world. This might affect tracking if you use css files.")
return;
@ -99,9 +103,9 @@ export default class API {
Performance(this.app, options);
Scroll(this.app);
Longtasks(this.app);
(window as any).__OPENREPLAY__ = (window as any).__OPENREPLAY__ || this;
(window as any).__OPENREPLAY__ = this;
} else {
console.log("OpenReplay: browser doesn't support API required for tracking.")
console.log("OpenReplay: browser doesn't support API required for tracking or doNotTrack is set to 1.")
const req = new XMLHttpRequest();
const orig = options.ingestPoint || DEFAULT_INGEST_POINT;
req.open("POST", orig + "/v1/web/not-started");
@ -133,7 +137,7 @@ export default class API {
start(): void {
if (!IN_BROWSER) {
console.error(`OpenReplay: you are trying to start Tracker on a node.js environment. If you want to use OpenReplay with SSR, please, use componentDidMount or useEffect API for placing the \`tracker.start()\` line. Check documentation on https://docs.openreplay.com${ DOCS_SETUP }`)
console.error(`OpenReplay: you are trying to start Tracker on a node.js environment. If you want to use OpenReplay with SSR, please, use componentDidMount or useEffect API for placing the \`tracker.start()\` line. Check documentation on ${DOCS_HOST}${DOCS_SETUP}`)
return;
}
if (this.app === null) {

View file

@ -123,7 +123,7 @@ export default function (app: App, opts: Partial<Options>): void {
options.consoleMethods.forEach((method) => {
if (consoleMethods.indexOf(method) === -1) {
console.error(`Asayer: unsupported console method ${method}`);
console.error(`OpenReplay: unsupported console method "${method}"`);
return;
}
const fn = (console as any)[method];

View file

@ -21,7 +21,8 @@ export const IN_BROWSER = !(typeof window === "undefined");
export const log = console.log
export const warn = console.warn
const DOCS_HOST = 'https://docs.openreplay.com';
export const DOCS_HOST = 'https://docs.openreplay.com';
const warnedFeatures: { [key: string]: boolean; } = {};
export function deprecationWarn(nameOfFeature: string, useInstead: string, docsPath: string = "/"): void {
if (warnedFeatures[ nameOfFeature ]) {
@ -56,3 +57,4 @@ export function hasOpenreplayAttribute(e: Element, name: string): boolean {
return false;
}

View file

@ -77,6 +77,9 @@ export default class Writer {
return this.offset <= this.size;
}
uint(value: number): boolean {
if (value < 0 || value > Number.MAX_SAFE_INTEGER) {
value = 0
}
while (value >= 0x80) {
this.data[this.offset++] = value % 0x100 | 0x80;
value = Math.floor(value / 128);

View file

@ -49,7 +49,7 @@ function sendBatch(batch: Uint8Array):void {
if (this.status >= 400) { // TODO: test workflow. After 400+ it calls /start for some reason
reset();
sendQueue.length = 0;
if (this.status === 403) { // Unauthorised (Token expired)
if (this.status === 401) { // Unauthorised (Token expired)
self.postMessage("restart")
return
}
@ -74,6 +74,7 @@ function sendBatch(batch: Uint8Array):void {
attemptsCount++;
setTimeout(() => sendBatch(batch), ATTEMPT_TIMEOUT);
}
// TODO: handle offline exception
req.send(batch.buffer);
}