Skip to content

Commit fa7ab8d

Browse files
committed
fix: save already logged in user before allowing a second login
- Fixes the case where a new character is created and logged in on the client but has not saved yet and then the editor is logged into afterwards (but before the user auto-saves)
1 parent 6bc1b35 commit fa7ab8d

File tree

6 files changed

+109
-34
lines changed

6 files changed

+109
-34
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
namespace Intersect.Server.Database.PlayerData;
2+
3+
public record struct LoginFailureReason(LoginFailureType Type);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Intersect.Server.Database.PlayerData;
2+
3+
public enum LoginFailureType
4+
{
5+
None,
6+
InvalidCredentials,
7+
ServerError,
8+
}

Intersect.Server.Core/Database/PlayerData/User.cs

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929
namespace Intersect.Server.Database.PlayerData;
3030

31-
3231
[ApiVisibility(ApiVisibility.Restricted | ApiVisibility.Private)]
3332
public partial class User
3433
{
@@ -543,37 +542,73 @@ public static Tuple<Client, User> Fetch(string userName)
543542
return new Tuple<Client, User>(client, client?.User ?? Find(userName));
544543
}
545544

546-
public static User TryLogin(string username, string ptPassword)
545+
public static bool TryLogin(
546+
string username,
547+
string ptPassword,
548+
[NotNullWhen(true)] out User? user,
549+
out LoginFailureReason failureReason
550+
)
547551
{
548-
var user = FindOnline(username);
552+
user = FindOnline(username);
553+
failureReason = default;
554+
549555
if (user != null)
550556
{
551557
var hashedPassword = SaltPasswordHash(ptPassword, user.Salt);
552-
if (string.Equals(user.Password, hashedPassword, StringComparison.Ordinal))
558+
if (!string.Equals(user.Password, hashedPassword, StringComparison.Ordinal))
553559
{
554-
return PostLoad(user);
560+
Log.Debug($"Login to {username} failed due invalid credentials");
561+
user = default;
562+
failureReason = new LoginFailureReason(LoginFailureType.InvalidCredentials);
563+
return false;
555564
}
556-
}
557-
else
558-
{
559-
try
565+
566+
var result = user.Save();
567+
if (result != UserSaveResult.Completed)
560568
{
561-
using var context = DbInterface.CreatePlayerContext();
562-
var salt = GetUserSalt(username);
563-
if (!string.IsNullOrWhiteSpace(salt))
564-
{
565-
var pass = SaltPasswordHash(ptPassword, salt);
566-
var queriedUser = QueryUserByNameAndPasswordShallow(context, username, pass);
567-
return PostLoad(queriedUser, context);
568-
}
569+
Log.Error($"Login to {username} failed due to pre-logged in User save failure: {result}");
570+
user = default;
571+
failureReason = new LoginFailureReason(LoginFailureType.ServerError);
572+
return false;
569573
}
570-
catch (Exception exception)
574+
575+
user = PostLoad(user);
576+
if (user != default)
571577
{
572-
Log.Error(exception);
578+
return true;
573579
}
580+
581+
Log.Error($"Login to {username} failed due to {nameof(PostLoad)}() returning null.");
582+
user = default;
583+
failureReason = new LoginFailureReason(LoginFailureType.ServerError);
584+
return false;
585+
574586
}
575587

576-
return null;
588+
try
589+
{
590+
using var context = DbInterface.CreatePlayerContext();
591+
var salt = GetUserSalt(username);
592+
if (string.IsNullOrWhiteSpace(salt))
593+
{
594+
Log.Error($"Login to {username} failed because the salt is empty.");
595+
user = default;
596+
failureReason = new LoginFailureReason(LoginFailureType.ServerError);
597+
return false;
598+
}
599+
600+
var pass = SaltPasswordHash(ptPassword, salt);
601+
var queriedUser = QueryUserByNameAndPasswordShallow(context, username, pass);
602+
user = PostLoad(queriedUser, context);
603+
return user != default;
604+
}
605+
catch (Exception exception)
606+
{
607+
Log.Error(exception, $"Login to {username} failed due to an exception");
608+
user = default;
609+
failureReason = new LoginFailureReason(LoginFailureType.ServerError);
610+
return false;
611+
}
577612
}
578613

