Skip to content

Instantly share code, notes, and snippets.

@gioragutt
Last active November 1, 2019 20:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gioragutt/aac37fa00f8aadd81cd1fd5edf888107 to your computer and use it in GitHub Desktop.
Save gioragutt/aac37fa00f8aadd81cd1fd5edf888107 to your computer and use it in GitHub Desktop.
Reverse engineered HotJar-iframe script, handles analytics action permission handling and passes actions to the parent site.
(function () {
function HtmlStorageWrapper(storage) {
return {
get: function (key) {
const valueFromStorage = JSON.parse(storage.getItem(key));
return !valueFromStorage || Date.parse(valueFromStorage.expires) <= (new Date).getTime()
? (storage.removeItem(key), null)
: valueFromStorage.value
},
set: function (key, value, expiresDate) {
value = {
value: value,
expires: expiresDate.toUTCString()
};
storage.setItem(key, JSON.stringify(value))
},
remove: function (key) {
storage.removeItem(key)
}
}
}
let htmlStorages;
try {
htmlStorages = {
cookie: {
get: function (key) {
return (key = RegExp("(?:^|; )" + key + "=([^;]*)").exec(document.cookie)) ? key[1] : void 0
},
set: function (key, value, expiresInDate) {
document.cookie = key + "=" + value + "; path=/; expires=" + expiresInDate.toUTCString()
},
remove: function (key) {
document.cookie = key + "=; expires=Tue, 13 Mar 1979 00:00:00 UTC; path=/;"
}
},
localStorage: HtmlStorageWrapper(localStorage),
sessionStorage: HtmlStorageWrapper(sessionStorage)
}
} catch (t) {
return
}
function StoredPermission(storageName, readPermissionList, writePermissionList, excludeSiteIdFromStorageKey) {
this.parseCommand = function (eventData, origin) {
const storage = htmlStorages[storageName];
const { action, key, messageId, value, siteId } = eventData;
const storageKey = excludeSiteIdFromStorageKey ? key : key + ":" + siteId;
const expiresInMinutes = eventData.expiresMinutes || 1440 * (eventData.expiresDays || 365);
const expiresDate = function () {
const a = new Date;
a.setTime(a.getTime() + expiresInMinutes * 60 * 1000);
return a;
}();
if (!function () {
const actionToPermissionList = {
_hjSet: writePermissionList,
_hjGet: readPermissionList,
_hjRemove: writePermissionList
}[action] || [];
return 0 <= actionToPermissionList.indexOf("*") ||
0 <= actionToPermissionList.indexOf(origin);
}()) {
throw Error("Command " + action + " not allowed on key: " + key);
}
function bubbleEventToWindowParent() {
const message = JSON.stringify({
messageId: messageId,
value: value || !1
});
window.parent.postMessage(message, "*");
}
switch (action) {
case "_hjSet":
storage.set(storageKey, value, expiresDate);
break;
case "_hjGet":
value = storage.get(storageKey);
bubbleEventToWindowParent();
break;
case "_hjRemove": storage.remove(storageKey);
}
};
}
const permissions = {
_hjOptOut: new StoredPermission("cookie", ["*"], [
"https://www.hotjar.com",
"https://local.hotjar.com",
"http://local.hotjar.com",
"https://insights-staging.hotjar.com",
"http://insights-staging.hotjar.com"
], true),
grant_consent: new StoredPermission("cookie", ["*"], ["*"], false),
screenshot_retake: new StoredPermission("localStorage", ["*"], ["*"], false),
screenshot_active_retake: new StoredPermission("sessionStorage", ["*"], ["*"], false),
form_html: new StoredPermission("localStorage", [
"https://insights.hotjar.com",
"https://insights-stating.hotjar.com",
"https://local.hotjar.com"
], ["*"], true)
};
function handleEvent(event) {
try {
const eventData = JSON.parse(event.data);
eventData.key &&
permissions[eventData.key] &&
permissions[eventData.key].parseCommand(eventData, event.origin)
} catch (c) {
return null
}
}
window.addEventListener
? window.addEventListener("message", handleEvent, false)
: window.attachEvent("onmessage", handleEvent)
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment