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