// ==UserScript==
// @name Anti-Fingerprinting Shield Plus
// @namespace https://365devnet.eu/userscripts
// @version 4.7
// @description Full spoofing logic + settings UI panel. Browser-specific spoofing (Safari, Chrome, Edge) with persistent toggles.
// @author Richard B
// @match *://*/*
// @run-at document-start
// @grant none
// @license MIT
// ==/UserScript==
(() => {
const DEBUG = true;
const settingsKey = '__afs_user_settings';
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);
}
}
// --- Spoofed values ---
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']))
};
// --- Apply spoofing based on settings ---
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);
}
// === UI Panel ===
const panel = document.createElement('div');
panel.style.cssText = 'position:fixed;top:10px;right:10px;background:#1b1b1b;color:#fff;padding:10px;border-radius:8px;z-index:99999;font-family:sans-serif;font-size:13px;';
panel.innerHTML = '<strong>🛡️ AFS+ 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 closeBtn = document.createElement('button');
closeBtn.textContent = 'Close';
closeBtn.style.cssText = 'margin-top:8px;padding:2px 6px;font-size:12px;';
closeBtn.onclick = () => panel.remove();
panel.appendChild(closeBtn);
const toggleBtn = document.createElement('div');
toggleBtn.textContent = '⚙️';
toggleBtn.style.cssText = 'position:fixed;top:10px;left:10px;cursor:pointer;z-index:99999;font-size:18px;';
toggleBtn.onclick = () => {
if (!document.body.contains(panel)) document.body.appendChild(panel);
};
document.addEventListener('keydown', e => {
if (e.ctrlKey && e.shiftKey && e.key === 'F') {
document.body.appendChild(panel);
}
});
document.addEventListener('DOMContentLoaded', () => {
document.body.appendChild(toggleBtn);
});
})();