Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Intersect.Server.Database.PlayerData;

public record struct LoginFailureReason(LoginFailureType Type);
8 changes: 8 additions & 0 deletions Intersect.Server.Core/Database/PlayerData/LoginFailureType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Intersect.Server.Database.PlayerData;

public enum LoginFailureType
{
None,
InvalidCredentials,
ServerError,
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public BankSlot(int slot)
public Guid PlayerId { get; private set; }

[JsonIgnore]
[ForeignKey(nameof(PlayerId))]
public virtual Player Player { get; private set; }

public int Slot { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public GuildBankSlot(int slot)
public Guid GuildId { get; private set; }

[JsonIgnore]
[ForeignKey(nameof(GuildId))]
public virtual Guild Guild { get; private set; }

public int Slot { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ public GuildVariable(Guid id)
public Guid GuildId { get; protected set; }

[JsonIgnore]
[ForeignKey(nameof(GuildId))]
public virtual Guild Guild { get; protected set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public string StatBuffsJson
public Guid PlayerId { get; private set; }

[JsonIgnore]
[ForeignKey(nameof(PlayerId))]
public virtual Player Player { get; private set; }

[JsonIgnore]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public InventorySlot(int slot)
public Guid PlayerId { get; private set; }

[JsonIgnore]
[ForeignKey(nameof(PlayerId))]
public virtual Player Player { get; private set; }

public int Slot { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public PlayerVariable(Guid id)
public Guid PlayerId { get; protected set; }

[JsonIgnore]
[ForeignKey(nameof(PlayerId))]
public virtual Player Player { get; protected set; }

}
1 change: 1 addition & 0 deletions Intersect.Server.Core/Database/PlayerData/Players/Quest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public Quest(Guid id)
public Guid PlayerId { get; private set; }

[JsonIgnore]
[ForeignKey(nameof(PlayerId))]
public virtual Player Player { get; private set; }

public string Data()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public SpellSlot(int slot)
public Guid PlayerId { get; private set; }

[JsonIgnore]
[ForeignKey(nameof(PlayerId))]
public virtual Player Player { get; private set; }

public int Slot { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public Switch(Guid id)
public Guid PlayerId { get; private set; }

[JsonIgnore]
[ForeignKey(nameof(PlayerId))]
public virtual Player Player { get; private set; }

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ public UserVariable(Guid userVariableBaseId)
public Guid UserId { get; protected set; }

[JsonIgnore]
[ForeignKey(nameof(UserId))]
public virtual User User { get; protected set; }
}
77 changes: 56 additions & 21 deletions Intersect.Server.Core/Database/PlayerData/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

namespace Intersect.Server.Database.PlayerData;


[ApiVisibility(ApiVisibility.Restricted | ApiVisibility.Private)]
public partial class User
{
Expand Down Expand Up @@ -543,37 +542,73 @@ public static Tuple<Client, User> Fetch(string userName)
return new Tuple<Client, User>(client, client?.User ?? Find(userName));
}

public static User TryLogin(string username, string ptPassword)
public static bool TryLogin(
string username,
string ptPassword,
[NotNullWhen(true)] out User? user,
out LoginFailureReason failureReason
)
{
var user = FindOnline(username);
user = FindOnline(username);
failureReason = default;

if (user != null)
{
var hashedPassword = SaltPasswordHash(ptPassword, user.Salt);
if (string.Equals(user.Password, hashedPassword, StringComparison.Ordinal))
if (!string.Equals(user.Password, hashedPassword, StringComparison.Ordinal))
{
return PostLoad(user);
Log.Debug($"Login to {username} failed due invalid credentials");
user = default;
failureReason = new LoginFailureReason(LoginFailureType.InvalidCredentials);
return false;
}
}
else
{
try

var result = user.Save();
if (result != UserSaveResult.Completed)
{
using var context = DbInterface.CreatePlayerContext();
var salt = GetUserSalt(username);
if (!string.IsNullOrWhiteSpace(salt))
{
var pass = SaltPasswordHash(ptPassword, salt);
var queriedUser = QueryUserByNameAndPasswordShallow(context, username, pass);
return PostLoad(queriedUser, context);
}
Log.Error($"Login to {username} failed due to pre-logged in User save failure: {result}");
user = default;
failureReason = new LoginFailureReason(LoginFailureType.ServerError);
return false;
}
catch (Exception exception)

user = PostLoad(user);
if (user != default)
{
Log.Error(exception);
return true;
}

Log.Error($"Login to {username} failed due to {nameof(PostLoad)}() returning null.");
user = default;
failureReason = new LoginFailureReason(LoginFailureType.ServerError);
return false;

}

return null;
try
{
using var context = DbInterface.CreatePlayerContext();
var salt = GetUserSalt(username);
if (string.IsNullOrWhiteSpace(salt))
{
Log.Error($"Login to {username} failed because the salt is empty.");
user = default;
failureReason = new LoginFailureReason(LoginFailureType.ServerError);
return false;
}

var pass = SaltPasswordHash(ptPassword, salt);
var queriedUser = QueryUserByNameAndPasswordShallow(context, username, pass);
user = PostLoad(queriedUser, context);
return user != default;
}
catch (Exception exception)
{
Log.Error(exception, $"Login to {username} failed due to an exception");
user = default;
failureReason = new LoginFailureReason(LoginFailureType.ServerError);
return false;
}
}

public static User FindById(Guid userId)
Expand Down Expand Up @@ -918,7 +953,7 @@ public static bool TryRegister(
return true;
}

error = Strings.Account.UnknownError;
error = Strings.Account.UnknownErrorWhileSaving;
return false;
}

Expand Down
5 changes: 4 additions & 1 deletion Intersect.Server.Core/Localization/Strings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ public sealed partial class AccountNamespace : LocaleNamespace
public readonly LocalizedString UnbanSuccess = @"{00} has been unbanned!";

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public readonly LocalizedString UnknownError = @"An unknown error occurred while saving the user.";
public readonly LocalizedString UnknownErrorWhileSaving = @"An unknown error occurred while saving the user.";

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public readonly LocalizedString UnknownServerErrorRetryLogin = @"An unknown server error occurred, please try logging in again.";

[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public readonly LocalizedString UnmuteFail = @"Failed to unmute {00}. The user is not muted!";
Expand Down
25 changes: 19 additions & 6 deletions Intersect.Server.Core/Networking/PacketHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -521,13 +521,26 @@ public void HandlePacket(Client client, LoginPacket packet)
return;
}

var user = User.TryLogin(packet.Username, packet.Password);
if (user == null)
{
UserActivityHistory.LogActivity(Guid.Empty, Guid.Empty, client?.Ip, UserActivityHistory.PeerType.Client, UserActivityHistory.UserAction.FailedLogin, packet.Username);
if (!User.TryLogin(packet.Username, packet.Password, out var user, out var failureReason))
{
UserActivityHistory.LogActivity(
Guid.Empty,
Guid.Empty,
client?.Ip,
UserActivityHistory.PeerType.Client,
UserActivityHistory.UserAction.FailedLogin,
$"{packet.Username},{failureReason.Type}"
);

client.FailedAttempt();
PacketSender.SendError(client, Strings.Account.BadLogin, Strings.General.NoticeError);
if (failureReason.Type == LoginFailureType.InvalidCredentials)
{
client.FailedAttempt();
PacketSender.SendError(client, Strings.Account.BadLogin, Strings.General.NoticeError);
}
else
{
PacketSender.SendError(client, Strings.Account.UnknownServerErrorRetryLogin, Strings.General.NoticeError);
}

return;
}
Expand Down
25 changes: 19 additions & 6 deletions Intersect.Server/Networking/NetworkedPacketHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,26 @@ public void HandlePacket(Client client, Network.Packets.Editor.LoginPacket packe

client.ResetTimeout();

var user = User.TryLogin(packet.Username, packet.Password);
if (user == null)
if (!User.TryLogin(packet.Username, packet.Password, out var user, out var failureReason))
{
UserActivityHistory.LogActivity(Guid.Empty, Guid.Empty, client?.Ip, UserActivityHistory.PeerType.Editor, UserActivityHistory.UserAction.FailedLogin, packet.Username);

client.FailedAttempt();
PacketSender.SendError(client, Strings.Account.BadLogin, Strings.General.NoticeError);
UserActivityHistory.LogActivity(
Guid.Empty,
Guid.Empty,
client.Ip,
UserActivityHistory.PeerType.Editor,
UserActivityHistory.UserAction.FailedLogin,
$"{packet.Username},{failureReason.Type}"
);

if (failureReason.Type == LoginFailureType.InvalidCredentials)
{
client.FailedAttempt();
PacketSender.SendError(client, Strings.Account.BadLogin, Strings.General.NoticeError);
}
else
{
PacketSender.SendError(client, Strings.Account.UnknownServerErrorRetryLogin, Strings.General.NoticeError);
}

return;
}
Expand Down
Loading