diff --git a/apps/qqinfo.js b/apps/qqinfo.js index 2fd304b..c7851c9 100644 --- a/apps/qqinfo.js +++ b/apps/qqinfo.js @@ -26,20 +26,39 @@ export class QQinfo extends plugin { if (mid == "" || !/^\d+$/.test(mid)) { return e.reply("请输入qq号或者直接艾特再发送命令", true) } - // 获取用户 - const KEY_DATA = await bot.sendApi('get_credentials', { - domain: "vip.qq.com", - }) - // logger.info(KEY_DATA.data.cookies, 666) - const skeyRegex = /skey=([^;]+)/.exec(KEY_DATA.data.cookies) - const pSkeyRegex = /p_skey=([^;]+)/.exec(KEY_DATA.data.cookies) - const uinRegex = /uin=([^;]+)/.exec(KEY_DATA.data.cookies) + // 判断协议端类型:NapCat 用 get_credentials,LLBot 等 OneBot 11 标准用 get_cookies + const isNapCat = bot.version?.name?.toLowerCase().includes('napcat') || + bot.adapter?.name?.toLowerCase().includes('napcat') + const apiName = isNapCat ? 'get_credentials' : 'get_cookies' + + let KEY_DATA + try { + KEY_DATA = await bot.sendApi(apiName, { domain: "vip.qq.com" }) + } catch (err) { + return e.reply(`获取 QQ 凭证失败:${apiName} 接口调用异常`, true) + } + + const cookies = (KEY_DATA?.data ?? KEY_DATA)?.cookies || "" + if (!cookies) { + return e.reply("获取 QQ 凭证失败:返回数据为空", true) + } - const skey = skeyRegex?.[1] // 输出 @sFOi60Ji4 - const p_skey = pSkeyRegex?.[1] // 输出 RLsR0kc5JtYiGuHxndsBYRQh3ugVWBVvdMstgQXrEdc_ - const url = `http://jiuli.xiaoapi.cn/i/qq/qq_level.php?qq=${mid}&return=json&uin=${uinRegex}&skey=${skey}&pskey=${p_skey}` - const DATA_JSON = await fetch(url).then(res => res.json()) + // p_skey 在部分协议端返回为 skey 同名前缀(p_skey / pskey),uin 可能带 o 前缀 + // 注意:必须先匹配 p_skey 再匹配 skey,否则 skey 正则会误匹配到 "p_skey" 里的 "skey" + const p_skey = /(?:^|;)\s*p_?skey=([^;]+)/.exec(cookies)?.[1] + const skey = /(?:^|;)\s*skey=([^;]+)/.exec(cookies)?.[1] + const uin = /(?:^|;)\s*uin=o?0*([^;]+)/.exec(cookies)?.[1] || bot.uin + + if (!skey || !p_skey) { + return e.reply("获取 QQ 凭证不完整(缺少 skey/p_skey),该协议端可能不支持 vip.qq.com 域名的 Cookie", true) + } + + const url = `http://jiuli.xiaoapi.cn/i/qq/qq_level.php?qq=${mid}&return=json&uin=${uin}&skey=${skey}&pskey=${p_skey}` + const DATA_JSON = await fetch(url, { signal: AbortSignal.timeout(15000) }).then(res => res.json()) + if (DATA_JSON?.code === -1) { + return e.reply(`查询失败:${DATA_JSON.msg || "接口返回异常"}`, true) + } DATA_JSON.cardTitle = '信息查询成功!!!' logger.info(DATA_JSON, 88) diff --git a/utils/QQApi.js b/utils/QQApi.js index 83f3aab..b4c0931 100644 --- a/utils/QQApi.js +++ b/utils/QQApi.js @@ -76,13 +76,31 @@ export class QQApi { // }), // }).then(res => res.json()) - const KEY_DATA = await Bot.sendApi('get_credentials', { - "domain": "qzone.qq.com", - }) - // logger.info(KEY_DATA.data.cookies, 666) + // 凭证接口:NapCat 名 get_credentials,LLBot 等 OneBot 11 标准实现名 get_cookies + // (后者只返回 cookies,csrf_token 需另调 get_csrf_token) + let data = null + for (const action of ['get_credentials', 'get_cookies']) { + try { + const res = await Bot.sendApi(action, { "domain": "qzone.qq.com" }) + const payload = res?.data ?? res + if (payload?.cookies) { data = payload; break } + } catch (err) { + logger?.debug?.(`[QQApi] ${action} 获取失败: ${err.message}`) + } + } + if (!data) return undefined + // NapCat 返回 token 字段,LLBot 等 OneBot 11 标准实现返回 csrf_token 字段,两者取值算法相同 - const data = KEY_DATA.data - return { ...data, token: data.token ?? data.csrf_token } + let token = data.token ?? data.csrf_token + if (token === undefined) { + try { + const res = await Bot.sendApi('get_csrf_token', {}) + token = (res?.data ?? res)?.token + } catch (err) { + logger?.debug?.(`[QQApi] get_csrf_token 获取失败: ${err.message}`) + } + } + return { ...data, token } } catch (error) {