Compare commits

...

43 Commits

Author SHA1 Message Date
手瓜一十雪
8569a45114 release: v3.1.5 2024-10-24 20:16:12 +08:00
手瓜一十雪
c790311fc3 release: v3.1.5 2024-10-24 20:11:39 +08:00
手瓜一十雪
3c45c8bd80 feat: 28971 2024-10-24 20:11:07 +08:00
手瓜一十雪
d5b7b3ae31 feat: ntappid 2024-10-24 17:55:33 +08:00
手瓜一十雪
43e73a5f24 doc: big Logo 2024-10-24 17:03:23 +08:00
手瓜一十雪
f3d967ae07 release: 3.1.4 2024-10-24 13:39:05 +08:00
手瓜一十雪
dbe72fa07e feat: SetGroupSign 2024-10-24 13:38:22 +08:00
Wesley F. Young
8fe37d1c1e chore: reformat package.json 2024-10-23 17:54:12 +08:00
手瓜一十雪
31365505d8 Merge pull request #461 from huankong233/main
优化 contact 支持群聊和私聊
2024-10-23 09:09:07 +08:00
huankong233
b3fbe9e34a 优化 contact 支持群聊和私聊 2024-10-23 09:05:45 +08:00
手瓜一十雪
5190b26399 Merge pull request #457 from huankong233/main
删除一些过时的接口
2024-10-22 17:57:04 +08:00
手瓜一十雪
29a8db96f4 fix 2024-10-22 17:56:51 +08:00
huankong233
1a4c2cabfd 删除一些过时的接口 2024-10-22 16:45:52 +08:00
手瓜一十雪
ef9189055c release: 3.1.3 2024-10-22 12:43:54 +08:00
手瓜一十雪
5cc3719125 fix: rkey 2024-10-22 12:42:24 +08:00
手瓜一十雪
5d46f41348 fix: dep 2024-10-22 12:14:43 +08:00
手瓜一十雪
3c2c1963f4 release: 3.1.2 2024-10-22 12:11:02 +08:00
手瓜一十雪
4896ca9279 fix 2024-10-22 11:37:01 +08:00
手瓜一十雪
f0afba6cd9 fix: GetOnlineClient 2024-10-22 11:34:28 +08:00
手瓜一十雪
bd717c298a fix: get_online_clients 2024-10-22 11:17:39 +08:00
手瓜一十雪
baaa8a70dc release: 3.1.1 2024-10-22 11:08:24 +08:00
手瓜一十雪
6d561c6e6f Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-10-22 11:04:43 +08:00
手瓜一十雪
e6b6947d49 feat: 标准化凭据获取 2024-10-22 11:04:28 +08:00
手瓜一十雪
52e99a2175 Merge pull request #454 from huankong233/main
简单修复一些小问题
2024-10-22 10:17:08 +08:00
手瓜一十雪
052d17a46f fix: getfile 2024-10-22 10:15:16 +08:00
huankong233
1aa1f4c212 优化 getFile 处理逻辑 2024-10-22 09:48:55 +08:00
huankong233
c3a48e3344 修复标记好友/群聊信息已读逻辑 2024-10-21 19:51:17 +08:00
手瓜一十雪
1d5483dc28 Merge pull request #451 from huankong233/main
对接口顺序和文档同步
2024-10-21 16:47:46 +08:00
huankong233
54277fa0df CleanCache 未实现 2024-10-21 16:09:27 +08:00
huankong233
ab04bd262f 对接口顺序和文档同步 2024-10-21 15:49:57 +08:00
手瓜一十雪
fb23087b65 release: 3.1.0 2024-10-21 14:35:57 +08:00
手瓜一十雪
846fee7ac8 fix: error import 2024-10-21 14:33:12 +08:00
手瓜一十雪
977eacc679 try: fix arm64 2024-10-21 14:12:10 +08:00
手瓜一十雪
dacfefe644 style: lint 2024-10-21 10:17:31 +08:00
pk5ls20
345e941e11 chore: remove unnecessary comments 2024-10-21 04:10:53 +08:00
pk5ls20
6cb7d45464 feat & refactor: decouple the forwardMsg construction logic and implement the OB11 element conversion for the forward node. 2024-10-21 04:05:02 +08:00
pk5ls20
e7222653fa release: 3.0.6 2024-10-20 23:54:21 +08:00
pk5ls20
014f0758f5 chore: 部分回滚 https://github.com/NapNeko/NapCatQQ/commit/bb72d70b 2024-10-20 23:52:36 +08:00
pk5ls20
0e8b416f6d Merge pull request #448 from pk5ls20/feat/friend-poke
feat: add `friend_poke` OneBot11 API
2024-10-20 23:18:26 +08:00
pk5ls20
09a60a2204 feat: add friend_poke OneBot11 API 2024-10-20 23:09:38 +08:00
手瓜一十雪
b0eae307c2 release: 3.0.5 2024-10-20 22:18:57 +08:00
手瓜一十雪
f5d2b54cca fix: 兼容晚启动 2024-10-20 22:18:34 +08:00
手瓜一十雪
3eefec3899 release: v3.0.4 2024-10-20 19:52:23 +08:00
51 changed files with 743 additions and 527 deletions

View File

