This commit is contained in:
2026-10-16 16:34:15 +08:00
parent 7a3769670b
commit ff366a4daf
80 changed files with 9961 additions and 888 deletions

40
main/audit-rate.js Normal file
View File

@@ -0,0 +1,40 @@
// P2-7(audit):IPC 高频调用检测 —— 滑动窗口按 key 计数。
//
// 背景:app:open-config-dir 这类「打开系统目录」的 handler 被 renderer 任意
// JS 调到(XSS / devtools 注入)。单次调用无害,但脚本化高频调用能弹出一串
// 文件管理器窗口骚扰用户。主进程记一笔滑动窗口计数,超阈值 console.warn
// (会同步进 notes-main.log,事后可查)。
//
// 只检测、不拦截 —— 拦截合法双击/连点会误伤,先只留审计痕迹。
'use strict';
/**
* @param {object} opts
* @param {number} opts.windowMs 滑动窗口毫秒数
* @param {number} opts.threshold 窗口内允许的最大次数;第 threshold+1 次起 exceeded=true
* @param {() => number} [opts.now] 时钟注入,默认 Date.now(单测推进时间用)
* @returns {{ hit: (key: string) => { count: number, exceeded: boolean } }}
*/
function createAuditRateTracker({ windowMs, threshold, now } = {}) {
const clock = typeof now === 'function' ? now : Date.now;
/** @type {Map<string, number[]>} key → 窗口内各次调用的时间戳(升序) */
const buckets = new Map();
return {
hit(key) {
const t = clock();
const cutoff = t - windowMs;
let arr = buckets.get(key);
if (!arr) {
arr = [];
buckets.set(key, arr);
}
// 过期剔除:[cutoff, t) 语义 —— 恰好 windowMs 前的记录视为过期
while (arr.length > 0 && arr[0] <= cutoff) arr.shift();
arr.push(t);
return { count: arr.length, exceeded: arr.length > threshold };
},
};
}
module.exports = { createAuditRateTracker };