blob: 46f78449ccb56a8e9a36d5312fd1443539e909ad [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the 'License'); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { Settings } from "./types";
let sessionId: string | null = null;
let httpSessionId: string | null = null;
/**
* Extracts the initial configuration settings from the
* currently executing script tag.
* @return {Object} The extracted configuration object
*/
export function getInitialSettings(): Settings.Config {
if (sessionId === null) {
sessionId = getsessionId(
"userAlesessionId",
"session_" + String(Date.now()),
);
}
if (httpSessionId === null) {
httpSessionId = getsessionId(
"userAleHttpSessionId",
generatehttpSessionId(),
);
}
const script =
document.currentScript ||
(function () {
const scripts = document.getElementsByTagName("script");
return scripts[scripts.length - 1];
})();
const get = script
? script.getAttribute.bind(script)
: function () {
return null;
};
const headers = get("data-headers");
const settings: Settings.Config = {
authHeader: get("data-auth") || null,
autostart: get("data-autostart") === "false" ? false : true,
browserSessionId: null,
custIndex: get("data-index") || null,
headers: headers ? JSON.parse(headers) : null,
httpSessionId: httpSessionId,
logCountThreshold: +(get("data-threshold") || 5),
logDetails: get("data-log-details") === "true" ? true : false,
resolution: +(get("data-resolution") || 500),
sessionId: get("data-session") || sessionId,
time: timeStampScale(document.createEvent("CustomEvent")),
toolName: get("data-tool") || null,
toolVersion: get("data-version") || null,
transmitInterval: +(get("data-interval") || 5000),
url: get("data-url") || "http://localhost:8000",
useraleVersion: get("data-userale-version") || null,
userFromParams: get("data-user-from-params") || null,
userId: get("data-user") || null,
};
return settings;
}
/**
* defines sessionId, stores it in sessionStorage, checks to see if there is a sessionId in
* storage when script is started. This prevents events like 'submit', which refresh page data
* from refreshing the current user session
*
*/
export function getsessionId(sessionKey: string, value: any) {
if (window.sessionStorage.getItem(sessionKey) === null) {
window.sessionStorage.setItem(sessionKey, JSON.stringify(value));
return value;
}
return JSON.parse(window.sessionStorage.getItem(sessionKey) || "");
}
/**
* Creates a function to normalize the timestamp of the provided event.
* @param {Event} e An event containing a timeStamp property.
* @return {typeof timeStampScale~tsScaler} The timestamp normalizing function.
*/
export function timeStampScale(e: Event): Settings.TimeFunction {
let tsScaler: Settings.TimeFunction;
if (e.timeStamp && e.timeStamp > 0) {
const delta = Date.now() - e.timeStamp;
/**
* Returns a timestamp depending on various browser quirks.
* @param {?Number} ts A timestamp to use for normalization.
* @return {Number} A normalized timestamp.
*/
if (delta < 0) {
tsScaler = function () {
return e.timeStamp / 1000;
};
} else if (delta > e.timeStamp) {
const navStart = performance.timeOrigin;
tsScaler = function (ts) {
return ts + navStart;
};
} else {
tsScaler = function (ts) {
return ts;
};
}
} else {
tsScaler = function () {
return Date.now();
};
}
return tsScaler;
}
/**
* Creates a cryptographiclly random string to represent this http session.
* @return {String} A random 32 digit hex string
*/
function generatehttpSessionId(): string {
// 32 digit hex -> 128 bits of info -> 2^64 ~= 10^19 sessions needed for 50% chance of collison
const len = 32;
const arr = new Uint8Array(len / 2);
window.crypto.getRandomValues(arr);
return Array.from(arr, (dec) => {
return dec.toString(16).padStart(2, "0");
}).join("");
}