From f7ab795e1900fade159d369cdcf6dc8b31836440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Fri, 30 Oct 2026 13:50:43 +0800 Subject: [PATCH] fix: #2133 #2114 --- packages/napcat-core/apis/group.ts | 4 +-- .../action/group/GetGroupMemberInfo.ts | 29 ++++++++++--------- packages/napcat-protobuf/NapProto.ts | 8 +++-- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/packages/napcat-core/apis/group.ts b/packages/napcat-core/apis/group.ts index df85e615..858599a9 100644 --- a/packages/napcat-core/apis/group.ts +++ b/packages/napcat-core/apis/group.ts @@ -341,7 +341,7 @@ export class NTQQGroupApi { return undefined; } if (isNumeric(memberUinOrUidStr)) { - return Array.from(members.values()).find(member => member.uin === memberUinOrUidStr); + return Array.from(members.values()).find(member => member.uin?.toString() === memberUinOrUidStr); } else { return members.get(memberUinOrUidStr); } @@ -360,7 +360,7 @@ export class NTQQGroupApi { getUidFromMemberCache (uin: string) { for (const members of this.groupMemberCache.values()) { for (const [uid, member] of members) { - if (member.uin === uin) { + if (member.uin?.toString() === uin) { return uid; } } diff --git a/packages/napcat-onebot/action/group/GetGroupMemberInfo.ts b/packages/napcat-onebot/action/group/GetGroupMemberInfo.ts index 4e65f411..1f776d4f 100644 --- a/packages/napcat-onebot/action/group/GetGroupMemberInfo.ts +++ b/packages/napcat-onebot/action/group/GetGroupMemberInfo.ts @@ -38,28 +38,31 @@ class GetGroupMemberInfo extends OneBotAction { return uid; } - private async getGroupMemberInfo (payload: PayloadType, uid: string, isNocache: boolean) { - const groupMemberCache = this.core.apis.GroupApi.groupMemberCache.get(payload.group_id.toString()); - const groupMember = groupMemberCache?.get(uid); + private async getGroupMemberInfo (payload: PayloadType, isNocache: boolean) { + const groupId = payload.group_id.toString(); + // 全局 UIN -> UID 转换可能与目标群的成员记录不一致,优先按 QQ 号在本群查询。 + // getGroupMember 会在缓存未命中时刷新一次,避免冷缓存被误判为成员不存在。 + const groupMember = await this.core.apis.GroupApi.getGroupMember(groupId, payload.user_id); + const uid = groupMember?.uid || await this.getUid(payload.user_id); const [member, info] = await Promise.all([ - this.core.apis.GroupApi.getGroupMemberEx(payload.group_id.toString(), uid, isNocache), - this.core.apis.UserApi.getUserDetailInfo(uid, isNocache), + this.core.apis.GroupApi.getGroupMemberEx(groupId, uid, isNocache), + this.core.apis.UserApi.getUserDetailInfo(uid, isNocache).catch((error) => { + this.core.context.logger.logDebug(`获取群成员补充资料失败, 群号: ${groupId}, QQ号: ${payload.user_id}, 错误: ${error}`); + return undefined; + }), ]); - if (!member || !groupMember) throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在`); + const baseMember = member ?? groupMember; + if (!baseMember) throw new Error(`群(${payload.group_id})成员${payload.user_id}不存在`); - return info ? { ...groupMember, ...member, ...info } : member; + // 个人资料只补充信息,不能覆盖已确认的群成员身份。 + return { ...groupMember, ...baseMember, ...info, uid: baseMember.uid, uin: baseMember.uin }; } async _handle (payload: PayloadType) { const isNocache = this.parseBoolean(payload.no_cache ?? true); - const uid = await this.getUid(payload.user_id); - const member = await this.getGroupMemberInfo(payload, uid, isNocache); - - if (!member) { - this.core.context.logger.logDebug('获取群成员详细信息失败, 只能返回基础信息'); - } + const member = await this.getGroupMemberInfo(payload, isNocache); return OB11Construct.groupMember(payload.group_id.toString(), member); } diff --git a/packages/napcat-protobuf/NapProto.ts b/packages/napcat-protobuf/NapProto.ts index 09e47c3a..3233d662 100644 --- a/packages/napcat-protobuf/NapProto.ts +++ b/packages/napcat-protobuf/NapProto.ts @@ -1,5 +1,5 @@ // @ts-nocheck -import { MessageType, PartialMessage, RepeatType, ScalarType } from '@protobuf-ts/runtime'; +import { BinaryReader, MessageType, PartialMessage, RepeatType, ScalarType } from '@protobuf-ts/runtime'; import { PartialFieldInfo } from '@protobuf-ts/runtime/build/types/reflection-info'; export type LowerCamelCase = CamelCaseHelper; @@ -179,7 +179,11 @@ class NapProtoRealMsg { } decode (data: Uint8Array): NapProtoDecodeStructType { - return this._proto_msg.fromBinary(data) as NapProtoDecodeStructType; + return this._proto_msg.fromBinary(data, { + // QQ may send truncated UTF-8 in names. Replace invalid characters without + // dropping the whole packet; retain BinaryReader's bounds checks and BOM handling. + readerFactory: bytes => new BinaryReader(bytes, new TextDecoder('utf-8', { fatal: false, ignoreBOM: true })), + }) as NapProtoDecodeStructType; } }