fix: Reverts GetAccount to use IAccount. Adds IAccount to serialization. (#1565)
### Summary - Fixes usernames not being `Intern`ed - Reverts methods related to getting accounts from returning `Account` to `IAccount`. - Makes `IAccount` also `ISerializable` - Adds `IGenericReader.ReadAccount()` and `IGenericWriter.Write(IAccount)` -> The read method supports the original serialization of username, and using `IAccount.Serial`. The write method only serializes the `Serial`. - Exposes `ReadStringRaw()` to allow some advanced scenarios.
This commit is contained in:
parent
a4e2226a5c
commit
e6d30fef0f
9 changed files with 201 additions and 19 deletions
|
|
@ -47,15 +47,19 @@ public class AccountPacketTests : IClassFixture<ServerFixture>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Delete()
|
public DateTime Created { get; set; }
|
||||||
{
|
public long SavePosition { get; set; }
|
||||||
throw new NotImplementedException();
|
public BufferWriter SaveBuffer { get; set; }
|
||||||
}
|
public Serial Serial { get; }
|
||||||
|
public void Deserialize(IGenericReader reader) => throw new NotImplementedException();
|
||||||
|
|
||||||
public void SetPassword(string password)
|
public void Serialize(IGenericWriter writer) => throw new NotImplementedException();
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
public bool Deleted { get; }
|
||||||
}
|
|
||||||
|
public void Delete() => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public void SetPassword(string password) => throw new NotImplementedException();
|
||||||
|
|
||||||
public bool CheckPassword(string password) => throw new NotImplementedException();
|
public bool CheckPassword(string password) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ public interface IGoldAccount
|
||||||
long GetTotalGold();
|
long GetTotalGold();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IAccount : IGoldAccount, IComparable<IAccount>
|
public interface IAccount : ISerializable, IGoldAccount, IComparable<IAccount>
|
||||||
{
|
{
|
||||||
string Username { get; set; }
|
string Username { get; set; }
|
||||||
string Email { get; set; }
|
string Email { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ public interface IGenericReader
|
||||||
DateTime LastSerialized { get; init; }
|
DateTime LastSerialized { get; init; }
|
||||||
|
|
||||||
string ReadString(bool intern = false);
|
string ReadString(bool intern = false);
|
||||||
|
public string ReadStringRaw(bool intern = false);
|
||||||
|
|
||||||
long ReadLong();
|
long ReadLong();
|
||||||
ulong ReadULong();
|
ulong ReadULong();
|
||||||
int ReadInt();
|
int ReadInt();
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,30 @@ namespace Server.Accounting
|
||||||
{
|
{
|
||||||
public partial class Account
|
public partial class Account
|
||||||
{
|
{
|
||||||
|
// Username was not interned
|
||||||
|
private void MigrateFrom(V4Content content)
|
||||||
|
{
|
||||||
|
_username = content.Username;
|
||||||
|
_passwordAlgorithm = content.PasswordAlgorithm;
|
||||||
|
_password = content.Password;
|
||||||
|
_accessLevel = content.AccessLevel;
|
||||||
|
_flags = content.Flags;
|
||||||
|
_lastLogin = content.LastLogin;
|
||||||
|
_totalGold = content.TotalGold;
|
||||||
|
_totalPlat = content.TotalPlat;
|
||||||
|
_mobiles = content.Mobiles;
|
||||||
|
_comments = content.Comments;
|
||||||
|
_tags = content.Tags;
|
||||||
|
_loginIPs = content.LoginIPs;
|
||||||
|
_ipRestrictions = content.IpRestrictions;
|
||||||
|
_totalGameTime = content.TotalGameTime;
|
||||||
|
_email = content.Email;
|
||||||
|
}
|
||||||
|
|
||||||
private void MigrateFrom(V3Content content)
|
private void MigrateFrom(V3Content content)
|
||||||
{
|
{
|
||||||
_username = content.Username;
|
_username = content.Username;
|
||||||
|
_username.Intern();
|
||||||
_passwordAlgorithm = content.PasswordAlgorithm;
|
_passwordAlgorithm = content.PasswordAlgorithm;
|
||||||
_password = content.Password;
|
_password = content.Password;
|
||||||
_accessLevel = content.AccessLevel;
|
_accessLevel = content.AccessLevel;
|
||||||
|
|
@ -35,7 +56,7 @@ namespace Server.Accounting
|
||||||
reader.Seek(0, SeekOrigin.Begin);
|
reader.Seek(0, SeekOrigin.Begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
_username = reader.ReadString();
|
_username = reader.ReadString(true);
|
||||||
_passwordAlgorithm = version < 2 ? (PasswordProtectionAlgorithm)reader.ReadInt() : reader.ReadEnum<PasswordProtectionAlgorithm>();
|
_passwordAlgorithm = version < 2 ? (PasswordProtectionAlgorithm)reader.ReadInt() : reader.ReadEnum<PasswordProtectionAlgorithm>();
|
||||||
_password = reader.ReadString();
|
_password = reader.ReadString();
|
||||||
_accessLevel = version < 2 ? (AccessLevel)reader.ReadInt() : reader.ReadEnum<AccessLevel>();
|
_accessLevel = version < 2 ? (AccessLevel)reader.ReadInt() : reader.ReadEnum<AccessLevel>();
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,14 @@ using Server.Network;
|
||||||
|
|
||||||
namespace Server.Accounting
|
namespace Server.Accounting
|
||||||
{
|
{
|
||||||
[SerializationGenerator(4)]
|
[SerializationGenerator(5)]
|
||||||
public partial class Account : IAccount, IComparable<Account>, ISerializable
|
public partial class Account : IAccount, IComparable<Account>
|
||||||
{
|
{
|
||||||
public static readonly TimeSpan YoungDuration = TimeSpan.FromHours(40.0);
|
public static readonly TimeSpan YoungDuration = TimeSpan.FromHours(40.0);
|
||||||
public static readonly TimeSpan InactiveDuration = TimeSpan.FromDays(180.0);
|
public static readonly TimeSpan InactiveDuration = TimeSpan.FromDays(180.0);
|
||||||
public static readonly TimeSpan EmptyInactiveDuration = TimeSpan.FromDays(30.0);
|
public static readonly TimeSpan EmptyInactiveDuration = TimeSpan.FromDays(30.0);
|
||||||
|
|
||||||
|
[InternString]
|
||||||
[SerializableField(0)]
|
[SerializableField(0)]
|
||||||
private string _username;
|
private string _username;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ using Server.Logging;
|
||||||
|
|
||||||
namespace Server.Accounting;
|
namespace Server.Accounting;
|
||||||
|
|
||||||
public class Accounts : GenericEntityPersistence<Account>
|
public class Accounts : GenericEntityPersistence<IAccount>
|
||||||
{
|
{
|
||||||
private static readonly ILogger logger = LogFactory.GetLogger(typeof(Accounts));
|
private static readonly ILogger logger = LogFactory.GetLogger(typeof(Accounts));
|
||||||
|
|
||||||
private static readonly Dictionary<string, Account> _accountsByName = new(32, StringComparer.OrdinalIgnoreCase);
|
private static readonly Dictionary<string, IAccount> _accountsByName = new(32, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
public static int Count => _accountsByName.Count;
|
public static int Count => _accountsByName.Count;
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ public class Accounts : GenericEntityPersistence<Account>
|
||||||
|
|
||||||
public static IEnumerable<IAccount> GetAccounts() => _accountsByName.Values;
|
public static IEnumerable<IAccount> GetAccounts() => _accountsByName.Values;
|
||||||
|
|
||||||
public static Account GetAccount(string username)
|
public static IAccount GetAccount(string username)
|
||||||
{
|
{
|
||||||
_accountsByName.TryGetValue(username, out var a);
|
_accountsByName.TryGetValue(username, out var a);
|
||||||
return a;
|
return a;
|
||||||
|
|
@ -41,7 +41,7 @@ public class Accounts : GenericEntityPersistence<Account>
|
||||||
_accountsPersistence.AddEntity(a);
|
_accountsPersistence.AddEntity(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Remove(Account a)
|
public static void Remove(IAccount a)
|
||||||
{
|
{
|
||||||
_accountsByName.Remove(a.Username);
|
_accountsByName.Remove(a.Username);
|
||||||
_accountsPersistence.RemoveEntity(a);
|
_accountsPersistence.RemoveEntity(a);
|
||||||
|
|
@ -91,5 +91,5 @@ public class Accounts : GenericEntityPersistence<Account>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IAccount FindAccount(Serial serial) => _accountsPersistence.FindEntity<Account>(serial);
|
public static IAccount FindAccount(Serial serial) => _accountsPersistence.FindEntity<IAccount>(serial);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
125
Projects/UOContent/Migrations/Server.Accounting.Account.v5.json
generated
Normal file
125
Projects/UOContent/Migrations/Server.Accounting.Account.v5.json
generated
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
{
|
||||||
|
"version": 5,
|
||||||
|
"type": "Server.Accounting.Account",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "Username",
|
||||||
|
"type": "string",
|
||||||
|
"rule": "PrimitiveTypeMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
"InternString"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "PasswordAlgorithm",
|
||||||
|
"type": "Server.Accounting.Security.PasswordProtectionAlgorithm",
|
||||||
|
"rule": "EnumMigrationRule"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Password",
|
||||||
|
"type": "string",
|
||||||
|
"rule": "PrimitiveTypeMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "AccessLevel",
|
||||||
|
"type": "Server.AccessLevel",
|
||||||
|
"rule": "EnumMigrationRule"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Flags",
|
||||||
|
"type": "int",
|
||||||
|
"rule": "PrimitiveTypeMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LastLogin",
|
||||||
|
"type": "System.DateTime",
|
||||||
|
"rule": "PrimitiveTypeMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TotalGold",
|
||||||
|
"type": "int",
|
||||||
|
"rule": "PrimitiveTypeMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TotalPlat",
|
||||||
|
"type": "int",
|
||||||
|
"rule": "PrimitiveTypeMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mobiles",
|
||||||
|
"type": "Server.Mobile[]",
|
||||||
|
"rule": "ArrayMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
"Server.Mobile",
|
||||||
|
"SerializableInterfaceMigrationRule"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Comments",
|
||||||
|
"type": "System.Collections.Generic.List\u003CServer.Accounting.AccountComment\u003E",
|
||||||
|
"rule": "ListMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
"Server.Accounting.AccountComment",
|
||||||
|
"SerializationMethodSignatureMigrationRule",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tags",
|
||||||
|
"type": "System.Collections.Generic.List\u003CServer.Accounting.AccountTag\u003E",
|
||||||
|
"rule": "ListMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
"Server.Accounting.AccountTag",
|
||||||
|
"SerializationMethodSignatureMigrationRule",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LoginIPs",
|
||||||
|
"type": "System.Net.IPAddress[]",
|
||||||
|
"rule": "ArrayMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
"System.Net.IPAddress",
|
||||||
|
"PrimitiveTypeMigrationRule"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "IpRestrictions",
|
||||||
|
"type": "string[]",
|
||||||
|
"rule": "ArrayMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
"string",
|
||||||
|
"PrimitiveTypeMigrationRule",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "TotalGameTime",
|
||||||
|
"type": "System.TimeSpan",
|
||||||
|
"rule": "PrimitiveTypeMigrationRule"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Email",
|
||||||
|
"type": "string",
|
||||||
|
"rule": "PrimitiveTypeMigrationRule",
|
||||||
|
"ruleArguments": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
29
Projects/UOContent/Misc/SerializationExt.cs
Normal file
29
Projects/UOContent/Misc/SerializationExt.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
using Server.Accounting;
|
||||||
|
|
||||||
|
namespace Server.Misc;
|
||||||
|
|
||||||
|
public static class SerializationExt
|
||||||
|
{
|
||||||
|
public static IAccount ReadAccount(this IGenericReader reader)
|
||||||
|
{
|
||||||
|
return reader.ReadByte() switch
|
||||||
|
{
|
||||||
|
0 => null,
|
||||||
|
1 => Accounts.GetAccount(reader.ReadStringRaw()),
|
||||||
|
2 => Accounts.FindAccount(reader.ReadSerial())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Write(this IGenericWriter writer, IAccount acct)
|
||||||
|
{
|
||||||
|
if (acct == null)
|
||||||
|
{
|
||||||
|
writer.Write((byte)0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writer.Write((byte)2);
|
||||||
|
writer.Write(acct.Serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -76,8 +76,8 @@ public static class ServerAccess
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var acct = Accounts.GetAccount(username);
|
if (Accounts.GetAccount(username) is not Account acct
|
||||||
if (acct == null || !acct.Banned && acct.AccessLevel >= AccessLevel.Owner || !acct.CheckPassword(e.Password))
|
|| !acct.Banned && acct.AccessLevel >= AccessLevel.Owner || !acct.CheckPassword(e.Password))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue