Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions apps/qqinfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
30 changes: 24 additions & 6 deletions utils/QQApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Expand Down
Loading