您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhanced input preservation with security checks, performance optimizations, and user controls.
当前为
// ==UserScript== // @name Input Guardian // @namespace https://spin.rip/ // @match *://*/* // @grant GM_registerMenuCommand // @version 1.0 // @author Spinfal // @description Enhanced input preservation with security checks, performance optimizations, and user controls. // @license AGPL-3.0 License // ==/UserScript== (function () { 'use strict'; const dbName = "InputGuardianDB"; const storeName = "inputs"; const dbVersion = 2; const DEBOUNCE_TIME = 500; // ms const CLEANUP_DAYS = 30; const SENSITIVE_NAMES = /(ccnum|creditcard|cvv|ssn|sin|securitycode)/i; // Security: Additional sensitive field check const isSensitiveField = (input) => { return SENSITIVE_NAMES.test(input.id) || SENSITIVE_NAMES.test(input.name) || input.closest('[data-sensitive="true"]'); }; // Performance: Debounce function const debounce = (func, wait) => { let timeout; return (...args) => { clearTimeout(timeout); timeout = setTimeout(() => func.apply(this, args), wait); }; }; // Enhanced database with timestamp const openDatabase = () => { return new Promise((resolve, reject) => { const request = indexedDB.open(dbName, dbVersion); request.onupgradeneeded = (event) => { const db = event.target.result; // Create or upgrade object store let store; if (!db.objectStoreNames.contains(storeName)) { store = db.createObjectStore(storeName, { keyPath: "id" }); } else { store = request.transaction.objectStore(storeName); } // Ensure the "timestamp" index exists if (!store.indexNames.contains("timestamp")) { store.createIndex("timestamp", "timestamp", { unique: false }); } }; request.onsuccess = (event) => resolve(event.target.result); request.onerror = (event) => reject(event.target.error); }); }; // Cleanup old entries const cleanupOldEntries = async () => { try { const db = await openDatabase(); const transaction = db.transaction(storeName, "readwrite"); const store = transaction.objectStore(storeName); const index = store.index("timestamp"); const threshold = Date.now() - (CLEANUP_DAYS * 86400000); let cursor = await new Promise((resolve, reject) => { const request = index.openCursor(IDBKeyRange.upperBound(threshold)); request.onsuccess = (event) => resolve(event.target.result); request.onerror = (event) => reject(event.target.error); }); while (cursor) { store.delete(cursor.primaryKey); cursor = await new Promise((resolve, reject) => { cursor.continue(); cursor.onsuccess = (event) => resolve(event.target.result); cursor.onerror = (event) => reject(event.target.error); }); } } catch (error) { console.error("Cleanup failed:", error); } }; const saveInput = debounce(async (id, value) => { try { const db = await openDatabase(); const transaction = db.transaction(storeName, "readwrite"); const store = transaction.objectStore(storeName); store.put({ id, value, timestamp: Date.now() }); } catch (error) { console.error("Error saving input:", error); } }, DEBOUNCE_TIME); // Handle contenteditable elements const handleRichText = (element) => { const id = element.id || element.dataset.guardianId || Math.random().toString(36).substr(2, 9); element.dataset.guardianId = id; return id; }; // User controls const addControls = () => { // Add menu command if (typeof GM_registerMenuCommand === 'function') { GM_registerMenuCommand("Clear Saved Inputs", async () => { try { const db = await openDatabase(); const transaction = db.transaction(storeName, "readwrite"); const store = transaction.objectStore(storeName); await store.clear(); showFeedback('Cleared all saved inputs!'); } catch (error) { console.error("Clear failed:", error); showFeedback('Failed to clear inputs'); } }); } // Add hotkey (Ctrl+Shift+Z) document.addEventListener('keydown', (e) => { if (e.ctrlKey && e.shiftKey && e.key === 'Z') { indexedDB.deleteDatabase(dbName); showFeedback('Database reset! Please reload the page.'); } }); }; // Visual feedback const showFeedback = (message) => { const existing = document.getElementById('guardian-feedback'); if (existing) existing.remove(); const div = document.createElement('div'); div.id = 'guardian-feedback'; div.style = ` position: fixed; bottom: 20px; right: 20px; padding: 10px 20px; background: #4CAF50; color: white; border-radius: 5px; z-index: 9999; opacity: 1; transition: opacity 0.5s ease-in-out; `; div.textContent = message; document.body.appendChild(div); // Fade out and remove after 2 seconds setTimeout(() => { div.style.opacity = '0'; setTimeout(() => div.remove(), 500); }, 2000); }; // Enhanced input detection const isValidInput = (input) => { const isHidden = input.offsetParent === null || window.getComputedStyle(input).visibility === 'hidden'; return !isHidden && input.type !== 'password' && input.autocomplete !== 'off' && !isSensitiveField(input); }; // Modified event listener with contenteditable support document.addEventListener('input', (event) => { const target = event.target; let id, value; if (target.isContentEditable) { id = handleRichText(target); value = target.innerHTML; } else if (['INPUT', 'TEXTAREA', 'SELECT'].includes(target.tagName)) { id = target.id || target.name; value = target.value; } if (id && isValidInput(target)) { saveInput(id, value); } }); // Initialize window.addEventListener('load', () => { restoreInputs(); addControls(); cleanupOldEntries(); }); // Modified restore function with timestamp const restoreInputs = async () => { try { const db = await openDatabase(); const transaction = db.transaction(storeName, "readonly"); const store = transaction.objectStore(storeName); const request = store.getAll(); request.onsuccess = () => { let restoredCount = 0; request.result.forEach(({ id, value }) => { const input = document.querySelector(`[id="${id}"], [name="${id}"]`); if (input && isValidInput(input)) { if (input.isContentEditable) { input.innerHTML = value; } else { input.value = value; } restoredCount++; } }); if (restoredCount > 0) { showFeedback(`Restored ${restoredCount} input${restoredCount !== 1 ? 's' : ''}!`); } }; } catch (error) { console.error("Restore failed:", error); } }; })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址