From 11530c342d8c15de361d66c265a46f0b2789ec8d Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Sun, 17 May 2026 16:47:16 +0800 Subject: [PATCH] fix: fallback qdreader uid to cookie guid --- js/qdreader_sign_autman.js | 17 ++++++++++++----- plugins/qdreader/README.md | 6 +++++- plugins/qdreader/qdreader_sign_autman.js | 17 ++++++++++++----- tests/qdreader_plugin.test.mjs | 8 ++++++++ 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/js/qdreader_sign_autman.js b/js/qdreader_sign_autman.js index 04b265a..ffafeae 100644 --- a/js/qdreader_sign_autman.js +++ b/js/qdreader_sign_autman.js @@ -129,22 +129,29 @@ function cookieToString(jar) { return arr.join("; ") } function b64decode(s) { - s = String(s || "") + s = String(s || "").trim() + try { s = decodeURIComponent(s) } catch (e) {} + s = s.replace(/-/g, "+").replace(/_/g, "/") + while (s.length % 4) s += "=" try { if (typeof Buffer !== "undefined") return Buffer.from(s, "base64").toString("utf8") } catch (e) {} try { return decodeURIComponent(escape(atob(s))) } catch (e) { return "" } } +function isRealUid(uid) { + uid = String(uid === undefined || uid === null ? "" : uid).trim() + return /^\d{5,}$/.test(uid) ? uid : "" +} function uidFromQDHeader(qdheader) { var decoded = b64decode(qdheader) var uid = decoded ? trim(decoded.split("|")[0] || "") : "" - return /^\d+$/.test(uid) ? uid : "" + return isRealUid(uid) } function extractUid(cookie) { var jar = parseCookieString(cookie) var uid = uidFromQDHeader(jar.QDHeader || jar.qdheader || jar.QDHEADER || "") if (uid) return uid - if (jar.uid) return String(jar.uid) - if (jar.userid) return String(jar.userid) - return "" + uid = isRealUid(jar.uid || jar.userid || jar.userId || jar.UserId) + if (uid) return uid + return isRealUid(jar.ywguid || jar.gwguid || jar.guid) } function maskCookie(cookie) { cookie = String(cookie || "") diff --git a/plugins/qdreader/README.md b/plugins/qdreader/README.md index 48ed091..b3559ee 100644 --- a/plugins/qdreader/README.md +++ b/plugins/qdreader/README.md @@ -117,7 +117,11 @@ set(key, value) ## 签名与签到流程 -1. 从 Cookie 解析 `QDHeader/qdh/uid/guid/qimei/qimei36`。 +1. 从 Cookie 解析账号标识与签名参数: + - 优先解析 `QDHeader` 第一段有效数字 uid; + - 其次读取 `uid/userid/userId/UserId`; + - 若 `QDHeader` 第一段为 `(null)` 或无效,回退 `ywguid/gwguid/guid`,与 QX 抓包脚本保持一致; + - 同时提取 `qdh/QDHeader/guid/qimei/qimei36` 供签名网关使用。 2. `POST /sign` 获取请求签名头。 3. `POST https://h5.if.qidian.com/argus/api/v3/checkin/checkin` 完成签到。 4. 写入单账号最后结果 `qdreader_last_result_json`,包括 `ok/msg/time/source/runId`。 diff --git a/plugins/qdreader/qdreader_sign_autman.js b/plugins/qdreader/qdreader_sign_autman.js index 04b265a..ffafeae 100644 --- a/plugins/qdreader/qdreader_sign_autman.js +++ b/plugins/qdreader/qdreader_sign_autman.js @@ -129,22 +129,29 @@ function cookieToString(jar) { return arr.join("; ") } function b64decode(s) { - s = String(s || "") + s = String(s || "").trim() + try { s = decodeURIComponent(s) } catch (e) {} + s = s.replace(/-/g, "+").replace(/_/g, "/") + while (s.length % 4) s += "=" try { if (typeof Buffer !== "undefined") return Buffer.from(s, "base64").toString("utf8") } catch (e) {} try { return decodeURIComponent(escape(atob(s))) } catch (e) { return "" } } +function isRealUid(uid) { + uid = String(uid === undefined || uid === null ? "" : uid).trim() + return /^\d{5,}$/.test(uid) ? uid : "" +} function uidFromQDHeader(qdheader) { var decoded = b64decode(qdheader) var uid = decoded ? trim(decoded.split("|")[0] || "") : "" - return /^\d+$/.test(uid) ? uid : "" + return isRealUid(uid) } function extractUid(cookie) { var jar = parseCookieString(cookie) var uid = uidFromQDHeader(jar.QDHeader || jar.qdheader || jar.QDHEADER || "") if (uid) return uid - if (jar.uid) return String(jar.uid) - if (jar.userid) return String(jar.userid) - return "" + uid = isRealUid(jar.uid || jar.userid || jar.userId || jar.UserId) + if (uid) return uid + return isRealUid(jar.ywguid || jar.gwguid || jar.guid) } function maskCookie(cookie) { cookie = String(cookie || "") diff --git a/tests/qdreader_plugin.test.mjs b/tests/qdreader_plugin.test.mjs index 52226cd..c299dc2 100644 --- a/tests/qdreader_plugin.test.mjs +++ b/tests/qdreader_plugin.test.mjs @@ -65,6 +65,14 @@ test('manual cookie save masks cookie and stores by uid', () => { assert.equal(JSON.parse(r.bucketStore['hermes_qidian.qdreader_user_bind_json'])['12345'], 'user-a'); }); +test('manual cookie save falls back to ywguid when QDHeader uid is null', () => { + const fallbackCookie = 'QDHeader=KG51bGwpfHg=; ywguid=54321; qdh=qdh; sessionyw=s; appId=10'; + const r = runPlugin({ content: '启点ck ' + fallbackCookie }); + assert.match(r.replies.join('\n'), /CK新增成功/); + assert.match(r.replies.join('\n'), /uid: 54321/); + assert.equal(JSON.parse(r.store.qdreader_cookie_json)['54321'], fallbackCookie); +}); + test('manual sign and cron sign both call sign gateway then qidian checkin', () => { const store = { qdreader_cookie_json: JSON.stringify({ '12345': cookie }) }; const manual = runPlugin({ content: '启点签到', store: { ...store } });