From 2aa755eeb6d3e535f60ccd70e2682e3310a24f91 Mon Sep 17 00:00:00 2001 From: yoNico21 <119441054+yoNico21@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:12:21 +0200 Subject: [PATCH] upgraded 1000 bots to manifest v3, added visual element to when the extension is turned on --- 1000_bots_webextension/background.js | 281 +++++++++++++++++++---- 1000_bots_webextension/content.js | 96 ++++++++ 1000_bots_webextension/manifest.json | 68 ++++-- 1000_bots_webextension/old.background.js | 79 +++++++ 1000_bots_webextension/old.manifest.json | 22 ++ 1000_bots_webextension/style.css | 171 ++++++++++++++ 6 files changed, 655 insertions(+), 62 deletions(-) create mode 100644 1000_bots_webextension/content.js create mode 100644 1000_bots_webextension/old.background.js create mode 100644 1000_bots_webextension/old.manifest.json create mode 100644 1000_bots_webextension/style.css diff --git a/1000_bots_webextension/background.js b/1000_bots_webextension/background.js index 34f592f..b0ecc22 100644 --- a/1000_bots_webextension/background.js +++ b/1000_bots_webextension/background.js @@ -18,62 +18,259 @@ */ -'use strict'; +"use strict"; -var browser = browser || chrome -var user_agent = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"; +// Use chrome or browser depending on the environment +var browser = chrome || browser; + +// Custom user-agent to spoof Googlebot +var user_agent = + "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"; var target_urls = "*://*/*"; -var status = 0; +// Duration to display the injected HTML (in milliseconds) +const DISPLAY_DURATION = 8000; // Set to 8 seconds +// Initialize storage for duration +browser.storage.local + .set({ duration: DISPLAY_DURATION }) + .then(() => { + console.log("Duration set to:", DISPLAY_DURATION); + }) + .catch((error) => { + console.error("Error setting duration:", error); + }); + +// Set extension status to ON function set_extension_status_ON() { - status = 1; - //console.log('Setting status to ON'); - browser.browserAction.setIcon({path: 'icon_ON_48.png'}); - browser.browserAction.setTitle({title: "1000 Bots"}); + browser.storage.local + .set({ status: 1 }) + .then(() => { + console.log("Extension status set to ON"); + return browser.action.setIcon({ path: "icon_ON_48.png" }); + }) + .then(() => { + return browser.action.setTitle({ title: "1000 Bots" }); + }) + .then(() => { + // Start user-agent spoofing + return startUserAgentSpoofing(); + }) + .then(() => { + // Refresh all tabs after starting user-agent spoofing + return refreshAllTabs(); + }) + .then(() => { + // Inject the content script into all active tabs after refreshing + return injectContentScript(); + }) + .catch((error) => { + console.error("Error setting extension status ON:", error); + }); } +// Set extension status to OFF function set_extension_status_OFF() { - status = 0; - //console.log('Setting status to OFF'); - browser.browserAction.setIcon({path: 'icon_OFF_48.png'}); - browser.browserAction.setTitle({title: "1000 Bots activate"}); + browser.storage.local + .set({ status: 0 }) + .then(() => { + console.log("Extension status set to OFF"); + return browser.action.setIcon({ path: "icon_OFF_48.png" }); + }) + .then(() => { + return browser.action.setTitle({ title: "1000 Bots activate" }); + }) + .then(() => { + // Remove the content from all active tabs + return removeInjectedContent(); + }) + .then(() => { + // Stop user-agent spoofing + return stopUserAgentSpoofing(); + }) + .then(() => { + // Refresh all tabs before stopping the extension + return refreshAllTabs(); + }) + .catch((error) => { + console.error("Error setting extension status OFF:", error); + }); } -function update_icon(){ - if(status == 0) { - set_extension_status_ON(); - }else{ - set_extension_status_OFF(); - } +// Toggle the icon between ON and OFF +function update_icon() { + browser.storage.local + .get("status") + .then((result) => { + if (result.status === 0) { + set_extension_status_ON(); + } else { + set_extension_status_OFF(); + } + }) + .catch((error) => { + console.error("Error fetching extension status:", error); + }); } +// Start user-agent spoofing +function startUserAgentSpoofing() { + const rules = [ + { + id: 1, + priority: 1, + action: { + type: "modifyHeaders", + requestHeaders: [ + { + operation: "set", + header: "User-Agent", + value: user_agent, + }, + ], + }, + condition: { + urlFilter: target_urls, + resourceTypes: ["main_frame"], + }, + }, + ]; -function rewrite_user_agent_header(e){ - - //console.log('Browser http request!'); - - if(status == 0) { - // console.log('Nothing to do'); - return {requestHeaders: e.requestHeaders}; - } - - for (var header of e.requestHeaders) { - if (header.name.toLowerCase() === "user-agent") { - header.value = user_agent; - } - } - //console.log('Set user-agent header to: ' + user_agent); - return {requestHeaders: e.requestHeaders}; - + // Add the rules + return browser.declarativeNetRequest + .updateDynamicRules({ + addRules: rules, + removeRuleIds: [], + }) + .then(() => { + return console.log("User-Agent spoofing rules added successfully."); + }) + .then(() => {}) + .catch((error) => { + console.error("Error adding rules:", error); + }); } +// Stop user-agent spoofing +function stopUserAgentSpoofing() { + return browser.declarativeNetRequest + .updateDynamicRules({ + removeRuleIds: [1], + }) + .then(() => { + console.log("User-Agent spoofing rules removed successfully."); + }) + .then(() => { + // Clear the bannerInjected flag when stopping the extension + return browser.storage.local.set({ bannerInjected: false }); + }) + .catch((error) => { + console.error("Error removing rules:", error); + }); +} -browser.runtime.onStartup.addListener(set_extension_status_OFF); -browser.browserAction.onClicked.addListener(update_icon); +// Function to refresh all active tabs +function refreshAllTabs() { + return browser.tabs.query({}).then((tabs) => { + tabs.forEach((tab) => { + browser.tabs + .reload(tab.id) + .then(() => { + console.log(`Refreshed tab: ${tab.id}`); + }) + .catch((error) => { + console.error(`Error refreshing tab ${tab.id}:`, error); + }); + }); + }); +} -browser.webRequest.onBeforeSendHeaders.addListener( - rewrite_user_agent_header, - {urls: [target_urls]}, - ["blocking", "requestHeaders"] -); +// Inject the content.js script into all active tabs +function injectContentScript() { + return browser.tabs + .query({}) + .then((tabs) => { + return Promise.all( + tabs.map((tab) => { + // Check if the tab is not a chrome URL + if (!tab.url.startsWith("chrome://")) { + return browser.scripting + .executeScript({ + target: { tabId: tab.id }, + files: ["content.js"], + }) + .then(() => { + console.log( + `Content script injected into tab ${tab.id}` + ); + }) + .catch((error) => { + console.error( + `Error injecting content script into tab ${tab.id}:`, + error + ); + }); + } else { + console.log( + `Skipped injecting content script into tab ${tab.id} (chrome:// URL)` + ); + } + }) + ); + }) + .catch((error) => { + console.error("Error querying tabs:", error); + }); +} + +// Remove the content from all active tabs +function removeInjectedContent() { + return browser.tabs + .query({}) + .then((tabs) => { + tabs.forEach((tab) => { + if (!tab.url.startsWith("chrome://")) { + browser.scripting + .executeScript({ + target: { tabId: tab.id }, + function: () => { + const banner = + document.querySelector(".extension-banner"); + if (banner && banner.parentNode) { + banner.parentNode.removeChild(banner); + } + }, + }) + .then(() => { + console.log( + `Removed injected content from tab ${tab.id}` + ); + }) + .catch((error) => { + console.error( + `Error removing injected content from tab ${tab.id}:`, + error + ); + }); + } else { + console.log( + `Skipped removing injected content from tab ${tab.id} (chrome:// URL)` + ); + } + }); + }) + .catch((error) => { + console.error( + "Error querying tabs for injected content removal:", + error + ); + }); +} + +// Event listeners for Manifest v3 Service Worker +browser.runtime.onInstalled.addListener(() => { + set_extension_status_OFF(); // Set status to OFF on installation/startup +}); + +// Handle browser action clicks to toggle status +browser.action.onClicked.addListener(update_icon); diff --git a/1000_bots_webextension/content.js b/1000_bots_webextension/content.js new file mode 100644 index 0000000..0e72239 --- /dev/null +++ b/1000_bots_webextension/content.js @@ -0,0 +1,96 @@ +(function () { + // Use chrome or browser depending on the environment + var browser = chrome || browser; + + // Duration to show the banner (in milliseconds) + let DISPLAY_DURATION = 5000; // Initialize the duration to 5 seconds + let banner; // Declare the banner variable in the outer scope + + // Get the duration from local storage and update the DISPLAY_DURATION variable + browser.storage.local + .get(["duration", "status"]) // Fetch both duration and status + .then((result) => { + DISPLAY_DURATION = result.duration || DISPLAY_DURATION; + console.log("Duration set to:", DISPLAY_DURATION, "(in ms)"); + + // Set variables to css for delay for animation + let CSS_ANIMATION_DURATION = 300 / 1000; + let CSS_DURATION = DISPLAY_DURATION / 1000; + let CSS_DELAY = + CSS_DURATION - CSS_ANIMATION_DURATION - CSS_ANIMATION_DURATION; + + console.log("--duration:", `${CSS_ANIMATION_DURATION}s`); + console.log("--delay:", `${CSS_DURATION}s`); + + CSS_ANIMATION_DURATION = CSS_ANIMATION_DURATION + "s"; + document.body.style.setProperty( + "--duration", + CSS_ANIMATION_DURATION + ); + + CSS_DELAY = CSS_DELAY + "s"; + document.body.style.setProperty("--delay", CSS_DELAY); + + if (result.status === 0) { + // Extension is OFF, do nothing + console.log("Extension is OFF, exiting."); + return; + } + + if (result.bannerInjected) { + // Banner has already been injected, do nothing + console.log("Banner already injected, exiting."); + return; + } + + console.log("Injecting the banner..."); + + // Inject the CSS file + const link = document.createElement("link"); + link.href = browser.runtime.getURL("style.css"); + link.rel = "stylesheet"; + document.head.appendChild(link); + console.log("CSS file injected."); + + // Create and style the banner container + banner = document.createElement("div"); + banner.classList.add("extension-banner-container"); + + const marqeeText = "YOU ARE NOW SURFING THE WEB AS A BOT đŸ¤– "; + + const bannerContent = ` + + `; + + // Set the banner content + banner.innerHTML = bannerContent; + + // Append the banner to the body + document.body.appendChild(banner); + console.log("Banner injected:", banner); + + // Set the flag in local storage to indicate that the banner was injected + return browser.storage.local.set({ bannerInjected: true }); + }) + .then(() => { + // Remove the banner after the specified duration + setTimeout(() => { + if (banner && banner.parentNode) { + banner.parentNode.removeChild(banner); + console.log("Banner removed after duration."); + + // Reset the flag when the banner is removed + browser.storage.local.set({ bannerInjected: false }); + } + }, DISPLAY_DURATION); + }) + .catch((error) => { + console.error("Error in content script:", error); + }); +})(); diff --git a/1000_bots_webextension/manifest.json b/1000_bots_webextension/manifest.json index e5ff046..6831b9a 100644 --- a/1000_bots_webextension/manifest.json +++ b/1000_bots_webextension/manifest.json @@ -1,22 +1,50 @@ { - "homepage_url": "http://1000scores.com/portfolio-items/mediengruppe-bitnik-1000-bots/", - "name": "1000 Bots", - "browser_specific_settings": { - "gecko": { - "id": "trash@bitnik.org", - "strict_min_version": "55.0" - } - }, - "description": "Surf the Web as Googlebot. Ever wondered what the Googlebot get’s to see online that you do not?", - "version": "0.0.1", - "background": { - "scripts": ["background.js"], - "persistent": true - }, - "permissions": ["webRequest", "webRequestBlocking", "*://*/*"], - "browser_action": { - "name": "Click to change your browsers perspective", - "default_icon": "icon_OFF_48.png" - }, - "manifest_version": 2 + "name": "1000 Bots", + "version": "0.0.1", + "description": "Surf the Web as Googlebot. Ever wondered what the Googlebot get’s to see online that you do not?", + "homepage_url": "http://1000scores.com/portfolio-items/mediengruppe-bitnik-1000-bots/", + "manifest_version": 3, + + "background": { + "service_worker": "background.js" + }, + + "permissions": [ + "storage", + "tabs", + "scripting", + "activeTab", + "declarativeNetRequest", + "declarativeNetRequestFeedback" + ], + + "host_permissions": ["*://*/*"], + + "action": { + "default_title": "Click to change your browser's perspective", + "default_icon": "icon_OFF_48.png" + }, + + "content_scripts": [ + { + "matches": [""], + "js": ["content.js"], + "css": ["style.css"], + "run_at": "document_idle" + } + ], + + "web_accessible_resources": [ + { + "resources": ["style.css"], + "matches": [""] + } + ], + + "browser_specific_settings": { + "gecko": { + "id": "trash@bitnik.org", + "strict_min_version": "55.0" + } + } } diff --git a/1000_bots_webextension/old.background.js b/1000_bots_webextension/old.background.js new file mode 100644 index 0000000..34f592f --- /dev/null +++ b/1000_bots_webextension/old.background.js @@ -0,0 +1,79 @@ +/* + 1000 Bots - Surf the Web as Googlebot + + Copyleft (C) 2020 !Mediengruppe Bitnik, connect@bitnik.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +'use strict'; + +var browser = browser || chrome +var user_agent = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"; +var target_urls = "*://*/*"; +var status = 0; + + +function set_extension_status_ON() { + status = 1; + //console.log('Setting status to ON'); + browser.browserAction.setIcon({path: 'icon_ON_48.png'}); + browser.browserAction.setTitle({title: "1000 Bots"}); +} + +function set_extension_status_OFF() { + status = 0; + //console.log('Setting status to OFF'); + browser.browserAction.setIcon({path: 'icon_OFF_48.png'}); + browser.browserAction.setTitle({title: "1000 Bots activate"}); +} + +function update_icon(){ + if(status == 0) { + set_extension_status_ON(); + }else{ + set_extension_status_OFF(); + } +} + + +function rewrite_user_agent_header(e){ + + //console.log('Browser http request!'); + + if(status == 0) { + // console.log('Nothing to do'); + return {requestHeaders: e.requestHeaders}; + } + + for (var header of e.requestHeaders) { + if (header.name.toLowerCase() === "user-agent") { + header.value = user_agent; + } + } + //console.log('Set user-agent header to: ' + user_agent); + return {requestHeaders: e.requestHeaders}; + +} + + +browser.runtime.onStartup.addListener(set_extension_status_OFF); +browser.browserAction.onClicked.addListener(update_icon); + +browser.webRequest.onBeforeSendHeaders.addListener( + rewrite_user_agent_header, + {urls: [target_urls]}, + ["blocking", "requestHeaders"] +); diff --git a/1000_bots_webextension/old.manifest.json b/1000_bots_webextension/old.manifest.json new file mode 100644 index 0000000..e5ff046 --- /dev/null +++ b/1000_bots_webextension/old.manifest.json @@ -0,0 +1,22 @@ +{ + "homepage_url": "http://1000scores.com/portfolio-items/mediengruppe-bitnik-1000-bots/", + "name": "1000 Bots", + "browser_specific_settings": { + "gecko": { + "id": "trash@bitnik.org", + "strict_min_version": "55.0" + } + }, + "description": "Surf the Web as Googlebot. Ever wondered what the Googlebot get’s to see online that you do not?", + "version": "0.0.1", + "background": { + "scripts": ["background.js"], + "persistent": true + }, + "permissions": ["webRequest", "webRequestBlocking", "*://*/*"], + "browser_action": { + "name": "Click to change your browsers perspective", + "default_icon": "icon_OFF_48.png" + }, + "manifest_version": 2 +} diff --git a/1000_bots_webextension/style.css b/1000_bots_webextension/style.css new file mode 100644 index 0000000..ca2dfa7 --- /dev/null +++ b/1000_bots_webextension/style.css @@ -0,0 +1,171 @@ +@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap"); + +:root { + --main-bg-color: black; + --main-color: white; + --bg: #8f8f8f; +} + +.montserrat { + font-family: "Montserrat", sans-serif; + font-optical-sizing: auto; + font-weight: 800; + font-style: italic; +} + +.extension-banner-container { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; /* Full screen height */ + background-color: transparent; + z-index: 9999; /* High z-index to ensure it blocks everything below */ + display: flex; + justify-content: center; + align-items: center; + pointer-events: none; /* Allow clicks to pass through */ + background: linear-gradient(var(--main-color), var(--bg)); + opacity: 0; + /* fade-in and fade-out for the screen take-over */ + animation: var(--duration) ease-in-out var(--duration) 1 normal forwards + show, + var(--duration) ease-in-out var(--delay) 1 reverse forwards show; +} + +@keyframes show { + 0% { + opacity: 0; + } + 100% { + opacity: 0.8; + } +} + +.banner { + background: var(--main-bg-color); + color: var(--main-color); + position: relative; + padding: 1rem; + font-size: 5rem; + line-height: 11rem; + transform: rotate(-25deg); /* Rotates the banner */ + width: 200vw; /* Extra-wide to ensure the marquee scrolls smoothly across */ + height: auto; + + /* Apply gradients to the banner itself */ + /* Add a left-to-transparent gradient on the left */ + /* Add a right-to-transparent gradient on the right */ +} + +.banner::before, +.banner::after { + position: absolute; + top: 0; + z-index: 9999; + width: 15%; + height: 100%; + content: ""; +} + +.banner::before { + left: 0; + background: linear-gradient(to right, var(--main-bg-color), transparent); +} + +.banner::after { + right: 0; + background: linear-gradient(to left, var(--main-bg-color), transparent); +} + +.marquee { + overflow: hidden; + position: relative; + width: 100%; +} + +.marquee__inner { + display: inline-block; + white-space: nowrap; + /* Adjust the speed using --ad which can be set dynamically in the HTML */ + animation: scroll var(--ad, 100s) linear infinite; + transform: translate3d(0, 0, 0); /* Force hardware acceleration */ +} + +.marquee span { + display: inline-block; + padding-right: 2rem; /* Add some space between each repeat */ +} + +/* Keyframes to make the animation appear infinite without gaps */ +@keyframes scroll { + 0% { + transform: translate3d( + -50%, + 0, + 0 + ); /* Start in the middle of the loop */ + } + 100% { + transform: translate3d(-100%, 0, 0); /* Move left but only 50% */ + } +} + +/* Mobile screens */ +@media (max-width: 30rem) { + .extension-banner-container { + width: 110vw; + height: 110vh; + } + .banner { + transform: rotate(-60deg); + width: 250vw; + margin-left: -15rem; + } +} + +/* Tablet screens */ +@media (min-width: 48rem) { + .banner { + transform: rotate(-50deg); + width: 225vw; + margin-left: -5rem; + } +} + +/* iPad Mini */ +@media (min-width: 48rem) and (max-width: 64rem) and (orientation: landscape) { + .banner { + transform: rotate(-40deg); + width: 225vw; + margin-left: -5rem; + } +} + +/* Laptop screens */ +@media (min-width: 64rem) { + .extension-banner-container { + width: 115vw; + height: 115vh; + } + .banner { + transform: rotate(-30deg); + width: 210vw; + margin-left: -5rem; + margin-top: -5rem; + } +} + +/* Desktop screens */ +@media (min-width: 80rem) { + .extension-banner-container { + width: 115vw; + height: 115vh; + } + .banner { + transform: rotate(-32deg); + width: 200vw; + margin-left: -15rem; + margin-top: -15rem; + } +}