From c2d028af2ed35005a195b5a655ecfa6bc34ec2f3 Mon Sep 17 00:00:00 2001 From: DrSmoothl <1787882683@qq.com> Date: Thu, 16 Jul 2026 20:17:38 +0800 Subject: [PATCH] fix(protocol): preserve member operation high bits Clear only the membership flag bit when normalizing group increase operation codes so unrelated high bits cannot collapse into the invitation value. Add regression coverage for extended operation codes. --- packages/core/tests/msg-push-handler.test.ts | 11 +++++++++++ .../src/msg-push/decoders/group-member-change.ts | 11 ++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/core/tests/msg-push-handler.test.ts b/packages/core/tests/msg-push-handler.test.ts index 3e7d9ab5..33606ecc 100644 --- a/packages/core/tests/msg-push-handler.test.ts +++ b/packages/core/tests/msg-push-handler.test.ts @@ -181,9 +181,20 @@ describe('parseMsgPush group member increase', () => { ), identity, ) as GroupMemberJoin[]; + const [unknownHighBits] = parseMsgPush( + makeGroupIncreasePacket( + member.uid, + operator.uid, + GROUP_ID, + Buffer.from(operator.uid, 'utf8'), + 0x103, + ), + identity, + ) as GroupMemberJoin[]; expect(approved.joinType).toBe('approve'); expect(invited.joinType).toBe('invite'); + expect(unknownHighBits.joinType).toBe('approve'); }); it('reports malformed raw operator bytes with bounded context', () => { diff --git a/packages/protocol/src/msg-push/decoders/group-member-change.ts b/packages/protocol/src/msg-push/decoders/group-member-change.ts index c94a5b1d..263de7ae 100644 --- a/packages/protocol/src/msg-push/decoders/group-member-change.ts +++ b/packages/protocol/src/msg-push/decoders/group-member-change.ts @@ -5,11 +5,12 @@ import { decodeNestedOperatorUid, decodeRawOperatorUid, resolveUidToUin } from ' import type { MsgPushDecoder } from '../registry'; function joinTypeFromOperationType(raw: number): NonNullable { - // QQ sets the high bit on the PkgType=33 operation code. After normalizing - // it, code 3 means an invitation; code 2 (and unknown/absent values) means - // approval. Do not use the nested `join_type`: that is an invitation-source - // enum rather than OneBot's approve/invite distinction. - return (raw & 0x7f) === 3 ? 'invite' : 'approve'; + // QQ uses bit 0x80 as a flag on the PkgType=33 operation code. Clear only + // that bit: other high bits remain significant in the native handler. The + // normalized code 3 means an invitation; all other values mean approval. + // Do not use the nested `join_type`: that is an invitation-source enum. + const normalized = raw - (raw & 0x80); + return normalized === 3 ? 'invite' : 'approve'; } export const decodeGroupMemberJoin: MsgPushDecoder = (ctx) => {