@@ -1,5 +1,7 @@
<div align="center"> <div align="center">
<img src="https://socialify.git.ci/NapNeko/NapCatQQ/image?font=Jost&logo=https%3A%2F%2Fnapneko.github.io%2Fassets%2Flogo.png&name=1&owner=1&pattern=Diagonal%20Stripes&stargazers=1&theme=Auto" alt="NapCatQQ" width="640" height="320" />
![Logo](https://socialify.git.ci/NapNeko/NapCatQQ/image?font=Jost&logo=https%3A%2F%2Fnapneko.github.io%2Fassets%2Flogo.png&name=1&owner=1&pattern=Diagonal%20Stripes&stargazers=1&theme=Auto)
</div> </div>
--- ---

View File

@@ -4,7 +4,7 @@
"name": "NapCatQQ", "name": "NapCatQQ",
"slug": "NapCat.Framework", "slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现", "description": "高性能的 OneBot 11 协议实现",
"version": "3.0.3", "version": "3.1.5",
"icon": "./logo.png", "icon": "./logo.png",
"authors": [ "authors": [
{ {

View File

@@ -2,7 +2,7 @@
"name": "napcat", "name": "napcat",
"private": true, "private": true,
"type": "module", "type": "module",
"version": "3.0.3", "version": "3.1.5",
"scripts": { "scripts": {
"build:framework": "vite build --mode framework", "build:framework": "vite build --mode framework",
"build:shell": "vite build --mode shell", "build:shell": "vite build --mode shell",
@@ -13,6 +13,7 @@
"devDependencies": { "devDependencies": {
"@babel/preset-typescript": "^7.24.7", "@babel/preset-typescript": "^7.24.7",
"@log4js-node/log4js-api": "^1.0.2", "@log4js-node/log4js-api": "^1.0.2",
"@protobuf-ts/runtime": "^2.9.4",
"@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-typescript": "^11.1.6", "@rollup/plugin-typescript": "^11.1.6",
"@types/cors": "^2.8.17", "@types/cors": "^2.8.17",
@@ -23,29 +24,28 @@
"@types/ws": "^8.5.12", "@types/ws": "^8.5.12",
"@typescript-eslint/eslint-plugin": "^8.3.0", "@typescript-eslint/eslint-plugin": "^8.3.0",
"@typescript-eslint/parser": "^8.3.0", "@typescript-eslint/parser": "^8.3.0",
"ajv": "^8.13.0",
"async-mutex": "^0.5.0",
"chalk": "^5.3.0",
"commander": "^12.1.0",
"cors": "^2.8.5",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-import-resolver-typescript": "^3.6.1", "eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-import": "^2.29.1",
"fast-xml-parser": "^4.3.6",
"file-type": "^19.0.0",
"image-size": "^1.1.1",
"json-schema-to-ts": "^3.1.1",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.2.6", "vite": "^5.2.6",
"vite-plugin-cp": "^4.0.8", "vite-plugin-cp": "^4.0.8",
"vite-tsconfig-paths": "^4.3.2", "vite-tsconfig-paths": "^4.3.2"
"@protobuf-ts/runtime": "^2.9.4",
"ajv": "^8.13.0",
"fast-xml-parser": "^4.3.6",
"chalk": "^5.3.0",
"commander": "^12.1.0",
"async-mutex": "^0.5.0",
"file-type": "^19.0.0",
"json-schema-to-ts": "^3.1.0",
"image-size": "^1.1.1",
"cors": "^2.8.5"
}, },
"dependencies": { "dependencies": {
"qrcode-terminal": "^0.12.0",
"fluent-ffmpeg": "^2.1.2",
"express": "^5.0.0-beta.2", "express": "^5.0.0-beta.2",
"fluent-ffmpeg": "^2.1.2",
"log4js": "^6.9.1", "log4js": "^6.9.1",
"qrcode-terminal": "^0.12.0",
"silk-wasm": "^3.6.1", "silk-wasm": "^3.6.1",
"ws": "^8.18.0" "ws": "^8.18.0"
} }

View File

@@ -0,0 +1,106 @@
import { PacketMsg } from "@/core/packet/msg/message";
import * as crypto from "node:crypto";
interface ForwardMsgJson {
app: string
config: ForwardMsgJsonConfig,
desc: string,
extra: ForwardMsgJsonExtra,
meta: ForwardMsgJsonMeta,
prompt: string,
ver: string,
view: string
}
interface ForwardMsgJsonConfig {
autosize: number,
forward: number,
round: number,
type: string,
width: number
}
interface ForwardMsgJsonExtra {
filename: string,
tsum: number,
}
interface ForwardMsgJsonMeta {
detail: ForwardMsgJsonMetaDetail
}
interface ForwardMsgJsonMetaDetail {
news: {
text: string
}[],
resid: string,
source: string,
summary: string,
uniseq: string
}
interface ForwardAdaptMsg {
senderName?: string;
isGroupMsg?: boolean;
msg?: ForwardAdaptMsgElement[];
}
interface ForwardAdaptMsgElement {
preview?: string;
}
export class ForwardMsgBuilder {
private static build(resId: string, msg: ForwardAdaptMsg[]): ForwardMsgJson {
const id = crypto.randomUUID();
const isGroupMsg = msg.some(m => m.isGroupMsg);
return {
app: "com.tencent.multimsg",
config: {
autosize: 1,
forward: 1,
round: 1,
type: "normal",
width: 300
},
desc: "[聊天记录]",
extra: {
filename: id,
tsum: msg.length,
},
meta: {
detail: {
news: msg.length === 0 ? [{
text: "Nya~ This message is send from NapCat.Packet!",
}] : msg.map(m => ({
text: `${m.senderName}: ${m.msg?.map(msg => msg.preview).join('')}`,
})),
resid: resId,
source: isGroupMsg ? "群聊的聊天记录" :
msg.length
? Array.from(new Set(msg.map(m => m.senderName)))
.join('和') + '的聊天记录'
: '聊天记录',
summary: `查看${msg.length}条转发消息`,
uniseq: id,
}
},
prompt: "[聊天记录]",
ver: "0.0.0.5",
view: "contact",
};
}
static fromResId(resId: string): ForwardMsgJson {
return this.build(resId, []);
}
static fromPacketMsg(resId: string, packetMsg: PacketMsg[]): ForwardMsgJson {
return this.build(resId, packetMsg.map(msg => ({
senderName: msg.senderName,
isGroupMsg: msg.groupId !== undefined,
msg: msg.msg.map(m => ({
preview: m.toPreview(),
}))
})));
}
}

View File

@@ -1 +1 @@
export const napCatVersion = '3.0.3'; export const napCatVersion = '3.1.5';

View File

@@ -30,7 +30,7 @@ export class NTQQFileApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
rkeyManager: RkeyManager; rkeyManager: RkeyManager;
packetRkey: Array<{ rkey: string; time: number; type: number; }> | undefined; packetRkey: Array<{ rkey: string; time: number; type: number; ttl: bigint }> | undefined;
constructor(context: InstanceContext, core: NapCatCore) { constructor(context: InstanceContext, core: NapCatCore) {
this.context = context; this.context = context;
@@ -378,10 +378,12 @@ export class NTQQFileApi {
}; };
try { try {
if (this.core.apis.PacketApi.available) { if (this.core.apis.PacketApi.available) {
if ((!this.packetRkey || this.packetRkey[0].time > Date.now() / 1000)) { let rkey_expired_private = !this.packetRkey || this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000;
let rkey_expired_group = !this.packetRkey || this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000;
if (rkey_expired_private || rkey_expired_group) {
this.packetRkey = await this.core.apis.PacketApi.sendRkeyPacket(); this.packetRkey = await this.core.apis.PacketApi.sendRkeyPacket();
} }
if (this.packetRkey.length > 0) { if (this.packetRkey && this.packetRkey.length > 0) {
rkeyData.group_rkey = this.packetRkey[1].rkey.slice(6); rkeyData.group_rkey = this.packetRkey[1].rkey.slice(6);
rkeyData.private_rkey = this.packetRkey[0].rkey.slice(6); rkeyData.private_rkey = this.packetRkey[0].rkey.slice(6);
rkeyData.online_rkey = true; rkeyData.online_rkey = true;

View File

@@ -318,7 +318,7 @@ export class NTQQGroupApi {
async getGroupMembersV2(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> { async getGroupMembersV2(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow'); const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow');
let once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', 1, 2000, (params) => params.sceneId === sceneId) const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', 1, 2000, (params) => params.sceneId === sceneId)
.catch(); .catch();
const result = await this.context.session.getGroupService().getNextMemberList(sceneId!, undefined, num); const result = await this.context.session.getGroupService().getNextMemberList(sceneId!, undefined, num);
if (result.errCode !== 0) { if (result.errCode !== 0) {

View File

@@ -14,6 +14,7 @@ import {PacketMsg} from "@/core/packet/msg/message";
import { OidbSvcTrpcTcp0x6D6Response } from "@/core/packet/proto/oidb/Oidb.0x6D6"; import { OidbSvcTrpcTcp0x6D6Response } from "@/core/packet/proto/oidb/Oidb.0x6D6";
import { PacketMsgPicElement } from "@/core/packet/msg/element"; import { PacketMsgPicElement } from "@/core/packet/msg/element";
interface OffsetType { interface OffsetType {
[key: string]: { [key: string]: {
recv: string; recv: string;
@@ -26,7 +27,7 @@ const typedOffset: OffsetType = offset;
export class NTQQPacketApi { export class NTQQPacketApi {
context: InstanceContext; context: InstanceContext;
core: NapCatCore; core: NapCatCore;
logger: LogWrapper logger: LogWrapper;
serverUrl: string | undefined; serverUrl: string | undefined;
qqVersion: string | undefined; qqVersion: string | undefined;
packetSession: PacketSession | undefined; packetSession: PacketSession | undefined;
@@ -59,8 +60,12 @@ export class NTQQPacketApi {
if (!table) return false; if (!table) return false;
const url = 'ws://' + this.serverUrl + '/ws'; const url = 'ws://' + this.serverUrl + '/ws';
this.packetSession = new PacketSession(this.core.context.logger, new PacketClient(url, this.core)); this.packetSession = new PacketSession(this.core.context.logger, new PacketClient(url, this.core));
await this.packetSession.client.connect(); const cb = () => {
await this.packetSession.client.init(process.pid, table.recv, table.send); if (this.packetSession && this.packetSession.client) {
this.packetSession.client.init(process.pid, table.recv, table.send).then().catch(this.logger.logError.bind(this.logger));
}
};
await this.packetSession.client.connect(cb);
return true; return true;
} }
@@ -68,8 +73,8 @@ export class NTQQPacketApi {
return this.packetSession!.client.sendPacket(cmd, data, rsp); return this.packetSession!.client.sendPacket(cmd, data, rsp);
} }
async sendPokePacket(group: number, peer: number) { async sendPokePacket(peer: number, group?: number) {
const data = this.packetSession?.packer.packPokePacket(group, peer); const data = this.packetSession?.packer.packPokePacket(peer, group);
await this.sendPacket('OidbSvcTrpcTcp.0xed3_1', data!, false); await this.sendPacket('OidbSvcTrpcTcp.0xed3_1', data!, false);
} }
@@ -81,7 +86,10 @@ export class NTQQPacketApi {
const retData = new NapProtoMsg(OidbSvcTrpcTcp0X9067_202_Rsp_Body).decode(body); const retData = new NapProtoMsg(OidbSvcTrpcTcp0X9067_202_Rsp_Body).decode(body);
return retData.data.rkeyList; return retData.data.rkeyList;
} }
async sendGroupSignPacket(groupCode: string) {
const packet = this.packetSession?.packer.packGroupSignReq(this.core.selfInfo.uin, groupCode);
await this.sendPacket('OidbSvcTrpcTcp.0xeb7', packet!, true);
}
async sendStatusPacket(uin: number): Promise<{ status: number; ext_status: number; } | undefined> { async sendStatusPacket(uin: number): Promise<{ status: number; ext_status: number; } | undefined> {
let status = 0; let status = 0;
try { try {
@@ -107,7 +115,7 @@ export class NTQQPacketApi {
} }
private async uploadResources(msg: PacketMsg[], groupUin: number = 0) { private async uploadResources(msg: PacketMsg[], groupUin: number = 0) {
const reqList = [] const reqList = [];
for (const m of msg) { for (const m of msg) {
for (const e of m.msg) { for (const e of m.msg) {
if (e instanceof PacketMsgPicElement) { if (e instanceof PacketMsgPicElement) {
@@ -138,6 +146,6 @@ export class NTQQPacketApi {
if (resp.download.retCode !== 0) { if (resp.download.retCode !== 0) {
throw new Error(`sendGroupFileDownloadReq error: ${resp.download.clientWording}`); throw new Error(`sendGroupFileDownloadReq error: ${resp.download.clientWording}`);
} }
return `https://${resp.download.downloadDns}/ftn_handler/${Buffer.from(resp.download.downloadUrl).toString('hex')}/?fname=` return `https://${resp.download.downloadDns}/ftn_handler/${Buffer.from(resp.download.downloadUrl).toString('hex')}/?fname=`;
} }
} }

View File

@@ -338,4 +338,12 @@ export class NTQQWebApi {
} }
return (hash & 0x7FFFFFFF).toString(); return (hash & 0x7FFFFFFF).toString();
} }
public getBknFromSKey(sKey: string) {
let hash = 5381;
for (let i = 0; i < sKey.length; i++) {
const code = sKey.charCodeAt(i);
hash = hash + (hash << 5) + code;
}
return (hash & 0x7FFFFFFF).toString();
}
} }

View File

@@ -50,5 +50,13 @@
"9.9.16-28788": { "9.9.16-28788": {
"appid": 537249739, "appid": 537249739,
"qua": "V1_WIN_NQ_9.9.16_28788_GW_B" "qua": "V1_WIN_NQ_9.9.16_28788_GW_B"
},
"9.9.16-28971":{
"appid": 537249775,
"qua": "V1_WIN_NQ_9.9.16_28971_GW_B"
},
"3.2.13-28971": {
"appid": 537249848,
"qua": "V1_LNX_NQ_3.2.13_28971_GW_B"
} }
} }

View File

@@ -18,5 +18,13 @@
"3.2.13-28788-x64": { "3.2.13-28788-x64": {
"send": "A0CEC20", "send": "A0CEC20",
"recv": "A0D2520" "recv": "A0D2520"
},
"3.2.13-28788-arm64": {
"send": "6E91018",
"recv": "6E94850"
},
"9.9.16-28971-x64": {
"send": "38079F0",
"recv": "380BE24"
} }
} }

View File

@@ -22,7 +22,7 @@ export class PacketClient {
private websocket: WebSocket | undefined; private websocket: WebSocket | undefined;
private isConnected: boolean = false; private isConnected: boolean = false;
private reconnectAttempts: number = 0; private reconnectAttempts: number = 0;
private readonly maxReconnectAttempts: number = 5;//现在暂时不可配置 private readonly maxReconnectAttempts: number = 60;//现在暂时不可配置
private readonly cb = new LRUCache<string, (json: RecvPacketData) => Promise<void>>(500); // trace_id-type callback private readonly cb = new LRUCache<string, (json: RecvPacketData) => Promise<void>>(500); // trace_id-type callback
private readonly clientUrl: string = ''; private readonly clientUrl: string = '';
readonly napCatCore: NapCatCore; readonly napCatCore: NapCatCore;
@@ -47,7 +47,7 @@ export class PacketClient {
return text; return text;
} }
connect(): Promise<void> { connect(cb: any): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
//this.logger.log.bind(this.logger)(`[Core] [Packet Server] Attempting to connect to ${this.clientUrl}`); //this.logger.log.bind(this.logger)(`[Core] [Packet Server] Attempting to connect to ${this.clientUrl}`);
this.websocket = new WebSocket(this.clientUrl); this.websocket = new WebSocket(this.clientUrl);
@@ -57,6 +57,7 @@ export class PacketClient {
this.isConnected = true; this.isConnected = true;
this.reconnectAttempts = 0; this.reconnectAttempts = 0;
this.logger.log.bind(this.logger)(`[Core] [Packet Server] Connected to ${this.clientUrl}`); this.logger.log.bind(this.logger)(`[Core] [Packet Server] Connected to ${this.clientUrl}`);
cb();
resolve(); resolve();
}; };
@@ -74,17 +75,17 @@ export class PacketClient {
this.websocket.onclose = () => { this.websocket.onclose = () => {
this.isConnected = false; this.isConnected = false;
//this.logger.logWarn.bind(this.logger)(`[Core] [Packet Server] Disconnected from ${this.clientUrl}`); //this.logger.logWarn.bind(this.logger)(`[Core] [Packet Server] Disconnected from ${this.clientUrl}`);
this.attemptReconnect(); this.attemptReconnect(cb);
}; };
}); });
} }
private attemptReconnect(): void { private attemptReconnect(cb: any): void {
try { try {
if (this.reconnectAttempts < this.maxReconnectAttempts) { if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++; this.reconnectAttempts++;
setTimeout(() => { setTimeout(() => {
this.connect().catch((error) => { this.connect(cb).catch((error) => {
this.logger.logError.bind(this.logger)(`[Core] [Packet Server] Reconnecting attempt failed,${error.message}`); this.logger.logError.bind(this.logger)(`[Core] [Packet Server] Reconnecting attempt failed,${error.message}`);
}); });
}, 5000 * this.reconnectAttempts); }, 5000 * this.reconnectAttempts);

View File

@@ -42,7 +42,7 @@ export class PacketHighwaySession {
sigSession: null, sigSession: null,
sessionKey: null, sessionKey: null,
serverAddr: [], serverAddr: [],
} };
this.packer = packer; this.packer = packer;
this.packetHighwayClient = new PacketHighwayClient(this.sig, this.logger); this.packetHighwayClient = new PacketHighwayClient(this.sig, this.logger);
} }
@@ -69,8 +69,8 @@ export class PacketHighwaySession {
const rsp = new NapProtoMsg(HttpConn0x6ff_501Response).decode( const rsp = new NapProtoMsg(HttpConn0x6ff_501Response).decode(
Buffer.from(req.hex_data, 'hex') Buffer.from(req.hex_data, 'hex')
); );
this.sig.sigSession = rsp.httpConn.sigSession this.sig.sigSession = rsp.httpConn.sigSession;
this.sig.sessionKey = rsp.httpConn.sessionKey this.sig.sessionKey = rsp.httpConn.sessionKey;
for (const info of rsp.httpConn.serverInfos) { for (const info of rsp.httpConn.serverInfos) {
if (info.serviceType !== 1) continue; if (info.serviceType !== 1) continue;
for (const addr of info.serverAddrs) { for (const addr of info.serverAddrs) {
@@ -78,7 +78,7 @@ export class PacketHighwaySession {
this.sig.serverAddr.push({ this.sig.serverAddr.push({
ip: int32ip2str(addr.ip), ip: int32ip2str(addr.ip),
port: addr.port port: addr.port
}) });
} }
} }
} }
@@ -118,7 +118,7 @@ export class PacketHighwaySession {
hash: { hash: {
fileSha1: [sha1] fileSha1: [sha1]
} }
}) });
await this.packetHighwayClient.upload( await this.packetHighwayClient.upload(
1004, 1004,
fs.createReadStream(img.path, { highWaterMark: BlockSize }), fs.createReadStream(img.path, { highWaterMark: BlockSize }),
@@ -157,7 +157,7 @@ export class PacketHighwaySession {
hash: { hash: {
fileSha1: [sha1] fileSha1: [sha1]
} }
}) });
await this.packetHighwayClient.upload( await this.packetHighwayClient.upload(
1003, 1003,
fs.createReadStream(img.path, { highWaterMark: BlockSize }), fs.createReadStream(img.path, { highWaterMark: BlockSize }),

View File

@@ -53,7 +53,7 @@ abstract class HighwayUploader {
uint32LoginSigType: 8, uint32LoginSigType: 8,
appId: 1600001604, appId: 1600001604,
} }
}) });
} }
abstract upload(): Promise<void>; abstract upload(): Promise<void>;
@@ -90,7 +90,7 @@ export class HighwayTcpUploader extends HighwayUploader {
const upload = new Promise<void>((resolve, _) => { const upload = new Promise<void>((resolve, _) => {
const socket = net.connect(this.trans.port, this.trans.server, () => { const socket = net.connect(this.trans.port, this.trans.server, () => {
this.trans.data.pipe(highwayTransForm).pipe(socket, { end: false }); this.trans.data.pipe(highwayTransForm).pipe(socket, { end: false });
}) });
const handleRspHeader = (header: Buffer) => { const handleRspHeader = (header: Buffer) => {
const rsp = new NapProtoMsg(RespDataHighwayHead).decode(header); const rsp = new NapProtoMsg(RespDataHighwayHead).decode(header);
if (rsp.errorCode !== 0) { if (rsp.errorCode !== 0) {
@@ -111,25 +111,25 @@ export class HighwayTcpUploader extends HighwayUploader {
} catch (e) { } catch (e) {
this.logger.logError(`[Highway] tcpUpload parse response error: ${e}`); this.logger.logError(`[Highway] tcpUpload parse response error: ${e}`);
} }
}) });
socket.on('close', () => { socket.on('close', () => {
this.logger.logDebug('[Highway] tcpUpload socket closed.'); this.logger.logDebug('[Highway] tcpUpload socket closed.');
resolve(); resolve();
}) });
socket.on('error', (err) => { socket.on('error', (err) => {
this.logger.logError('[Highway] tcpUpload socket.on error:', err); this.logger.logError('[Highway] tcpUpload socket.on error:', err);
}) });
this.trans.data.on('error', (err) => { this.trans.data.on('error', (err) => {
this.logger.logError('[Highway] tcpUpload readable error:', err); this.logger.logError('[Highway] tcpUpload readable error:', err);
socket.end(); socket.end();
}) });
}) });
const timeout = new Promise<void>((_, reject) => { const timeout = new Promise<void>((_, reject) => {
setTimeout(() => { setTimeout(() => {
reject(new Error(`[Highway] tcpUpload timeout after ${this.trans.timeout}s`)) reject(new Error(`[Highway] tcpUpload timeout after ${this.trans.timeout}s`));
}, (this.trans.timeout ?? Infinity) * 1000 }, (this.trans.timeout ?? Infinity) * 1000
) );
}) });
await Promise.race([upload, timeout]); await Promise.race([upload, timeout]);
} }
} }
@@ -139,7 +139,7 @@ export class HighwayHttpUploader extends HighwayUploader {
async upload(): Promise<void> { async upload(): Promise<void> {
let offset = 0; let offset = 0;
for await (const chunk of this.trans.data) { for await (const chunk of this.trans.data) {
let block = chunk as Buffer; const block = chunk as Buffer;
try { try {
await this.uploadBlock(block, offset); await this.uploadBlock(block, offset);
} catch (err) { } catch (err) {
@@ -153,7 +153,7 @@ export class HighwayHttpUploader extends HighwayUploader {
private async uploadBlock(block: Buffer, offset: number): Promise<void> { private async uploadBlock(block: Buffer, offset: number): Promise<void> {
const chunkMD5 = crypto.createHash('md5').update(block).digest(); const chunkMD5 = crypto.createHash('md5').update(block).digest();
const payload = this.buildPicUpHead(offset, block.length, chunkMD5); const payload = this.buildPicUpHead(offset, block.length, chunkMD5);
const frame = Frame.pack(Buffer.from(payload), block) const frame = Frame.pack(Buffer.from(payload), block);
const resp = await this.httpPostHighwayContent(frame, `http://${this.trans.server}:${this.trans.port}/cgi-bin/httpconn?htcmd=0x6FF0087&uin=${this.trans.uin}`); const resp = await this.httpPostHighwayContent(frame, `http://${this.trans.server}:${this.trans.port}/cgi-bin/httpconn?htcmd=0x6FF0087&uin=${this.trans.uin}`);
const [head, body] = Frame.unpack(resp); const [head, body] = Frame.unpack(resp);
const headData = new NapProtoMsg(RespDataHighwayHead).decode(head); const headData = new NapProtoMsg(RespDataHighwayHead).decode(head);

View File

@@ -5,7 +5,7 @@ import {NTHighwayIPv4} from "@/core/packet/proto/highway/highway";
export const int32ip2str = (ip: number) => { export const int32ip2str = (ip: number) => {
ip = ip & 0xffffffff; ip = ip & 0xffffffff;
return [ip & 0xff, (ip & 0xff00) >> 8, (ip & 0xff0000) >> 16, ((ip & 0xff000000) >> 24) & 0xff].join('.'); return [ip & 0xff, (ip & 0xff00) >> 8, (ip & 0xff0000) >> 16, ((ip & 0xff000000) >> 24) & 0xff].join('.');
} };
export const oidbIpv4s2HighwayIpv4s = (ipv4s: NapProtoEncodeStructType<typeof IPv4>[]): NapProtoEncodeStructType<typeof NTHighwayIPv4>[] =>{ export const oidbIpv4s2HighwayIpv4s = (ipv4s: NapProtoEncodeStructType<typeof IPv4>[]): NapProtoEncodeStructType<typeof NTHighwayIPv4>[] =>{
return ipv4s.map((ip) => { return ipv4s.map((ip) => {
@@ -15,6 +15,6 @@ export const oidbIpv4s2HighwayIpv4s = (ipv4s: NapProtoEncodeStructType<typeof IP
ip: int32ip2str(ip.outIP!), ip: int32ip2str(ip.outIP!),
}, },
port: ip.outPort! port: ip.outPort!
} as NapProtoEncodeStructType<typeof NTHighwayIPv4> } as NapProtoEncodeStructType<typeof NTHighwayIPv4>;
}) });
} };

View File

@@ -82,50 +82,50 @@ export class PacketMsgConverter {
); );
if (key) { if (key) {
const elementData = (element as any)[key]; // TODO: const elementData = (element as any)[key]; // TODO:
if (elementData) return this.rawToPacketMsgConverters[key](element as any) if (elementData) return this.rawToPacketMsgConverters[key](element as any);
} }
return null; return null;
}).filter((e) => e !== null) }).filter((e) => e !== null)
} };
} }
private rawToPacketMsgConverters: RawToPacketMsgConverters = { private rawToPacketMsgConverters: RawToPacketMsgConverters = {
textElement: (element: SendTextElement) => { textElement: (element: SendTextElement) => {
if (element.textElement.atType) { if (element.textElement.atType) {
return new PacketMsgAtElement(element) return new PacketMsgAtElement(element);
} }
return new PacketMsgTextElement(element) return new PacketMsgTextElement(element);
}, },
picElement: (element: SendPicElement) => { picElement: (element: SendPicElement) => {
return new PacketMsgPicElement(element) return new PacketMsgPicElement(element);
}, },
replyElement: (element: SendReplyElement) => { replyElement: (element: SendReplyElement) => {
return new PacketMsgReplyElement(element) return new PacketMsgReplyElement(element);
}, },
faceElement: (element: SendFaceElement) => { faceElement: (element: SendFaceElement) => {
return new PacketMsgFaceElement(element) return new PacketMsgFaceElement(element);
}, },
marketFaceElement: (element: SendMarketFaceElement) => { marketFaceElement: (element: SendMarketFaceElement) => {
return new PacketMsgMarkFaceElement(element) return new PacketMsgMarkFaceElement(element);
}, },
videoElement: (element: SendVideoElement) => { videoElement: (element: SendVideoElement) => {
return new PacketMsgVideoElement(element) return new PacketMsgVideoElement(element);
}, },
fileElement: (element: SendFileElement) => { fileElement: (element: SendFileElement) => {
return new PacketMsgFileElement(element) return new PacketMsgFileElement(element);
}, },
pttElement: (element: SendPttElement) => { pttElement: (element: SendPttElement) => {
return new PacketMsgPttElement(element) return new PacketMsgPttElement(element);
}, },
arkElement: (element: SendArkElement) => { arkElement: (element: SendArkElement) => {
return new PacketMsgLightAppElement(element) return new PacketMsgLightAppElement(element);
}, },
markdownElement: (element: SendMarkdownElement) => { markdownElement: (element: SendMarkdownElement) => {
return new PacketMsgMarkDownElement(element) return new PacketMsgMarkDownElement(element);
}, },
// TODO: check this logic, move it in arkElement? // TODO: check this logic, move it in arkElement?
structLongMsgElement: (element: SendStructLongMsgElement) => { structLongMsgElement: (element: SendStructLongMsgElement) => {
return new PacketMultiMsgElement(element) return new PacketMultiMsgElement(element);
}
} }
};
} }

