upgraded 1000 bots to manifest v3, added visual element to when the extension is turned on

This commit is contained in:
yoNico21 2024-09-25 16:12:21 +02:00
parent 1d4dc47187
commit 2aa755eeb6
6 changed files with 655 additions and 62 deletions

View File

@ -18,62 +18,259 @@
*/ */
'use strict'; "use strict";
var browser = browser || chrome // Use chrome or browser depending on the environment
var user_agent = "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"; 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 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() { function set_extension_status_ON() {
status = 1; browser.storage.local
//console.log('Setting status to ON'); .set({ status: 1 })
browser.browserAction.setIcon({path: 'icon_ON_48.png'}); .then(() => {
browser.browserAction.setTitle({title: "1000 Bots"}); 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() { function set_extension_status_OFF() {
status = 0; browser.storage.local
//console.log('Setting status to OFF'); .set({ status: 0 })
browser.browserAction.setIcon({path: 'icon_OFF_48.png'}); .then(() => {
browser.browserAction.setTitle({title: "1000 Bots activate"}); 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(){ // Toggle the icon between ON and OFF
if(status == 0) { function update_icon() {
set_extension_status_ON(); browser.storage.local
}else{ .get("status")
set_extension_status_OFF(); .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){ // Add the rules
return browser.declarativeNetRequest
//console.log('Browser http request!'); .updateDynamicRules({
addRules: rules,
if(status == 0) { removeRuleIds: [],
// console.log('Nothing to do'); })
return {requestHeaders: e.requestHeaders}; .then(() => {
} return console.log("User-Agent spoofing rules added successfully.");
})
for (var header of e.requestHeaders) { .then(() => {})
if (header.name.toLowerCase() === "user-agent") { .catch((error) => {
header.value = user_agent; console.error("Error adding rules:", error);
} });
}
//console.log('Set user-agent header to: ' + user_agent);
return {requestHeaders: e.requestHeaders};
} }
// 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); // Function to refresh all active tabs
browser.browserAction.onClicked.addListener(update_icon); 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( // Inject the content.js script into all active tabs
rewrite_user_agent_header, function injectContentScript() {
{urls: [target_urls]}, return browser.tabs
["blocking", "requestHeaders"] .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);

View File

@ -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 = `
<div class="banner montserrat">
<div class="marquee">
<span class="marquee__inner" style="--ad: 80s;">
${new Array(30).fill(marqeeText).join("")}
</span>
</div>
</div>
`;
// 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);
});
})();

View File

@ -1,22 +1,50 @@
{ {
"homepage_url": "http://1000scores.com/portfolio-items/mediengruppe-bitnik-1000-bots/", "name": "1000 Bots",
"name": "1000 Bots", "version": "0.0.1",
"browser_specific_settings": { "description": "Surf the Web as Googlebot. Ever wondered what the Googlebot gets to see online that you do not?",
"gecko": { "homepage_url": "http://1000scores.com/portfolio-items/mediengruppe-bitnik-1000-bots/",
"id": "trash@bitnik.org", "manifest_version": 3,
"strict_min_version": "55.0"
} "background": {
}, "service_worker": "background.js"
"description": "Surf the Web as Googlebot. Ever wondered what the Googlebot gets to see online that you do not?", },
"version": "0.0.1",
"background": { "permissions": [
"scripts": ["background.js"], "storage",
"persistent": true "tabs",
}, "scripting",
"permissions": ["webRequest", "webRequestBlocking", "*://*/*"], "activeTab",
"browser_action": { "declarativeNetRequest",
"name": "Click to change your browsers perspective", "declarativeNetRequestFeedback"
"default_icon": "icon_OFF_48.png" ],
},
"manifest_version": 2 "host_permissions": ["*://*/*"],
"action": {
"default_title": "Click to change your browser's perspective",
"default_icon": "icon_OFF_48.png"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"],
"css": ["style.css"],
"run_at": "document_idle"
}
],
"web_accessible_resources": [
{
"resources": ["style.css"],
"matches": ["<all_urls>"]
}
],
"browser_specific_settings": {
"gecko": {
"id": "trash@bitnik.org",
"strict_min_version": "55.0"
}
}
} }

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
'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"]
);

View File

@ -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 gets 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
}

View File

@ -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;
}
}