diff --git a/Server/Client.cs b/Server/Client.cs index 691f2ff..5832806 100644 --- a/Server/Client.cs +++ b/Server/Client.cs @@ -117,7 +117,7 @@ namespace PSO2SERVER return; } - //Logger.Write("[<--] 接收到 {0} 字节", size); + Logger.Write("[<--] 接收到 {0} 字节", size); Array.Copy(data, 0, _readBuffer, _readBufferSize, size); diff --git a/Server/Network/SocketServer.cs b/Server/Network/SocketServer.cs index df752cd..eaf1239 100644 --- a/Server/Network/SocketServer.cs +++ b/Server/Network/SocketServer.cs @@ -55,6 +55,8 @@ namespace PSO2SERVER.Network { var c = new SocketClient(this, _listener.AcceptTcpClient()); + Logger.WriteInternal("[HI!] 新的客户端接入!"); + _clients.Add(c); _socketMap.Add(c.Socket.Client, c); diff --git a/Server/Program.cs b/Server/Program.cs index b485b50..b6c4537 100644 --- a/Server/Program.cs +++ b/Server/Program.cs @@ -31,7 +31,7 @@ namespace PSO2SERVER public const int ServerShipListProtNums_JP = 10; public const int ServerShipListProt_JP = 12099; - public const int ServerShipListProtNums_NA = 6; + public const int ServerShipListProtNums_NA = 10; public const int ServerShipListProt_NA = 13001; public const string ServerBlockBalanceName = "Test"; @@ -41,11 +41,8 @@ namespace PSO2SERVER public const string ServerMemoryPacket = "Resources\\setMemoryPacket.bin"; //TODO // 密钥BLOB格式 - public const string ServerPrivateKeyBlob_JP = "key\\privateKey_jp.blob"; - public const string ServerPublicKeyBlob_JP = "key\\publicKey_jp.blob"; - - public const string ServerPrivateKeyBlob_VITA = "key\\privateKey_vita.blob"; - public const string ServerPublicKeyBlob_VITA = "key\\publicKey_vita.blob"; + public const string ServerPrivateKeyBlob = "key\\privateKey.blob"; + public const string ServerPublicKeyBlob = "key\\publicKey.blob"; public const string ServerSEGAKeyBlob = "key\\SEGAKey.blob"; @@ -180,7 +177,7 @@ namespace PSO2SERVER public void GenerateKeys() { // Process private key files - KeyLoader.ProcessKeyFiles(ServerPrivatePem, ServerPrivateKeyBlob_JP, true, File.Exists(ServerPrivatePem)); + KeyLoader.ProcessKeyFiles(ServerPrivatePem, ServerPrivateKeyBlob, true, File.Exists(ServerPrivatePem)); // Process SEGA public key files KeyLoader.ProcessKeyFiles(ServerSEGAPem, ServerSEGAKeyBlob, false, File.Exists(ServerSEGAPem)); @@ -189,11 +186,8 @@ namespace PSO2SERVER using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) { // Process private and public RSA keys - KeyLoader.GenerateAndSaveKeyIfNotExists(rsa, ServerPrivateKeyBlob_JP, true); - KeyLoader.GenerateAndSaveKeyIfNotExists(rsa, ServerPublicKeyBlob_JP, false); - - KeyLoader.GenerateAndSaveKeyIfNotExists(rsa, ServerPrivateKeyBlob_VITA, true); - KeyLoader.GenerateAndSaveKeyIfNotExists(rsa, ServerPublicKeyBlob_VITA, false); + KeyLoader.GenerateAndSaveKeyIfNotExists(rsa, ServerPrivateKeyBlob, true); + KeyLoader.GenerateAndSaveKeyIfNotExists(rsa, ServerPublicKeyBlob, false); } } diff --git a/Server/Protocol/Handlers/11-ClientHandler/11-0B-KeyExchange.cs b/Server/Protocol/Handlers/11-ClientHandler/11-0B-KeyExchange.cs index b55a46e..08a9793 100644 --- a/Server/Protocol/Handlers/11-ClientHandler/11-0B-KeyExchange.cs +++ b/Server/Protocol/Handlers/11-ClientHandler/11-0B-KeyExchange.cs @@ -21,7 +21,7 @@ namespace PSO2SERVER.Protocol.Handlers // Extract the first 0x80 bytes into a separate array var cryptedBlob = new byte[0x80]; - var rsaBlob = File.ReadAllBytes(ServerApp.ServerPrivateKeyBlob_JP); + var rsaBlob = File.ReadAllBytes(ServerApp.ServerPrivateKeyBlob); Array.Copy(data, position, cryptedBlob, 0, 0x80); Array.Reverse(cryptedBlob); diff --git a/Server/Protocol/Handlers/11-ClientHandler/11-63-VitaLogin.cs b/Server/Protocol/Handlers/11-ClientHandler/11-63-VitaLogin.cs new file mode 100644 index 0000000..f6454f1 --- /dev/null +++ b/Server/Protocol/Handlers/11-ClientHandler/11-63-VitaLogin.cs @@ -0,0 +1,250 @@ +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using PSO2SERVER.Database; +using PSO2SERVER.Protocol.Packets; +using PSO2SERVER.Models; +using System.Text; +using System.Collections.Generic; +using System; + +namespace PSO2SERVER.Protocol.Handlers +{ + [PacketHandlerAttr(0x11, 0x63)] + public class VitaLogin : PacketHandler + { + public uint Unk1 { get; set; } + public uint Unk2 { get; set; } + public uint Unk3 { get; set; } + public byte[] VerId { get; set; } = new byte[0x20]; + public List Interfaces { get; set; } = new List(); + public byte[] Unk4 { get; set; } = new byte[0x90]; + public byte[] Unk5 { get; set; } = new byte[0x10]; + public Language TextLang { get; set; } + public Language VoiceLang { get; set; } + public Language TextLang2 { get; set; } + public Language LangLang { get; set; } + public string LanguageCode { get; set; } = new string('\0', 0x10); + public uint Unk6 { get; set; } + public uint Unk7 { get; set; } + public uint Magic1 { get; set; } + public byte[] Unk8 { get; set; } = new byte[0x20]; + public byte[] Unk9 { get; set; } = new byte[0x44]; + public string Username { get; set; } = new string('\0', 0x40); + public string Password { get; set; } = new string('\0', 0x40); + public uint Unk10 { get; set; } + public string Unk11 { get; set; } = string.Empty; + + public List ReadNetInterfaces(PacketReader reader, uint count) + { + var interfaces = new List(); + for (uint i = 0; i < count; i++) + { + var netInterface = new NetInterface(); + netInterface.ReadFromStream(reader); + interfaces.Add(netInterface); + } + return interfaces; + } + + public void SaveNetInterfacesToDatabase(int AccountId, string Username, List interfaces) + { + using (var db = new ServerEf()) + { + // 使用 AddRange 来批量插入数据 + var newInterfaces = interfaces.Select(netInterface => new AccountNetInterFace + { + AccountId = AccountId, + Username = Username, + State = (int)netInterface.State, // 确保转换类型正确 + Mac = netInterface.Mac + }).ToList(); + + db.AccountsNetInterFaces.AddRange(newInterfaces); + db.SaveChanges(); // 批量保存更改 + } + } + + // 假设你有一个读取到的实例 + public void PrintInterfaces(List interfaces) + { + foreach (var netInterface in interfaces) + { + Logger.Write(netInterface.ToString()); + } + } + + public void ReadFromStream(PacketReader reader) + { + Unk1 = reader.ReadUInt32(); + Unk2 = reader.ReadUInt32(); + Unk3 = reader.ReadUInt32(); + VerId = reader.ReadBytes(0x20); + + var macCount = reader.ReadMagic(0x5E6, 107); + // Assuming Interfaces is populated somehow + // e.g. Interfaces = ReadNetInterfaces(reader); + Interfaces = ReadNetInterfaces(reader, macCount); + // Read the fixed length fields + reader.BaseStream.Seek(0x14, SeekOrigin.Current); + Unk4 = reader.ReadBytes(0x90); + reader.BaseStream.Seek(0x10, SeekOrigin.Current); + Unk5 = reader.ReadBytes(0x10); + reader.BaseStream.Seek(0x10, SeekOrigin.Current); + TextLang = (Language)reader.ReadUInt32(); // Adjust based on actual type + VoiceLang = (Language)reader.ReadUInt32(); // Adjust based on actual type + TextLang2 = (Language)reader.ReadUInt32(); // Adjust based on actual type + LangLang = (Language)reader.ReadUInt32(); // Adjust based on actual type + reader.BaseStream.Seek(0x8, SeekOrigin.Current); + LanguageCode = reader.ReadFixedLengthUtf16(0x10); + Unk6 = reader.ReadUInt32(); + Unk7 = reader.ReadUInt32(); + Magic1 = reader.ReadUInt32(); + Unk8 = reader.ReadBytes(0x20); + Unk9 = reader.ReadBytes(0x44); + + // Read Username and Password + reader.BaseStream.Seek(0x104, SeekOrigin.Current); + Username = reader.ReadFixedLengthAscii(0x40); + reader.BaseStream.Seek(0x20, SeekOrigin.Current); + Password = reader.ReadFixedLengthAscii(0x40); + reader.BaseStream.Seek(0x04, SeekOrigin.Current); + Unk10 = reader.ReadUInt32(); + Unk11 = reader.ReadFixedLengthAscii(0x08); + } + + #region implemented abstract members of PacketHandler + + public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size) + { + var info = string.Format("[<--] 接收到的数据 (hex): {0}字节", data.Length); + Logger.WriteHex(info, data); + + var reader = new PacketReader(data, position, size); + + ReadFromStream(reader); + + //Logger.Write("用户名 {0} 密码 {1} - {2}", Username, Password, BCrypt.Net.BCrypt.HashPassword(Password)); + + // What am I doing here even + using (var db = new ServerEf()) + { + var users = from u in db.Accounts + where u.Username.ToLower().Equals(Username.ToLower()) + select u; + + + var error = ""; + Account user; + + if (!users.Any()) + { + // Check if there is an empty field + if (string.IsNullOrWhiteSpace(Username)) + { + error = "賬戶名為空."; + user = null; + } + + if (string.IsNullOrWhiteSpace(Password)) + { + error = "密碼為空 #1."; + user = null; + } + + // Check for special characters + else if (!Regex.IsMatch(Username, "^[a-zA-Z0-9 ]*$", RegexOptions.IgnoreCase)) + { + error = "用戶名不能包含特殊字符\n請只使用字母和數字."; + user = null; + } + else // We're all good! + { + // 直接插入新账户至数据库 + user = new Account + { + Username = Username.ToLower(), + Password = BCrypt.Net.BCrypt.HashPassword(Password), + Nickname = Username.ToLower(), + // Since we can't display the Nickname prompt yet, just default it to the username + SettingsIni = File.ReadAllText(ServerApp.ServerSettingsKey), + TextLang = (int)TextLang, + VoiceLang = (int)VoiceLang, + TextLang2 = (int)TextLang2, + LangLang = (int)LangLang, + LanguageCode = LanguageCode, + + }; + + db.Accounts.Add(user); + db.SaveChanges(); + + context.SendPacket(new NicknameRequestPacket()); // Request Nickname + } + } + else + { + user = users.First(); + + var existingUser = db.Accounts.FirstOrDefault(u => u.AccountId == user.AccountId); + + if (existingUser != null) + { + // 更新值 + existingUser.TextLang = (int)TextLang; + existingUser.VoiceLang = (int)VoiceLang; + existingUser.TextLang2 = (int)TextLang2; + existingUser.LangLang = (int)LangLang; + existingUser.LanguageCode = LanguageCode; + + // 提交更改到数据库 + db.SaveChanges(); + + SaveNetInterfacesToDatabase(user.AccountId, Username, Interfaces); + } + + //TODO 方便GM测试 + //if (Password != user.Password) + //{ + // if (Password == "") + // { + // error = "密碼為空 #2."; + // user = null; + // } + // else + // if (!BCrypt.Net.BCrypt.Verify(Password, user.Password)) + // { + // error = "密碼錯誤."; + // user = null; + // } + //} + } + + context.SendPacket(new LoginDataPacket("夢幻之星2", error, (user == null) ? (uint)0 : (uint)user.AccountId)); + + //Mystery packet + //var mystery = new PacketWriter(); + //mystery.Write((uint)100); + //context.SendPacket(0x11, 0x49, 0, mystery.ToArray()); + + // SegaIDLogin response packet + + if (user == null) + { + return; + } + + context._account = user; + + } + + if (ServerApp.Config.motd != "") + { + context.SendPacket(new SystemMessagePacket(ServerApp.Config.motd, SystemMessagePacket.MessageType.AdminMessageInstant)); + } + + } + + #endregion + } +} \ No newline at end of file diff --git a/Server/QueryServer.cs b/Server/QueryServer.cs index e79b9fb..798f7a7 100644 --- a/Server/QueryServer.cs +++ b/Server/QueryServer.cs @@ -108,7 +108,6 @@ namespace PSO2SERVER { order = (ushort)i, number = (uint)i, - //status = i == 2 ? ShipStatus.Online : ShipStatus.Full, // Maybe move to Config? status = CheckShipStatus(ServerApp.ServerShipProt + (100 * (i - 1))), // Maybe move to Config? name = String.Format("Ship{0:0#}", i), ip = ServerApp.BindAddress.GetAddressBytes() diff --git a/Server/Server.csproj b/Server/Server.csproj index 1ff2149..6554c1f 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -347,6 +347,7 @@ +