View File

@@ -1,6 +1,5 @@
import assert from "node:assert"; import assert from "node:assert";
import * as zlib from "node:zlib"; import * as zlib from "node:zlib";
import * as crypto from "node:crypto";
import { NapProtoEncodeStructType, NapProtoMsg } from "@/core/packet/proto/NapProto"; import { NapProtoEncodeStructType, NapProtoMsg } from "@/core/packet/proto/NapProto";
import { import {
CustomFace, CustomFace,
@@ -28,10 +27,9 @@ import {
} from "@/core"; } from "@/core";
import { MsgInfo } from "@/core/packet/proto/oidb/common/Ntv2.RichMediaReq"; import { MsgInfo } from "@/core/packet/proto/oidb/common/Ntv2.RichMediaReq";
import { PacketMsg, PacketSendMsgElement } from "@/core/packet/msg/message"; import { PacketMsg, PacketSendMsgElement } from "@/core/packet/msg/message";
import { ForwardMsgBuilder } from "@/common/forward-msg-builder";
// raw <-> packet // raw <-> packet
// TODO: check ob11 -> raw impl!
// TODO: parse to raw element
// TODO: SendStructLongMsgElement // TODO: SendStructLongMsgElement
export abstract class IPacketMsgElement<T extends PacketSendMsgElement> { export abstract class IPacketMsgElement<T extends PacketSendMsgElement> {
protected constructor(rawElement: T) { protected constructor(rawElement: T) {
@@ -103,7 +101,7 @@ export class PacketMsgAtElement extends PacketMsgTextElement {
export class PacketMsgPicElement extends IPacketMsgElement<SendPicElement> { export class PacketMsgPicElement extends IPacketMsgElement<SendPicElement> {
path: string; path: string;
name: string name: string;
size: number; size: number;
md5: string; md5: string;
width: number; width: number;
@@ -133,7 +131,7 @@ export class PacketMsgPicElement extends IPacketMsgElement<SendPicElement> {
pbElem: new NapProtoMsg(MsgInfo).encode(this.msgInfo), pbElem: new NapProtoMsg(MsgInfo).encode(this.msgInfo),
businessType: 10, businessType: 10,
} }
}] }];
} }
toPreview(): string { toPreview(): string {
@@ -187,7 +185,7 @@ export class PacketMsgReplyElement extends IPacketMsgElement<SendReplyElement> {
uid: String(this.targetUid), uid: String(this.targetUid),
}), }),
} : undefined, } : undefined,
}] }];
} }
toPreview(): string { toPreview(): string {
@@ -221,7 +219,7 @@ export class PacketMsgFaceElement extends IPacketMsgElement<SendFaceElement> {
}), }),
businessType: 1 businessType: 1
} }
}] }];
} else if (this.faceId < 260) { } else if (this.faceId < 260) {
return [{ return [{
face: { face: {
@@ -239,7 +237,7 @@ export class PacketMsgFaceElement extends IPacketMsgElement<SendFaceElement> {
}), }),
businessType: 1 businessType: 1
} }
}] }];
} }
} }
@@ -278,11 +276,11 @@ export class PacketMsgMarkFaceElement extends IPacketMsgElement<SendMarketFaceEl
field8: 1 field8: 1
} }
} }
}] }];
} }
toPreview(): string { toPreview(): string {
return this.emojiName; return `[${this.emojiName}]`;
} }
} }
@@ -320,11 +318,11 @@ export class PacketMsgLightAppElement extends IPacketMsgElement<SendArkElement>
zlib.deflateSync(Buffer.from(this.payload, 'utf-8')) zlib.deflateSync(Buffer.from(this.payload, 'utf-8'))
]) ])
} }
}] }];
} }
toPreview(): string { toPreview(): string {
return "[小程序]"; return "[卡片消息]";
} }
} }
@@ -345,11 +343,11 @@ export class PacketMsgMarkDownElement extends IPacketMsgElement<SendMarkdownElem
}), }),
businessType: 1 businessType: 1
} }
}] }];
} }
toPreview(): string { toPreview(): string {
return this.content; return `[Markdown消息 ${this.content}]`;
} }
} }
@@ -363,58 +361,15 @@ export class PacketMultiMsgElement extends IPacketMsgElement<SendStructLongMsgEl
this.message = message ?? []; this.message = message ?? [];
} }
get isGroupMsg(): boolean {
return this.message.some(msg => msg.groupId !== undefined);
}
get JSON() {
const id = crypto.randomUUID();
return {
app: "com.tencent.multimsg",
config: {
autosize: 1,
forward: 1,
round: 1,
type: "normal",
width: 300
},
desc: "[聊天记录]",
extra: {
filename: id,
tsum: this.message.length,
},
meta: {
detail: {
news: this.message.length === 0 ? [{
text: "[Nya~ This message is send from NapCat.Packet!]",
}] : this.message.map(packetMsg => ({
text: `${packetMsg.senderName}: ${packetMsg.msg.map(msg => msg.toPreview()).join('')}`,
})),
resid: this.resid,
source: this.isGroupMsg ? "群聊的聊天记录" :
this.message.length
? Array.from(new Set(this.message.map(msg => msg.senderName)))
.join('和') + '的聊天记录'
: '聊天记录',
summary: `查看${this.message.length}条转发消息`,
uniseq: id,
}
},
prompt: "[聊天记录]",
ver: "0.0.0.5",
view: "contact",
}
}
buildElement(): NapProtoEncodeStructType<typeof Elem>[] { buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
return [{ return [{
lightAppElem: { lightAppElem: {
data: Buffer.concat([ data: Buffer.concat([
Buffer.from([0x01]), Buffer.from([0x01]),
zlib.deflateSync(Buffer.from(JSON.stringify(this.JSON), 'utf-8')) zlib.deflateSync(Buffer.from(JSON.stringify(ForwardMsgBuilder.fromPacketMsg(this.resid, this.message)), 'utf-8'))
]) ])
} }
}] }];
} }
toPreview(): string { toPreview(): string {

View File

@@ -1,6 +1,6 @@
import * as zlib from "node:zlib"; import * as zlib from "node:zlib";
import * as crypto from "node:crypto"; import * as crypto from "node:crypto";
import {calculateSha1} from "@/core/packet/utils/crypto/hash" import { calculateSha1 } from "@/core/packet/utils/crypto/hash";
import { NapProtoMsg } from "@/core/packet/proto/NapProto"; import { NapProtoMsg } from "@/core/packet/proto/NapProto";
import { OidbSvcTrpcTcpBase } from "@/core/packet/proto/oidb/OidbBase"; import { OidbSvcTrpcTcpBase } from "@/core/packet/proto/oidb/OidbBase";
import { OidbSvcTrpcTcp0X9067_202 } from "@/core/packet/proto/oidb/Oidb.0x9067_202"; import { OidbSvcTrpcTcp0X9067_202 } from "@/core/packet/proto/oidb/Oidb.0x9067_202";
@@ -18,6 +18,7 @@ import {OidbSvcTrpcTcp0x6D6} from "@/core/packet/proto/oidb/Oidb.0x6D6";
import { OidbSvcTrpcTcp0XE37_1200 } from "@/core/packet/proto/oidb/Oidb.0xE37_1200"; import { OidbSvcTrpcTcp0XE37_1200 } from "@/core/packet/proto/oidb/Oidb.0xE37_1200";
import { PacketMsgConverter } from "@/core/packet/msg/converter"; import { PacketMsgConverter } from "@/core/packet/msg/converter";
import { PacketClient } from "@/core/packet/client"; import { PacketClient } from "@/core/packet/client";
import { OidbSvcTrpcTcp0XEB7 } from "./proto/oidb/Oidb.0xEB7";
export type PacketHexStr = string & { readonly hexNya: unique symbol }; export type PacketHexStr = string & { readonly hexNya: unique symbol };
@@ -47,11 +48,11 @@ export class PacketPacker {
}); });
} }
packPokePacket(group: number, peer: number): PacketHexStr { packPokePacket(peer: number, group?: number): PacketHexStr {
const oidb_0xed3 = new NapProtoMsg(OidbSvcTrpcTcp0XED3_1).encode({ const oidb_0xed3 = new NapProtoMsg(OidbSvcTrpcTcp0XED3_1).encode({
uin: peer, uin: peer,
groupUin: group, groupUin: group,
friendUin: group, friendUin: group ?? peer,
ext: 0 ext: 0
}); });
return this.toHexStr(this.packOidbPacket(0xed3, 1, oidb_0xed3)); return this.toHexStr(this.packOidbPacket(0xed3, 1, oidb_0xed3));
@@ -217,7 +218,7 @@ export class PacketPacker {
noNeedCompatMsg: false, noNeedCompatMsg: false,
} }
} }
) );
return this.toHexStr(this.packOidbPacket(0x11c4, 100, req, true, false)); return this.toHexStr(this.packOidbPacket(0x11c4, 100, req, true, false));
} }
@@ -285,7 +286,7 @@ export class PacketPacker {
noNeedCompatMsg: false, noNeedCompatMsg: false,
} }
} }
) );
return this.toHexStr(this.packOidbPacket(0x11c5, 100, req, true, false)); return this.toHexStr(this.packOidbPacket(0x11c5, 100, req, true, false));
} }
@@ -299,7 +300,7 @@ export class PacketPacker {
fileId: fileUUID fileId: fileUUID
} }
}), true, false) }), true, false)
) );
} }
packC2CFileDownloadReq(selfUid: string, fileUUID: string, fileHash: string): PacketHexStr { packC2CFileDownloadReq(selfUid: string, fileUUID: string, fileHash: string): PacketHexStr {
@@ -319,6 +320,19 @@ export class PacketPacker {
field200: 1, field200: 1,
field99999: Buffer.from([0xc0, 0x85, 0x2c, 0x01]) field99999: Buffer.from([0xc0, 0x85, 0x2c, 0x01])
}) })
) );
}
packGroupSignReq(uin: string, groupCode: string): PacketHexStr {
return this.toHexStr(
this.packOidbPacket(0XEB7, 1, new NapProtoMsg(OidbSvcTrpcTcp0XEB7).encode(
{
body: {
uin: uin,
groupUin: groupCode,
version: "9.0.90"
}
}
), false, false)
);
} }
} }

