fix(qdreader): harden cron trigger detection
This commit is contained in:
@@ -103,6 +103,8 @@ Python 示例:
|
|||||||
|
|
||||||
- `rule` 支持正则,可写多行表示多个触发规则。
|
- `rule` 支持正则,可写多行表示多个触发规则。
|
||||||
- `cron` 支持 5 位或 6 位 cron 表达式。
|
- `cron` 支持 5 位或 6 位 cron 表达式。
|
||||||
|
- 定时入口必须按运行环境判断,而不是只靠“消息内容为空”。推荐先检测 `ImType()` / `GetImType()` 是否为 `cron`,命中后直接走定时分支;不要在主入口用 `input()` 兜底读取命令内容。`input()` 是交互等待函数,定时场景可能返回 `q`、阻塞或把空触发误判成普通命令,导致 cron 已触发但业务没跑。参考茅台插件模式:`ImType() === "cron" ? "fake" : ImType()` 后显式进入 `cronTask()`。
|
||||||
|
- cron 头注兼容性优先使用带空格格式 `// [cron: 1 7 * * *]`,避免不同 Autman 解析器只识别一种注释风格。
|
||||||
- `admin: true` 表示仅管理员可执行。
|
- `admin: true` 表示仅管理员可执行。
|
||||||
- `priority` 数字越大优先级越高。
|
- `priority` 数字越大优先级越高。
|
||||||
- `bypass: true` 常用于全拦截规则,例如 `[rule: ?]`,表示旁路并行处理。
|
- `bypass: true` 常用于全拦截规则,例如 `[rule: ?]`,表示旁路并行处理。
|
||||||
|
|||||||
+21
-18
@@ -4,17 +4,17 @@
|
|||||||
//[author: Hermes]
|
//[author: Hermes]
|
||||||
//[service: BOSS]
|
//[service: BOSS]
|
||||||
//[class: 工具类]
|
//[class: 工具类]
|
||||||
//[version: 2.11.1]
|
// [version: 2.12.0]
|
||||||
//[platform: web,qq,wx,tg,tb,fs,we]
|
// [platform: web,qq,wx,tg,tb,fs,we]
|
||||||
//[public: false]
|
// [public: false]
|
||||||
//[price: 0]
|
// [price: 0]
|
||||||
//[disable: false]
|
// [disable: false]
|
||||||
//[description: 启点读书(QDReader) Autman 签到插件:保存 QX 抓到的 H5 Cookie,支持手动“启点签到”;定时使用 `1 7 * * *` 每日 07:01 签到;完全体可选任务按上游原项目解密流程执行;每次签到运行结束后立即归档并清空最近运行日志,不再依赖单独归档定时;带独立 bucket、多用户隔离、请求重试、签名响应解析、结果摘要和安全脱敏。]
|
// [description: 启点读书(QDReader) Autman 签到插件:保存 QX 抓到的 H5 Cookie,支持手动“启点签到”;定时使用 `1 7 * * *` 每日 07:01 签到;完全体可选任务按上游原项目解密流程执行;每次签到运行结束后立即归档并清空最近运行日志,不再依赖单独归档定时;带独立 bucket、多用户隔离、请求重试、签名响应解析、结果摘要和安全脱敏。]
|
||||||
//[rule: ^启点(账号|查询|ck|CK|cookie|Cookie|签到|读书|归档|日志归档)(.*)$]
|
// [rule: ^启点(账号|查询|ck|CK|cookie|Cookie|签到|读书|归档|日志归档)(.*)$]
|
||||||
//[rule: ^qdreader(.*)$]
|
// [rule: ^qdreader(.*)$]
|
||||||
//[admin: true]
|
// [admin: true]
|
||||||
//[priority: 600]
|
// [priority: 600]
|
||||||
//[cron: 1 7 * * *]
|
// [cron: 1 7 * * *]
|
||||||
|
|
||||||
|
|
||||||
var BUCKET = "hermes_qidian"
|
var BUCKET = "hermes_qidian"
|
||||||
@@ -266,17 +266,20 @@ function maskUid(uid) {
|
|||||||
|
|
||||||
function contentText() {
|
function contentText() {
|
||||||
var s = ""
|
var s = ""
|
||||||
try { if (typeof getContent === "function") s = getContent() || "" } catch (e) {}
|
var im = ""
|
||||||
try { if (!s && typeof GetContent === "function") s = GetContent() || "" } catch (e) {}
|
try { if (typeof ImType === "function") im = ImType() || "" } catch (e) {}
|
||||||
try { if (!s && typeof input === "function") s = input() || "" } catch (e) {}
|
try { if (!im && typeof GetImType === "function") im = GetImType() || "" } catch (e2) {}
|
||||||
try { if (!s && typeof sender !== "undefined" && sender && sender.getContent) s = sender.getContent() || "" } catch (e) {}
|
if (lower(trim(im)) === "cron") return ""
|
||||||
try { if (!s && typeof sender !== "undefined" && sender && sender.getMessage) s = sender.getMessage() || "" } catch (e) {}
|
try { if (typeof getContent === "function") s = getContent() || "" } catch (e3) {}
|
||||||
try { if (!s && typeof message !== "undefined") s = String(message) } catch (e) {}
|
try { if (!s && typeof GetContent === "function") s = GetContent() || "" } catch (e4) {}
|
||||||
|
try { if (!s && typeof sender !== "undefined" && sender && sender.getContent) s = sender.getContent() || "" } catch (e5) {}
|
||||||
|
try { if (!s && typeof sender !== "undefined" && sender && sender.getMessage) s = sender.getMessage() || "" } catch (e6) {}
|
||||||
|
try { if (!s && typeof message !== "undefined") s = String(message) } catch (e7) {}
|
||||||
return trim(s)
|
return trim(s)
|
||||||
}
|
}
|
||||||
function usage() {
|
function usage() {
|
||||||
return [
|
return [
|
||||||
"启点读书签到插件 v2.11.0",
|
"启点读书签到插件 v2.12.0",
|
||||||
"【一级菜单】",
|
"【一级菜单】",
|
||||||
"账号管理:启点账号",
|
"账号管理:启点账号",
|
||||||
"执行查询:启点查询",
|
"执行查询:启点查询",
|
||||||
|
|||||||
@@ -4,17 +4,17 @@
|
|||||||
//[author: Hermes]
|
//[author: Hermes]
|
||||||
//[service: BOSS]
|
//[service: BOSS]
|
||||||
//[class: 工具类]
|
//[class: 工具类]
|
||||||
//[version: 2.11.1]
|
// [version: 2.12.0]
|
||||||
//[platform: web,qq,wx,tg,tb,fs,we]
|
// [platform: web,qq,wx,tg,tb,fs,we]
|
||||||
//[public: false]
|
// [public: false]
|
||||||
//[price: 0]
|
// [price: 0]
|
||||||
//[disable: false]
|
// [disable: false]
|
||||||
//[description: 启点读书(QDReader) Autman 签到插件:保存 QX 抓到的 H5 Cookie,支持手动“启点签到”;定时使用 `1 7 * * *` 每日 07:01 签到;完全体可选任务按上游原项目解密流程执行;每次签到运行结束后立即归档并清空最近运行日志,不再依赖单独归档定时;带独立 bucket、多用户隔离、请求重试、签名响应解析、结果摘要和安全脱敏。]
|
// [description: 启点读书(QDReader) Autman 签到插件:保存 QX 抓到的 H5 Cookie,支持手动“启点签到”;定时使用 `1 7 * * *` 每日 07:01 签到;完全体可选任务按上游原项目解密流程执行;每次签到运行结束后立即归档并清空最近运行日志,不再依赖单独归档定时;带独立 bucket、多用户隔离、请求重试、签名响应解析、结果摘要和安全脱敏。]
|
||||||
//[rule: ^启点(账号|查询|ck|CK|cookie|Cookie|签到|读书|归档|日志归档)(.*)$]
|
// [rule: ^启点(账号|查询|ck|CK|cookie|Cookie|签到|读书|归档|日志归档)(.*)$]
|
||||||
//[rule: ^qdreader(.*)$]
|
// [rule: ^qdreader(.*)$]
|
||||||
//[admin: true]
|
// [admin: true]
|
||||||
//[priority: 600]
|
// [priority: 600]
|
||||||
//[cron: 1 7 * * *]
|
// [cron: 1 7 * * *]
|
||||||
|
|
||||||
|
|
||||||
var BUCKET = "hermes_qidian"
|
var BUCKET = "hermes_qidian"
|
||||||
@@ -266,17 +266,20 @@ function maskUid(uid) {
|
|||||||
|
|
||||||
function contentText() {
|
function contentText() {
|
||||||
var s = ""
|
var s = ""
|
||||||
try { if (typeof getContent === "function") s = getContent() || "" } catch (e) {}
|
var im = ""
|
||||||
try { if (!s && typeof GetContent === "function") s = GetContent() || "" } catch (e) {}
|
try { if (typeof ImType === "function") im = ImType() || "" } catch (e) {}
|
||||||
try { if (!s && typeof input === "function") s = input() || "" } catch (e) {}
|
try { if (!im && typeof GetImType === "function") im = GetImType() || "" } catch (e2) {}
|
||||||
try { if (!s && typeof sender !== "undefined" && sender && sender.getContent) s = sender.getContent() || "" } catch (e) {}
|
if (lower(trim(im)) === "cron") return ""
|
||||||
try { if (!s && typeof sender !== "undefined" && sender && sender.getMessage) s = sender.getMessage() || "" } catch (e) {}
|
try { if (typeof getContent === "function") s = getContent() || "" } catch (e3) {}
|
||||||
try { if (!s && typeof message !== "undefined") s = String(message) } catch (e) {}
|
try { if (!s && typeof GetContent === "function") s = GetContent() || "" } catch (e4) {}
|
||||||
|
try { if (!s && typeof sender !== "undefined" && sender && sender.getContent) s = sender.getContent() || "" } catch (e5) {}
|
||||||
|
try { if (!s && typeof sender !== "undefined" && sender && sender.getMessage) s = sender.getMessage() || "" } catch (e6) {}
|
||||||
|
try { if (!s && typeof message !== "undefined") s = String(message) } catch (e7) {}
|
||||||
return trim(s)
|
return trim(s)
|
||||||
}
|
}
|
||||||
function usage() {
|
function usage() {
|
||||||
return [
|
return [
|
||||||
"启点读书签到插件 v2.11.0",
|
"启点读书签到插件 v2.12.0",
|
||||||
"【一级菜单】",
|
"【一级菜单】",
|
||||||
"账号管理:启点账号",
|
"账号管理:启点账号",
|
||||||
"执行查询:启点查询",
|
"执行查询:启点查询",
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ function runPlugin({ pluginCode = code, filename = pluginPath, content = '', sto
|
|||||||
if (String(req.url).includes('/sign')) return { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } };
|
if (String(req.url).includes('/sign')) return { body: { code: 0, data: { headers: { 'QD-Sign': 'sig' } } } };
|
||||||
return { statusCode: 200, body: { code: 0, msg: '签到成功' } };
|
return { statusCode: 200, body: { code: 0, msg: '签到成功' } };
|
||||||
},
|
},
|
||||||
|
input: () => '',
|
||||||
...globals,
|
...globals,
|
||||||
};
|
};
|
||||||
vm.createContext(ctx);
|
vm.createContext(ctx);
|
||||||
@@ -717,6 +718,27 @@ test('manual sign replies per account first and summary separately for multi-acc
|
|||||||
assert.match(r.replies[2], /日志已归档/);
|
assert.match(r.replies[2], /日志已归档/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('cron detection uses ImType cron and does not consume input as command text', () => {
|
||||||
|
const store = {
|
||||||
|
qdreader_cookie_json: JSON.stringify({ '12345': cookie }),
|
||||||
|
qdreader_user_bind_json: JSON.stringify({ '12345': 'user-a' }),
|
||||||
|
};
|
||||||
|
const r = runPlugin({
|
||||||
|
content: '',
|
||||||
|
store,
|
||||||
|
userId: 'cron',
|
||||||
|
globals: {
|
||||||
|
ImType: () => 'cron',
|
||||||
|
input: () => 'q',
|
||||||
|
Date: fixedDateClass('2026-05-19T07:01:00.000+08:00'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.equal(r.calls.length, 4);
|
||||||
|
assert.equal(r.replies.length, 1);
|
||||||
|
assert.match(r.replies[0], /汇总:成功 1 \/ 失败 0 \/ 总计 1/);
|
||||||
|
assert.match(r.replies[0], /定时任务\/零点任务/);
|
||||||
|
});
|
||||||
|
|
||||||
test('manual sign only runs current user accounts while cron runs all accounts', () => {
|
test('manual sign only runs current user accounts while cron runs all accounts', () => {
|
||||||
const store = {
|
const store = {
|
||||||
qdreader_cookie_json: JSON.stringify({ '12345': cookie, '67890': cookie.replace(/12345/g, '67890') }),
|
qdreader_cookie_json: JSON.stringify({ '12345': cookie, '67890': cookie.replace(/12345/g, '67890') }),
|
||||||
|
|||||||
Reference in New Issue
Block a user