From 00b355b8772516f039a6aba1419764285c6267fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E6=B1=A0?= Date: Fri, 23 Feb 2024 08:36:34 +0800 Subject: [PATCH] `Shamrock`: fix #248 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 白池 --- .../src/main/java/protobuf/msg/ImMsgBody.kt | 104 ++++++++++++++++++ .../src/main/java/protobuf/msg/SendMessage.kt | 66 +++++++++++ .../remote/action/handlers/SendMsgByResid.kt | 53 +++++++++ .../shamrock/remote/api/OtherAction.kt | 10 ++ 4 files changed, 233 insertions(+) create mode 100644 protobuf/src/main/java/protobuf/msg/ImMsgBody.kt create mode 100644 protobuf/src/main/java/protobuf/msg/SendMessage.kt create mode 100644 xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMsgByResid.kt diff --git a/protobuf/src/main/java/protobuf/msg/ImMsgBody.kt b/protobuf/src/main/java/protobuf/msg/ImMsgBody.kt new file mode 100644 index 00000000..d40c37f8 --- /dev/null +++ b/protobuf/src/main/java/protobuf/msg/ImMsgBody.kt @@ -0,0 +1,104 @@ +package protobuf.msg + +import com.google.protobuf.Internal.EMPTY_BYTE_ARRAY +import kotlinx.serialization.Serializable +import kotlinx.serialization.protobuf.ProtoNumber + +@Serializable +data class MsgBody( + @ProtoNumber(1) var richText: RichText, + //@ProtoNumber(2) var msgContent: ByteArray = EMPTY_BYTE_ARRAY, + //@/ProtoNumber(3) var msgEncryptContent: ByteArray = EMPTY_BYTE_ARRAY, +) + +@Serializable +data class RichText( + //@ProtoNumber(1) var attr: Attr? = null, + @ProtoNumber(2) var elems: ArrayList? = null, + //@ProtoNumber(3) var not_online_file: NotOnlineFile? = null, + //@ProtoNumber(4) var ptt: Ptt? = null, + //@ProtoNumber(5) var tmp_ptt: TmpPtt? = null, + //@ProtoNumber(6) var trans_211_tmp_msg: Trans211TmpMsg? = null, +) + +@Serializable +data class Elem( + /*@ProtoNumber(1) var text: TextMsg? = null, + @ProtoNumber(2) var face: FaceMsg? = null, + @ProtoNumber(3) var online_image: OnlineImage? = null, + @ProtoNumber(4) var not_online_image: NotOnlineImage? = null, + @ProtoNumber(5) var trans_elem_info: TransElem? = null, + @ProtoNumber(6) var market_face: MarketFace? = null, + @ProtoNumber(7) var elem_flags: ElemFlags? = null, + @ProtoNumber(8) var customFace: CustomFace? = null, + @ProtoNumber(9) var elem_flags2: ElemFlags2? = null, + @ProtoNumber(10) var fun_face: FunFace? = null, + @ProtoNumber(11) var secret_file: SecretFileMsg? = null, + @ProtoNumber(12) var rich_msg: RichMsg? = null, + @ProtoNumber(13) var group_file: GroupFile? = null, + @ProtoNumber(14) var pub_group: PubGroup? = null, + @ProtoNumber(15) var market_trans: MarketTrans? = null, + @ProtoNumber(16) var extra_info: ExtraInfo? = null, + @ProtoNumber(17) var shake_window: ShakeWindow? = null, + @ProtoNumber(18) var pub_account: PubAccount? = null, + @ProtoNumber(19) var video_file: VideoFile? = null, + @ProtoNumber(20) var tips_info: TipsInfo? = null, + @ProtoNumber(21) var anon_group_msg: AnonymousGroupMsg? = null, + @ProtoNumber(22) var qq_live_old: QQLiveOld? = null, + @ProtoNumber(23) var life_online: LifeOnlineAccount? = null, + @ProtoNumber(24) var qqwallet_msg: QQWalletMsg? = null, + @ProtoNumber(25) var crm_elem: CrmElem? = null, + @ProtoNumber(26) var conference_tips_info: ConferenceTipsInfo? = null, + @ProtoNumber(27) var redbag_info: RedBagInfo? = null, + @ProtoNumber(28) var low_version_tips: LowVersionTips? = null, + @ProtoNumber(29) var bankcode_ctrl_info: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(30) var near_by_msg: NearByMessageType? = null, + @ProtoNumber(31) var custom_elem: CustomElem? = null, + @ProtoNumber(32) var location_info: LocationInfo? = null, + @ProtoNumber(33) var pub_acc_info: PubAccInfo? = null, + @ProtoNumber(34) var small_emoji: SmallEmoji? = null, + @ProtoNumber(35) var fsj_msg_elem: FSJMessageElem? = null, + @ProtoNumber(36) var ark_app: ArkAppElem? = null, +*/ + @ProtoNumber(37) var generalFlags: GeneralFlags? = null, +/* + @ProtoNumber(38) var hc_flash_pic: CustomFace? = null, + @ProtoNumber(39) var deliver_gift_msg: DeliverGiftMsg? = null, + @ProtoNumber(40) var bitapp_msg: BitAppMsg? = null, + @ProtoNumber(41) var open_qq_data: OpenQQData? = null, + @ProtoNumber(42) var apollo_msg: ApolloActMsg? = null, + @ProtoNumber(43) var group_pub_acc_info: GroupPubAccountInfo? = null, + @ProtoNumber(44) var bless_msg: BlessingMessage? = null, + @ProtoNumber(45) var src_msg: SourceMsg? = null, + @ProtoNumber(46) var lola_msg: LolaMsg? = null, + @ProtoNumber(47) var group_business_msg: GroupBusinessMsg? = null, + @ProtoNumber(48) var msg_workflow_notify: WorkflowNotifyMsg? = null, + @ProtoNumber(49) var pat_elem: PatsElem? = null, + @ProtoNumber(50) var group_post_elem: GroupPostElem? = null, + @ProtoNumber(51) var light_app: LightAppElem? = null, + @ProtoNumber(52) var eim_info: EIMInfo? = null, + @ProtoNumber(53) var commonElem: CommonElem? = null,*/ +) + +@Serializable +data class GeneralFlags( + @ProtoNumber(1) var uint32_bubble_diy_text_id: UInt = 0u, + @ProtoNumber(2) var uint32_group_flag_new: UInt = 0u, + @ProtoNumber(3) var uint64_uin: ULong = 0u, + @ProtoNumber(4) var bytes_rp_id: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(5) var uint32_prp_fold: UInt = 0u, + @ProtoNumber(6) var long_text_flag: UInt = 0u, + @ProtoNumber(7) var long_text_resid: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(8) var uint32_group_type: UInt = 0u, + @ProtoNumber(9) var uint32_to_uin_flag: UInt = 0u, + @ProtoNumber(10) var uint32_glamour_level: UInt = 0u, + @ProtoNumber(11) var uint32_member_level: UInt = 0u, + @ProtoNumber(12) var uint64_group_rank_seq: ULong = 0u, + @ProtoNumber(13) var uint32_olympic_torch: UInt = 0u, + @ProtoNumber(14) var babyq_guide_msg_cookie: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(15) var uin32_expert_flag: UInt = 0u, + @ProtoNumber(16) var uint32_bubble_sub_id: UInt = 0u, + @ProtoNumber(17) var pendantId: ULong = 0u, + @ProtoNumber(18) var bytes_rp_index: ByteArray = EMPTY_BYTE_ARRAY, + @ProtoNumber(19) var reserve: ByteArray = EMPTY_BYTE_ARRAY, +) \ No newline at end of file diff --git a/protobuf/src/main/java/protobuf/msg/SendMessage.kt b/protobuf/src/main/java/protobuf/msg/SendMessage.kt new file mode 100644 index 00000000..64bde07a --- /dev/null +++ b/protobuf/src/main/java/protobuf/msg/SendMessage.kt @@ -0,0 +1,66 @@ +package protobuf.msg + +import kotlinx.serialization.Serializable +import kotlinx.serialization.protobuf.ProtoNumber + +@Serializable +class PbSendMsgReq( + @ProtoNumber(1) var routingHead: RoutingHead, + @ProtoNumber(2) var contentHead: ContentHead, + @ProtoNumber(3) var msgBody: MsgBody, + @ProtoNumber(4) var msgSeq: ULong = 0u, + @ProtoNumber(5) var msgRand: UInt = 0u, + //@ProtoNumber(6) var sync_cookie: ByteArray = EMPTY_BYTE_ARRAY, + //@ProtoNumber(7) var app_share: AppShareInfo? = null, + @ProtoNumber(8) var msgVia: UInt = 0u, + //@ProtoNumber(9) var data_statist: UInt = 0u, + //@ProtoNumber(10) var multi_msg_assist: MultiMsgAssist? = null, + //@ProtoNumber(11) var input_notify_info: PbInputNotifyInfo? = null, + //@ProtoNumber(12) var msgCtrl: MsgCtrl? = null, + //@ProtoNumber(13) var receipt_req: ReceiptReq? = null, + //@ProtoNumber(14) var multi_send_seq: UInt = 0u, +) + +@Serializable +data class ContentHead( + @ProtoNumber(1) var pkg_num: UInt = 0u, + @ProtoNumber(2) var pkg_index: UInt = 0u, + @ProtoNumber(3) var div_seq: UInt = 0u, + @ProtoNumber(4) var auto_reply: UInt = 0u, +) + +@Serializable +class RoutingHead( + @ProtoNumber(1) var c2c: C2C? = null, + @ProtoNumber(2) var grp: Grp? = null, + // @ProtoNumber(3) var grp_tmp: GrpTmp? = null, + //@ProtoNumber(4) var dis: Dis? = null, + // @ProtoNumber(5) var dis_tmp: DisTmp? = null, + // @ProtoNumber(6) var wpa_tmp: WPATmp? = null, + // @ProtoNumber(7) var secret_file: SecretFileHead? = null, + // @ProtoNumber(8) var public_plat: PublicPlat? = null, + /*@ProtoNumber(9) var trans_msg: TransMsg? = null, + @ProtoNumber(10) var address_list: AddressListTmp? = null, + @ProtoNumber(11) var rich_status_tmp: RichStatusTmp? = null, + @ProtoNumber(12) var trans_cmd: TransCmd? = null, + @ProtoNumber(13) var accost_tmp: AccostTmp? = null, + @ProtoNumber(14) var pub_group_tmp: PubGroupTmp? = null, + @ProtoNumber(15) var trans_0x211: Trans0x211? = null, + @ProtoNumber(16) var business_wpa_tmp: BusinessWPATmp? = null, + @ProtoNumber(17) var auth_tmp: AuthTmp? = null, + @ProtoNumber(18) var bsns_tmp: BsnsTmp? = null, + @ProtoNumber(19) var qq_querybusiness_tmp: QQQueryBusinessTmp? = null, + @ProtoNumber(20) var nearby_dating_tmp: NearByDatingTmp? = null, + @ProtoNumber(21) var nearby_assistant_tmp: NearByAssistantTmp? = null, + @ProtoNumber(22) var comm_tmp: CommTmp? = null,*/ +) + +@Serializable +class C2C( + @ProtoNumber(1) var to_uin: ULong = 0u, +) + +@Serializable +class Grp( + @ProtoNumber(1) var groupCode: ULong = 0u, +) \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMsgByResid.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMsgByResid.kt new file mode 100644 index 00000000..8343f7fa --- /dev/null +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMsgByResid.kt @@ -0,0 +1,53 @@ +package moe.fuqiuluo.shamrock.remote.action.handlers + +import kotlinx.atomicfu.atomic +import kotlinx.serialization.encodeToByteArray +import kotlinx.serialization.protobuf.ProtoBuf +import moe.fuqiuluo.qqinterface.servlet.BaseSvc +import moe.fuqiuluo.shamrock.remote.action.ActionSession +import moe.fuqiuluo.shamrock.remote.action.IActionHandler +import moe.fuqiuluo.symbols.OneBotHandler +import protobuf.msg.C2C +import protobuf.msg.ContentHead +import protobuf.msg.Elem +import protobuf.msg.GeneralFlags +import protobuf.msg.Grp +import protobuf.msg.MsgBody +import protobuf.msg.PbSendMsgReq +import protobuf.msg.RichText +import protobuf.msg.RoutingHead +import kotlin.random.Random +import kotlin.random.nextUInt + +@OneBotHandler("send_msg_by_resid") +internal object SendMsgByResid: IActionHandler() { + private val msgSeq = atomic(1000) + + override suspend fun internalHandle(session: ActionSession): String { + val resid = session.getString("resid") + val peerId = session.getString("peer") + val req = PbSendMsgReq( + routingHead = RoutingHead().apply { + when(session.getStringOrNull("message_type")) { + "group" -> grp = Grp(peerId.toULong()) + "private" -> c2c = C2C(peerId.toULong()) + else -> grp = Grp(peerId.toULong()) + } + }, + contentHead = ContentHead(1u, 0u, 0u, 0u), + msgBody = MsgBody( + richText = RichText(arrayListOf(Elem( + generalFlags = GeneralFlags( + long_text_flag = 1u, + long_text_resid = resid.toByteArray() + ) + ))) + ), + msgSeq = msgSeq.incrementAndGet().toULong(), + msgRand = Random.nextUInt(), + msgVia = 0u + ) + BaseSvc.sendBufferAW("MessageSvc.PbSendMsg", true, ProtoBuf.encodeToByteArray(req)) + return ok("ok", session.echo) + } +} \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt index d551a8ff..36258efa 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/OtherAction.kt @@ -18,6 +18,7 @@ import moe.fuqiuluo.shamrock.remote.action.handlers.DownloadFile import moe.fuqiuluo.shamrock.remote.action.handlers.GetDeviceBattery import moe.fuqiuluo.shamrock.remote.action.handlers.GetVersionInfo import moe.fuqiuluo.shamrock.remote.action.handlers.RestartMe +import moe.fuqiuluo.shamrock.remote.action.handlers.UploadFileToShamrock import moe.fuqiuluo.shamrock.remote.structures.Status import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig import moe.fuqiuluo.shamrock.tools.asString @@ -25,6 +26,7 @@ import moe.fuqiuluo.shamrock.tools.fetchOrNull import moe.fuqiuluo.shamrock.tools.fetchOrThrow import moe.fuqiuluo.shamrock.tools.fetchPostJsonArray import moe.fuqiuluo.shamrock.tools.getOrPost +import moe.fuqiuluo.shamrock.tools.hex2ByteArray import moe.fuqiuluo.shamrock.tools.isJsonArray import moe.fuqiuluo.shamrock.tools.json import moe.fuqiuluo.shamrock.tools.respond @@ -113,6 +115,14 @@ fun Routing.otherAction() { respond(false, Status.BadRequest, "没有上传文件信息") } + getOrPost("/upload_file_to_shamrock") { + val md5 = fetchOrThrow("md5").hex2ByteArray() + val offset = fetchOrNull("offset")?.toULong() ?: 0uL + val chunk = fetchOrThrow("chunk").toByteArray() + val fileSize = fetchOrNull("file_size")?.toULong() ?: chunk.size.toULong() + call.respondText(UploadFileToShamrock(md5, fileSize, offset, chunk), ContentType.Application.Json) + } + getOrPost("/config/set_boolean") { val key = fetchOrThrow("key") val value = fetchOrThrow("value").toBooleanStrict()