// ==UserScript==
// @name Anti-Fingerprinting Shield Plus
// @namespace https://365devnet.eu/userscripts
// @version 4.9
// @description Floating UI enhancements: draggable gear icon, saved position, toggling panel, hover tooltip, and adaptive placement. Improved usability in Safari and Chrome.
// @author Richard B
// @match *://*/*
// @run-at document-start
// @grant none
// @license MIT
// ==/UserScript==
(() => {
const DEBUG = true;
const settingsKey = '__afs_user_settings';
const positionKey = '__afs_ui_position';
const sessionExpiryKey = '__afs_last_seen';
const spoofDefaults = {
userAgent: true,
platform: true,
language: true,
screen: true,
hardwareConcurrency: true,
timezone: true,
canvas: true,
webgl: true,
audio: true,
plugins: true,
mediaDevices: true,
storageEstimate: true,
matchMedia: true,
sharedArrayBuffer: true
};
const spoofSettings = loadSettings();
const now = Date.now();
const SESSION_TIMEOUT_MINUTES = 30;
const browser = detectBrowser();
if (isExpired()) {
clearStoredValues();
log(`Session expired. Values cleared.`);
}
localStorage.setItem(sessionExpiryKey, now.toString());
const sessionId = getOrCreatePersistent('__afs_session_id', () => Math.random().toString(36).substring(2, 10));
function log(...args) {
if (DEBUG) console.log('[AFS+]', ...args);
}
function loadSettings() {
const saved = localStorage.getItem(settingsKey);
return saved ? JSON.parse(saved) : { ...spoofDefaults };
}
function saveSettings(settings) {
localStorage.setItem(settingsKey, JSON.stringify(settings));
}
function clearStoredValues() {
Object.keys(localStorage).forEach(key => {
if (key.startsWith('__afs_')) localStorage.removeItem(key);
});
}
function isExpired() {
const lastSeen = parseInt(localStorage.getItem(sessionExpiryKey), 10);
return isNaN(lastSeen) || now - lastSeen > SESSION_TIMEOUT_MINUTES * 60 * 1000;
}
function getOrCreatePersistent(key, generator) {
const fullKey = '__afs_' + key;
let value = localStorage.getItem(fullKey);
if (!value) {
value = generator();
localStorage.setItem(fullKey, value);
}
return value;
}
function detectBrowser() {
const ua = navigator.userAgent;
if (/Safari/.test(ua) && !/Chrome/.test(ua)) return 'Safari';
if (/Edg\//.test(ua)) return 'Edge';
if (/Chrome/.test(ua)) return 'Chrome';
return 'Other';
}
function pick(arr) {
return arr[Math.floor(Math.random() * arr.length)];
}
function spoof(obj, prop, valueFn) {
try {
Object.defineProperty(obj, prop, {
get: valueFn,
configurable: true
});
} catch (e) {
log('Spoof failed:', prop, e);
}
}
const spoofed = {
userAgent: getOrCreatePersistent('ua', () => pick([
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Safari/605.1.15',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'
])),
platform: getOrCreatePersistent('platform', () => pick(['MacIntel', 'Win32', 'Linux x86_64'])),
language: getOrCreatePersistent('lang', () => pick(['en-US', 'nl-NL', 'de-DE'])),
screenWidth: parseInt(getOrCreatePersistent('sw', () => pick([1920, 1366, 1440]))),
screenHeight: parseInt(getOrCreatePersistent('sh', () => pick([1080, 900, 768]))),
cores: parseInt(getOrCreatePersistent('cores', () => pick([2, 4, 8]))),
memory: parseInt(getOrCreatePersistent('mem', () => pick([2, 4, 8]))),
timezone: getOrCreatePersistent('tz', () => pick(['UTC', 'Europe/Amsterdam', 'America/New_York']))
};
if (spoofSettings.userAgent) spoof(navigator, 'userAgent', () => spoofed.userAgent);
if (spoofSettings.platform) spoof(navigator, 'platform', () => spoofed.platform);
if (spoofSettings.language) {
spoof(navigator, 'language', () => spoofed.language);
spoof(navigator, 'languages', () => [spoofed.language, 'en']);
}
if (spoofSettings.screen) {
spoof(window.screen, 'width', () => spoofed.screenWidth);
spoof(window.screen, 'height', () => spoofed.screenHeight);
spoof(window, 'innerWidth', () => spoofed.screenWidth);
spoof(window, 'innerHeight', () => spoofed.screenHeight - 40);
}
if (spoofSettings.hardwareConcurrency) {
spoof(navigator, 'hardwareConcurrency', () => spoofed.cores);
spoof(navigator, 'deviceMemory', () => spoofed.memory);
}
if (spoofSettings.timezone && typeof Intl !== 'undefined') {
const orig = Intl.DateTimeFormat.prototype.resolvedOptions;
Intl.DateTimeFormat.prototype.resolvedOptions = function () {
const options = orig.call(this);
options.timeZone = spoofed.timezone;
return options;
};
}
if (spoofSettings.canvas && CanvasRenderingContext2D) {
const originalGetImageData = CanvasRenderingContext2D.prototype.getImageData;
CanvasRenderingContext2D.prototype.getImageData = function (x, y, w, h) {
const data = originalGetImageData.call(this, x, y, w, h);
for (let i = 0; i < data.data.length; i += 4) {
data.data[i] += Math.floor(Math.random() * 3);
data.data[i + 1] += Math.floor(Math.random() * 3);
data.data[i + 2] += Math.floor(Math.random() * 3);
}
return data;
};
}
if (spoofSettings.webgl && WebGLRenderingContext) {
const originalGL = WebGLRenderingContext.prototype.getParameter;
WebGLRenderingContext.prototype.getParameter = function (param) {
const spoofMap = { 37445: 'FakeVendor Inc.', 37446: 'Virtual GPU Renderer', 3379: 4096, 35661: 8 };
return spoofMap[param] || originalGL.call(this, param);
};
}
if (spoofSettings.audio && window.AudioContext) {
const ctx = window.AudioContext.prototype;
spoof(ctx, 'sampleRate', () => 44100);
if (AnalyserNode.prototype.getFloatFrequencyData) {
const original = AnalyserNode.prototype.getFloatFrequencyData;
AnalyserNode.prototype.getFloatFrequencyData = function (arr) {
original.call(this, arr);
for (let i = 0; i < arr.length; i++) {
arr[i] += Math.random() * 0.1;
}
};
}
}
if (spoofSettings.mediaDevices) {
spoof(navigator, 'mediaDevices', () => ({
enumerateDevices: () => Promise.resolve([])
}));
}
if (spoofSettings.plugins) {
spoof(navigator, 'plugins', () => []);
spoof(navigator, 'mimeTypes', () => ({ length: 0 }));
}
if (spoofSettings.storageEstimate) {
navigator.storage.estimate = () => Promise.resolve({
usage: 5242880,
quota: 1073741824
});
}
if (spoofSettings.matchMedia) {
const originalMatchMedia = window.matchMedia;
window.matchMedia = function (query) {
if (query.includes('color-scheme') || query.includes('forced-colors')) {
return { matches: Math.random() > 0.5, media: query };
}
return originalMatchMedia.call(this, query);
};
}
if (spoofSettings.sharedArrayBuffer) {
spoof(window, 'SharedArrayBuffer', () => undefined);
}
function createUI() {
if (!DEBUG) return;
const savedPos = JSON.parse(localStorage.getItem(positionKey) || '{"top":10,"left":10}');
const panel = document.createElement('div');
panel.style.cssText = 'position:absolute;background:#1b1b1b;color:#fff;padding:10px;border-radius:8px;z-index:99999;font-family:sans-serif;font-size:13px;';
panel.style.display = 'none';
panel.innerHTML = '<strong>Anti-Fingerprinting Shield Settings</strong><br>';
Object.keys(spoofDefaults).forEach(key => {
const line = document.createElement('div');
line.innerHTML = `<label><input type="checkbox" ${spoofSettings[key] ? 'checked' : ''} /> ${key}</label>`;
line.querySelector('input').addEventListener('change', () => {
spoofSettings[key] = !spoofSettings[key];
saveSettings(spoofSettings);
location.reload();
});
panel.appendChild(line);
});
const icon = document.createElement('div');
icon.textContent = '⚙️';
icon.title = 'Anti-Fingerprinting Shield Plus';
icon.style.cssText = `
position:fixed;
top:${savedPos.top}px;
left:${savedPos.left}px;
cursor:move;
z-index:99999;
font-size:20px;
user-select:none;
`;
icon.addEventListener('click', () => {
panel.style.display = (panel.style.display === 'none') ? 'block' : 'none';
const iconBox = icon.getBoundingClientRect();
panel.style.top = `${iconBox.top + 25}px`;
panel.style.left = `${iconBox.left}px`;
});
let isDragging = false;
let offsetX = 0;
let offsetY = 0;
icon.addEventListener('mousedown', e => {
isDragging = true;
offsetX = e.clientX - icon.offsetLeft;
offsetY = e.clientY - icon.offsetTop;
});
document.addEventListener('mousemove', e => {
if (isDragging) {
icon.style.left = `${e.clientX - offsetX}px`;
icon.style.top = `${e.clientY - offsetY}px`;
}
});
document.addEventListener('mouseup', () => {
if (isDragging) {
isDragging = false;
localStorage.setItem(positionKey, JSON.stringify({
top: icon.offsetTop,
left: icon.offsetLeft
}));
}
});
document.addEventListener('fullscreenchange', () => {
const isFullscreen = !!document.fullscreenElement;
icon.style.display = isFullscreen ? 'none' : 'block';
});
document.addEventListener('keydown', e => {
if (e.ctrlKey && e.shiftKey && e.key === 'F') {
if (!document.body.contains(panel)) document.body.appendChild(panel);
panel.style.display = 'block';
}
});
document.addEventListener('DOMContentLoaded', () => {
document.body.appendChild(icon);
document.body.appendChild(panel);
});
}
createUI();
})();