Tracking Proxy Helper v1.0
This commit is contained in:
parent
53fcdc02c1
commit
97e1ab9232
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
tmp/
|
||||
desktop.ini
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
.vscode
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
.obsidian
|
||||
.idea
|
||||
.trash
|
||||
54
README.md
54
README.md
@ -1,2 +1,54 @@
|
||||
# tracking-proxy-helper
|
||||
# Tracking Proxy Helper
|
||||
|
||||
## Overview
|
||||
|
||||
The "Tracking Proxy Helper" Chrome Extension provides various functions to manage and monitor Tracking Proxy events. This extension allows setting HTTP headers, injecting JavaScript, and tracking events in real-time.
|
||||
|
||||
## Installation
|
||||
|
||||
1. **Download the project files** or clone the repository.
|
||||
2. **Open Google Chrome** and navigate to `chrome://extensions/`.
|
||||
3. **Enable Developer mode** (top right).
|
||||
4. **Click on "Load unpacked"** and select the folder containing the downloaded files.
|
||||
|
||||
## Usage
|
||||
|
||||
### Popup
|
||||
|
||||
The popup window displays the current status of the Tracking Proxy and lists all captured events.
|
||||
|
||||
- **Account ID:** Displays the current Tracking Proxy ID.
|
||||
- **Events:** Shows a list of events captured by the Tracking Proxy.
|
||||
|
||||
### Options
|
||||
|
||||
Configure the extension settings through the options page.
|
||||
|
||||
1. **HTTP Header for Dev Environment:**
|
||||
- Set the HTTP header name and value.
|
||||
- Add URLs to match for applying the header, with an option to use regex.
|
||||
|
||||
2. **JavaScript Injection and Blocking:**
|
||||
- Specify a URL for JavaScript injection and blocking.
|
||||
- Enter the JavaScript content to inject.
|
||||
- Options to block Google Tag Manager and Tracking Proxy code based on specified criteria.
|
||||
|
||||
### Scripts and Files
|
||||
|
||||
- **content.js:** Injects scripts into the web page and handles messaging between the extension and the web page.
|
||||
- **inject-listener.js:** Listens for specific messages to manage the Tracking Proxy.
|
||||
- **inject-userscript.js:** Injects user scripts into the web page.
|
||||
- **popup.html:** HTML structure for the extension's popup interface.
|
||||
- **popup.js:** JavaScript to handle the logic for the popup interface.
|
||||
- **options.html:** HTML structure for the extension's options page.
|
||||
- **options.js:** JavaScript to handle the logic for the options page.
|
||||
- **worker.js:** Service worker to manage background tasks and event tracking.
|
||||
- **manifest.json:** Defines the extension's metadata, permissions, and configurations.
|
||||
|
||||
## Contributing
|
||||
|
||||
Feel free to contribute by submitting issues or pull requests. For significant changes, please open an issue first to discuss what you would like to change.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License.
|
||||
|
||||
90
content.js
Normal file
90
content.js
Normal file
@ -0,0 +1,90 @@
|
||||
/***** Content JS for Chrome Extension: Tracking Proxy Helper *****/
|
||||
|
||||
/*** Initialisation ***/
|
||||
let tpdm = { activeTabId: null, activeWindowId: null, extInit: false, tpl: { tpId: '', eventCount: 0 } };
|
||||
tpdm.data = tpdm.data || JSON.parse(JSON.stringify(tpdm.tpl));
|
||||
//console.log('content.js loaded');
|
||||
|
||||
/*** Logic ***/
|
||||
|
||||
// Function to inject javascript code into the Page DOM
|
||||
// --> Accessing window object see: https://silverbirder.github.io/en-US/blog/contents/chrome_extension_development_feedback/
|
||||
const injectScript = (filePath, id, tag) => {
|
||||
if (!document.getElementById(id)) {
|
||||
var node = document.getElementsByTagName(tag)[0];
|
||||
var script = document.createElement("script");
|
||||
script.setAttribute("type", "text/javascript");
|
||||
script.setAttribute("src", filePath);
|
||||
script.setAttribute("id", id);
|
||||
node.appendChild(script);
|
||||
}
|
||||
};
|
||||
|
||||
// Listener to receive messages from the injected script
|
||||
window.addEventListener('message', function(event) {
|
||||
//console.log('Message received from injected script:', event);
|
||||
if (event.data.type === 'CHECK_TPT_RESULT') {
|
||||
//console.log('Message received from injected script:', event);
|
||||
chrome.runtime.sendMessage({ type: 'CHECK_TPT', hasTPT: event.data.hasTPT, tpobj:event.data.tpobj });
|
||||
}
|
||||
if (event.data.type === 'TRACKING_PROXY_RESPONSE') {
|
||||
//console.log('Message received from injected TP script:', event);
|
||||
const eventData = event.data.details.eventData;
|
||||
const metaData = event.data.details.metaData;
|
||||
chrome.runtime.sendMessage({ type: 'TRACKING_PROXY_EVENT', details: { eventData:eventData, metaData:metaData } });
|
||||
}
|
||||
});
|
||||
|
||||
// Listener for messages from the background script
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
if (message.type === 'TRACKING_PROXY_REQUEST') {
|
||||
window.postMessage({ type: 'TRACKING_PROXY_REDIRECT', details: message.details }, '*');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inject script on document load
|
||||
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
||||
injectScript(chrome.runtime.getURL("inject-listener.js"), "tp_dev_mode_script", "head");
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
injectScript(chrome.runtime.getURL("inject-listener.js"), "tp_dev_mode_script", "head");
|
||||
});
|
||||
}
|
||||
|
||||
chrome.storage.sync.get(['scriptContent', 'scriptUrl', 'scriptUrlIsRegex'], function(data) {
|
||||
const scriptContent = data.scriptContent || '';
|
||||
const scriptUrl = data.scriptUrl || '';
|
||||
const scriptUrlIsRegex = data.scriptUrlIsRegex || false;
|
||||
|
||||
if (!scriptUrl || !scriptContent) {
|
||||
//console.log('No script URL or script content defined, no script injected');
|
||||
return;
|
||||
}
|
||||
|
||||
let urlMatches;
|
||||
if (scriptUrlIsRegex) {
|
||||
const regex = new RegExp(scriptUrl);
|
||||
urlMatches = regex.test(window.location.href);
|
||||
} else {
|
||||
urlMatches = window.location.href.includes(scriptUrl);
|
||||
}
|
||||
|
||||
if (urlMatches) {
|
||||
if (!document.getElementById('tp_user_script')) {
|
||||
//console.log(`Injecting script into URL: ${window.location.href}`);
|
||||
const script = document.createElement('script');
|
||||
script.src = chrome.runtime.getURL('inject-userscript.js');
|
||||
script.setAttribute("id", "tp_user_script");
|
||||
(document.head || document.documentElement).appendChild(script);
|
||||
script.onload = function() {
|
||||
window.postMessage({ type: 'INJECT_USER_SCRIPT', scriptContent: scriptContent }, '*');
|
||||
script.remove();
|
||||
};
|
||||
}
|
||||
} else {
|
||||
//console.log(`URL does not match, no script injected for URL ${window.location.href}`);
|
||||
}
|
||||
});
|
||||
|
||||
// EOF
|
||||
BIN
img/icon_48.png
Normal file
BIN
img/icon_48.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
110
inject-listener.js
Normal file
110
inject-listener.js
Normal file
@ -0,0 +1,110 @@
|
||||
// inject-listener.js
|
||||
//console.log('Injected listener loaded');
|
||||
|
||||
window.addEventListener('message', function(event) {
|
||||
if (!event.data || !event.data.type || !event.data.details) return;
|
||||
//console.log('TRACKING_PROXY_REQUEST message 1', event.data);
|
||||
if (event.data.type === 'TRACKING_PROXY_REDIRECT') {
|
||||
//console.log('TRACKING_PROXY_REQUEST message 2', event);
|
||||
const eventData = event.data.details.eventData;
|
||||
const metaData = event.data.details.metaData;
|
||||
if (eventData.cid && window.__tpt && eventData.cid === window.__tpt.cid) {
|
||||
//console.log('Tracking Proxy Event detected:', event);
|
||||
window.postMessage({ type: 'TRACKING_PROXY_RESPONSE', details: { eventData:eventData, metaData:metaData } }, '*');
|
||||
} else {
|
||||
//console.log('No matching cid found in request body', details);
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
|
||||
// Function to post messages
|
||||
function sendTPmsg(o){
|
||||
window.postMessage(o, '*');
|
||||
}
|
||||
|
||||
function getTPDetails() {
|
||||
return window.__tpt ? JSON.parse(JSON.stringify(window.__tpt)) : {};
|
||||
}
|
||||
|
||||
// Function to check for TP and send message if available
|
||||
function checkTPT() {
|
||||
const tpDetails = getTPDetails();
|
||||
sendTPmsg({ type: 'CHECK_TPT_RESULT', hasTPT: !!tpDetails.cid, tpobj: tpDetails });
|
||||
}
|
||||
|
||||
// Proxy handler to detect changes
|
||||
const handler = {
|
||||
set(target, property, value) {
|
||||
target[property] = value;
|
||||
//console.log(`Property ${property} changed to`, value);
|
||||
if (property === 'cid') {
|
||||
checkTPT();
|
||||
}
|
||||
return true;
|
||||
},
|
||||
get(target, property) {
|
||||
return target[property];
|
||||
}
|
||||
};
|
||||
|
||||
// Wrap the __tpt object with a Proxy
|
||||
if (window.__tpt) {
|
||||
window.__tpt = new Proxy(window.__tpt, handler);
|
||||
} else {
|
||||
Object.defineProperty(window, '__tpt', {
|
||||
set(value) {
|
||||
if (value && typeof value === 'object') {
|
||||
value = new Proxy(value, handler);
|
||||
}
|
||||
Object.defineProperty(this, '__tpt', { value, writable: true, configurable: true, enumerable: true });
|
||||
checkTPT();
|
||||
},
|
||||
configurable: true,
|
||||
enumerable: true
|
||||
});
|
||||
}
|
||||
|
||||
function exposeTPT() {
|
||||
if (!window.__tpt) {
|
||||
//console.log('No __tpt object found.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Deep clone the object to break references
|
||||
const tpDetails = JSON.parse(JSON.stringify(window.__tpt));
|
||||
//console.log('Current TP details:', tpDetails);
|
||||
} catch (error) {
|
||||
//console.error('Error exposing __tpt details:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Expose the function to global scope for easy access from the console
|
||||
window.exposeTPT = exposeTPT;
|
||||
|
||||
/*
|
||||
(function() {
|
||||
let tpid = '';
|
||||
//console.log("inject.js loaded");
|
||||
function checkTPT() {
|
||||
if (!window.__tpt) return;
|
||||
let tpobj = JSON.parse(JSON.stringify(window.__tpt));
|
||||
console.log('checkTPT result:', tpobj);
|
||||
if (!tpobj.cid) return;
|
||||
window.postMessage({ type: 'CHECK_TPT_RESULT', tpobj:tpobj }, '*');
|
||||
}
|
||||
// Überprüfe sofort
|
||||
checkTPT();
|
||||
// Wiederhole die Überprüfung nach einer kurzen Verzögerung, um sicherzustellen, dass das Objekt geladen ist
|
||||
const observer = new MutationObserver((mutations, observer) => {
|
||||
if (window.__tpt && window.__tpt.cid) {
|
||||
//console.log('TP is now available');
|
||||
checkTPT();
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
// Starten des MutationObserver
|
||||
if (!window.__tpt && !window.__tpt.cid) observer.observe(document.documentElement, { childList: true, subtree: true });
|
||||
//console.log('injected listener executed');
|
||||
})();
|
||||
*/
|
||||
15
inject-userscript.js
Normal file
15
inject-userscript.js
Normal file
@ -0,0 +1,15 @@
|
||||
// inject-userscript.js
|
||||
//console.log('Injected userscript executed');
|
||||
|
||||
window.addEventListener('message', function(event) {
|
||||
if (event.source !== window || !event.data || event.data.type !== 'INJECT_USER_SCRIPT') return;
|
||||
const scriptContent = event.data.scriptContent;
|
||||
if (scriptContent) {
|
||||
const script = document.createElement('script');
|
||||
script.textContent = scriptContent;
|
||||
(document.head || document.documentElement).appendChild(script);
|
||||
script.onload = function () {
|
||||
script.remove();
|
||||
};
|
||||
}
|
||||
}, false);
|
||||
73
manifest.json
Normal file
73
manifest.json
Normal file
@ -0,0 +1,73 @@
|
||||
/***** Manifest for Chrome Extension: Tracking Proxy Helper *****/
|
||||
|
||||
// Doku Manifest: https://developer.chrome.com/docs/extensions/reference/manifest?hl=de
|
||||
// Doku Extension API: https://developer.chrome.com/docs/extensions/reference/api/?hl=de
|
||||
// Very helpful: https://silverbirder.github.io/en-US/blog/contents/chrome_extension_development_feedback/
|
||||
// Example Extensions: https://developer.chrome.com/docs/extensions/samples?hl=de
|
||||
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Tracking Proxy Helper",
|
||||
"author": "andi@tracking-garden.com",
|
||||
"version": "1.0",
|
||||
"description": "This extension gives some information and options using the Tracking Proxy.",
|
||||
"icons": {
|
||||
//"16": "/img/get_started16.png",
|
||||
//"32": "/img/get_started32.png",
|
||||
"48": "/img/icon_48.png"
|
||||
//"128": "/img/get_started128.png"
|
||||
},
|
||||
//"default_locale": "en_US",
|
||||
"background": {
|
||||
"service_worker": "worker.js"
|
||||
},
|
||||
//"externally_connectable": {
|
||||
// "matches": ["*://*/*"]
|
||||
//},
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"declarativeNetRequest",
|
||||
"declarativeNetRequestFeedback",
|
||||
"declarativeNetRequestWithHostAccess",
|
||||
"scripting",
|
||||
"storage",
|
||||
"tabs",
|
||||
"webNavigation",
|
||||
"webRequest",
|
||||
//"webRequestBlocking",
|
||||
"userScripts"
|
||||
],
|
||||
//"optional_permissions": ["topSites"],
|
||||
//"content_security_policy": {
|
||||
// "extension_pages": "default-src 'self' 'wasm-unsafe-eval'"
|
||||
//}
|
||||
"host_permissions": [
|
||||
"*://*/*"
|
||||
],
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["*://*/*"],
|
||||
//"matches": ["<all_urls>"],
|
||||
"js": ["content.js"/*,"inject.js"*/]
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"matches": ["*://*/*"],
|
||||
"resources": ["inject-listener.js","inject-userscript.js"]
|
||||
}
|
||||
],
|
||||
"action": {
|
||||
"default_popup": "popup.html",
|
||||
"default_title": "Tracking Proxy - Dev Mode",
|
||||
"default_icon": {
|
||||
//"16": "/img/get_started16.png",
|
||||
//"32": "/img/get_started32.png",
|
||||
"48": "/img/icon_48.png"
|
||||
//"128": "/img/get_started128.png"
|
||||
}
|
||||
},
|
||||
"options_page": "options.html"
|
||||
}
|
||||
|
||||
// EOF
|
||||
102
options.css
Normal file
102
options.css
Normal file
@ -0,0 +1,102 @@
|
||||
/***** Options CSS for Chrome Extension: Tracking Proxy Helper *****/
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
background-color: #382d3d; /* Hintergrundfarbe der Seite */
|
||||
color: white; /* Allgemeine Textfarbe */
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 20px;
|
||||
color: #fe6845; /* Farbe für H1 Überschriften */
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
margin-top: 20px;
|
||||
color: #382d3d; /* Farbe für H2 Überschriften */
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 20px;
|
||||
margin-top: 20px;
|
||||
color: white; /* Farbe für H3 Überschriften */
|
||||
}
|
||||
|
||||
.section {
|
||||
background-color: #eeeeee; /* Hintergrundfarbe der Kästen */
|
||||
border: 1px solid #000000;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
color: #382d3d; /* Farbe der Labels */
|
||||
}
|
||||
|
||||
input[type="text"],
|
||||
textarea {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff; /* Hintergrund der Eingabefelder */
|
||||
color: #000; /* Textfarbe in Eingabefeldern */
|
||||
border: 1px solid #ccc; /* Rahmen der Eingabefelder */
|
||||
}
|
||||
|
||||
.url-field {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.url-input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.regex-checkbox {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.inline-checkbox {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 10px 15px;
|
||||
background-color: #fe6845;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.remove-url-field {
|
||||
background-color: #382d3d;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
button#add-url-field {
|
||||
background-color: #382d3d;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.url-match-label {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
margin-top: 15px;
|
||||
color: #382d3d; /* Farbe für URL Match Labels */
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
82
options.html
Normal file
82
options.html
Normal file
@ -0,0 +1,82 @@
|
||||
<!----- Options HTML for Chrome Extension: Tracking Proxy Helper ----->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tracking Proxy Helper - Extension Options</title>
|
||||
<link rel="stylesheet" href="options.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Tracking Proxy Helper Settings</h1>
|
||||
<form id="options-form">
|
||||
<div class="section" id="httpheader">
|
||||
<h2>HTTP Header for Dev.Environment</h2>
|
||||
<p class="url-match-label">Notice: The HTTP Header Name is: <strong>Tp-Dev</strong></p>
|
||||
<div class="form-group">
|
||||
<label for="header-value">HTTP Header Value:</label>
|
||||
<input type="text" id="header-value" name="header-value">
|
||||
</div>
|
||||
<strong class="url-match-label">URLs to match:</strong>
|
||||
<div id="url-fields-container">
|
||||
<div class="url-field">
|
||||
<input type="text" class="url-input" name="url[]">
|
||||
<label>
|
||||
<input type="checkbox" class="regex-checkbox"> Is Regex
|
||||
</label>
|
||||
<button type="button" class="remove-url-field">Remove</button>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" id="add-url-field">Add URL Field</button>
|
||||
</div>
|
||||
<div class="section" id="blocking">
|
||||
<h2>JavaScript Injection and Blocking</h2>
|
||||
<div class="form-group">
|
||||
<label for="script-url">URL for JavaScript Injection and Blocking:</label>
|
||||
<div class="url-field">
|
||||
<input type="text" id="script-url" name="script-url">
|
||||
<label class="inline-checkbox">
|
||||
<input type="checkbox" id="script-url-regex"> Is Regex
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="script-content">JavaScript to Inject:</label>
|
||||
<textarea id="script-content" name="script-content" rows="4"></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="block-gtm"> Block Google Tag Manager
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="gtm-container-id">Google Tag Manager Container ID:</label>
|
||||
<div class="url-field">
|
||||
<input type="text" id="gtm-container-id" name="gtm-container-id">
|
||||
<label class="inline-checkbox">
|
||||
<input type="checkbox" id="gtm-container-id-regex"> Is Regex
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>
|
||||
<input type="checkbox" id="block-tracking-proxy"> Block Tracking Proxy Code
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="tracking-proxy-url">URL for Tracking Proxy:</label>
|
||||
<div class="url-field">
|
||||
<input type="text" id="tracking-proxy-url" name="tracking-proxy-url">
|
||||
<label class="inline-checkbox">
|
||||
<input type="checkbox" id="tracking-proxy-url-regex"> Is Regex
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit">Save</button>
|
||||
</form>
|
||||
<h3>Saved Values</h3>
|
||||
<pre id="saved-values"></pre>
|
||||
<script src="options.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
151
options.js
Normal file
151
options.js
Normal file
@ -0,0 +1,151 @@
|
||||
/***** Options JS for Chrome Extension: Tracking Proxy Helper *****/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const form = document.getElementById('options-form');
|
||||
const addUrlButton = document.getElementById('add-url-field');
|
||||
const urlFieldsContainer = document.getElementById('url-fields-container');
|
||||
const savedValuesContainer = document.getElementById('saved-values');
|
||||
|
||||
// Add event listener for adding URL fields
|
||||
addUrlButton.addEventListener('click', function () {
|
||||
const urlField = createUrlField();
|
||||
urlFieldsContainer.appendChild(urlField);
|
||||
});
|
||||
|
||||
// Load saved options
|
||||
loadOptions();
|
||||
|
||||
// Save options on form submit
|
||||
form.addEventListener('submit', function (event) {
|
||||
event.preventDefault();
|
||||
saveOptions();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Create a new URL field element
|
||||
* @returns {HTMLDivElement} The created URL field element
|
||||
*/
|
||||
function createUrlField() {
|
||||
const urlField = document.createElement('div');
|
||||
urlField.className = 'url-field';
|
||||
urlField.innerHTML = `
|
||||
<input type="text" class="url-input" name="url[]">
|
||||
<label>
|
||||
<input type="checkbox" class="regex-checkbox"> Is Regex
|
||||
</label>
|
||||
<button type="button" class="remove-url-field">Remove</button>
|
||||
`;
|
||||
|
||||
// Add event listener for removing URL fields
|
||||
urlField.querySelector('.remove-url-field').addEventListener('click', function () {
|
||||
urlField.remove();
|
||||
});
|
||||
|
||||
return urlField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save options to chrome.storage.sync
|
||||
*/
|
||||
function saveOptions() {
|
||||
const headerValue = document.getElementById('header-value').value;
|
||||
const urlFields = document.querySelectorAll('#httpheader .url-field'); // Only URL fields
|
||||
const urls = Array.from(urlFields).map(urlField => {
|
||||
const urlInput = urlField.querySelector('.url-input');
|
||||
const regexCheckbox = urlField.querySelector('.regex-checkbox');
|
||||
|
||||
// Ensure that the inputs exist
|
||||
if (!urlInput || !regexCheckbox) {
|
||||
console.error('Invalid URL field:', urlField);
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
url: urlInput.value,
|
||||
isRegex: regexCheckbox.checked
|
||||
};
|
||||
}).filter(urlObj => urlObj !== null); // Remove null entries
|
||||
|
||||
const scriptContent = document.getElementById('script-content').value;
|
||||
const scriptUrl = document.getElementById('script-url').value;
|
||||
const scriptUrlIsRegex = document.getElementById('script-url-regex').checked;
|
||||
const blockGtm = document.getElementById('block-gtm').checked;
|
||||
const gtmContainerId = document.getElementById('gtm-container-id').value;
|
||||
const gtmContainerIdIsRegex = document.getElementById('gtm-container-id-regex').checked;
|
||||
const trackingProxyUrl = document.getElementById('tracking-proxy-url').value;
|
||||
const trackingProxyUrlIsRegex = document.getElementById('tracking-proxy-url-regex').checked;
|
||||
const blockTrackingProxy = document.getElementById('block-tracking-proxy').checked;
|
||||
|
||||
chrome.storage.sync.set({
|
||||
headerValue,
|
||||
urls,
|
||||
scriptContent,
|
||||
scriptUrl,
|
||||
scriptUrlIsRegex,
|
||||
blockGtm,
|
||||
gtmContainerId,
|
||||
gtmContainerIdIsRegex,
|
||||
trackingProxyUrl,
|
||||
trackingProxyUrlIsRegex,
|
||||
blockTrackingProxy
|
||||
}, function () {
|
||||
alert('Options saved!');
|
||||
displaySavedValues(); // Update displayed saved values
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load options from chrome.storage.sync
|
||||
*/
|
||||
function loadOptions() {
|
||||
chrome.storage.sync.get([
|
||||
'headerValue',
|
||||
'urls',
|
||||
'scriptContent',
|
||||
'scriptUrl',
|
||||
'scriptUrlIsRegex',
|
||||
'blockGtm',
|
||||
'gtmContainerId',
|
||||
'gtmContainerIdIsRegex',
|
||||
'trackingProxyUrl',
|
||||
'trackingProxyUrlIsRegex',
|
||||
'blockTrackingProxy'
|
||||
], function (data) {
|
||||
document.getElementById('header-value').value = data.headerValue || '';
|
||||
|
||||
const urlFieldsContainer = document.getElementById('url-fields-container');
|
||||
urlFieldsContainer.innerHTML = '';
|
||||
|
||||
(data.urls || []).forEach(urlObj => {
|
||||
const urlField = createUrlField();
|
||||
urlField.querySelector('.url-input').value = urlObj.url;
|
||||
urlField.querySelector('.regex-checkbox').checked = urlObj.isRegex;
|
||||
urlFieldsContainer.appendChild(urlField);
|
||||
});
|
||||
|
||||
document.getElementById('script-content').value = data.scriptContent || '';
|
||||
document.getElementById('script-url').value = data.scriptUrl || '';
|
||||
document.getElementById('script-url-regex').checked = data.scriptUrlIsRegex || false;
|
||||
document.getElementById('block-gtm').checked = data.blockGtm || false;
|
||||
document.getElementById('gtm-container-id').value = data.gtmContainerId || '';
|
||||
document.getElementById('gtm-container-id-regex').checked = data.gtmContainerIdIsRegex || false;
|
||||
document.getElementById('tracking-proxy-url').value = data.trackingProxyUrl || '';
|
||||
document.getElementById('tracking-proxy-url-regex').checked = data.trackingProxyUrlIsRegex || false;
|
||||
document.getElementById('block-tracking-proxy').checked = data.blockTrackingProxy || false;
|
||||
|
||||
displaySavedValues(); // Display saved values on load
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Display saved values in a <pre> element
|
||||
*/
|
||||
function displaySavedValues() {
|
||||
chrome.storage.sync.get(null, function(items) {
|
||||
const savedValuesContainer = document.getElementById('saved-values');
|
||||
savedValuesContainer.textContent = JSON.stringify(items, null, 2);
|
||||
});
|
||||
}
|
||||
|
||||
// EOF
|
||||
114
popup.css
Normal file
114
popup.css
Normal file
@ -0,0 +1,114 @@
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #382d3d;
|
||||
color: #ffffff;
|
||||
margin: 0;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
/* Stil für den Event-Kasten */
|
||||
details {
|
||||
background-color: #eeeeee; /* Helles Grau für den zusammengeklappten Zustand */
|
||||
margin-bottom: 5px; /* Abstand zwischen den Event-Kästen */
|
||||
border-radius: 5px; /* Abgerundete Ecken */
|
||||
padding: 5px; /* Innenabstand innerhalb des details Elements */
|
||||
border: 1px solid #ccc; /* Leichter Rahmen um das Element */
|
||||
}
|
||||
|
||||
/* Stil für den aufklappbaren Teil des Event-Kastens */
|
||||
summary {
|
||||
font-weight: bold;
|
||||
color: #382d3d; /* Dunkle Schrift für den Event-Titel */
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
pre {
|
||||
background-color: #ffffff; /* Weißer Hintergrund für JSON-Inhalte */
|
||||
color: #382d3d; /* Dunkle Schriftfarbe für JSON-Inhalte */
|
||||
border: none; /* Entfernt jeglichen Rahmen */
|
||||
overflow-x: auto; /* Ermöglicht horizontales Scrollen bei langen Zeilen */
|
||||
white-space: pre-wrap; /* Ermöglicht den Zeilenumbruch bei Bedarf */
|
||||
padding: 5px; /* Innenabstand für bessere Lesbarkeit */
|
||||
}
|
||||
|
||||
/* Farben und Stil für die Eigenschaftsnamen innerhalb des JSON-Objekts */
|
||||
.json-property-name {
|
||||
color: #fe6845; /* Farbe für die Eigenschaftsnamen */
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Stil für die Werte innerhalb des JSON-Objekts, wenn benötigt */
|
||||
.json-property-value {
|
||||
color: #382d3d;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
background: #382d3d;
|
||||
padding: 5px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-weight: bold;
|
||||
color: #fe6845;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.events {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.event-details {
|
||||
color: #382d3d;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.event-details summary {
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
color: #382d3d; /* Dunkelviolett für Event-Namen */
|
||||
}
|
||||
|
||||
.event-details pre {
|
||||
background: #fff;
|
||||
color: #382d3d;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
overflow: auto;
|
||||
max-height: 200px;
|
||||
font-family: monospace; /* Schriftart für bessere Lesbarkeit von JSON */
|
||||
}
|
||||
|
||||
.event-details pre .key {
|
||||
color: #fe6845; /* Orange für JSON-Schlüssel/Eigenschaftsnamen */
|
||||
}
|
||||
|
||||
.event-details pre .string, .event-details pre .number {
|
||||
color: #382d3d; /* Dunkelviolett für Werte im JSON */
|
||||
}
|
||||
|
||||
#options-link {
|
||||
position: absolute; /* Absolut positioniert, relativ zum nächstgelegenen positionierten Vorfahren */
|
||||
top: 5px; /* Abstand von oben */
|
||||
right: 5px; /* Abstand von rechts */
|
||||
color: #ccc7aa; /* Linkfarbe */
|
||||
padding: 5px 5px;
|
||||
border-radius: 5px;
|
||||
text-decoration: none;
|
||||
font-weight: normal; /* Entfernt fettgedrucktes Styling */
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
#options-link:hover {
|
||||
background-color: #fe6845;
|
||||
color: #382d3d;
|
||||
}
|
||||
20
popup.html
Normal file
20
popup.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tracking Proxy Helper</title>
|
||||
<link rel="stylesheet" href="popup.css">
|
||||
<script src="popup.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<a href="#" id="options-link">Settings</a>
|
||||
<div class="container">
|
||||
<p><span class="label">Account ID:</span> <span id="tp-id" class="value">No Tracking Proxy detected</span></p>
|
||||
<p>
|
||||
<span class="label">Events:</span>
|
||||
<div id="events" class="events"></div>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
55
popup.js
Normal file
55
popup.js
Normal file
@ -0,0 +1,55 @@
|
||||
/***** Popup JS for Chrome Extension: Tracking Proxy Helper *****/
|
||||
|
||||
//function test(o){
|
||||
// chrome.runtime.sendMessage({ type: 'REQUEST_POPUP_DATA2',details:typeof o=='object'?JSON.parse(JSON.stringify(o)):null,test:123 });
|
||||
//}
|
||||
|
||||
function syntaxHighlight(json) {
|
||||
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
return json.replace(/("(\\u[\dA-F]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
|
||||
let cls = 'number';
|
||||
if (/^"/.test(match)) {
|
||||
if (/:$/.test(match)) {
|
||||
cls = 'key'; // Anwenden der CSS-Klasse 'key' auf JSON Schlüssel
|
||||
} else {
|
||||
cls = 'string';
|
||||
}
|
||||
} else if (/true|false/.test(match)) {
|
||||
cls = 'boolean';
|
||||
} else if (/null/.test(match)) {
|
||||
cls = 'null';
|
||||
}
|
||||
return '<span class="' + cls + '">' + match + '</span>';
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize popup with Tracking Proxy Events
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const tpIdElement = document.getElementById('tp-id');
|
||||
const eventsElement = document.getElementById('events');
|
||||
|
||||
chrome.runtime.sendMessage({ type: 'REQUEST_POPUP_DATA' }, function(response) {
|
||||
//test(response);
|
||||
if (typeof response=='object') {
|
||||
const tpId = response.tpId || 'Not Available';
|
||||
tpIdElement.textContent = tpId;
|
||||
const events = response.events || [];
|
||||
eventsElement.innerHTML = events.map((event, index) => `
|
||||
<details class="event-details">
|
||||
<summary>${event.event}</summary>
|
||||
<pre>${syntaxHighlight(JSON.stringify(event, null, 2))}</pre>
|
||||
</details>
|
||||
`).join('');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('options-link').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
// Öffnet die Options-Seite
|
||||
if (chrome.runtime.openOptionsPage) {
|
||||
chrome.runtime.openOptionsPage();
|
||||
} else {
|
||||
window.open(chrome.runtime.getURL('options.html'));
|
||||
}
|
||||
});
|
||||
323
worker.js
Normal file
323
worker.js
Normal file
@ -0,0 +1,323 @@
|
||||
/***** Service Worker JS for Chrome Extension: Tracking Proxy Helper *****/
|
||||
|
||||
/*** Initialisation ***/
|
||||
let tpdm = { activeTabId: null, activeWindowId: null, extInit: false, tpl: { tpId:'', eventCount:0, events:[] } };
|
||||
//tpdm.data = tpdm.data || JSON.parse(JSON.stringify(tpdm.tpl));
|
||||
tpdm.data = tpdm.data || {};
|
||||
//console.log('Worker loaded');
|
||||
|
||||
/*** Helper Function Library ***/
|
||||
|
||||
/**
|
||||
* Function to Update the Badge Text
|
||||
*/
|
||||
function updateBadge(text, tabId) {
|
||||
chrome.action.setBadgeBackgroundColor({ color: '#fe6845', tabId: tabId });
|
||||
chrome.action.setBadgeTextColor({ color: '#ffffff', tabId: tabId });
|
||||
chrome.action.setBadgeText({ text: text.toString(), tabId: tabId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to Clear the Badge
|
||||
*/
|
||||
function clearBadge(tabId) {
|
||||
chrome.action.setBadgeText({ text: '', tabId: tabId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to Reset the Badge Text
|
||||
*/
|
||||
function resetBadge(tabId) {
|
||||
if (typeof tpdm.data[tabId]!='object') tpdm.data[tabId] = JSON.parse(JSON.stringify(tpdm.tpl));
|
||||
tpdm.data[tabId] = JSON.parse(JSON.stringify(tpdm.tpl));
|
||||
clearBadge(tabId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to Increment Badge Counter
|
||||
*/
|
||||
function incrementBadge(tabId) {
|
||||
if (typeof tpdm.data[tabId]!='object') tpdm.data[tabId] = JSON.parse(JSON.stringify(tpdm.tpl));
|
||||
tpdm.data[tabId].eventCount += 1;
|
||||
updateBadge(tpdm.data[tabId].eventCount, tabId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get the current active tab ID
|
||||
*/
|
||||
function getCurrentTabId(callback) {
|
||||
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
|
||||
if (tabs.length > 0) {
|
||||
callback(tabs[0].id);
|
||||
} else {
|
||||
//console.error('No active tab found');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load options from storage and set declarativeNetRequest rules
|
||||
*/
|
||||
function loadOptionsAndSetRules() {
|
||||
console.log('Tracking Proxy Helper installed');
|
||||
chrome.storage.sync.get([
|
||||
'headerValue', 'urls', 'blockGtm', 'gtmContainerId', 'gtmContainerIdIsRegex',
|
||||
'trackingProxyUrl', 'trackingProxyUrlIsRegex', 'blockTrackingProxy', 'scriptUrl', 'scriptUrlIsRegex'
|
||||
], function(data) {
|
||||
const headerValue = data.headerValue || '';
|
||||
const urls = data.urls || [];
|
||||
const blockGtm = data.blockGtm || false;
|
||||
const gtmContainerId = data.gtmContainerId || '';
|
||||
const gtmContainerIdIsRegex = data.gtmContainerIdIsRegex || false;
|
||||
const trackingProxyUrl = data.trackingProxyUrl || '';
|
||||
const trackingProxyUrlIsRegex = data.trackingProxyUrlIsRegex || false;
|
||||
const blockTrackingProxy = data.blockTrackingProxy || false;
|
||||
const scriptUrl = data.scriptUrl || '';
|
||||
const scriptUrlIsRegex = data.scriptUrlIsRegex || false;
|
||||
|
||||
// If no header value or no URLs are defined, do not set any rules
|
||||
if (!headerValue || urls.length === 0) {
|
||||
//console.log('No header value or URLs defined, no rules set');
|
||||
return;
|
||||
}
|
||||
|
||||
// Create conditions based on the URLs and regex
|
||||
const conditions = urls
|
||||
.filter(urlObj => urlObj.url) // Filter out empty URLs
|
||||
.map((urlObj, index) => {
|
||||
const condition = {
|
||||
id: index + 1,
|
||||
priority: 1,
|
||||
action: {
|
||||
type: "modifyHeaders",
|
||||
requestHeaders: [
|
||||
{ header: "Tp-Dev", operation: "set", value: headerValue }
|
||||
]
|
||||
},
|
||||
condition: {
|
||||
regexFilter: urlObj.isRegex ? urlObj.url : `^${urlObj.url}$`,
|
||||
isUrlFilterCaseSensitive: false,
|
||||
//resourceTypes: ["main_frame", "sub_frame", "xmlhttprequest"]
|
||||
resourceTypes: ["main_frame", "sub_frame", "stylesheet", "script", "image", "font", "object", "xmlhttprequest", "ping", "csp_report", "media", "websocket", "other"]
|
||||
}
|
||||
};
|
||||
console.log('Condition created:', condition);
|
||||
return condition;
|
||||
});
|
||||
|
||||
const rules = conditions.map((condition, index) => ({
|
||||
...condition,
|
||||
id: index + 1
|
||||
}));
|
||||
|
||||
const scriptUrlMatches = (url) => {
|
||||
if (!scriptUrl) return false;
|
||||
if (scriptUrlIsRegex) {
|
||||
const regex = new RegExp(scriptUrl);
|
||||
return regex.test(url);
|
||||
}
|
||||
return url.includes(scriptUrl);
|
||||
};
|
||||
|
||||
// Add GTM blocking rule if blockGtm is enabled and scriptUrl matches
|
||||
if (blockGtm && gtmContainerId && scriptUrlMatches(scriptUrl)) {
|
||||
const gtmUrl = gtmContainerIdIsRegex ? gtmContainerId : `https://www.googletagmanager.com/gtm.js?id=${gtmContainerId}`;
|
||||
rules.push({
|
||||
id: rules.length + 1,
|
||||
priority: 1,
|
||||
action: {
|
||||
type: "block"
|
||||
},
|
||||
condition: {
|
||||
regexFilter: gtmContainerIdIsRegex ? gtmUrl : `https://www.googletagmanager.com/gtm.js\\?id=${gtmContainerId}`,
|
||||
resourceTypes: ["script"]
|
||||
}
|
||||
});
|
||||
console.log('Google Tag Manager blocked');
|
||||
}
|
||||
|
||||
// Add Tracking Proxy blocking rule if blockTrackingProxy is enabled and scriptUrl matches
|
||||
if (blockTrackingProxy && trackingProxyUrl && scriptUrlMatches(scriptUrl)) {
|
||||
const proxyUrl = trackingProxyUrlIsRegex ? trackingProxyUrl : `^${trackingProxyUrl}$`;
|
||||
rules.push({
|
||||
id: rules.length + 2,
|
||||
priority: 1,
|
||||
action: {
|
||||
type: "block"
|
||||
},
|
||||
condition: {
|
||||
regexFilter: proxyUrl,
|
||||
resourceTypes: ["script", "xmlhttprequest"]
|
||||
}
|
||||
});
|
||||
console.log('Tracking Proxy blocked');
|
||||
}
|
||||
|
||||
if (rules.length === 0) {
|
||||
//console.log('No valid URLs to match, no rules set');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the rules
|
||||
chrome.declarativeNetRequest.updateDynamicRules({
|
||||
addRules: rules,
|
||||
removeRuleIds: rules.map(rule => rule.id)
|
||||
}, () => {
|
||||
if (chrome.runtime.lastError) {
|
||||
console.error('Error setting declarativeNetRequest rules:', chrome.runtime.lastError);
|
||||
} else {
|
||||
console.log('DeclarativeNetRequest rules set up successfully');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*** Chrome Extension Function Library ***/
|
||||
|
||||
// Function to Initialise the Badge and add Request Header
|
||||
chrome.runtime.onInstalled.addListener(() => {
|
||||
// Clear badge on installation
|
||||
clearBadge();
|
||||
// Load options and set dynamic rules
|
||||
loadOptionsAndSetRules();
|
||||
});
|
||||
|
||||
chrome.storage.onChanged.addListener((changes, namespace) => {
|
||||
if (namespace === 'sync') {
|
||||
console.log('Options changed, updating rules');
|
||||
loadOptionsAndSetRules();
|
||||
}
|
||||
});
|
||||
|
||||
// Listener for Extension Icon Clicks
|
||||
chrome.action.onClicked.addListener((tab) => {
|
||||
//console.log('Action button clicked', tab);
|
||||
let tabId = tab.id;
|
||||
let windowId = tab.windowId;
|
||||
chrome.tabs.create({ url: 'popup.html' });
|
||||
});
|
||||
|
||||
// Listener for internal messages
|
||||
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||
//console.log('TP Received message:', message);
|
||||
if (message.type === 'CHECK_TPT') {
|
||||
getCurrentTabId((tabId) => {
|
||||
tpdm.activeTabId = tabId;
|
||||
//console.log('CHECK_TPT (Tab: '+tabId+'):', message);
|
||||
if (message.hasTPT) {
|
||||
tpdm.data.eventCount = 0;
|
||||
resetBadge(tabId);
|
||||
if (typeof tpdm.data[tabId]!='object') tpdm.data[tabId] = JSON.parse(JSON.stringify(tpdm.tpl));
|
||||
tpdm.data[tabId].tpId = message.tpobj.cid;
|
||||
} else {
|
||||
clearBadge(tabId);
|
||||
}
|
||||
});
|
||||
} else if (message.type === 'TRACKING_PROXY_EVENT' && message.details) {
|
||||
const eventData = message.details.eventData;
|
||||
const metaData = message.details.metaData;
|
||||
//console.log('TRACKING_PROXY_EVENT',message);
|
||||
incrementBadge(metaData.tabId);
|
||||
if (typeof tpdm.data[metaData.tabId]!='object') tpdm.data[metaData.tabId] = JSON.parse(JSON.stringify(tpdm.tpl));
|
||||
tpdm.data[metaData.tabId].events.push(JSON.parse(JSON.stringify(eventData)));
|
||||
} else if (message.type === 'REQUEST_POPUP_DATA') {
|
||||
//getCurrentTabId((tabId) => {
|
||||
if (typeof tpdm.data[tpdm.activeTabId]!='object') tpdm.data[tpdm.activeTabId] = JSON.parse(JSON.stringify(tpdm.tpl));
|
||||
let obj = {
|
||||
tpId: tpdm.data[tpdm.activeTabId].tpId,
|
||||
tabId: tpdm.activeTabId,
|
||||
events: tpdm.data[tpdm.activeTabId].events
|
||||
};
|
||||
//console.log('TP Received message:'+tpdm.data[tpdm.activeTabId].tpId, obj);
|
||||
sendResponse(obj);
|
||||
//});
|
||||
} else {
|
||||
//console.log('Unknown message type:', message.type);
|
||||
}
|
||||
});
|
||||
|
||||
// Listeners for Tab-Change
|
||||
chrome.tabs.onActivated.addListener(function(tab) {
|
||||
//console.log('TAB ACTIVATED', tab);
|
||||
tpdm.activeTabId = tab.tabId;
|
||||
tpdm.activeWindowId = tab.windowId;
|
||||
});
|
||||
|
||||
// Listeners for Tab-Update
|
||||
chrome.tabs.onUpdated.addListener(function(activeInfo, changeInfo, tab) {
|
||||
let tabId = tab.id;
|
||||
let windowId = tab.windowId;
|
||||
if (typeof changeInfo == 'object' && typeof changeInfo.status == 'string') {
|
||||
if (changeInfo.status == 'complete') {
|
||||
//console.log('TAB Load complete: ' + tab.url, tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
chrome.runtime.onStartup.addListener(function() {
|
||||
// Initialisiert alle Tabs beim Start der Erweiterung
|
||||
chrome.tabs.query({}, function(tabs) {
|
||||
tabs.forEach(tab => {
|
||||
resetBadge(tab.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
chrome.webNavigation.onBeforeNavigate.addListener(function(details) {
|
||||
if (details.frameId === 0) { // Haupt-Frame der Navigation
|
||||
//console.log('Navigation started for Tab:', details.tabId);
|
||||
resetBadge(details.tabId);
|
||||
}
|
||||
});
|
||||
|
||||
// Intercepting network requests to detect Tracking Proxy Events
|
||||
chrome.webRequest.onBeforeRequest.addListener(
|
||||
function(details) {
|
||||
if (details.method === "POST" && details.type === "xmlhttprequest" && details.tabId >= 0) {
|
||||
let eventData = {};
|
||||
if (details.requestBody) {
|
||||
if (details.requestBody.formData) {
|
||||
eventData = JSON.parse(JSON.stringify(details.requestBody.formData));
|
||||
//console.log('TRACKING_PROXY_REQUEST 1', eventData);
|
||||
} else if (details.requestBody.raw && details.requestBody.raw.length > 0 && details.requestBody.raw[0].bytes) {
|
||||
//console.warn('TRACKING_PROXY_REQUEST 0', details);
|
||||
try {
|
||||
const decodedString = decodeURIComponent(String.fromCharCode.apply(null, new Uint8Array(details.requestBody.raw[0].bytes)));
|
||||
if (decodedString.charAt(0) === '{') {
|
||||
eventData = JSON.parse(decodedString);
|
||||
}
|
||||
} catch (e) {
|
||||
//console.error('Failed to parse request body as JSON:', e);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
//console.log('Payload is no JSON object:', details);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!eventData || !eventData.cid) {
|
||||
//console.log('Payload has no cid:', details);
|
||||
return;
|
||||
}
|
||||
let metaData = { documentId:details.documentId, frameId:details.frameId, initiator:details.initiator, requestId:details.requestId, tabId:details.tabId, timeStamp:details.timeStamp, url:details.url };
|
||||
//console.log('TRACKING_PROXY_REQUEST available', eventData);
|
||||
chrome.tabs.query({ /*active: true, currentWindow: true*/ }, function(tabs) {
|
||||
if (tabs.length > 0) {
|
||||
//console.log('TRACKING_PROXY_REQUEST available', { eventData:eventData, metaData:metaData });
|
||||
chrome.tabs.sendMessage(details.tabId, { type: 'TRACKING_PROXY_REQUEST', details:{eventData:eventData, metaData:metaData} }, (response) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
//console.error('Error sending message to content script: '+chrome.runtime.lastError, { eventData:eventData, metaData:metaData });
|
||||
}
|
||||
//else { console.log('TRACKING_PROXY_REQUEST sent', { eventData:eventData, metaData:metaData }); }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
{ urls: ["<all_urls>"] },
|
||||
["requestBody"] // "blocking","requestBody","responseHeaders" | see: https://stackoverflow.com/questions/33106709/chrome-webrequest-doesnt-see-post-data-in-requestbody
|
||||
);
|
||||
|
||||
|
||||
// EOF
|
||||
Loading…
Reference in New Issue
Block a user