diff --git a/Lagrange.Core/Common/Interface/Api/OperationExt.cs b/Lagrange.Core/Common/Interface/Api/OperationExt.cs index 39900b1..9bc1a77 100644 --- a/Lagrange.Core/Common/Interface/Api/OperationExt.cs +++ b/Lagrange.Core/Common/Interface/Api/OperationExt.cs @@ -28,4 +28,7 @@ public static class OperationExt public static Task RecallGroupMessage(this BotContext bot, MessageChain chain) => bot.ContextCollection.Business.OperationLogic.RecallGroupMessage(chain); + + public static Task RequestFriend(this BotContext bot, uint targetUin, string message = "", string question = "") + => bot.ContextCollection.Business.OperationLogic.RequestFriend(targetUin, message, question); } diff --git a/Lagrange.Core/Core/Context/Logic/Implementation/OperationLogic.cs b/Lagrange.Core/Core/Context/Logic/Implementation/OperationLogic.cs index c85aa4b..1fc0760 100644 --- a/Lagrange.Core/Core/Context/Logic/Implementation/OperationLogic.cs +++ b/Lagrange.Core/Core/Context/Logic/Implementation/OperationLogic.cs @@ -112,6 +112,22 @@ internal class OperationLogic : LogicBase return events.Count != 0 && ((RecallGroupMessageEvent)events[0]).ResultCode == 0; } + public async Task RequestFriend(uint targetUin, string message, string question) + { + var requestFriendSearchEvent = RequestFriendSearchEvent.Create(targetUin); + var searchEvents = await Collection.Business.SendEvent(requestFriendSearchEvent); + if (searchEvents.Count == 0) return false; + await Task.Delay(5000); + + var requestFriendSettingEvent = RequestFriendSettingEvent.Create(targetUin); + var settingEvents = await Collection.Business.SendEvent(requestFriendSettingEvent); + if (settingEvents.Count == 0) return false; + + var requestFriendEvent = RequestFriendEvent.Create(targetUin, message, question); + var events = await Collection.Business.SendEvent(requestFriendEvent); + return events.Count != 0 && ((RequestFriendEvent)events[0]).ResultCode == 0; + } + private static int CalculateBkn(string sKey) => (int)sKey.Aggregate(5381, (current, t) => current + (current << 5) + t) & int.MaxValue; diff --git a/Lagrange.Core/Core/Event/Protocol/Action/RequestFriendEvent.cs b/Lagrange.Core/Core/Event/Protocol/Action/RequestFriendEvent.cs new file mode 100644 index 0000000..2b771fe --- /dev/null +++ b/Lagrange.Core/Core/Event/Protocol/Action/RequestFriendEvent.cs @@ -0,0 +1,25 @@ +namespace Lagrange.Core.Core.Event.Protocol.Action; + +internal class RequestFriendEvent : ProtocolEvent +{ + public uint TargetUin { get; set; } + + public string Question { get; set; } = ""; + + public string Message { get; set; } = ""; + + protected RequestFriendEvent(uint targetUin, string question, string message) : base(true) + { + TargetUin = targetUin; + Question = question; + Message = message; + } + + protected RequestFriendEvent(int resultCode) : base(resultCode) + { + } + + public static RequestFriendEvent Create(uint targetUin, string question, string message) => new(targetUin, question, message); + + public static RequestFriendEvent Result(int resultCode) => new(resultCode); +} \ No newline at end of file diff --git a/Lagrange.Core/Core/Event/Protocol/Action/RequestFriendSearchEvent.cs b/Lagrange.Core/Core/Event/Protocol/Action/RequestFriendSearchEvent.cs new file mode 100644 index 0000000..80d07c0 --- /dev/null +++ b/Lagrange.Core/Core/Event/Protocol/Action/RequestFriendSearchEvent.cs @@ -0,0 +1,19 @@ +namespace Lagrange.Core.Core.Event.Protocol.Action; + +internal class RequestFriendSearchEvent : ProtocolEvent +{ + public uint TargetUin { get; } + + private RequestFriendSearchEvent(uint targetUin) : base(true) + { + TargetUin = targetUin; + } + + private RequestFriendSearchEvent(int resultCode) : base(resultCode) + { + } + + public static RequestFriendSearchEvent Create(uint targetUin) => new(targetUin); + + public static RequestFriendSearchEvent Result(int resultCode) => new(resultCode); +} \ No newline at end of file diff --git a/Lagrange.Core/Core/Event/Protocol/Action/RequestFriendSettingEvent.cs b/Lagrange.Core/Core/Event/Protocol/Action/RequestFriendSettingEvent.cs new file mode 100644 index 0000000..6dbe242 --- /dev/null +++ b/Lagrange.Core/Core/Event/Protocol/Action/RequestFriendSettingEvent.cs @@ -0,0 +1,17 @@ +namespace Lagrange.Core.Core.Event.Protocol.Action; + +internal class RequestFriendSettingEvent : ProtocolEvent +{ + public uint TargetUin { get; set; } + + private RequestFriendSettingEvent(uint targetUin) : base(true) + { + TargetUin = targetUin; + } + + private RequestFriendSettingEvent(int resultCode) : base(resultCode) { } + + public static RequestFriendSettingEvent Create(uint targetUin) => new(targetUin); + + public static RequestFriendSettingEvent Result(int resultCode) => new(resultCode); +} \ No newline at end of file diff --git a/Lagrange.Core/Core/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x7C1_1.cs b/Lagrange.Core/Core/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x7C1_1.cs new file mode 100644 index 0000000..5e97cee --- /dev/null +++ b/Lagrange.Core/Core/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x7C1_1.cs @@ -0,0 +1,20 @@ +using ProtoBuf; + +namespace Lagrange.Core.Core.Packets.Service.Oidb.Request; + +// ReSharper disable InconsistentNaming + +[ProtoContract] +[OidbSvcTrpcTcp(0x7c1, 1)] +public class OidbSvcTrpcTcp0x7C1_1 +{ + [ProtoMember(1)] public uint Field1 { get; set; } // 1 + + [ProtoMember(2)] public uint SelfUin { get; set; } + + [ProtoMember(3)] public uint TargetUin { get; set; } + + [ProtoMember(4)] public uint Field4 { get; set; } // 3999 + + [ProtoMember(5)] public uint Field5 { get; set; } // 0 +} \ No newline at end of file diff --git a/Lagrange.Core/Core/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x7C2_5.cs b/Lagrange.Core/Core/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x7C2_5.cs new file mode 100644 index 0000000..d57de21 --- /dev/null +++ b/Lagrange.Core/Core/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x7C2_5.cs @@ -0,0 +1,36 @@ +using ProtoBuf; + +namespace Lagrange.Core.Core.Packets.Service.Oidb.Request; + +// ReSharper disable InconsistentNaming + +[ProtoContract] +[OidbSvcTrpcTcp(0x7c2, 5)] +internal class OidbSvcTrpcTcp0x7C2_5 +{ + [ProtoMember(1)] public uint SelfUin { get; set; } + + [ProtoMember(2)] public uint TargetUin { get; set; } + + [ProtoMember(3)] public uint Field3 { get; set; } // 1 + + [ProtoMember(4)] public uint Field4 { get; set; } // 1 + + [ProtoMember(5)] public uint Field5 { get; set; } // 0 + + [ProtoMember(7)] public string Remark { get; set; } = ""; + + [ProtoMember(11)] public uint SourceId { get; set; } // 1 + + [ProtoMember(12)] public uint SubSourceId { get; set; } // 3 + + [ProtoMember(18)] public string Verify { get; set; } = ""; + + [ProtoMember(20)] public uint CategoryId { get; set; } + + [ProtoMember(26)] public string Answer { get; set; } = ""; + + [ProtoMember(28)] public uint Field28 { get; set; } // 1 + + [ProtoMember(29)] public uint Field29 { get; set; } // 1 +} \ No newline at end of file diff --git a/Lagrange.Core/Core/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x972_6.cs b/Lagrange.Core/Core/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x972_6.cs new file mode 100644 index 0000000..f3ff167 --- /dev/null +++ b/Lagrange.Core/Core/Packets/Service/Oidb/Request/OidbSvcTrpcTcp0x972_6.cs @@ -0,0 +1,25 @@ +using ProtoBuf; + +namespace Lagrange.Core.Core.Packets.Service.Oidb.Request; + +// ReSharper disable InconsistentNaming +#pragma warning disable CS8618 + +[ProtoContract] +[OidbSvcTrpcTcp(0x972, 6)] +internal class OidbSvcTrpcTcp0x972_6 +{ + [ProtoMember(1)] public uint TargetUin { get; set; } + + [ProtoMember(3)] public OidbSvcTrpcTcp0x972_6Settings Settings { get; set; } +} + +[ProtoContract] +internal class OidbSvcTrpcTcp0x972_6Settings +{ + [ProtoMember(4)] public uint Field4 { get; set; } // 25 + + [ProtoMember(11)] public string Field11 { get; set; } // "" + + [ProtoMember(55)] public string Setting { get; set; } // {"search_by_uid":true, "scenario":"related_people_and_groups_panel"} +} \ No newline at end of file diff --git a/Lagrange.Core/Core/Service/Action/RequestFriendSearchService.cs b/Lagrange.Core/Core/Service/Action/RequestFriendSearchService.cs new file mode 100644 index 0000000..97d55c1 --- /dev/null +++ b/Lagrange.Core/Core/Service/Action/RequestFriendSearchService.cs @@ -0,0 +1,51 @@ +using Lagrange.Core.Common; +using Lagrange.Core.Core.Event.Protocol; +using Lagrange.Core.Core.Event.Protocol.Action; +using Lagrange.Core.Core.Packets; +using Lagrange.Core.Core.Packets.Service.Oidb; +using Lagrange.Core.Core.Packets.Service.Oidb.Request; +using Lagrange.Core.Core.Service.Abstraction; +using Lagrange.Core.Utility.Binary; +using Lagrange.Core.Utility.Extension; +using ProtoBuf; + +namespace Lagrange.Core.Core.Service.Action; + +[EventSubscribe(typeof(RequestFriendSearchEvent))] +[Service("OidbSvcTrpcTcp.0x972_6")] +internal class RequestFriendSearchService : BaseService +{ + protected override bool Build(RequestFriendSearchEvent input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, + out BinaryPacket output, out List? extraPackets) + { + var packet = new OidbSvcTrpcTcpBase(new OidbSvcTrpcTcp0x972_6 + { + TargetUin = input.TargetUin, + Settings = new OidbSvcTrpcTcp0x972_6Settings + { + Field4 = 25, + Field11 = "", + Setting = "{\"search_by_uid\":true, \"scenario\":\"related_people_and_groups_panel\"}" + } + }); + + using var stream = new MemoryStream(); + Serializer.Serialize(stream, packet); + output = new BinaryPacket(stream); + + extraPackets = null; + return true; + } + + protected override bool Parse(SsoPacket input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, + out RequestFriendSearchEvent output, out List? extraEvents) + { + var payload = input.Payload.ReadBytes(BinaryPacket.Prefix.Uint32 | BinaryPacket.Prefix.WithPrefix); + + Console.WriteLine(payload.Hex()); + + output = RequestFriendSearchEvent.Result(0); + extraEvents = null; + return true; + } +} \ No newline at end of file diff --git a/Lagrange.Core/Core/Service/Action/RequestFriendService.cs b/Lagrange.Core/Core/Service/Action/RequestFriendService.cs new file mode 100644 index 0000000..e731505 --- /dev/null +++ b/Lagrange.Core/Core/Service/Action/RequestFriendService.cs @@ -0,0 +1,67 @@ +using Lagrange.Core.Common; +using Lagrange.Core.Core.Event.Protocol; +using Lagrange.Core.Core.Event.Protocol.Action; +using Lagrange.Core.Core.Packets; +using Lagrange.Core.Core.Packets.Service.Oidb; +using Lagrange.Core.Core.Packets.Service.Oidb.Request; +using Lagrange.Core.Core.Service.Abstraction; +using Lagrange.Core.Utility.Binary; +using Lagrange.Core.Utility.Extension; +using ProtoBuf.Meta; + +namespace Lagrange.Core.Core.Service.Action; + +[EventSubscribe(typeof(RequestFriendEvent))] +[Service("OidbSvcTrpcTcp.0x7c2_5")] +internal class RequestFriendService : BaseService +{ + private static readonly RuntimeTypeModel Serializer; + + static RequestFriendService() + { + Serializer = RuntimeTypeModel.Create(); + Serializer.UseImplicitZeroDefaults = false; + } + + protected override bool Build(RequestFriendEvent input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, + out BinaryPacket output, out List? extraPackets) + { + var packet = new OidbSvcTrpcTcpBase(new OidbSvcTrpcTcp0x7C2_5 + { + SelfUin = keystore.Uin, + TargetUin = input.TargetUin, + Field3 = 1, + Field4 = 1, + Field5 = 0, + Remark = "", + SourceId = 1, + SubSourceId = 3, + Verify = input.Message, + CategoryId = 0, + Answer = input.Question, + Field28 = 1, + Field29 = 1 + }); + + var stream = new MemoryStream(); + Serializer.Serialize(stream, packet); + output = new BinaryPacket(stream); + + Console.WriteLine(output.ToArray().Hex()); + + extraPackets = null; + return true; + } + + protected override bool Parse(SsoPacket input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, + out RequestFriendEvent output, out List? extraEvents) + { + var payload = input.Payload.ReadBytes(BinaryPacket.Prefix.Uint32 | BinaryPacket.Prefix.WithPrefix); + + Console.WriteLine(payload.Hex()); + + output = RequestFriendEvent.Result(0); + extraEvents = null; + return true; + } +} \ No newline at end of file diff --git a/Lagrange.Core/Core/Service/Action/RequestFriendSettingService.cs b/Lagrange.Core/Core/Service/Action/RequestFriendSettingService.cs new file mode 100644 index 0000000..1ac32fd --- /dev/null +++ b/Lagrange.Core/Core/Service/Action/RequestFriendSettingService.cs @@ -0,0 +1,49 @@ +using Lagrange.Core.Common; +using Lagrange.Core.Core.Event.Protocol; +using Lagrange.Core.Core.Event.Protocol.Action; +using Lagrange.Core.Core.Packets; +using Lagrange.Core.Core.Packets.Service.Oidb; +using Lagrange.Core.Core.Packets.Service.Oidb.Request; +using Lagrange.Core.Core.Service.Abstraction; +using Lagrange.Core.Utility.Binary; +using Lagrange.Core.Utility.Extension; +using ProtoBuf; + +namespace Lagrange.Core.Core.Service.Action; + +[EventSubscribe(typeof(RequestFriendSettingEvent))] +[Service("OidbSvcTrpcTcp.0x7c1_1")] +internal class RequestFriendSettingService : BaseService +{ + protected override bool Build(RequestFriendSettingEvent input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, + out BinaryPacket output, out List? extraPackets) + { + var packet = new OidbSvcTrpcTcpBase(new OidbSvcTrpcTcp0x7C1_1 + { + Field1 = 1, + SelfUin = keystore.Uin, + TargetUin = input.TargetUin, + Field4 = 3999, + Field5 = 0 + }); + + using var stream = new MemoryStream(); + Serializer.Serialize(stream, packet); + output = new BinaryPacket(stream.ToArray()); + + extraPackets = null; + return true; + } + + protected override bool Parse(SsoPacket input, BotKeystore keystore, BotAppInfo appInfo, BotDeviceInfo device, + out RequestFriendSettingEvent output, out List? extraEvents) + { + var payload = input.Payload.ReadBytes(BinaryPacket.Prefix.Uint32 | BinaryPacket.Prefix.WithPrefix); + + Console.WriteLine(payload.Hex()); + + output = RequestFriendSettingEvent.Result(0); + extraEvents = null; + return true; + } +} \ No newline at end of file diff --git a/Lagrange.Core/Utility/Signature.cs b/Lagrange.Core/Utility/Signature.cs index f52f5dd..858bf48 100644 --- a/Lagrange.Core/Utility/Signature.cs +++ b/Lagrange.Core/Utility/Signature.cs @@ -29,6 +29,7 @@ internal static class Signature "trpc.login.ecdh.EcdhService.SsoNTLoginPasswordLoginUnusualDevice", "OidbSvcTrpcTcp.0x11ec_1", "OidbSvcTrpcTcp.0x758_1", // create group + "OidbSvcTrpcTcp.0x7c1_1", "OidbSvcTrpcTcp.0x7c2_5", // request friend "OidbSvcTrpcTcp.0x10db_1", "OidbSvcTrpcTcp.0x8a1_7", // request group