diff --git a/Lagrange.Core.NativeAPI.Test/NativeModel/ReverseEventCountStruct.cs b/Lagrange.Core.NativeAPI.Test/NativeModel/ReverseEventCountStruct.cs index 2a3fff2d..54db8daa 100644 --- a/Lagrange.Core.NativeAPI.Test/NativeModel/ReverseEventCountStruct.cs +++ b/Lagrange.Core.NativeAPI.Test/NativeModel/ReverseEventCountStruct.cs @@ -19,6 +19,7 @@ public ReverseEventCountStruct() { } public int BotLogEventCount = 0; public int BotMessageEventCount = 0; public int BotNewDeviceVerifyEventCount = 0; + public int BotOfflineEventCount = 0; public int BotOnlineEventCount = 0; public int BotQrCodeEventCount = 0; public int BotQrCodeQueryEventCount = 0; diff --git a/Lagrange.Core.NativeAPI/LoginEntryPoint.cs b/Lagrange.Core.NativeAPI/LoginEntryPoint.cs new file mode 100644 index 00000000..7b87c879 --- /dev/null +++ b/Lagrange.Core.NativeAPI/LoginEntryPoint.cs @@ -0,0 +1,39 @@ +using System.Runtime.InteropServices; +using System.Text; +using Lagrange.Core.Common.Interface; +using Lagrange.Core.NativeAPI.NativeModel.Common; + +namespace Lagrange.Core.NativeAPI +{ + public static class LoginEntryPoint + { + [UnmanagedCallersOnly(EntryPoint = "SubmitCaptcha")] + public static bool SubmitCaptcha(int index, ByteArrayNative ticket, ByteArrayNative randStr) + { + if (Program.Contexts.Count <= index) + { + return false; + } + + var ticketData = ticket.ToByteArrayWithoutFree(); + var randStrData = randStr.ToByteArrayWithoutFree(); + + BotContext context = Program.Contexts[index].BotContext; + return context.SubmitCaptcha(Encoding.UTF8.GetString(ticketData), Encoding.UTF8.GetString(randStrData)); + } + + [UnmanagedCallersOnly(EntryPoint = "SubmitSMSCode")] + public static bool SubmitSMSCode(int index, ByteArrayNative code) + { + if (Program.Contexts.Count <= index) + { + return false; + } + + var codeData = code.ToByteArrayWithoutFree(); + + BotContext context = Program.Contexts[index].BotContext; + return context.SubmitSMSCode(Encoding.UTF8.GetString(codeData)); + } + }; +}; \ No newline at end of file diff --git a/Lagrange.Core.NativeAPI/NativeModel/Common/BotKeystoreStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/BotKeystoreStruct.cs index 645bc352..404be6c6 100644 --- a/Lagrange.Core.NativeAPI/NativeModel/Common/BotKeystoreStruct.cs +++ b/Lagrange.Core.NativeAPI/NativeModel/Common/BotKeystoreStruct.cs @@ -5,7 +5,8 @@ namespace Lagrange.Core.NativeAPI.NativeModel.Common { public struct BotKeystoreStruct { - public BotKeystoreStruct() { } + public BotKeystoreStruct() + { } public long Uin = 0; @@ -105,7 +106,8 @@ public static implicit operator BotKeystoreStruct(BotKeystore keystore) { bytePsKey[i++] = new ByteArrayKVPNative { - Key = Encoding.UTF8.GetBytes(kvp.Key), Value = Encoding.UTF8.GetBytes(kvp.Value) + Key = Encoding.UTF8.GetBytes(kvp.Key), + Value = Encoding.UTF8.GetBytes(kvp.Value) }; } @@ -143,7 +145,8 @@ public BotKeystore ToKeystoreWithoutFree() var psKey = new Dictionary(); foreach (var kvp in (ByteArrayKVPNative[])PsKey) { - psKey[Encoding.UTF8.GetString(kvp.Key)] = Encoding.UTF8.GetString(kvp.Value); + // psKey[Encoding.UTF8.GetString(kvp.Key)] = Encoding.UTF8.GetString(kvp.Value); Oh shit, are u okay? + psKey[Encoding.UTF8.GetString(kvp.Key.ToByteArrayWithoutFree())] = Encoding.UTF8.GetString(kvp.Value.ToByteArrayWithoutFree()); } return new BotKeystore() @@ -178,4 +181,4 @@ public BotKeystore ToKeystoreWithoutFree() }; } } -} +} \ No newline at end of file diff --git a/Lagrange.Core.NativeAPI/NativeModel/Common/BotSignProvider.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/BotSignProvider.cs index 820ec297..ee6876bb 100644 --- a/Lagrange.Core.NativeAPI/NativeModel/Common/BotSignProvider.cs +++ b/Lagrange.Core.NativeAPI/NativeModel/Common/BotSignProvider.cs @@ -272,7 +272,8 @@ internal class AndroidSignProvider(string? signUrl) : AndroidBotSignProvider, ID ["seq"] = seq, ["buffer"] = Convert.ToHexString(body.Span), ["guid"] = Convert.ToHexString(Context.Keystore.Guid), - ["version"] = Context.AppInfo.PtVersion + ["version"] = Context.AppInfo.PtVersion, + ["qua"] = Context.AppInfo.Qua }; var response = await _client.PostAsync($"{_url}/sign", new StringContent(payload.ToJsonString(), Encoding.UTF8, "application/json")); @@ -305,7 +306,8 @@ public override async Task GetEnergy(long uin, string data) ["data"] = data, ["guid"] = Convert.ToHexString(Context.Keystore.Guid), ["ver"] = Context.AppInfo.SdkInfo.SdkVersion, - ["version"] = Context.AppInfo.PtVersion + ["version"] = Context.AppInfo.PtVersion, + ["qua"] = Context.AppInfo.Qua }; var response = await _client.PostAsync($"{_url}/energy", new StringContent(payload.ToJsonString(), Encoding.UTF8, "application/json")); @@ -330,7 +332,8 @@ public override async Task GetDebugXwid(long uin, string data) ["uin"] = uin, ["data"] = data, ["guid"] = Convert.ToHexString(Context.Keystore.Guid), - ["version"] = Context.AppInfo.PtVersion + ["version"] = Context.AppInfo.PtVersion, + ["qua"] = Context.AppInfo.Qua }; var response = await _client.PostAsync($"{_url}/get_tlv553", new StringContent(payload.ToJsonString(), Encoding.UTF8, "application/json")); @@ -371,12 +374,10 @@ internal class SignResponse internal static partial class JsonHelper { [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Default, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)] - [JsonSerializable(typeof(AndroidSignProvider.ResponseRoot))] [JsonSerializable(typeof(AndroidSignProvider.ResponseRoot))] [JsonSerializable(typeof(LinuxSignProvider.Root))] [JsonSerializable(typeof(LinuxSignProvider.Response))] - [JsonSerializable(typeof(JsonObject))] [JsonSerializable(typeof(LightApp))] private partial class CoreSerializerContext : JsonSerializerContext; diff --git a/Lagrange.Core.NativeAPI/NativeModel/Common/ByteArrayDictNative.cs b/Lagrange.Core.NativeAPI/NativeModel/Common/ByteArrayDictNative.cs index 13390d19..98051e79 100644 --- a/Lagrange.Core.NativeAPI/NativeModel/Common/ByteArrayDictNative.cs +++ b/Lagrange.Core.NativeAPI/NativeModel/Common/ByteArrayDictNative.cs @@ -6,7 +6,7 @@ public struct ByteArrayDictNative { public int Length; public IntPtr Data; - + public static implicit operator ByteArrayDictNative(ByteArrayKVPNative[] dict) { int size = Marshal.SizeOf(); @@ -15,26 +15,26 @@ public static implicit operator ByteArrayDictNative(ByteArrayKVPNative[] dict) { Marshal.StructureToPtr(dict[i], ptr + i * size, false); } - + return new ByteArrayDictNative { Length = dict.Length, Data = ptr }; } - + public static implicit operator ByteArrayKVPNative[](ByteArrayDictNative dict) { if (dict.Data == IntPtr.Zero || dict.Length == 0) { return []; } - + ByteArrayKVPNative[] result = new ByteArrayKVPNative[dict.Length]; int size = Marshal.SizeOf(); for (int i = 0; i < dict.Length; i++) { result[i] = Marshal.PtrToStructure(dict.Data + i * size); } - - Marshal.FreeHGlobal(dict.Data); - + + // Marshal.FreeHGlobal(dict.Data); Why release here? + return result; } } \ No newline at end of file diff --git a/Lagrange.Core.NativeAPI/NativeModel/Event/ReverseEventCountStruct.cs b/Lagrange.Core.NativeAPI/NativeModel/Event/ReverseEventCountStruct.cs index d0335621..527fdba2 100644 --- a/Lagrange.Core.NativeAPI/NativeModel/Event/ReverseEventCountStruct.cs +++ b/Lagrange.Core.NativeAPI/NativeModel/Event/ReverseEventCountStruct.cs @@ -22,6 +22,7 @@ public ReverseEventCountStruct() { } public int BotLogEventCount = 0; public int BotMessageEventCount = 0; public int BotNewDeviceVerifyEventCount = 0; + public int BotOfflineEventCount = 0; public int BotOnlineEventCount = 0; public int BotQrCodeEventCount = 0; public int BotQrCodeQueryEventCount = 0; diff --git a/Lagrange.Core.NativeAPI/Program.cs b/Lagrange.Core.NativeAPI/Program.cs index 53beafe3..3a805cf8 100644 --- a/Lagrange.Core.NativeAPI/Program.cs +++ b/Lagrange.Core.NativeAPI/Program.cs @@ -1,4 +1,5 @@ using System.Runtime.InteropServices; +using System.Text; using Lagrange.Core.Common; using Lagrange.Core.Common.Interface; using Lagrange.Core.NativeAPI.NativeModel.Common; @@ -37,8 +38,9 @@ public static int Initialize(IntPtr botConfigPtr, IntPtr keystorePtr, IntPtr app return index; } + //uin, password皆可选,传入 0 或结构体内Data/Length置0 [UnmanagedCallersOnly(EntryPoint = "Start")] - public static StatusCode Start(int index) + public static StatusCode Start(int index, long uin, ByteArrayNative password) { if (Contexts.Count <= index) { @@ -50,9 +52,22 @@ public static StatusCode Start(int index) return StatusCode.AlreadyStarted; } + if (uin == 0 || password.IsEmpty()) + { + Task.Run(async () => + { + await Contexts[index].BotContext.Login(); + await Task.Delay(Timeout.Infinite); + }); + + return StatusCode.Success; + } + + var passwordData = Encoding.UTF8.GetString(password.ToByteArrayWithoutFree()); + Task.Run(async () => { - await Contexts[index].BotContext.Login(); + await Contexts[index].BotContext.Login(uin, passwordData); await Task.Delay(Timeout.Infinite); }); @@ -80,4 +95,4 @@ public static void FreeMemory(IntPtr ptr) Marshal.FreeHGlobal(ptr); } } -} +} \ No newline at end of file diff --git a/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs b/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs index 343e9ea2..8ce55009 100644 --- a/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs +++ b/Lagrange.Core.NativeAPI/ReverseEvent/EventEntryPoint.cs @@ -25,6 +25,7 @@ public static IntPtr GetEventCount(int index) BotLogEventCount = Program.Contexts[index].EventInvoker.BotLogEvent.Events.Count, BotMessageEventCount = Program.Contexts[index].EventInvoker.BotMessageEvent.Events.Count, BotNewDeviceVerifyEventCount = Program.Contexts[index].EventInvoker.BotNewDeviceVerifyEvent.Events.Count, + BotOfflineEventCount = Program.Contexts[index].EventInvoker.BotOfflineEvent.Events.Count, BotOnlineEventCount = Program.Contexts[index].EventInvoker.BotOnlineEvent.Events.Count, BotQrCodeEventCount = Program.Contexts[index].EventInvoker.BotQrCodeEvent.Events.Count, BotQrCodeQueryEventCount = Program.Contexts[index].EventInvoker.BotQrCodeQueryEvent.Events.Count, @@ -172,7 +173,7 @@ public static IntPtr GetBotGroupReactionEvent(int index) return eventPtr; } - + [UnmanagedCallersOnly(EntryPoint = "GetBotGroupRecallEvent")] public static IntPtr GetBotGroupRecallEvent(int index) { @@ -183,7 +184,7 @@ public static IntPtr GetBotGroupRecallEvent(int index) var botGroupRecallEvent = Program.Contexts[index].EventInvoker.BotGroupRecallEvent; - IntPtr eventPtr = GetEventStructPtr(botGroupRecallEvent); + IntPtr eventPtr = GetEventStructPtr(botGroupRecallEvent); return eventPtr; } @@ -369,4 +370,4 @@ private static IntPtr GetEventStructPtr(ReverseEventBase reverseEvent) where return resultPtr; } } -} +} \ No newline at end of file diff --git a/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs b/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs index 178c64b4..1d9c5def 100644 --- a/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs +++ b/Lagrange.Core.NativeAPI/ReverseEvent/ReverseEventInvoker.cs @@ -1,6 +1,4 @@ -using Lagrange.Core.NativeAPI.ReverseEvent.Abstract; - -namespace Lagrange.Core.NativeAPI.ReverseEvent +namespace Lagrange.Core.NativeAPI.ReverseEvent { public class ReverseEventInvoker { @@ -8,12 +6,14 @@ public ReverseEventInvoker(BotContext context) { BotCaptchaEvent.RegisterEventHandler(context); BotFriendRequestEvent.RegisterEventHandler(context); + BotFriendRecallEvent.RegisterEventHandler(context); BotGroupInviteNotificationEvent.RegisterEventHandler(context); BotGroupJoinNotificationEvent.RegisterEventHandler(context); BotGroupMemberDecreaseEvent.RegisterEventHandler(context); BotGroupMemberIncreaseEvent.RegisterEventHandler(context); BotGroupNudgeEvent.RegisterEventHandler(context); BotGroupReactionEvent.RegisterEventHandler(context); + BotGroupRecallEvent.RegisterEventHandler(context); BotLoginEvent.RegisterEventHandler(context); BotLogEvent.RegisterEventHandler(context); BotMessageEvent.RegisterEventHandler(context); @@ -23,6 +23,7 @@ public ReverseEventInvoker(BotContext context) BotQrCodeEvent.RegisterEventHandler(context); BotQrCodeQueryEvent.RegisterEventHandler(context); BotRefreshKeystoreEvent.RegisterEventHandler(context); + BotSMSEvent.RegisterEventHandler(context); } public BotCaptchaReverseEvent BotCaptchaEvent { get; } = new(); diff --git a/Lagrange.Core/Internal/Logic/WtExchangeLogic.cs b/Lagrange.Core/Internal/Logic/WtExchangeLogic.cs index 4313001b..979808de 100644 --- a/Lagrange.Core/Internal/Logic/WtExchangeLogic.cs +++ b/Lagrange.Core/Internal/Logic/WtExchangeLogic.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Concurrent; +using System.Numerics; using System.Text; using System.Web; using Lagrange.Core.Common; @@ -206,6 +208,27 @@ private async Task ManualLogin(long uin, string? password) _token?.ThrowIfCancellationRequested(); result = await _context.EventContext.SendEvent(new LoginEventReq(LoginEventReq.Command.Captcha) { Ticket = ticket }); + + // --- Patch begin --- + if (result.State == LoginEventResp.States.SmsRequired) + { + string? url = null; + if (result.Tlvs.TryGetValue(0x204, out var tlv204)) { + url = Encoding.UTF8.GetString(tlv204); + } + + var tlv178 = new BinaryPacket(result.Tlvs[0x178].AsSpan()); + string countryCode = tlv178.ReadString(Prefix.Int16 | Prefix.LengthOnly); + string phone = tlv178.ReadString(Prefix.Int16 | Prefix.LengthOnly); + + _context.LogInfo(Tag, "SMS Verification required, Phone: {0}-{1} | URL: {2}", countryCode, phone, url); + _context.EventInvoker.PostEvent(new BotSMSEvent(url, $"{countryCode}-{phone}")); + + _smsSource = new TaskCompletionSource(); + string code = await _smsSource.Task; + result = await _context.EventContext.SendEvent(new LoginEventReq(LoginEventReq.Command.SubmitSMSCode) { Code = code }); + } + // --- Patch end --- } if (result.State == LoginEventResp.States.DeviceLockViaSmsNewArea) diff --git a/Lagrange.Core/Internal/Services/Login/LoginService.cs b/Lagrange.Core/Internal/Services/Login/LoginService.cs index c9949291..a88f9584 100644 --- a/Lagrange.Core/Internal/Services/Login/LoginService.cs +++ b/Lagrange.Core/Internal/Services/Login/LoginService.cs @@ -19,10 +19,10 @@ internal class LoginService : BaseService protected override ValueTask> Build(LoginEventReq input, BotContext context) { if (!_packet.IsValueCreated) _packet = new Lazy(() => new WtLogin(context)); - + return input.Cmd switch { - LoginEventReq.Command.Tgtgt => new ValueTask>(_packet.Value.BuildOicq09()), + LoginEventReq.Command.Tgtgt => new ValueTask>(_packet.Value.BuildOicq09()), _ => throw new ArgumentOutOfRangeException(nameof(input), $"Unknown command: {input.Cmd}") }; } @@ -48,7 +48,7 @@ protected override async ValueTask> Build(LoginEventReq inp return input.Cmd switch { - LoginEventReq.Command.Tgtgt => await _packet.Value.BuildOicq09Android(input.Password), + LoginEventReq.Command.Tgtgt => await _packet.Value.BuildOicq09Android(input.Password), LoginEventReq.Command.Captcha => await _packet.Value.BuildOicq02Android(input.Ticket), LoginEventReq.Command.FetchSMSCode => await _packet.Value.BuildOicq08Android(), LoginEventReq.Command.SubmitSMSCode => await _packet.Value.BuildOicq07Android(input.Code), @@ -72,7 +72,7 @@ public static LoginEventResp Parse(WtLogin packet, ReadOnlyMemory input, B var payload = packet.Parse(input.Span, out ushort command); var reader = new BinaryPacket(payload); Debug.Assert(command == 0x810); - + ushort internalCmd = reader.Read(); byte state = reader.Read(); var tlvs = ProtocolHelper.TlvUnPack(ref reader); @@ -83,7 +83,7 @@ public static LoginEventResp Parse(WtLogin packet, ReadOnlyMemory input, B uint _ = errorReader.Read(); // error code string errorTitle = errorReader.ReadString(Prefix.Int16 | Prefix.LengthOnly); string errorMessage = errorReader.ReadString(Prefix.Int16 | Prefix.LengthOnly); - + return new LoginEventResp(state, (errorTitle, errorMessage)); } @@ -93,7 +93,7 @@ public static LoginEventResp Parse(WtLogin packet, ReadOnlyMemory input, B var tlv119 = TeaProvider.CreateDecryptSpan(tgtgt); var tlv119Reader = new BinaryPacket(tlv119); var tlvCollection = ProtocolHelper.TlvUnPack(ref tlv119Reader); - + return new LoginEventResp(state, tlvCollection); } diff --git a/Lagrange.Core/Utility/ProtocolHelper.cs b/Lagrange.Core/Utility/ProtocolHelper.cs index 04e74374..f7d751fd 100644 --- a/Lagrange.Core/Utility/ProtocolHelper.cs +++ b/Lagrange.Core/Utility/ProtocolHelper.cs @@ -13,24 +13,24 @@ public static Dictionary TlvUnPack(ref BinaryPacket reader) { ushort tag = reader.Read(); ushort length = reader.Read(); - + var data = new byte[length]; reader.ReadBytes(data.AsSpan()); tlv[tag] = data; } - + return tlv; } - + public static string UInt32ToIPV4Addr(uint i) { Span ip = stackalloc byte[4]; - + ip[0] = (byte)(i & 0xFF); ip[1] = (byte)((i >> 8) & 0xFF); ip[2] = (byte)((i >> 16) & 0xFF); ip[3] = (byte)((i >> 24) & 0xFF); - + return $"{ip[0]}.{ip[1]}.{ip[2]}.{ip[3]}"; } } \ No newline at end of file