View File

@@ -12,7 +12,7 @@ export const DataHighwayHead = {
dataFlag: ProtoField(7, ScalarType.UINT32), dataFlag: ProtoField(7, ScalarType.UINT32),
commandId: ProtoField(8, ScalarType.UINT32), commandId: ProtoField(8, ScalarType.UINT32),
buildVer: ProtoField(9, ScalarType.BYTES, true), buildVer: ProtoField(9, ScalarType.BYTES, true),
} };
export const FileUploadExt = { export const FileUploadExt = {
unknown1: ProtoField(1, ScalarType.INT32), unknown1: ProtoField(1, ScalarType.INT32),
@@ -20,7 +20,7 @@ export const FileUploadExt = {
unknown3: ProtoField(3, ScalarType.INT32), unknown3: ProtoField(3, ScalarType.INT32),
entry: ProtoField(100, () => FileUploadEntry), entry: ProtoField(100, () => FileUploadEntry),
unknown200: ProtoField(200, ScalarType.INT32), unknown200: ProtoField(200, ScalarType.INT32),
} };
export const FileUploadEntry = { export const FileUploadEntry = {
busiBuff: ProtoField(100, () => ExcitingBusiInfo), busiBuff: ProtoField(100, () => ExcitingBusiInfo),
@@ -28,14 +28,14 @@ export const FileUploadEntry = {
clientInfo: ProtoField(300, () => ExcitingClientInfo), clientInfo: ProtoField(300, () => ExcitingClientInfo),
fileNameInfo: ProtoField(400, () => ExcitingFileNameInfo), fileNameInfo: ProtoField(400, () => ExcitingFileNameInfo),
host: ProtoField(500, () => ExcitingHostConfig), host: ProtoField(500, () => ExcitingHostConfig),
} };
export const ExcitingBusiInfo = { export const ExcitingBusiInfo = {
busId: ProtoField(1, ScalarType.INT32), busId: ProtoField(1, ScalarType.INT32),
senderUin: ProtoField(100, ScalarType.UINT64), senderUin: ProtoField(100, ScalarType.UINT64),
receiverUin: ProtoField(200, ScalarType.UINT64), receiverUin: ProtoField(200, ScalarType.UINT64),
groupCode: ProtoField(400, ScalarType.UINT64), groupCode: ProtoField(400, ScalarType.UINT64),
} };
export const ExcitingFileEntry = { export const ExcitingFileEntry = {
fileSize: ProtoField(100, ScalarType.UINT64), fileSize: ProtoField(100, ScalarType.UINT64),
@@ -44,7 +44,7 @@ export const ExcitingFileEntry = {
md5S2: ProtoField(400, ScalarType.BYTES), md5S2: ProtoField(400, ScalarType.BYTES),
fileId: ProtoField(600, ScalarType.STRING), fileId: ProtoField(600, ScalarType.STRING),
uploadKey: ProtoField(700, ScalarType.BYTES), uploadKey: ProtoField(700, ScalarType.BYTES),
} };
export const ExcitingClientInfo = { export const ExcitingClientInfo = {
clientType: ProtoField(100, ScalarType.INT32), clientType: ProtoField(100, ScalarType.INT32),
@@ -52,31 +52,31 @@ export const ExcitingClientInfo = {
terminalType: ProtoField(300, ScalarType.INT32), terminalType: ProtoField(300, ScalarType.INT32),
clientVer: ProtoField(400, ScalarType.STRING), clientVer: ProtoField(400, ScalarType.STRING),
unknown: ProtoField(600, ScalarType.INT32), unknown: ProtoField(600, ScalarType.INT32),
} };
export const ExcitingFileNameInfo = { export const ExcitingFileNameInfo = {
fileName: ProtoField(100, ScalarType.STRING), fileName: ProtoField(100, ScalarType.STRING),
} };
export const ExcitingHostConfig = { export const ExcitingHostConfig = {
hosts: ProtoField(200, () => ExcitingHostInfo, false, true), hosts: ProtoField(200, () => ExcitingHostInfo, false, true),
} };
export const ExcitingHostInfo = { export const ExcitingHostInfo = {
url: ProtoField(1, () => ExcitingUrlInfo), url: ProtoField(1, () => ExcitingUrlInfo),
port: ProtoField(2, ScalarType.UINT32), port: ProtoField(2, ScalarType.UINT32),
} };
export const ExcitingUrlInfo = { export const ExcitingUrlInfo = {
unknown: ProtoField(1, ScalarType.INT32), unknown: ProtoField(1, ScalarType.INT32),
host: ProtoField(2, ScalarType.STRING), host: ProtoField(2, ScalarType.STRING),
} };
export const LoginSigHead = { export const LoginSigHead = {
uint32LoginSigType: ProtoField(1, ScalarType.UINT32), uint32LoginSigType: ProtoField(1, ScalarType.UINT32),
bytesLoginSig: ProtoField(2, ScalarType.BYTES), bytesLoginSig: ProtoField(2, ScalarType.BYTES),
appId: ProtoField(3, ScalarType.UINT32), appId: ProtoField(3, ScalarType.UINT32),
} };
export const NTV2RichMediaHighwayExt = { export const NTV2RichMediaHighwayExt = {
fileUuid: ProtoField(1, ScalarType.STRING), fileUuid: ProtoField(1, ScalarType.STRING),
@@ -85,25 +85,25 @@ export const NTV2RichMediaHighwayExt = {
msgInfoBody: ProtoField(6, () => MsgInfoBody, false, true), msgInfoBody: ProtoField(6, () => MsgInfoBody, false, true),
blockSize: ProtoField(10, ScalarType.UINT32), blockSize: ProtoField(10, ScalarType.UINT32),
hash: ProtoField(11, () => NTHighwayHash), hash: ProtoField(11, () => NTHighwayHash),
} };
export const NTHighwayHash = { export const NTHighwayHash = {
fileSha1: ProtoField(1, ScalarType.BYTES, false, true), fileSha1: ProtoField(1, ScalarType.BYTES, false, true),
} };
export const NTHighwayNetwork = { export const NTHighwayNetwork = {
ipv4s: ProtoField(1, () => NTHighwayIPv4, false, true), ipv4s: ProtoField(1, () => NTHighwayIPv4, false, true),
} };
export const NTHighwayIPv4 = { export const NTHighwayIPv4 = {
domain: ProtoField(1, () => NTHighwayDomain), domain: ProtoField(1, () => NTHighwayDomain),
port: ProtoField(2, ScalarType.UINT32), port: ProtoField(2, ScalarType.UINT32),
} };
export const NTHighwayDomain = { export const NTHighwayDomain = {
isEnable: ProtoField(1, ScalarType.BOOL), isEnable: ProtoField(1, ScalarType.BOOL),
ip: ProtoField(2, ScalarType.STRING), ip: ProtoField(2, ScalarType.STRING),
} };
export const ReqDataHighwayHead = { export const ReqDataHighwayHead = {
msgBaseHead: ProtoField(1, () => DataHighwayHead, true), msgBaseHead: ProtoField(1, () => DataHighwayHead, true),
@@ -111,7 +111,7 @@ export const ReqDataHighwayHead = {
bytesReqExtendInfo: ProtoField(3, ScalarType.BYTES, true), bytesReqExtendInfo: ProtoField(3, ScalarType.BYTES, true),
timestamp: ProtoField(4, ScalarType.UINT64), timestamp: ProtoField(4, ScalarType.UINT64),
msgLoginSigHead: ProtoField(5, () => LoginSigHead, true), msgLoginSigHead: ProtoField(5, () => LoginSigHead, true),
} };
export const RespDataHighwayHead = { export const RespDataHighwayHead = {
msgBaseHead: ProtoField(1, () => DataHighwayHead, true), msgBaseHead: ProtoField(1, () => DataHighwayHead, true),
@@ -124,7 +124,7 @@ export const RespDataHighwayHead = {
timestamp: ProtoField(8, ScalarType.UINT64), timestamp: ProtoField(8, ScalarType.UINT64),
range: ProtoField(9, ScalarType.UINT64), range: ProtoField(9, ScalarType.UINT64),
isReset: ProtoField(10, ScalarType.UINT32), isReset: ProtoField(10, ScalarType.UINT32),
} };
export const SegHead = { export const SegHead = {
serviceId: ProtoField(1, ScalarType.UINT32, true), serviceId: ProtoField(1, ScalarType.UINT32, true),
@@ -140,7 +140,7 @@ export const SegHead = {
queryTimes: ProtoField(11, ScalarType.UINT32), queryTimes: ProtoField(11, ScalarType.UINT32),
updateCacheIp: ProtoField(12, ScalarType.UINT32), updateCacheIp: ProtoField(12, ScalarType.UINT32),
cachePort: ProtoField(13, ScalarType.UINT32, true), cachePort: ProtoField(13, ScalarType.UINT32, true),
} };
export const GroupAvatarExtra = { export const GroupAvatarExtra = {
type: ProtoField(1, ScalarType.UINT32), type: ProtoField(1, ScalarType.UINT32),
@@ -148,8 +148,8 @@ export const GroupAvatarExtra = {
field3: ProtoField(3, () => GroupAvatarExtraField3), field3: ProtoField(3, () => GroupAvatarExtraField3),
field5: ProtoField(5, ScalarType.UINT32), field5: ProtoField(5, ScalarType.UINT32),
field6: ProtoField(6, ScalarType.UINT32), field6: ProtoField(6, ScalarType.UINT32),
} };
export const GroupAvatarExtraField3 = { export const GroupAvatarExtraField3 = {
field1: ProtoField(1, ScalarType.UINT32), field1: ProtoField(1, ScalarType.UINT32),
} };

View File

@@ -118,7 +118,7 @@ export const MarketFace = {
export const MarketFacePbRes = { export const MarketFacePbRes = {
field8: ProtoField(8, ScalarType.INT32) field8: ProtoField(8, ScalarType.INT32)
} };
export const CustomFace = { export const CustomFace = {
guid: ProtoField(1, ScalarType.BYTES), guid: ProtoField(1, ScalarType.BYTES),
@@ -315,7 +315,7 @@ export const SrcMsgPbRes = {
senderUid: ProtoField(6, ScalarType.STRING, true), senderUid: ProtoField(6, ScalarType.STRING, true),
receiverUid: ProtoField(7, ScalarType.STRING, true), receiverUid: ProtoField(7, ScalarType.STRING, true),
friendSeq: ProtoField(8, ScalarType.UINT32, true), friendSeq: ProtoField(8, ScalarType.UINT32, true),
} };
export const LightAppElem = { export const LightAppElem = {
data: ProtoField(1, ScalarType.BYTES), data: ProtoField(1, ScalarType.BYTES),
@@ -358,4 +358,4 @@ export const QSmallFaceExtra = {
export const MarkdownData = { export const MarkdownData = {
content: ProtoField(1, ScalarType.STRING) content: ProtoField(1, ScalarType.STRING)
} };

View File

@@ -14,6 +14,7 @@ export const OidbSvcTrpcTcp0X9067_202Key = {
//Rsp //Rsp
export const OidbSvcTrpcTcp0X9067_202_RkeyList = { export const OidbSvcTrpcTcp0X9067_202_RkeyList = {
rkey: ProtoField(1, ScalarType.STRING), rkey: ProtoField(1, ScalarType.STRING),
ttl: ProtoField(2, ScalarType.UINT64),
time: ProtoField(4, ScalarType.UINT32), time: ProtoField(4, ScalarType.UINT32),
type: ProtoField(5, ScalarType.UINT32), type: ProtoField(5, ScalarType.UINT32),

View File

@@ -0,0 +1,12 @@
import { ScalarType } from "@protobuf-ts/runtime";
import { ProtoField } from "../NapProto";
export const OidbSvcTrpcTcp0XEB7_Body = {
uin: ProtoField(1, ScalarType.STRING),
groupUin: ProtoField(2, ScalarType.STRING),
version: ProtoField(3, ScalarType.STRING),
};
export const OidbSvcTrpcTcp0XEB7 = {
body: ProtoField(2, () => OidbSvcTrpcTcp0XEB7_Body),
}

View File

@@ -160,7 +160,7 @@ export const PicUrlExtInfo = {
export const VideoExtInfo = { export const VideoExtInfo = {
VideoCodecFormat: ProtoField(1, ScalarType.UINT32), VideoCodecFormat: ProtoField(1, ScalarType.UINT32),
} };
export const ExtBizInfo = { export const ExtBizInfo = {
Pic: ProtoField(1, () => PicExtBizInfo), Pic: ProtoField(1, () => PicExtBizInfo),

View File

@@ -13,20 +13,20 @@ export const NTV2RichMediaResp = {
uploadKeyRenewal: ProtoField(8, () => UploadKeyRenewalResp), uploadKeyRenewal: ProtoField(8, () => UploadKeyRenewalResp),
downloadSafe: ProtoField(9, () => DownloadSafeResp), downloadSafe: ProtoField(9, () => DownloadSafeResp),
extension: ProtoField(99, ScalarType.BYTES, true), extension: ProtoField(99, ScalarType.BYTES, true),
} };
export const MultiMediaRespHead = { export const MultiMediaRespHead = {
common: ProtoField(1, () => CommonHead), common: ProtoField(1, () => CommonHead),
retCode: ProtoField(2, ScalarType.UINT32), retCode: ProtoField(2, ScalarType.UINT32),
message: ProtoField(3, ScalarType.STRING), message: ProtoField(3, ScalarType.STRING),
} };
export const DownloadResp = { export const DownloadResp = {
rKeyParam: ProtoField(1, ScalarType.STRING), rKeyParam: ProtoField(1, ScalarType.STRING),
rKeyTtlSecond: ProtoField(2, ScalarType.UINT32), rKeyTtlSecond: ProtoField(2, ScalarType.UINT32),
info: ProtoField(3, () => DownloadInfo), info: ProtoField(3, () => DownloadInfo),
rKeyCreateTime: ProtoField(4, ScalarType.UINT32), rKeyCreateTime: ProtoField(4, ScalarType.UINT32),
} };
export const DownloadInfo = { export const DownloadInfo = {
domain: ProtoField(1, ScalarType.STRING), domain: ProtoField(1, ScalarType.STRING),
@@ -36,7 +36,7 @@ export const DownloadInfo = {
ipv6s: ProtoField(5, () => IPv6, false, true), ipv6s: ProtoField(5, () => IPv6, false, true),
picUrlExtInfo: ProtoField(6, () => PicUrlExtInfo), picUrlExtInfo: ProtoField(6, () => PicUrlExtInfo),
videoExtInfo: ProtoField(7, () => VideoExtInfo), videoExtInfo: ProtoField(7, () => VideoExtInfo),
} };
export const IPv4 = { export const IPv4 = {
outIP: ProtoField(1, ScalarType.UINT32), outIP: ProtoField(1, ScalarType.UINT32),
@@ -44,7 +44,7 @@ export const IPv4 = {
inIP: ProtoField(3, ScalarType.UINT32), inIP: ProtoField(3, ScalarType.UINT32),
inPort: ProtoField(4, ScalarType.UINT32), inPort: ProtoField(4, ScalarType.UINT32),
ipType: ProtoField(5, ScalarType.UINT32), ipType: ProtoField(5, ScalarType.UINT32),
} };
export const IPv6 = { export const IPv6 = {
outIP: ProtoField(1, ScalarType.BYTES), outIP: ProtoField(1, ScalarType.BYTES),
@@ -52,7 +52,7 @@ export const IPv6 = {
inIP: ProtoField(3, ScalarType.BYTES), inIP: ProtoField(3, ScalarType.BYTES),
inPort: ProtoField(4, ScalarType.UINT32), inPort: ProtoField(4, ScalarType.UINT32),
ipType: ProtoField(5, ScalarType.UINT32), ipType: ProtoField(5, ScalarType.UINT32),
} };
export const UploadResp = { export const UploadResp = {
uKey: ProtoField(1, ScalarType.STRING, true), uKey: ProtoField(1, ScalarType.STRING, true),
@@ -64,13 +64,13 @@ export const UploadResp = {
ext: ProtoField(7, () => RichMediaStorageTransInfo, false, true), ext: ProtoField(7, () => RichMediaStorageTransInfo, false, true),
compatQMsg: ProtoField(8, ScalarType.BYTES), compatQMsg: ProtoField(8, ScalarType.BYTES),
subFileInfos: ProtoField(10, () => SubFileInfo, false, true), subFileInfos: ProtoField(10, () => SubFileInfo, false, true),
} };
export const RichMediaStorageTransInfo = { export const RichMediaStorageTransInfo = {
subType: ProtoField(1, ScalarType.UINT32), subType: ProtoField(1, ScalarType.UINT32),
extType: ProtoField(2, ScalarType.UINT32), extType: ProtoField(2, ScalarType.UINT32),
extValue: ProtoField(3, ScalarType.BYTES), extValue: ProtoField(3, ScalarType.BYTES),
} };
export const SubFileInfo = { export const SubFileInfo = {
subType: ProtoField(1, ScalarType.UINT32), subType: ProtoField(1, ScalarType.UINT32),
@@ -78,32 +78,32 @@ export const SubFileInfo = {
uKeyTtlSecond: ProtoField(3, ScalarType.UINT32), uKeyTtlSecond: ProtoField(3, ScalarType.UINT32),
ipv4s: ProtoField(4, () => IPv4, false, true), ipv4s: ProtoField(4, () => IPv4, false, true),
ipv6s: ProtoField(5, () => IPv6, false, true), ipv6s: ProtoField(5, () => IPv6, false, true),
} };
export const DownloadSafeResp = { export const DownloadSafeResp = {
} };
export const UploadKeyRenewalResp = { export const UploadKeyRenewalResp = {
ukey: ProtoField(1, ScalarType.STRING), ukey: ProtoField(1, ScalarType.STRING),
ukeyTtlSec: ProtoField(2, ScalarType.UINT64), ukeyTtlSec: ProtoField(2, ScalarType.UINT64),
} };
export const MsgInfoAuthResp = { export const MsgInfoAuthResp = {
authCode: ProtoField(1, ScalarType.UINT32), authCode: ProtoField(1, ScalarType.UINT32),
msg: ProtoField(2, ScalarType.BYTES), msg: ProtoField(2, ScalarType.BYTES),
resultTime: ProtoField(3, ScalarType.UINT64), resultTime: ProtoField(3, ScalarType.UINT64),
} };
export const UploadCompletedResp = { export const UploadCompletedResp = {
msgSeq: ProtoField(1, ScalarType.UINT64), msgSeq: ProtoField(1, ScalarType.UINT64),
} };
export const DeleteResp = { export const DeleteResp = {
} };
export const DownloadRKeyResp = { export const DownloadRKeyResp = {
rKeys: ProtoField(1, () => RKeyInfo, false, true), rKeys: ProtoField(1, () => RKeyInfo, false, true),
} };
export const RKeyInfo = { export const RKeyInfo = {
rkey: ProtoField(1, ScalarType.STRING), rkey: ProtoField(1, ScalarType.STRING),
@@ -111,4 +111,4 @@ export const RKeyInfo = {
storeId: ProtoField(3, ScalarType.UINT32), storeId: ProtoField(3, ScalarType.UINT32),
rkeyCreateTime: ProtoField(4, ScalarType.UINT32, true), rkeyCreateTime: ProtoField(4, ScalarType.UINT32, true),
type: ProtoField(5, ScalarType.UINT32, true), type: ProtoField(5, ScalarType.UINT32, true),
} };

View File

@@ -76,7 +76,7 @@ export function decrypt(encrypted: Buffer, key: Buffer) {
encrypted.writeInt32BE(r1, i); encrypted.writeInt32BE(r1, i);
encrypted.writeInt32BE(r2, i + 4); encrypted.writeInt32BE(r2, i + 4);
} }
if (Buffer.compare(encrypted.subarray(encrypted.length - 7), BUF7) !== 0) throw ERROR_ENCRYPTED_ILLEGAL if (Buffer.compare(encrypted.subarray(encrypted.length - 7), BUF7) !== 0) throw ERROR_ENCRYPTED_ILLEGAL;
// if (Buffer.compare(encrypted.slice(encrypted.length - 7), BUF7) !== 0) throw ERROR_ENCRYPTED_ILLEGAL; // if (Buffer.compare(encrypted.slice(encrypted.length - 7), BUF7) !== 0) throw ERROR_ENCRYPTED_ILLEGAL;
return encrypted.subarray((encrypted[0] & 0x07) + 3, encrypted.length - 7); return encrypted.subarray((encrypted[0] & 0x07) + 3, encrypted.length - 7);
// return encrypted.slice((encrypted[0] & 0x07) + 3, encrypted.length - 7); // return encrypted.slice((encrypted[0] & 0x07) + 3, encrypted.length - 7);

View File

@@ -239,7 +239,7 @@ export interface NodeIKernelGroupService {
setMemberShutUp(groupCode: string, memberTimes: { uid: string, timeStamp: number }[]): Promise<void>; setMemberShutUp(groupCode: string, memberTimes: { uid: string, timeStamp: number }[]): Promise<void>;
getGroupRecommendContactArkJson(groupCode: string): unknown; getGroupRecommendContactArkJson(groupCode: string): Promise<GeneralCallResult & { arkJson: string }>;
getJoinGroupLink(param: { getJoinGroupLink(param: {
groupCode: string, groupCode: string,

View File

@@ -1,3 +1,4 @@
import { GroupNotifyMsgStatus } from '@/core';
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
@@ -11,18 +12,22 @@ export default class GetGroupAddRequest extends BaseAction<null, OB11GroupReques
actionName = ActionName.GetGroupIgnoreAddRequest; actionName = ActionName.GetGroupIgnoreAddRequest;
async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> { async _handle(payload: null): Promise<OB11GroupRequestNotify[] | null> {
// const data = await this.core.apis.GroupApi.getGroupIgnoreNotifies(); const ignoredNotifies = await this.core.apis.GroupApi.getSingleScreenNotifies(true, 10);
// log(data); const retData: any = {
// const notifies: GroupNotify[] = data.notifies.filter(notify => notify.status === GroupNotifyStatus.WAIT_HANDLE); join_requests: await Promise.all(
// const returnData: OB11GroupRequestNotify[] = []; ignoredNotifies
// for (const notify of notifies) { .filter(notify => notify.type === 7)
// const uin = || (await NTQQUserApi.getUserDetailInfo(notify.user1.uid))?.uin; .map(async SSNotify => ({
// returnData.push({ request_id: SSNotify.seq,
// group_id: parseInt(notify.group.groupCode), requester_uin: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user1?.uid),
// user_id: parseInt(uin), requester_nick: SSNotify.user1?.nickName,
// flag: notify.seq group_id: SSNotify.group?.groupCode,
// }); group_name: SSNotify.group?.groupName,
// } checked: SSNotify.status !== GroupNotifyMsgStatus.KUNHANDLE,
return null; actor: await this.core.apis.UserApi.getUinByUidV2(SSNotify.user2?.uid) || 0,
}))),
};
return retData;
} }
} }

View File

@@ -0,0 +1,22 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = {
type: 'object',
properties: {
group_id: { type: 'string' },
},
required: ['group_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class SetGroupSign extends BaseAction<Payload, any> {
actionName = ActionName.SetGroupSign;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
return await this.core.apis.PacketApi.sendGroupSignPacket(payload.group_id);
}
}

View File

@@ -5,9 +5,9 @@ import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts'; import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { OB11MessageImage, OB11MessageVideo } from '@/onebot/types'; import { OB11MessageImage, OB11MessageVideo } from '@/onebot/types';
export interface GetFilePayload { // interface GetFilePayload {
file: string; // 文件名或者fileUuid // file: string; // 文件名或者fileUuid
} // }
export interface GetFileResponse { export interface GetFileResponse {
file?: string; // path file?: string; // path
@@ -16,19 +16,25 @@ export interface GetFileResponse {
file_name?: string; file_name?: string;
base64?: string; base64?: string;
} }
const GetFileBase_PayloadSchema = { const GetFileBase_PayloadSchema = {
type: 'object', type: 'object',
properties: { properties: {
file: { type: 'string' }, file: { type: 'string' },
file_id: { type: 'string' }
}, },
required: ['file'], oneOf: [
{ required: ['file'] },
{ required: ['file_id'] }
]
} as const satisfies JSONSchema; } as const satisfies JSONSchema;
export type GetFilePayload = FromSchema<typeof GetFileBase_PayloadSchema>;
export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> { export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
payloadSchema: any = GetFileBase_PayloadSchema; payloadSchema = GetFileBase_PayloadSchema;
async _handle(payload: GetFilePayload): Promise<GetFileResponse> { async _handle(payload: GetFilePayload): Promise<GetFileResponse> {
payload.file ||= payload.file_id || '';
//接收消息标记模式 //接收消息标记模式
const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file); const contextMsgFile = FileNapCatOneBotUUID.decode(payload.file);
if (contextMsgFile) { if (contextMsgFile) {
@@ -115,27 +121,6 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
} }
} }
const GetFile_PayloadSchema = {
type: 'object',
properties: {
file_id: { type: 'string' },
file: { type: 'string' },
},
required: ['file_id'],
} as const satisfies JSONSchema;
type GetFile_Payload_Internal = FromSchema<typeof GetFile_PayloadSchema>;
interface GetFile_Payload extends GetFile_Payload_Internal {
file: string;
}
export default class GetFile extends GetFileBase { export default class GetFile extends GetFileBase {
actionName = ActionName.GetFile; actionName = ActionName.GetFile;
payloadSchema = GetFile_PayloadSchema;
async _handle(payload: GetFile_Payload): Promise<GetFileResponse> {
payload.file = payload.file_id;
return super._handle(payload);
}
} }

View File

@@ -27,7 +27,7 @@ export class GetGroupFileUrl extends GetPacketStatusDepends<Payload, GetGroupFil
if (contextMsgFile?.fileUUID) { if (contextMsgFile?.fileUUID) {
return { return {
url: await this.core.apis.PacketApi.sendGroupFileDownloadReq(+payload.group_id, contextMsgFile.fileUUID) url: await this.core.apis.PacketApi.sendGroupFileDownloadReq(+payload.group_id, contextMsgFile.fileUUID)
} };
} }
throw new Error('real fileUUID not found!'); throw new Error('real fileUUID not found!');
} }

View File

@@ -18,6 +18,6 @@ export class GroupPoke extends GetPacketStatusDepends<Payload, any> {
payloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
await this.core.apis.PacketApi.sendPokePacket(+payload.group_id, +payload.user_id); await this.core.apis.PacketApi.sendPokePacket(+payload.user_id, +payload.group_id);
} }
} }

View File

@@ -91,6 +91,9 @@ import { GetGroupShutList } from './group/GetGroupShutList';
import { GetGroupMemberList } from './group/GetGroupMemberList'; import { GetGroupMemberList } from './group/GetGroupMemberList';
import { GetGroupFileUrl } from "@/onebot/action/file/GetGroupFileUrl"; import { GetGroupFileUrl } from "@/onebot/action/file/GetGroupFileUrl";
import { GetPacketStatus } from "@/onebot/action/packet/GetPacketStatus"; import { GetPacketStatus } from "@/onebot/action/packet/GetPacketStatus";
import { FriendPoke } from "@/onebot/action/user/FriendPoke";
import { GetCredentials } from './system/GetCredentials';
import { SetGroupSign } from './extends/SetGroupSign';
export type ActionMap = Map<string, BaseAction<any, any>>; export type ActionMap = Map<string, BaseAction<any, any>>;
@@ -113,6 +116,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
new SetQQAvatar(obContext, core), new SetQQAvatar(obContext, core),
new TranslateEnWordToZn(obContext, core), new TranslateEnWordToZn(obContext, core),
new GetGroupRootFiles(obContext, core), new GetGroupRootFiles(obContext, core),
new SetGroupSign(obContext, core),
// onebot11 // onebot11
new SendLike(obContext, core), new SendLike(obContext, core),
new GetMsg(obContext, core), new GetMsg(obContext, core),
@@ -179,6 +183,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
new SetModelShow(obContext, core), new SetModelShow(obContext, core),
new SetInputStatus(obContext, core), new SetInputStatus(obContext, core),
new GetCSRF(obContext, core), new GetCSRF(obContext, core),
new GetCredentials(obContext, core),
new DelGroupNotice(obContext, core), new DelGroupNotice(obContext, core),
new DeleteGroupFile(obContext, core), new DeleteGroupFile(obContext, core),
new CreateGroupFileFolder(obContext, core), new CreateGroupFileFolder(obContext, core),
@@ -189,6 +194,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
new FetchUserProfileLike(obContext, core), new FetchUserProfileLike(obContext, core),
new GetPacketStatus(obContext, core), new GetPacketStatus(obContext, core),
new GroupPoke(obContext, core), new GroupPoke(obContext, core),
new FriendPoke(obContext, core),
new GetUserStatus(obContext, core), new GetUserStatus(obContext, core),
new GetRkey(obContext, core), new GetRkey(obContext, core),
new SetSpecialTittle(obContext, core), new SetSpecialTittle(obContext, core),

View File

@@ -1,7 +1,7 @@
import { ChatType, Peer } from '@/core/entities'; import { ChatType, Peer } from '@/core/entities';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { ActionName } from '../types'; import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
const SchemaData = { const SchemaData = {
type: 'object', type: 'object',
@@ -49,23 +49,14 @@ export class MarkGroupMsgAsRead extends MarkMsgAsRead {
actionName = ActionName.MarkGroupMsgAsRead; actionName = ActionName.MarkGroupMsgAsRead;
} }
export class GoCQHTTPMarkMsgAsRead extends MarkMsgAsRead {
interface Payload {
message_id: number;
}
export class GoCQHTTPMarkMsgAsRead extends BaseAction<Payload, null> {
actionName = ActionName.GoCQHTTP_MarkMsgAsRead; actionName = ActionName.GoCQHTTP_MarkMsgAsRead;
async _handle(payload: Payload): Promise<null> {
return null;
}
} }
export class MarkAllMsgAsRead extends BaseAction<Payload, null> { export class MarkAllMsgAsRead extends BaseAction<any, null> {
actionName = ActionName._MarkAllMsgAsRead; actionName = ActionName._MarkAllMsgAsRead;
async _handle(payload: Payload): Promise<null> { async _handle(): Promise<null> {
await this.core.apis.MsgApi.markAllMsgAsRead(); await this.core.apis.MsgApi.markAllMsgAsRead();
return null; return null;
} }

View File

@@ -13,7 +13,7 @@ import {ChatType, ElementType, NapCatCore, Peer, RawMessage, SendArkElement, Sen
import BaseAction from '../BaseAction'; import BaseAction from '../BaseAction';
import { rawMsgWithSendMsg } from "@/core/packet/msg/converter"; import { rawMsgWithSendMsg } from "@/core/packet/msg/converter";
import { PacketMsg } from "@/core/packet/msg/message"; import { PacketMsg } from "@/core/packet/msg/message";
import {PacketMultiMsgElement} from "@/core/packet/msg/element"; import { ForwardMsgBuilder } from "@/common/forward-msg-builder";
export interface ReturnDataType { export interface ReturnDataType {
message_id: number; message_id: number;
@@ -115,7 +115,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
); );
if (getSpecialMsgNum(payload, OB11MessageDataType.node)) { if (getSpecialMsgNum(payload, OB11MessageDataType.node)) {
const packetMode = this.core.apis.PacketApi.available const packetMode = this.core.apis.PacketApi.available;
const returnMsgAndResId = packetMode const returnMsgAndResId = packetMode
? await this.handleForwardedNodesPacket(peer, messages as OB11MessageNode[]) ? await this.handleForwardedNodesPacket(peer, messages as OB11MessageNode[])
: await this.handleForwardedNodes(peer, messages as OB11MessageNode[]); : await this.handleForwardedNodes(peer, messages as OB11MessageNode[]);
@@ -126,6 +126,8 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
chatType: peer.chatType, chatType: peer.chatType,
}, (returnMsgAndResId.message)!.msgId); }, (returnMsgAndResId.message)!.msgId);
return { message_id: msgShortId!, res_id: returnMsgAndResId.res_id }; return { message_id: msgShortId!, res_id: returnMsgAndResId.res_id };
} else if (returnMsgAndResId.res_id && !returnMsgAndResId.message) {
throw Error(`发送转发消息res_id${returnMsgAndResId.res_id} 失败`);
} }
throw Error('发送转发消息失败'); throw Error('发送转发消息失败');
} else { } else {
@@ -143,6 +145,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
return { message_id: returnMsg!.id! }; return { message_id: returnMsg!.id! };
} }
// TODO: recursively handle forwarded nodes
private async handleForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[]): Promise<{ private async handleForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[]): Promise<{
message: RawMessage | null, message: RawMessage | null,
res_id?: string res_id?: string
@@ -159,7 +162,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
groupId: msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : undefined, groupId: msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : undefined,
time: Date.now(), time: Date.now(),
msg: sendElements, msg: sendElements,
} };
logger.logDebug(`handleForwardedNodesPacket 开始转换 ${JSON.stringify(packetMsgElements)}`); logger.logDebug(`handleForwardedNodesPacket 开始转换 ${JSON.stringify(packetMsgElements)}`);
const transformedMsg = this.core.apis.PacketApi.packetSession?.packer.packetConverter.rawMsgWithSendMsgToPacketMsg(packetMsgElements); const transformedMsg = this.core.apis.PacketApi.packetSession?.packer.packetConverter.rawMsgWithSendMsgToPacketMsg(packetMsgElements);
logger.logDebug(`handleForwardedNodesPacket 转换为 ${JSON.stringify(transformedMsg)}`); logger.logDebug(`handleForwardedNodesPacket 转换为 ${JSON.stringify(transformedMsg)}`);
@@ -169,22 +172,20 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
} }
} }
const resid = await this.core.apis.PacketApi.sendUploadForwardMsg(packetMsg, msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : 0); const resid = await this.core.apis.PacketApi.sendUploadForwardMsg(packetMsg, msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : 0);
const forwardJson = new PacketMultiMsgElement({ const forwardJson = ForwardMsgBuilder.fromPacketMsg(resid, packetMsg);
elementType: ElementType.STRUCTLONGMSG,
elementId: "",
structLongMsgElement: {
xmlContent: "",
resId: resid
}
}, packetMsg).JSON;
const finallySendElements = { const finallySendElements = {
elementType: ElementType.ARK, elementType: ElementType.ARK,
elementId: "", elementId: "",
arkElement: { arkElement: {
bytesData: JSON.stringify(forwardJson), bytesData: JSON.stringify(forwardJson),
}, },
} as SendArkElement } as SendArkElement;
const returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(msgPeer, [finallySendElements], [], true).catch(_ => undefined) let returnMsg: RawMessage | undefined;
try {
returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(msgPeer, [finallySendElements], [], true).catch(_ => undefined);
} catch (e) {
logger.logWarn("发送伪造合并转发消息失败!", e);
}
return { message: returnMsg ?? null, res_id: resid }; return { message: returnMsg ?? null, res_id: resid };
} }

View File

@@ -10,16 +10,16 @@ export abstract class GetPacketStatusDepends<PT, RT> extends BaseAction<PT, RT>
return { return {
valid: false, valid: false,
message: "packetServer不可用请参照文档 https://napneko.github.io/config/advanced 检查packetServer状态或进行配置", message: "packetServer不可用请参照文档 https://napneko.github.io/config/advanced 检查packetServer状态或进行配置",
} };
} }
return { return {
valid: true, valid: true,
} };
} }
} }
export class GetPacketStatus extends GetPacketStatusDepends<any, null> { export class GetPacketStatus extends GetPacketStatusDepends<any, null> {
async _handle(payload: any) { async _handle(payload: any) {
return null return null;
} }
} }

View File

@@ -5,8 +5,12 @@ export class GetCSRF extends BaseAction<any, any> {
actionName = ActionName.GetCSRF; actionName = ActionName.GetCSRF;
async _handle(payload: any) { async _handle(payload: any) {
const sKey = await this.core.apis.UserApi.getSKey();
if (!sKey) {
throw new Error('SKey is undefined');
}
return { return {
token: '', token: +this.core.apis.WebApi.getBknFromSKey(sKey),
}; };
} }
} }

View File

@@ -0,0 +1,31 @@
import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
interface Response {
cookies: string,
token: number
}
const SchemaData = {
type: 'object',
properties: {
domain: { type: 'string' },
},
required: ['domain'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class GetCredentials extends BaseAction<Payload, Response> {
actionName = ActionName.GetCredentials;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
const cookiesObject = await this.core.apis.UserApi.getCookies(payload.domain);
//把获取到的cookiesObject转换成 k=v; 格式字符串拼接在一起
const cookies = Object.entries(cookiesObject).map(([key, value]) => `${key}=${value}`).join('; ');
const bkn = cookiesObject?.skey ? this.core.apis.WebApi.getBknFromCookie(cookiesObject) : '';
return { cookies: cookies, token: +bkn };
}
}

View File

@@ -1,4 +1,4 @@
export type BaseCheckResult = ValidCheckResult | InvalidCheckResult export type BaseCheckResult = ValidCheckResult | InvalidCheckResult;
export interface ValidCheckResult { export interface ValidCheckResult {
valid: true; valid: true;
@@ -14,117 +14,127 @@ export interface InvalidCheckResult {
} }
export enum ActionName { export enum ActionName {
// 以下为扩展napcat扩展
Unknown = 'unknown',
GroupPoke = 'group_poke',
SharePeer = 'ArkSharePeer',
ShareGroupEx = 'ArkShareGroup',
RebootNormal = 'reboot_normal',//无快速登录重新启动
GetRobotUinRange = 'get_robot_uin_range',
SetOnlineStatus = 'set_online_status',
GetFriendsWithCategory = 'get_friends_with_category',
GetGroupIgnoreAddRequest = 'get_group_ignore_add_request',
SetQQAvatar = 'set_qq_avatar',
GetConfig = 'get_config',
SetConfig = 'set_config',
Debug = 'debug',
GetFile = 'get_file',
ForwardFriendSingleMsg = 'forward_friend_single_msg',
ForwardGroupSingleMsg = 'forward_group_single_msg',
TranslateEnWordToZn = 'translate_en2zh',
GetGroupFileCount = 'get_group_file_count',
GetGroupFileList = 'get_group_file_list',
SetGroupFileFolder = 'set_group_file_folder',
DelGroupFile = 'del_group_file',
DelGroupFileFolder = 'del_group_file_folder',
// onebot 11 // onebot 11
Reboot = 'set_restart', SendPrivateMsg = 'send_private_msg',
SendGroupMsg = 'send_group_msg',
SendMsg = 'send_msg',
DeleteMsg = 'delete_msg',
GetMsg = 'get_msg',
GoCQHTTP_GetForwardMsg = 'get_forward_msg',
SendLike = 'send_like', SendLike = 'send_like',
SetGroupKick = 'set_group_kick',
SetGroupBan = 'set_group_ban',
// SetGroupAnoymousBan = 'set_group_anonymous_ban',
SetGroupWholeBan = 'set_group_whole_ban',
SetGroupAdmin = 'set_group_admin',
// SetGroupAnoymous = 'set_group_anonymous',
SetGroupCard = 'set_group_card',
SetGroupName = 'set_group_name',
SetGroupLeave = 'set_group_leave',
SetSpecialTittle = 'set_group_special_title',
SetFriendAddRequest = 'set_friend_add_request',
SetGroupAddRequest = 'set_group_add_request',
GetLoginInfo = 'get_login_info', GetLoginInfo = 'get_login_info',
GoCQHTTP_GetStrangerInfo = 'get_stranger_info',
GetFriendList = 'get_friend_list', GetFriendList = 'get_friend_list',
GetGroupInfo = 'get_group_info', GetGroupInfo = 'get_group_info',
GetGroupList = 'get_group_list', GetGroupList = 'get_group_list',
GetGroupMemberInfo = 'get_group_member_info', GetGroupMemberInfo = 'get_group_member_info',
GetGroupMemberList = 'get_group_member_list', GetGroupMemberList = 'get_group_member_list',
GetMsg = 'get_msg',
SendMsg = 'send_msg',
SendGroupMsg = 'send_group_msg',
SendPrivateMsg = 'send_private_msg',
DeleteMsg = 'delete_msg',
SetMsgEmojiLike = 'set_msg_emoji_like',
SetGroupAddRequest = 'set_group_add_request',
SetFriendAddRequest = 'set_friend_add_request',
SetGroupLeave = 'set_group_leave',
GetVersionInfo = 'get_version_info',
GetStatus = 'get_status',
CanSendRecord = 'can_send_record',
CanSendImage = 'can_send_image',
SetGroupKick = 'set_group_kick',
SetGroupBan = 'set_group_ban',
SetGroupWholeBan = 'set_group_whole_ban',
SetGroupAdmin = 'set_group_admin',
SetGroupCard = 'set_group_card',
SetGroupName = 'set_group_name',
GetImage = 'get_image',
GetRecord = 'get_record',
CleanCache = 'clean_cache',
GetCookies = 'get_cookies',
// 以下为go-cqhttp api
GoCQHTTP_HandleQuickAction = '.handle_quick_operation',
GetGroupHonorInfo = 'get_group_honor_info', GetGroupHonorInfo = 'get_group_honor_info',
GoCQHTTP_GetEssenceMsg = 'get_essence_msg_list', GetCookies = 'get_cookies',
GoCQHTTP_SendGroupNotice = '_send_group_notice', GetCSRF = 'get_csrf_token',
GoCQHTTP_GetGroupNotice = '_get_group_notice', GetCredentials = 'get_credentials',
GoCQHTTP_SendForwardMsg = 'send_forward_msg', GetRecord = 'get_record',
GetImage = 'get_image',
CanSendImage = 'can_send_image',
CanSendRecord = 'can_send_record',
GetStatus = 'get_status',
GetVersionInfo = 'get_version_info',
// Reboot = 'set_restart',
// CleanCache = 'clean_cache',
// go-cqhttp
SetQQProfile = 'set_qq_profile',
// QidianGetAccountInfo = 'qidian_get_account_info',
// GetModelShow = '_get_model_show',
// SetModelShow = '_set_model_show',
GetOnlineClient = 'get_online_clients',
// GetUnidirectionalFriendList = 'get_unidirectional_friend_list',
// DeleteFriend = 'delete_friend',
// DeleteUnidirectionalFriendList = 'delete_unidirectional_friend',
GoCQHTTP_MarkMsgAsRead = 'mark_msg_as_read',
GoCQHTTP_SendGroupForwardMsg = 'send_group_forward_msg', GoCQHTTP_SendGroupForwardMsg = 'send_group_forward_msg',
GoCQHTTP_SendPrivateForwardMsg = 'send_private_forward_msg', GoCQHTTP_SendPrivateForwardMsg = 'send_private_forward_msg',
GoCQHTTP_GetStrangerInfo = 'get_stranger_info', GoCQHTTP_GetGroupMsgHistory = 'get_group_msg_history',
GoCQHTTP_MarkMsgAsRead = 'mark_msg_as_read', OCRImage = 'ocr_image',
GetGuildList = 'get_guild_list', IOCRImage = '.ocr_image',
MarkPrivateMsgAsRead = 'mark_private_msg_as_read', GetGroupSystemMsg = 'get_group_system_msg',
MarkGroupMsgAsRead = 'mark_group_msg_as_read', GoCQHTTP_GetEssenceMsg = 'get_essence_msg_list',
// GetGroupAtAllRemain = 'get_group_at_all_remain',
SetGroupPortrait = 'set_group_portrait',
SetEssenceMsg = 'set_essence_msg',
DelEssenceMsg = 'delete_essence_msg',
GoCQHTTP_SendGroupNotice = '_send_group_notice',
GoCQHTTP_GetGroupNotice = '_get_group_notice',
GoCQHTTP_UploadGroupFile = 'upload_group_file', GoCQHTTP_UploadGroupFile = 'upload_group_file',
GOCQHTTP_DeleteGroupFile = 'delete_group_file', GOCQHTTP_DeleteGroupFile = 'delete_group_file',
GOCQHTTP_GetGroupFileUrl = 'get_group_file_url',
GoCQHTTP_CreateGroupFileFolder = 'create_group_file_folder', GoCQHTTP_CreateGroupFileFolder = 'create_group_file_folder',
GoCQHTTP_DeleteGroupFileFolder = 'delete_group_file_folder', GoCQHTTP_DeleteGroupFileFolder = 'delete_group_folder',
GoCQHTTP_GetGroupFileSystemInfo = 'get_group_file_system_info', GoCQHTTP_GetGroupFileSystemInfo = 'get_group_file_system_info',
GoCQHTTP_GetGroupRootFiles = 'get_group_root_files', GoCQHTTP_GetGroupRootFiles = 'get_group_root_files',
GoCQHTTP_GetGroupFilesByFolder = 'get_group_files_by_folder', GoCQHTTP_GetGroupFilesByFolder = 'get_group_files_by_folder',
GOCQHTTP_GetGroupFileUrl = 'get_group_file_url',
GOCQHTTP_UploadPrivateFile = 'upload_private_file',
// GOCQHTTP_ReloadEventFilter = 'reload_event_filter',
GoCQHTTP_DownloadFile = 'download_file', GoCQHTTP_DownloadFile = 'download_file',
GoCQHTTP_GetGroupMsgHistory = 'get_group_msg_history', // GoCQHTTP_CheckUrlSafely = 'check_url_safely',
GoCQHTTP_GetForwardMsg = 'get_forward_msg', // GoCQHTTP_GetWordSlices = '.get_word_slices',
GoCQHTTP_HandleQuickAction = '.handle_quick_operation',
// 以下为扩展napcat扩展
Unknown = 'unknown',
SharePeer = 'ArkSharePeer',
ShareGroupEx = 'ArkShareGroup',
// RebootNormal = 'reboot_normal', //无快速登录重新启动
GetRobotUinRange = 'get_robot_uin_range',
SetOnlineStatus = 'set_online_status',
GetFriendsWithCategory = 'get_friends_with_category',
SetQQAvatar = 'set_qq_avatar',
GetFile = 'get_file',
ForwardFriendSingleMsg = 'forward_friend_single_msg',
ForwardGroupSingleMsg = 'forward_group_single_msg',
TranslateEnWordToZn = 'translate_en2zh',
SetMsgEmojiLike = 'set_msg_emoji_like',
GoCQHTTP_SendForwardMsg = 'send_forward_msg',
MarkPrivateMsgAsRead = 'mark_private_msg_as_read',
MarkGroupMsgAsRead = 'mark_group_msg_as_read',
GetFriendMsgHistory = 'get_friend_msg_history', GetFriendMsgHistory = 'get_friend_msg_history',
GetGroupIgnoredNotifies = 'get_group_ignored_notifies',
GetOnlineClient = 'get_online_clients',
OCRImage = 'ocr_image',
IOCRImage = '.ocr_image',
SetQQProfile = 'set_qq_profile',
CreateCollection = 'create_collection', CreateCollection = 'create_collection',
GetCollectionList = 'get_collection_list', GetCollectionList = 'get_collection_list',
SetLongNick = 'set_self_longnick', SetLongNick = 'set_self_longnick',
SetEssenceMsg = 'set_essence_msg',
DelEssenceMsg = 'delete_essence_msg',
GetRecentContact = 'get_recent_contact', GetRecentContact = 'get_recent_contact',
_MarkAllMsgAsRead = '_mark_all_as_read', _MarkAllMsgAsRead = '_mark_all_as_read',
GetProfileLike = 'get_profile_like', GetProfileLike = 'get_profile_like',
SetGroupPortrait = 'set_group_portrait',
FetchCustomFace = 'fetch_custom_face', FetchCustomFace = 'fetch_custom_face',
GOCQHTTP_UploadPrivateFile = 'upload_private_file',
TestApi01 = 'test_api_01',
FetchEmojiLike = 'fetch_emoji_like', FetchEmojiLike = 'fetch_emoji_like',
GetGuildProfile = 'get_guild_service_profile',
SetModelShow = '_set_model_show',
SetInputStatus = 'set_input_status', SetInputStatus = 'set_input_status',
GetCSRF = 'get_csrf_token', GetGroupInfoEx = 'get_group_info_ex',
GetGroupIgnoreAddRequest = 'get_group_ignore_add_request',
DelGroupNotice = '_del_group_notice', DelGroupNotice = '_del_group_notice',
GetGroupInfoEx = "get_group_info_ex", FetchUserProfileLike = 'fetch_user_profile_like',
GetGroupSystemMsg = 'get_group_system_msg', FriendPoke = 'friend_poke',
FetchUserProfileLike = "fetch_user_profile_like", GroupPoke = 'group_poke',
GetPacketStatus = 'nc_get_packet_status', GetPacketStatus = 'nc_get_packet_status',
GetUserStatus = "nc_get_user_status", GetUserStatus = 'nc_get_user_status',
GetRkey = "nc_get_rkey", GetRkey = 'nc_get_rkey',
SetSpecialTittle = "set_group_special_title", GetGroupShutList = 'get_group_shut_list',
GetGuildList = 'get_guild_list',
GetGuildProfile = 'get_guild_service_profile',
GetGroupIgnoredNotifies = 'get_group_ignored_notifies',
SetGroupSign = "set_group_sign",
// UploadForwardMsg = "upload_forward_msg", // UploadForwardMsg = "upload_forward_msg",
GetGroupShutList = "get_group_shut_list",
} }

View File

@@ -0,0 +1,22 @@
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { GetPacketStatusDepends } from "@/onebot/action/packet/GetPacketStatus";
const SchemaData = {
type: 'object',
properties: {
user_id: { type: ['number', 'string'] },
},
required: ['user_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class FriendPoke extends GetPacketStatusDepends<Payload, any> {
actionName = ActionName.FriendPoke;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
await this.core.apis.PacketApi.sendPokePacket(+payload.user_id);
}
}

View File

@@ -35,6 +35,7 @@ import fs from 'node:fs';
import fsPromise from 'node:fs/promises'; import fsPromise from 'node:fs/promises';
import { OB11FriendAddNoticeEvent } from '@/onebot/event/notice/OB11FriendAddNoticeEvent'; import { OB11FriendAddNoticeEvent } from '@/onebot/event/notice/OB11FriendAddNoticeEvent';
import { decodeSysMessage } from '@/core/packet/proto/old/ProfileLike'; import { decodeSysMessage } from '@/core/packet/proto/old/ProfileLike';
import { ForwardMsgBuilder } from "@/common/forward-msg-builder";
type RawToOb11Converters = { type RawToOb11Converters = {
[Key in keyof MessageElement as Key extends `${string}Element` ? Key : never]: ( [Key in keyof MessageElement as Key extends `${string}Element` ? Key : never]: (
@@ -600,7 +601,13 @@ export class OneBotMsgApi {
[OB11MessageDataType.node]: async () => undefined, [OB11MessageDataType.node]: async () => undefined,
[OB11MessageDataType.forward]: async () => undefined, [OB11MessageDataType.forward]: async ({ data }, context) => {
const jsonData = ForwardMsgBuilder.fromResId(data.id);
return this.ob11ToRawConverters.json({
data: { data: JSON.stringify(jsonData) },
type: OB11MessageDataType.json
}, context);
},
[OB11MessageDataType.xml]: async () => undefined, [OB11MessageDataType.xml]: async () => undefined,
@@ -617,12 +624,20 @@ export class OneBotMsgApi {
[OB11MessageDataType.miniapp]: async () => undefined, [OB11MessageDataType.miniapp]: async () => undefined,
[OB11MessageDataType.contact]: async ({ data }, context) => { [OB11MessageDataType.contact]: async ({ data: { type = "qq", id } }, context) => {
const arkJson = await this.core.apis.UserApi.getBuddyRecommendContactArkJson(data.id.toString(), ''); if(type === "qq"){
const arkJson = await this.core.apis.UserApi.getBuddyRecommendContactArkJson(id.toString(), '');
return this.ob11ToRawConverters.json({ return this.ob11ToRawConverters.json({
data: { data: arkJson.arkMsg }, data: { data: arkJson.arkMsg },
type: OB11MessageDataType.json type: OB11MessageDataType.json
}, context); }, context);
}else if(type === "group"){
const arkJson = await this.core.apis.GroupApi.getGroupRecommendContactArkJson(id.toString());
return this.ob11ToRawConverters.json({
data: { data: arkJson.arkJson },
type: OB11MessageDataType.json
}, context);
}
} }
}; };

View File

@@ -304,10 +304,10 @@ export class NapCatOneBot11Adapter {
}, },
m.msgId, m.msgId,
); );
if (m.sourceType == MsgSourceType.K_DOWN_SOURCETYPE_AIOINNER) { // if (m.sourceType == MsgSourceType.K_DOWN_SOURCETYPE_AIOINNER) {
await this.emitMsg(m) await this.emitMsg(m)
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e)); .catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e));
} // }
} }
}; };
@@ -576,8 +576,6 @@ export class NapCatOneBot11Adapter {
this.networkManager.emitEvent(ob11Msg); this.networkManager.emitEvent(ob11Msg);
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructMessage error: ', e)); }).catch(e => this.context.logger.logError.bind(this.context.logger)('constructMessage error: ', e));
console.log('message', message);
this.apis.GroupApi.parseGroupEvent(message).then(groupEvent => { this.apis.GroupApi.parseGroupEvent(message).then(groupEvent => {
if (groupEvent) { if (groupEvent) {
// log("post group event", groupEvent); // log("post group event", groupEvent);

View File

@@ -85,6 +85,7 @@ export interface OB11MessageText {
export interface OB11MessageContext { export interface OB11MessageContext {
type: OB11MessageDataType.contact, type: OB11MessageDataType.contact,
data: { data: {
type:"qq"|"group",
id: string, id: string,
} }
} }

View File

@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
SettingItem( SettingItem(
'<span id="napcat-update-title">Napcat</span>', '<span id="napcat-update-title">Napcat</span>',
undefined, undefined,
SettingButton('V3.0.3', 'napcat-update-button', 'secondary'), SettingButton('V3.1.5', 'napcat-update-button', 'secondary'),
), ),
]), ]),
SettingList([ SettingList([

View File

@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
SettingItem( SettingItem(
'<span id="napcat-update-title">Napcat</span>', '<span id="napcat-update-title">Napcat</span>',
void 0, void 0,
SettingButton("V3.0.3", "napcat-update-button", "secondary") SettingButton("V3.1.5", "napcat-update-button", "secondary")
) )
]), ]),
SettingList([ SettingList([