diff --git a/client/operation.go b/client/operation.go index 24afe11..263d7d6 100644 --- a/client/operation.go +++ b/client/operation.go @@ -14,10 +14,9 @@ import ( "strconv" "strings" - "github.com/LagrangeDev/LagrangeGo/utils" "github.com/pkg/errors" - "github.com/tidwall/gjson" + "golang.org/x/net/html" "github.com/LagrangeDev/LagrangeGo/client/entity" @@ -29,6 +28,7 @@ import ( "github.com/LagrangeDev/LagrangeGo/client/packets/pb/service/oidb" "github.com/LagrangeDev/LagrangeGo/internal/proto" message2 "github.com/LagrangeDev/LagrangeGo/message" + "github.com/LagrangeDev/LagrangeGo/utils" "github.com/LagrangeDev/LagrangeGo/utils/binary" "github.com/LagrangeDev/LagrangeGo/utils/crypto" ) @@ -1319,7 +1319,7 @@ func (c *QQClient) GetUnidirectionalFriendList() (ret []*entity.Friend, err erro // DeleteUnidirectionalFriend 删除单向好友 // ref https://github.com/Mrs4s/MiraiGo/blob/54bdd873e3fed9fe1c944918924674dacec5ac76/client/web.go#L62 -func (c *QQClient) DeleteUnidirectionalFriend(uin int64) error { +func (c *QQClient) DeleteUnidirectionalFriend(uin uint32) error { webRsp := &struct { ErrorCode int32 `json:"ErrorCode"` }{} @@ -1335,3 +1335,17 @@ func (c *QQClient) DeleteUnidirectionalFriend(uin int64) error { } return nil } + +// CheckURLSafely 通过TX服务器检查URL安全性 +// ref https://github.com/Mrs4s/MiraiGo/blob/54bdd873e3fed9fe1c944918924674dacec5ac76/client/security.go#L24 +func (c *QQClient) CheckURLSafely(url string) (oidb2.URLSecurityLevel, error) { + pkt, err := oidb2.BuildURLCheckRequest(c.Uin, url) + if err != nil { + return oidb2.URLSecurityLevelUnknown, err + } + resp, err := c.sendOidbPacketAndWait(pkt) + if err != nil { + return oidb2.URLSecurityLevelUnknown, err + } + return oidb2.ParseURLCheckResponse(resp) +} diff --git a/client/packets/oidb/security_url.go b/client/packets/oidb/security_url.go new file mode 100644 index 0000000..88d8dd3 --- /dev/null +++ b/client/packets/oidb/security_url.go @@ -0,0 +1,67 @@ +package oidb + +import ( + "errors" + + "github.com/LagrangeDev/LagrangeGo/client/packets/pb/service/oidb" +) + +// see https://github.com/Mrs4s/MiraiGo/blob/master/client/security.go + +type URLSecurityLevel int + +const ( + URLSecurityLevelSafe URLSecurityLevel = iota + 1 + URLSecurityLevelUnknown + URLSecurityLevelDanger +) + +func (m URLSecurityLevel) String() string { + switch m { + case URLSecurityLevelSafe: + return "safe" + case URLSecurityLevelDanger: + return "danger" + case URLSecurityLevelUnknown: + return "unknown" + default: + return "unknown" + } +} + +func BuildURLCheckRequest(botuin uint32, url string) (*Packet, error) { + body := &oidb.OidbSvcTrpcTcp0XBCB_0_ReqBody{ + CheckUrlReq: &oidb.CheckUrlReq{ + Url: []string{url}, + QqPfTo: "mqq.group", + Type: 2, + SendUin: uint64(botuin), + ReqType: "webview", + OriginalUrl: url, + IsArk: false, + IsFinish: false, + SrcUrls: []string{url}, + SrcPlatform: 1, + Qua: "AQQ_2013 4.6/2013 8.4.184945&NA_0/000000&ADR&null18&linux&2017&C2293D02BEE31158&7.1.2&V3", + }, + } + return BuildOidbPacket(0xBCB, 0, body, false, false) +} + +func ParseURLCheckResponse(data []byte) (URLSecurityLevel, error) { + var rsp oidb.OidbSvcTrpcTcp0XBCB_0_RspBody + _, err := ParseOidbPacket(data, &rsp) + if err != nil { + return URLSecurityLevelUnknown, err + } + if rsp.CheckUrlRsp == nil || len(rsp.CheckUrlRsp.Results) == 0 { + return URLSecurityLevelUnknown, errors.New("response is empty") + } + if rsp.CheckUrlRsp.Results[0].JumpUrl != "" { + return URLSecurityLevelDanger, nil + } + if rsp.CheckUrlRsp.Results[0].Umrtype == 2 { + return URLSecurityLevelSafe, nil + } + return URLSecurityLevelUnknown, nil +} diff --git a/client/packets/pb/service/oidb/OidbSvcTrpcTcp0xBCB_0.pb.go b/client/packets/pb/service/oidb/OidbSvcTrpcTcp0xBCB_0.pb.go new file mode 100644 index 0000000..409dec1 --- /dev/null +++ b/client/packets/pb/service/oidb/OidbSvcTrpcTcp0xBCB_0.pb.go @@ -0,0 +1,54 @@ +// Code generated by protoc-gen-golite. DO NOT EDIT. +// source: pb/service/oidb/OidbSvcTrpcTcp0xBCB_0.proto + +package oidb + +type OidbSvcTrpcTcp0XBCB_0_ReqBody struct { + NotUseCache int32 `protobuf:"varint,9,opt"` + CheckUrlReq *CheckUrlReq `protobuf:"bytes,10,opt"` + _ [0]func() +} + +type CheckUrlReq struct { + Url []string `protobuf:"bytes,1,rep"` + Refer string `protobuf:"bytes,2,opt"` + Plateform string `protobuf:"bytes,3,opt"` + QqPfTo string `protobuf:"bytes,4,opt"` + Type uint32 `protobuf:"varint,5,opt"` + From uint32 `protobuf:"varint,6,opt"` + Chatid uint64 `protobuf:"varint,7,opt"` + ServiceType uint64 `protobuf:"varint,8,opt"` + SendUin uint64 `protobuf:"varint,9,opt"` + ReqType string `protobuf:"bytes,10,opt"` + OriginalUrl string `protobuf:"bytes,11,opt"` + IsArk bool `protobuf:"varint,12,opt"` + ArkName string `protobuf:"bytes,13,opt"` + IsFinish bool `protobuf:"varint,14,opt"` + SrcUrls []string `protobuf:"bytes,15,rep"` + SrcPlatform uint32 `protobuf:"varint,16,opt"` + Qua string `protobuf:"bytes,17,opt"` +} + +type OidbSvcTrpcTcp0XBCB_0_RspBody struct { + Wording string `protobuf:"bytes,1,opt"` + CheckUrlRsp *CheckUrlRsp `protobuf:"bytes,10,opt"` + _ [0]func() +} + +type CheckUrlRsp struct { + Results []*UrlCheckResult `protobuf:"bytes,1,rep"` + NextReqDuration uint32 `protobuf:"varint,2,opt"` +} + +type UrlCheckResult struct { + Url string `protobuf:"bytes,1,opt"` + Result uint32 `protobuf:"varint,2,opt"` + JumpResult uint32 `protobuf:"varint,3,opt"` + JumpUrl string `protobuf:"bytes,4,opt"` + Level uint32 `protobuf:"varint,5,opt"` + SubLevel uint32 `protobuf:"varint,6,opt"` + Umrtype uint32 `protobuf:"varint,7,opt"` + RetFrom uint32 `protobuf:"varint,8,opt"` + OperationBit uint64 `protobuf:"varint,9,opt"` + _ [0]func() +} diff --git a/client/packets/pb/service/oidb/OidbSvcTrpcTcp0xBCB_0.proto b/client/packets/pb/service/oidb/OidbSvcTrpcTcp0xBCB_0.proto new file mode 100644 index 0000000..0a8f691 --- /dev/null +++ b/client/packets/pb/service/oidb/OidbSvcTrpcTcp0xBCB_0.proto @@ -0,0 +1,67 @@ +syntax = "proto3"; + +// ref https://github.com/Mrs4s/MiraiGo/blob/master/client/pb/oidb/oidb0xbcb.proto + +option go_package = "github.com/LagrangeDev/LagrangeGo/client/packets/pb/service/oidb"; + +message OidbSvcTrpcTcp0xBCB_0_ReqBody { + int32 notUseCache = 9; + CheckUrlReq checkUrlReq = 10; +} + +message CheckUrlReq { + repeated string url = 1; + string refer = 2; + string plateform = 3; + string qqPfTo = 4; + uint32 type = 5; + uint32 from = 6; + uint64 chatid = 7; + uint64 serviceType = 8; + uint64 sendUin = 9; + string reqType = 10; + string originalUrl = 11; + bool isArk = 12; + string arkName = 13; + bool isFinish = 14; + repeated string srcUrls = 15; + uint32 srcPlatform = 16; + string qua = 17; +} + +message OidbSvcTrpcTcp0xBCB_0_RspBody { + string wording = 1; + CheckUrlRsp checkUrlRsp = 10; +} + +message CheckUrlRsp { + repeated UrlCheckResult results = 1; + uint32 nextReqDuration = 2; +} + +message UrlCheckResult { + string url = 1; + uint32 result = 2; + uint32 jumpResult = 3; + string jumpUrl = 4; + uint32 level = 5; + uint32 subLevel = 6; + uint32 umrtype = 7; + uint32 retFrom = 8; + uint64 operationBit = 9; +} + +/* +message CheckUrlReqItem { + string url = 1; + string refer = 2; + string plateform = 3; + string qqPfTo = 4; + uint32 type = 5; + uint32 from = 6; + uint64 chatid = 7; + uint64 serviceType = 8; + uint64 sendUin = 9; + string reqType = 10; +} +*/