Closed Star-Vk closed 1 year ago
看起来可能好像和 ArkAppMessage
, MessageForArkApp
, resIDForLongMsg
有关系
是的是的,可惜我比较菜,希望mirai能支持,这样就能填补mirai不能发送视频消息的空缺了
最近我也遇到了这个问题,也在想办法能不能制作token出来,但是能力有限根本不知道怎么计算,不知道你是怎么通过oicq的core去获取token的呢?
最近我也遇到了这个问题,也在想办法能不能制作token出来,但是能力有限根本不知道怎么计算,不知道你是怎么通过oicq的core去获取token的呢?
在第一条帖子中我已经说明了获取token的方法,这个token值并不是oicq进行计算的,我也试图找到他的算法,但最终以失败告终,通过oicq的底层代码可知,原本的json的文本内容,通过了增加了一些新的东西进去之后进行了两次编码(or 加密?)通过发送消息的方式发送回了腾讯服务器,然后本地监听了message事件,等待腾讯服务器返回签名好的json,然后在返回给ark签名的函数结果。关于oicq实现的代码不方便展现,这一功能实现原理在第一条已经提到过了,可以通过原来音乐分享的入口将type改为10通过小程序的方式”申请“签名好的token值,oicq的ark签名方法无法整个移植到mirai来,以为他需要发送消息的协议。
这个是从服务器动态拉取js代码来计算的吧?我之前找的,可能忘了
这个是从服务器动态拉取js代码来计算的吧?我之前找的,可能忘了
emmmmm,反正token值不是本地计算的,是要把json文本发送回腾讯服务器然后腾讯服务器计算完,返回带有签名的json回来,然后QQ机器人发出去
emmmmm,反正token值不是本地计算的,是要把json文本发送回腾讯服务器然后腾讯服务器计算完,返回带有签名的json回来,然后QQ机器人发出去
新版macqq查询打开的文件就能看到arkapp的js缓存文件
emmmmm,反正token值不是本地计算的,是要把json文本发送回腾讯服务器然后腾讯服务器计算完,返回带有签名的json回来,然后QQ机器人发出去
新版macqq查询打开的文件就能看到arkapp的js缓存文件
这样子嘛?有能找到相关的token的算法嘛?望提供下,谢谢!
这样子嘛?有能找到相关的token的算法嘛?望提供下,谢谢!
我还没仔细看过,这玩意可能是算法,可能是界面,而且是从服务器拉取的
this.sendUni是oicq发送”数据包“(应该是这么叫)的方法,再往下追踪就是涉及到收发消息的协议了,同时oicq发送普通消息也是通过this.sendUni实现的。
直接贴链接不好么
this.sendUni是oicq发送”数据包“(应该是这么叫)的方法,再往下追踪就是涉及到收发消息的协议了,同时oicq发送普通消息也是通过this.sendUni实现的。
直接贴链接不好么
这个方法是根据oicq单独写出来,链接只有oicq通过OidbSvc.0xb77_9分享音乐的方法
this.sendUni是oicq发送”数据包“(应该是这么叫)的方法,再往下追踪就是涉及到收发消息的协议了,同时oicq发送普通消息也是通过this.sendUni实现的。
直接贴链接不好么
好吧
谢谢!我昨天在好几个地方看见你的id在问这个问题,但是都没人回答,谢谢你的代码!
谢谢!我昨天在好几个地方看见你的id在问这个问题,但是都没人回答,谢谢你的代码!
好的
我根据这个测了下,不知道为什么都是Time Out :( 以及 oicq 的包格式和 mirai 里的有一些差别,我这里以 oicq 为主改了下 mirai 里的包结构 https://github.com/Nambers/mirai/blob/6e09aab2d7c6dfa298e0dc992bddcd088e4d5fed/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/SignArkPacket.kt 测试代码:
val app = """
{"app":"com.tencent.bot.task.deblock","desc":"","view":"index","ver":"2.0.4.0","prompt":"XKBot6.0 Menu","appID":"","sourceName":"","actionData":"","actionData_A":"","sourceUrl":"","meta":{"detail":{"appID":"1109937557","battleDesc":"","botName":"XKbot","cmdList":[{"cmd":" ","cmdDesc":"欢迎您的使用!!!","cmdTitle":"QQ"}],"cmdTitle":"","content":"121212","guildID":"","iconLeft":[{"num":"10"}],"iconRight":[],"receiverName":"","subGuildID":"SUBGUILDID#","title":"","titleColor":""}}}
""".trimIndent()
bot.asQQAndroidBot().network.sendAndExpect(
SignArkPacket(
bot.client,
app
)
).response.printStructure()
以上的json只有手机端能显示吗
@Nambers 如果你用的最新的miria源代码的话,应该是QQ版本不支持该OidbSvc,可能需要你重新抓
@Nambers 如果你用的最新的miria源代码的话,应该是QQ版本不支持该OidbSvc,可能需要你重新抓
qs 不过我对着 qq 8.8.95里面看了下,结构体和mirai一样的。我晚点可以试一下能不能抓到这个包
@Nambers 如果你用的最新的miria源代码的话,应该是QQ版本不支持该OidbSvc,可能需要你重新抓
我看了下,我没抓到 0xb77 这个包, 但是有另外两个可能有关系的包
LightAppSvc.mini_app_share.AdaptShareInfo
和 ~LightAppSvc.mini_app_usr_time.ReportShare
~
@Nambers 如果你用的最新的miria源代码的话,应该是QQ版本不支持该OidbSvc,可能需要你重新抓
我看了下,我没抓到 0xb77 这个包, 但是有另外两个可能有关系的包
LightAppSvc.mini_app_share.AdaptShareInfo
和 ~LightAppSvc.mini_app_usr_time.ReportShare
~
我看了下AdaptShareInfo, 我觉得他比较有可能取到ark, 他的发送包和返回包:
@Serializable
internal class StAdaptShareInfoReq(
@JvmField @ProtoNumber(1) val extInfo: StCommonExt? = null,
@JvmField @ProtoNumber(2) val appid: String = "",
@JvmField @ProtoNumber(3) val title: String = "",
@JvmField @ProtoNumber(4) val desc: String = "",
@JvmField @ProtoNumber(5) val time: Int = 0,
@JvmField @ProtoNumber(6) val scene: Int /* enum */ = 0,
@JvmField @ProtoNumber(7) val templetType: Int /* enum */ = 0,
@JvmField @ProtoNumber(8) val businessType: Int /* enum */ = 0,
@JvmField @ProtoNumber(9) val picUrl: String = "",
@JvmField @ProtoNumber(10) val vidUrl: String = "",
@JvmField @ProtoNumber(11) val jumpUrl: String = "",
@JvmField @ProtoNumber(12) val iconUrl: String = "",
@JvmField @ProtoNumber(13) val verType: Int = 0,
@JvmField @ProtoNumber(14) val shareType: Int = 0,
@JvmField @ProtoNumber(15) val versionId: String = "",
@JvmField @ProtoNumber(16) val withShareTicket: Int = 0,
@JvmField @ProtoNumber(17) val webURL: String = "",
@JvmField @ProtoNumber(18) val appidRich: String = "",
@JvmField @ProtoNumber(19) val template: StTemplateInfo? = null,
@JvmField @ProtoNumber(20) val rcvOpenId: String = ""
) : ProtoBuf
@Serializable
internal class StAdaptShareInfoRsp(
@JvmField @ProtoNumber(1) val extInfo: StCommonExt? = null,
@JvmField @ProtoNumber(2) val jsonData: String = ""
) : ProtoBuf
但是因为我模拟器上的qq不知道为什么打开不了任何小程序了(比如腾讯文档/qq音乐), 唯一抓到的包还是坏的, 然后我手上没有真机来抓 :( 你们谁要是有时间有兴趣可以去看看这个包,他发送部分是不带 token 的,返回部分的 jsonData 是带 token 的. PS: extInfo 是设备信息
结果大佬许可,下面是oicq对ark签名的代码实现
/** * 使用须知 * 1.代码语言为:TypeScript * 2.基于的框架为:oicq * 3.使用函数ArkSign前,请先执行npm i oicq */ import { Client } from "oicq"; /** * 通过小程序对json消息进行ark签名 基于oicq的core * @param json 要签名的json * @param Bot 已经创建好的机器人实例 * @param core oicq的核心 * @returns */ async function ArkSign(json:any,Bot:Client,core:any){ return new Promise((resolve, reject) => { class Result{ code:number = -1; [key:string]:any } let result = new Result(); let json_data = null; try{ json_data = JSON.parse(json); }catch(err){} if(!json_data){ result.code = -1; result.msg = '签名失败,不是有效的json!'; resolve(result); return; } delete json_data['extra']; //style 改成 10表示小程序发送 let appid = 100951776, style = 10, appname = 'tv.danmaku.bili', appsign = '7194d531cbe7960a22007b9f6bdaa38b'; let send_type = 0, recv_uin = Bot.uin, recv_guild_id = 0; let time = new Date().getTime(); function random(min:number,max:number){ const range = max - min; const random = Math.random(); const result = min + Math.round(random * range); return result; } let msg_seq = BigInt(`${time}${random(100,999)}`); //拼凑一个发送包 let body = { 1: appid, 2: 1, 3: style, 5: { 1: 1, 2: "0.0.0", 3: appname, 4: appsign, }, 7: { 15: msg_seq }, 10: send_type, 11: recv_uin, 18: { 1: 1109937557, 2: { 14: 'pages', }, 3: 'url', 4: 'text', 5: 'text', 6: 'text', 10: JSON.stringify(json_data), } }; //接收到签名好的json消息的处理函数 let json_handle = function(e:any){ if(Bot.uin == e.user_id && e?.message[0]?.type == 'json'){ let json_str = e.message[0].data; let json = null; let extra = null; try{ json = JSON.parse(json_str); extra = typeof(json.extra) == 'object' ? json.extra : JSON.parse(json.extra); }catch(err){} if(extra && extra.msg_seq == msg_seq){ Bot.off('message',json_handle); clearTimeout(timer); delete json['extra']; result.code = 1; result.msg = '签名成功!'; result.data = JSON.stringify(json); resolve(result); } } } let timer = setTimeout(function(){ Bot.off('message',json_handle); result.code = -1; result.msg = '签名失败,请稍后再试!'; resolve(result); },3000); //监听TX服务器返回签名好的json文本 Bot.on('message',json_handle); //发送数据包 Bot.sendOidb("OidbSvc.0xb77_9", core.pb.encode(body)); }); } export {ArkSign};
最终把消息进行core.pb.encode(body)得封装后传递进sendOidb方法,继续单步跟踪如下
/** dont use it if not clear the usage */ sendOidb(cmd: string, body: Uint8Array, timeout = 5) { const sp = cmd //OidbSvc.0x568_22 .replace("OidbSvc.", "") .replace("oidb_", "") .split("_") const type1 = parseInt(sp[0], 16), type2 = parseInt(sp[1]) body = pb.encode({ 1: type1, 2: isNaN(type2) ? 1 : type2, 3: 0, 4: body, 6: "android " + this.apk.ver, }) return this.sendUni(cmd, body, timeout) }
除去其他信息以外,主要是对发送消息就行了两次encode方法
this.sendUni是oicq发送”数据包“(应该是这么叫)的方法,再往下追踪就是涉及到收发消息的协议了,同时oicq发送普通消息也是通过this.sendUni实现的。
您好 请问如何正确调用此函数 本人不太熟悉nodejs 望回复 谢谢!
结果大佬许可,下面是oicq对ark签名的代码实现
/** * 使用须知 * 1.代码语言为:TypeScript * 2.基于的框架为:oicq * 3.使用函数ArkSign前,请先执行npm i oicq */ import { Client } from "oicq"; /** * 通过小程序对json消息进行ark签名 基于oicq的core * @param json 要签名的json * @param Bot 已经创建好的机器人实例 * @param core oicq的核心 * @returns */ async function ArkSign(json:any,Bot:Client,core:any){ return new Promise((resolve, reject) => { class Result{ code:number = -1; [key:string]:any } let result = new Result(); let json_data = null; try{ json_data = JSON.parse(json); }catch(err){} if(!json_data){ result.code = -1; result.msg = '签名失败,不是有效的json!'; resolve(result); return; } delete json_data['extra']; //style 改成 10表示小程序发送 let appid = 100951776, style = 10, appname = 'tv.danmaku.bili', appsign = '7194d531cbe7960a22007b9f6bdaa38b'; let send_type = 0, recv_uin = Bot.uin, recv_guild_id = 0; let time = new Date().getTime(); function random(min:number,max:number){ const range = max - min; const random = Math.random(); const result = min + Math.round(random * range); return result; } let msg_seq = BigInt(`${time}${random(100,999)}`); //拼凑一个发送包 let body = { 1: appid, 2: 1, 3: style, 5: { 1: 1, 2: "0.0.0", 3: appname, 4: appsign, }, 7: { 15: msg_seq }, 10: send_type, 11: recv_uin, 18: { 1: 1109937557, 2: { 14: 'pages', }, 3: 'url', 4: 'text', 5: 'text', 6: 'text', 10: JSON.stringify(json_data), } }; //接收到签名好的json消息的处理函数 let json_handle = function(e:any){ if(Bot.uin == e.user_id && e?.message[0]?.type == 'json'){ let json_str = e.message[0].data; let json = null; let extra = null; try{ json = JSON.parse(json_str); extra = typeof(json.extra) == 'object' ? json.extra : JSON.parse(json.extra); }catch(err){} if(extra && extra.msg_seq == msg_seq){ Bot.off('message',json_handle); clearTimeout(timer); delete json['extra']; result.code = 1; result.msg = '签名成功!'; result.data = JSON.stringify(json); resolve(result); } } } let timer = setTimeout(function(){ Bot.off('message',json_handle); result.code = -1; result.msg = '签名失败,请稍后再试!'; resolve(result); },3000); //监听TX服务器返回签名好的json文本 Bot.on('message',json_handle); //发送数据包 Bot.sendOidb("OidbSvc.0xb77_9", core.pb.encode(body)); }); } export {ArkSign};
最终把消息进行core.pb.encode(body)得封装后传递进sendOidb方法,继续单步跟踪如下
/** dont use it if not clear the usage */ sendOidb(cmd: string, body: Uint8Array, timeout = 5) { const sp = cmd //OidbSvc.0x568_22 .replace("OidbSvc.", "") .replace("oidb_", "") .split("_") const type1 = parseInt(sp[0], 16), type2 = parseInt(sp[1]) body = pb.encode({ 1: type1, 2: isNaN(type2) ? 1 : type2, 3: 0, 4: body, 6: "android " + this.apk.ver, }) return this.sendUni(cmd, body, timeout) }
除去其他信息以外,主要是对发送消息就行了两次encode方法 this.sendUni是oicq发送”数据包“(应该是这么叫)的方法,再往下追踪就是涉及到收发消息的协议了,同时oicq发送普通消息也是通过this.sendUni实现的。
您好 请问如何正确调用此函数 本人不太熟悉nodejs 望回复 谢谢!
我很抱歉,如果你不是oicq的开发者无法使用这个函数,以及有人写出了mirai支持的方法,详情可参考https://github.com/Mrs4s/MiraiGo/pull/307,我的疑惑也就此解开,也提醒各位请勿滥用ark签名去签名违法、违规的标签,json卡片最终会因为ark签名滥用而导致和谐,祝您早日替换成图片替换成卡片,再次关闭本issue
结果大佬许可,下面是oicq对ark签名的代码实现
/** * 使用须知 * 1.代码语言为:TypeScript * 2.基于的框架为:oicq * 3.使用函数ArkSign前,请先执行npm i oicq */ import { Client } from "oicq"; /** * 通过小程序对json消息进行ark签名 基于oicq的core * @param json 要签名的json * @param Bot 已经创建好的机器人实例 * @param core oicq的核心 * @returns */ async function ArkSign(json:any,Bot:Client,core:any){ return new Promise((resolve, reject) => { class Result{ code:number = -1; [key:string]:any } let result = new Result(); let json_data = null; try{ json_data = JSON.parse(json); }catch(err){} if(!json_data){ result.code = -1; result.msg = '签名失败,不是有效的json!'; resolve(result); return; } delete json_data['extra']; //style 改成 10表示小程序发送 let appid = 100951776, style = 10, appname = 'tv.danmaku.bili', appsign = '7194d531cbe7960a22007b9f6bdaa38b'; let send_type = 0, recv_uin = Bot.uin, recv_guild_id = 0; let time = new Date().getTime(); function random(min:number,max:number){ const range = max - min; const random = Math.random(); const result = min + Math.round(random * range); return result; } let msg_seq = BigInt(`${time}${random(100,999)}`); //拼凑一个发送包 let body = { 1: appid, 2: 1, 3: style, 5: { 1: 1, 2: "0.0.0", 3: appname, 4: appsign, }, 7: { 15: msg_seq }, 10: send_type, 11: recv_uin, 18: { 1: 1109937557, 2: { 14: 'pages', }, 3: 'url', 4: 'text', 5: 'text', 6: 'text', 10: JSON.stringify(json_data), } }; //接收到签名好的json消息的处理函数 let json_handle = function(e:any){ if(Bot.uin == e.user_id && e?.message[0]?.type == 'json'){ let json_str = e.message[0].data; let json = null; let extra = null; try{ json = JSON.parse(json_str); extra = typeof(json.extra) == 'object' ? json.extra : JSON.parse(json.extra); }catch(err){} if(extra && extra.msg_seq == msg_seq){ Bot.off('message',json_handle); clearTimeout(timer); delete json['extra']; result.code = 1; result.msg = '签名成功!'; result.data = JSON.stringify(json); resolve(result); } } } let timer = setTimeout(function(){ Bot.off('message',json_handle); result.code = -1; result.msg = '签名失败,请稍后再试!'; resolve(result); },3000); //监听TX服务器返回签名好的json文本 Bot.on('message',json_handle); //发送数据包 Bot.sendOidb("OidbSvc.0xb77_9", core.pb.encode(body)); }); } export {ArkSign};
最终把消息进行core.pb.encode(body)得封装后传递进sendOidb方法,继续单步跟踪如下
/** dont use it if not clear the usage */ sendOidb(cmd: string, body: Uint8Array, timeout = 5) { const sp = cmd //OidbSvc.0x568_22 .replace("OidbSvc.", "") .replace("oidb_", "") .split("_") const type1 = parseInt(sp[0], 16), type2 = parseInt(sp[1]) body = pb.encode({ 1: type1, 2: isNaN(type2) ? 1 : type2, 3: 0, 4: body, 6: "android " + this.apk.ver, }) return this.sendUni(cmd, body, timeout) }
除去其他信息以外,主要是对发送消息就行了两次encode方法 this.sendUni是oicq发送”数据包“(应该是这么叫)的方法,再往下追踪就是涉及到收发消息的协议了,同时oicq发送普通消息也是通过this.sendUni实现的。
您好 请问如何正确调用此函数 本人不太熟悉nodejs 望回复 谢谢!
我很抱歉,如果你不是oicq的开发者无法使用这个函数,以及有人写出了mirai支持的方法,详情可参考https://github.com/Mrs4s/MiraiGo/pull/307,我的疑惑也就此解开,也提醒各位请勿滥用ark签名去签名违法、违规的标签,json卡片最终会因为ark签名滥用而导致和谐,祝您早日替换成图片替换成卡片,再次关闭本issue
了解 因为我是Java开发者 所以对于这两种语言不太熟悉 感谢您的回复 我再学习下
结果大佬许可,下面是oicq对ark签名的代码实现
/** * 使用须知 * 1.代码语言为:TypeScript * 2.基于的框架为:oicq * 3.使用函数ArkSign前,请先执行npm i oicq */ import { Client } from "oicq"; /** * 通过小程序对json消息进行ark签名 基于oicq的core * @param json 要签名的json * @param Bot 已经创建好的机器人实例 * @param core oicq的核心 * @returns */ async function ArkSign(json:any,Bot:Client,core:any){ return new Promise((resolve, reject) => { class Result{ code:number = -1; [key:string]:any } let result = new Result(); let json_data = null; try{ json_data = JSON.parse(json); }catch(err){} if(!json_data){ result.code = -1; result.msg = '签名失败,不是有效的json!'; resolve(result); return; } delete json_data['extra']; //style 改成 10表示小程序发送 let appid = 100951776, style = 10, appname = 'tv.danmaku.bili', appsign = '7194d531cbe7960a22007b9f6bdaa38b'; let send_type = 0, recv_uin = Bot.uin, recv_guild_id = 0; let time = new Date().getTime(); function random(min:number,max:number){ const range = max - min; const random = Math.random(); const result = min + Math.round(random * range); return result; } let msg_seq = BigInt(`${time}${random(100,999)}`); //拼凑一个发送包 let body = { 1: appid, 2: 1, 3: style, 5: { 1: 1, 2: "0.0.0", 3: appname, 4: appsign, }, 7: { 15: msg_seq }, 10: send_type, 11: recv_uin, 18: { 1: 1109937557, 2: { 14: 'pages', }, 3: 'url', 4: 'text', 5: 'text', 6: 'text', 10: JSON.stringify(json_data), } }; //接收到签名好的json消息的处理函数 let json_handle = function(e:any){ if(Bot.uin == e.user_id && e?.message[0]?.type == 'json'){ let json_str = e.message[0].data; let json = null; let extra = null; try{ json = JSON.parse(json_str); extra = typeof(json.extra) == 'object' ? json.extra : JSON.parse(json.extra); }catch(err){} if(extra && extra.msg_seq == msg_seq){ Bot.off('message',json_handle); clearTimeout(timer); delete json['extra']; result.code = 1; result.msg = '签名成功!'; result.data = JSON.stringify(json); resolve(result); } } } let timer = setTimeout(function(){ Bot.off('message',json_handle); result.code = -1; result.msg = '签名失败,请稍后再试!'; resolve(result); },3000); //监听TX服务器返回签名好的json文本 Bot.on('message',json_handle); //发送数据包 Bot.sendOidb("OidbSvc.0xb77_9", core.pb.encode(body)); }); } export {ArkSign};
最终把消息进行core.pb.encode(body)得封装后传递进sendOidb方法,继续单步跟踪如下
/** dont use it if not clear the usage */ sendOidb(cmd: string, body: Uint8Array, timeout = 5) { const sp = cmd //OidbSvc.0x568_22 .replace("OidbSvc.", "") .replace("oidb_", "") .split("_") const type1 = parseInt(sp[0], 16), type2 = parseInt(sp[1]) body = pb.encode({ 1: type1, 2: isNaN(type2) ? 1 : type2, 3: 0, 4: body, 6: "android " + this.apk.ver, }) return this.sendUni(cmd, body, timeout) }
除去其他信息以外,主要是对发送消息就行了两次encode方法 this.sendUni是oicq发送”数据包“(应该是这么叫)的方法,再往下追踪就是涉及到收发消息的协议了,同时oicq发送普通消息也是通过this.sendUni实现的。
您好 请问如何正确调用此函数 本人不太熟悉nodejs 望回复 谢谢!
我很抱歉,如果你不是oicq的开发者无法使用这个函数,以及有人写出了mirai支持的方法,详情可参考https://github.com/Mrs4s/MiraiGo/pull/307,我的疑惑也就此解开,也提醒各位请勿滥用ark签名去签名违法、违规的标签,json卡片最终会因为ark签名滥用而导致和谐,祝您早日替换成图片替换成卡片,再次关闭本issue
了解 因为我是Java开发者 所以对于这两种语言不太熟悉 感谢您的回复 我再学习下
好的好的
关于mirai发送json不显示的问题&分析
一、问题复现
代码编写采用的是mirai-js以及TypeScript语言,实现代码如下:
发送完的卡片消息如下,但是手机端无法显示(不截图了)
二、问题分析
经过多方求助,根据oicq某某大佬提供,发出去的卡片需要带上token值,而这个token值是和整个token文本相呼应的,整个文本改了token值也要跟着变化,否则就会出现只能发不能收的现象,获取token这个一过程叫做ark签名(小栗子框架是这么定义的)
现在已经知晓的方法除了小栗子框架以外,开源的机器人框架可以使用小程序分享来获取签名后的json,由于我不熟悉Java和Kotlin没办法使用mirai的代码去实现一个签名的函数作为参考,因此采用oicq的core来签名上述的json如下:
可以看到签名后已经拿到了对应的token值“e0e8a49720c42903dc476783aced2d77”,在使用mirai发送试试
发送成功!!!!
三、总结与期盼
根据大佬提供的思路,只要支持音乐分享的框架,仅仅只需要把原来的type类型改成10就是小程序分享,具体代码如何实现的我不清楚,不是我发现的这一签名方法,希望mirai能支持ark签名的功能,让json消息不再是多余的存在!