579614
public static User FindById(Guid userId)
@@ -918,7 +953,7 @@ public static bool TryRegister(
918953
return true;
919954
}
920955

921-
error = Strings.Account.UnknownError;
956+
error = Strings.Account.UnknownErrorWhileSaving;
922957
return false;
923958
}
924959

Intersect.Server.Core/Localization/Strings.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ public sealed partial class AccountNamespace : LocaleNamespace
9292
public readonly LocalizedString UnbanSuccess = @"{00} has been unbanned!";
9393

9494
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
95-
public readonly LocalizedString UnknownError = @"An unknown error occurred while saving the user.";
95+
public readonly LocalizedString UnknownErrorWhileSaving = @"An unknown error occurred while saving the user.";
96+
97+
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
98+
public readonly LocalizedString UnknownServerErrorRetryLogin = @"An unknown server error occurred, please try logging in again.";
9699

97100
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
98101
public readonly LocalizedString UnmuteFail = @"Failed to unmute {00}. The user is not muted!";

Intersect.Server.Core/Networking/PacketHandler.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -521,13 +521,26 @@ public void HandlePacket(Client client, LoginPacket packet)
521521
return;
522522
}
523523

524-
var user = User.TryLogin(packet.Username, packet.Password);
525-
if (user == null)
526-
{
527-
UserActivityHistory.LogActivity(Guid.Empty, Guid.Empty, client?.Ip, UserActivityHistory.PeerType.Client, UserActivityHistory.UserAction.FailedLogin, packet.Username);
524+
if (!User.TryLogin(packet.Username, packet.Password, out var user, out var failureReason))
525+
{
526+
UserActivityHistory.LogActivity(
527+
Guid.Empty,
528+
Guid.Empty,
529+
client?.Ip,
530+
UserActivityHistory.PeerType.Client,
531+
UserActivityHistory.UserAction.FailedLogin,
532+
$"{packet.Username},{failureReason.Type}"
533+
);
528534

529-
client.FailedAttempt();
530-
PacketSender.SendError(client, Strings.Account.BadLogin, Strings.General.NoticeError);
535+
if (failureReason.Type == LoginFailureType.InvalidCredentials)
536+
{
537+
client.FailedAttempt();
538+
PacketSender.SendError(client, Strings.Account.BadLogin, Strings.General.NoticeError);
539+
}
540+
else
541+
{
542+
PacketSender.SendError(client, Strings.Account.UnknownServerErrorRetryLogin, Strings.General.NoticeError);
543+
}
531544

532545
return;
533546
}

Intersect.Server/Networking/NetworkedPacketHandler.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,13 +100,26 @@ public void HandlePacket(Client client, Network.Packets.Editor.LoginPacket packe
100100

101101
client.ResetTimeout();
102102

103-
var user = User.TryLogin(packet.Username, packet.Password);
104-
if (user == null)
103+
if (!User.TryLogin(packet.Username, packet.Password, out var user, out var failureReason))
105104
{
106-
UserActivityHistory.LogActivity(Guid.Empty, Guid.Empty, client?.Ip, UserActivityHistory.PeerType.Editor, UserActivityHistory.UserAction.FailedLogin, packet.Username);
107-
108-
client.FailedAttempt();
109-
PacketSender.SendError(client, Strings.Account.BadLogin, Strings.General.NoticeError);
105+
UserActivityHistory.LogActivity(
106+
Guid.Empty,
107+
Guid.Empty,
108+
client.Ip,
109+
UserActivityHistory.PeerType.Editor,
110+
UserActivityHistory.UserAction.FailedLogin,
111+
$"{packet.Username},{failureReason.Type}"
112+
);
113+
114+
if (failureReason.Type == LoginFailureType.InvalidCredentials)
115+
{
116+
client.FailedAttempt();
117+
PacketSender.SendError(client, Strings.Account.BadLogin, Strings.General.NoticeError);
118+
}
119+
else
120+
{
121+
PacketSender.SendError(client, Strings.Account.UnknownServerErrorRetryLogin, Strings.General.NoticeError);
122+
}
110123

111124
return;
112125
}

0 commit comments

Comments
 (0)