From 10ae2878faebabaf613a9328069bbb6ad95c22e7 Mon Sep 17 00:00:00 2001 From: Bia10 Date: Sat, 30 Sep 2023 18:39:15 +0200 Subject: [PATCH] Add auto login, auto register, and flipped username handling to Rue (#80) * initial work on login side of Rue plugin * move autoregister to login plugin * Update Rue login plugin to use updated IPluginHost * Add config loading, cleanup code, add IsFlippedUsername config and handling * Fix nullable --------- Co-authored-by: Keith --- .../Configs/ProgramConfigStageLogin.cs | 3 -- .../appsettings.json | 4 +- .../Handlers/CheckPasswordHandler.cs | 14 ++---- .../Handlers/CreateSecurityHandleHandler.cs | 21 ++++++++ .../Plugs/UserOnPacketCheckPasswordPlug.cs | 11 ---- .../Configs/RueConfigLogin.cs | 10 ++++ .../Configs/RueConfigLoginCredentials.cs | 7 +++ .../UserOnPacketCheckPasswordFlipped.cs | 14 ++++++ .../Edelstein.Plugin.Rue.csproj | 3 ++ .../UserOnPacketCheckPasswordAutoLoginPlug.cs | 32 ++++++++++++ .../UserOnPacketCheckPasswordFlippedPlug.cs | 36 +++++++++++++ ...ketCreateSecurityHandleAutoRegisterPlug.cs | 40 +++++++++++++++ .../Edelstein.Plugin.Rue/RueGamePlugin.cs | 9 ++-- .../Edelstein.Plugin.Rue/RueLoginPlugin.cs | 50 +++++++++++++++++++ .../Edelstein.Plugin.Rue/appsettings.json | 7 +++ .../Contexts/GameContext.cs | 1 + .../Contexts/LoginContext.cs | 1 + .../Contexts/LoginContextPipelines.cs | 1 + .../UserOnPacketCreateSecurityHandle.cs | 5 ++ .../ILoginStageOptions.cs | 4 -- 20 files changed, 235 insertions(+), 38 deletions(-) create mode 100644 src/common/Edelstein.Common.Gameplay.Login/Handlers/CreateSecurityHandleHandler.cs create mode 100644 src/plugin/Edelstein.Plugin.Rue/Configs/RueConfigLogin.cs create mode 100644 src/plugin/Edelstein.Plugin.Rue/Configs/RueConfigLoginCredentials.cs create mode 100644 src/plugin/Edelstein.Plugin.Rue/Contracts/UserOnPacketCheckPasswordFlipped.cs create mode 100644 src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordAutoLoginPlug.cs create mode 100644 src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordFlippedPlug.cs create mode 100644 src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCreateSecurityHandleAutoRegisterPlug.cs create mode 100644 src/plugin/Edelstein.Plugin.Rue/RueLoginPlugin.cs create mode 100644 src/protocol/Edelstein.Protocol.Gameplay.Login/Contracts/UserOnPacketCreateSecurityHandle.cs diff --git a/src/app/Edelstein.Application.Server/Configs/ProgramConfigStageLogin.cs b/src/app/Edelstein.Application.Server/Configs/ProgramConfigStageLogin.cs index 4d0f032cc..f85c0a359 100644 --- a/src/app/Edelstein.Application.Server/Configs/ProgramConfigStageLogin.cs +++ b/src/app/Edelstein.Application.Server/Configs/ProgramConfigStageLogin.cs @@ -5,7 +5,4 @@ namespace Edelstein.Application.Server.Configs; public record ProgramConfigStageLogin : ProgramConfigStage, ILoginStageOptions { public byte[] Worlds { get; set; } - - public bool IsAutoRegister { get; set; } = true; - public bool IsFlippedUsername { get; set; } = false; } diff --git a/src/app/Edelstein.Application.Server/appsettings.json b/src/app/Edelstein.Application.Server/appsettings.json index 42c32d289..ae3c2c998 100644 --- a/src/app/Edelstein.Application.Server/appsettings.json +++ b/src/app/Edelstein.Application.Server/appsettings.json @@ -8,9 +8,7 @@ "Worlds": [ 0, 1 - ], - "IsAutoRegister": true, - "IsFlippedUsername": false + ] } ], "GameStages": [ diff --git a/src/common/Edelstein.Common.Gameplay.Login/Handlers/CheckPasswordHandler.cs b/src/common/Edelstein.Common.Gameplay.Login/Handlers/CheckPasswordHandler.cs index 2b4a65782..167e66949 100644 --- a/src/common/Edelstein.Common.Gameplay.Login/Handlers/CheckPasswordHandler.cs +++ b/src/common/Edelstein.Common.Gameplay.Login/Handlers/CheckPasswordHandler.cs @@ -17,17 +17,9 @@ public CheckPasswordHandler(IPipeline pipeline) : bas public override bool Check(ILoginStageUser user) => user.State == LoginState.CheckPassword; public override UserOnPacketCheckPassword Serialize(ILoginStageUser user, IPacketReader reader) - { - var username = reader.ReadString(); - var password = reader.ReadString(); - - if (user.Context.Options.IsFlippedUsername) - (username, password) = (password, username); - - return new( + => new( user, - username, - password + reader.ReadString(), + reader.ReadString() ); - } } diff --git a/src/common/Edelstein.Common.Gameplay.Login/Handlers/CreateSecurityHandleHandler.cs b/src/common/Edelstein.Common.Gameplay.Login/Handlers/CreateSecurityHandleHandler.cs new file mode 100644 index 000000000..3cb91c1ec --- /dev/null +++ b/src/common/Edelstein.Common.Gameplay.Login/Handlers/CreateSecurityHandleHandler.cs @@ -0,0 +1,21 @@ +using Edelstein.Common.Gameplay.Packets; +using Edelstein.Protocol.Gameplay.Login.Contracts; +using Edelstein.Protocol.Gameplay.Login; +using Edelstein.Protocol.Utilities.Packets; +using Edelstein.Protocol.Utilities.Pipelines; + +namespace Edelstein.Common.Gameplay.Login.Handlers; + +public class CreateSecurityHandleHandler : AbstractPipedPacketHandler +{ + public CreateSecurityHandleHandler(IPipeline pipeline) : base(pipeline) + { + } + + public override short Operation => (short)PacketRecvOperations.CreateSecurityHandle; + + public override bool Check(ILoginStageUser user) => user.State == LoginState.CheckPassword; + + public override UserOnPacketCreateSecurityHandle? Serialize(ILoginStageUser user, IPacketReader reader) + => new(user); +} diff --git a/src/common/Edelstein.Common.Gameplay.Login/Plugs/UserOnPacketCheckPasswordPlug.cs b/src/common/Edelstein.Common.Gameplay.Login/Plugs/UserOnPacketCheckPasswordPlug.cs index b0d1c3015..a76af2a42 100644 --- a/src/common/Edelstein.Common.Gameplay.Login/Plugs/UserOnPacketCheckPasswordPlug.cs +++ b/src/common/Edelstein.Common.Gameplay.Login/Plugs/UserOnPacketCheckPasswordPlug.cs @@ -50,17 +50,6 @@ public async Task Handle(IPipelineContext ctx, UserOnPacketCheckPassword message _ => LoginResult.Unknown }; - if (message.User.Context.Options.IsAutoRegister && result == LoginResult.NotRegistered) - { - // TODO: Move autoregister this to plugin - result = LoginResult.Success; - await _auth.Register(new AuthRequest(message.Username, message.Password)); - _logger.LogInformation( - "Created new user {Username} with password {Password}", - message.Username, message.Password - ); - } - var account = await _repository.RetrieveByUsername(message.Username) ?? await _repository.Insert(new Account { Username = message.Username }); diff --git a/src/plugin/Edelstein.Plugin.Rue/Configs/RueConfigLogin.cs b/src/plugin/Edelstein.Plugin.Rue/Configs/RueConfigLogin.cs new file mode 100644 index 000000000..c42e17ab7 --- /dev/null +++ b/src/plugin/Edelstein.Plugin.Rue/Configs/RueConfigLogin.cs @@ -0,0 +1,10 @@ +namespace Edelstein.Plugin.Rue.Configs; + +public record RueConfigLogin +{ + public bool IsAutoRegister { get; set; } + public bool IsAutoLogin { get; set; } + public bool IsFlippedUsername { get; set; } + + public RueConfigLoginCredentials? LoginCredentials { get; set; } +} diff --git a/src/plugin/Edelstein.Plugin.Rue/Configs/RueConfigLoginCredentials.cs b/src/plugin/Edelstein.Plugin.Rue/Configs/RueConfigLoginCredentials.cs new file mode 100644 index 000000000..b8a8a3ee0 --- /dev/null +++ b/src/plugin/Edelstein.Plugin.Rue/Configs/RueConfigLoginCredentials.cs @@ -0,0 +1,7 @@ +namespace Edelstein.Plugin.Rue.Configs; + +public record RueConfigLoginCredentials +{ + public string Username { get; set; } + public string Password { get; set; } +} diff --git a/src/plugin/Edelstein.Plugin.Rue/Contracts/UserOnPacketCheckPasswordFlipped.cs b/src/plugin/Edelstein.Plugin.Rue/Contracts/UserOnPacketCheckPasswordFlipped.cs new file mode 100644 index 000000000..502c6a26e --- /dev/null +++ b/src/plugin/Edelstein.Plugin.Rue/Contracts/UserOnPacketCheckPasswordFlipped.cs @@ -0,0 +1,14 @@ +using Edelstein.Protocol.Gameplay.Login; +using Edelstein.Protocol.Gameplay.Login.Contracts; + +namespace Edelstein.Plugin.Rue.Contracts; + +public record UserOnPacketCheckPasswordFlipped( + ILoginStageUser User, + string Username, + string Password +) : UserOnPacketCheckPassword( + User, + Username, + Password +); diff --git a/src/plugin/Edelstein.Plugin.Rue/Edelstein.Plugin.Rue.csproj b/src/plugin/Edelstein.Plugin.Rue/Edelstein.Plugin.Rue.csproj index d24f689d9..b17d9275f 100644 --- a/src/plugin/Edelstein.Plugin.Rue/Edelstein.Plugin.Rue.csproj +++ b/src/plugin/Edelstein.Plugin.Rue/Edelstein.Plugin.Rue.csproj @@ -4,13 +4,16 @@ + + + diff --git a/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordAutoLoginPlug.cs b/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordAutoLoginPlug.cs new file mode 100644 index 000000000..868e738ec --- /dev/null +++ b/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordAutoLoginPlug.cs @@ -0,0 +1,32 @@ +using Edelstein.Plugin.Rue.Configs; +using Edelstein.Protocol.Gameplay.Login.Contexts; +using Edelstein.Protocol.Gameplay.Login.Contracts; +using Edelstein.Protocol.Services.Auth.Contracts; +using Edelstein.Protocol.Utilities.Pipelines; +using Microsoft.Extensions.Logging; + +namespace Edelstein.Plugin.Rue.Plugs; + +public class UserOnPacketCheckPasswordAutoLoginPlug : IPipelinePlug +{ + private readonly ILogger? _logger; + private readonly RueConfigLogin? _config; + private readonly LoginContext _context; + + public UserOnPacketCheckPasswordAutoLoginPlug(ILogger? logger, RueConfigLogin? config, LoginContext context) + { + _logger = logger; + _config = config; + _context = context; + } + + public async Task Handle(IPipelineContext ctx, UserOnPacketCheckPassword message) + { + if ((_config?.IsAutoRegister ?? false) && + (await _context.Services.Auth.Login(new AuthRequest(message.Username, message.Password))).Result == AuthResult.FailedInvalidUsername) + { + await _context.Services.Auth.Register(new AuthRequest(message.Username, message.Password)); + _logger?.LogInformation("Created new user {Username} with password {Password}", message.Username, message.Password); + } + } +} diff --git a/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordFlippedPlug.cs b/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordFlippedPlug.cs new file mode 100644 index 000000000..bb1a897b0 --- /dev/null +++ b/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCheckPasswordFlippedPlug.cs @@ -0,0 +1,36 @@ +using Edelstein.Plugin.Rue.Configs; +using Edelstein.Plugin.Rue.Contracts; +using Edelstein.Protocol.Gameplay.Login.Contexts; +using Edelstein.Protocol.Gameplay.Login.Contracts; +using Edelstein.Protocol.Services.Auth.Contracts; +using Edelstein.Protocol.Utilities.Pipelines; +using Microsoft.Extensions.Logging; + +namespace Edelstein.Plugin.Rue.Plugs; + +public class UserOnPacketCheckPasswordFlippedPlug : IPipelinePlug +{ + private readonly ILogger? _logger; + private readonly RueConfigLogin? _config; + private readonly LoginContext _context; + + public UserOnPacketCheckPasswordFlippedPlug(ILogger? logger, RueConfigLogin? config, LoginContext context) + { + _logger = logger; + _config = config; + _context = context; + } + + public async Task Handle(IPipelineContext ctx, UserOnPacketCheckPassword message) + { + if ((_config?.IsFlippedUsername ?? false) && message is not UserOnPacketCheckPasswordFlipped) + { + await _context.Pipelines.UserOnPacketCheckPassword.Process(new UserOnPacketCheckPasswordFlipped( + message.User, + message.Password, + message.Username + )); + ctx.Cancel(); + } + } +} diff --git a/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCreateSecurityHandleAutoRegisterPlug.cs b/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCreateSecurityHandleAutoRegisterPlug.cs new file mode 100644 index 000000000..2c35ff888 --- /dev/null +++ b/src/plugin/Edelstein.Plugin.Rue/Plugs/UserOnPacketCreateSecurityHandleAutoRegisterPlug.cs @@ -0,0 +1,40 @@ +using Edelstein.Plugin.Rue.Configs; +using Edelstein.Plugin.Rue.Contracts; +using Edelstein.Protocol.Gameplay.Game.Contexts; +using Edelstein.Protocol.Gameplay.Login.Contexts; +using Edelstein.Protocol.Gameplay.Login.Contracts; +using Edelstein.Protocol.Utilities.Pipelines; +using Microsoft.Extensions.Logging; + +namespace Edelstein.Plugin.Rue.Plugs; + +public class UserOnPacketCreateSecurityHandleAutoRegisterPlug : IPipelinePlug +{ + private readonly ILogger? _logger; + private readonly RueConfigLogin? _config; + private readonly LoginContext _context; + + public UserOnPacketCreateSecurityHandleAutoRegisterPlug(ILogger? logger, RueConfigLogin? config, LoginContext context) + { + _logger = logger; + _config = config; + _context = context; + } + + public async Task Handle(IPipelineContext ctx, UserOnPacketCreateSecurityHandle message) + { + if ((_config?.IsAutoLogin ?? false) && _config.LoginCredentials is { Username: not null, Password: not null }) + { + _logger?.LogInformation( + "Logging in user {Username} with password {Password}", + _config.LoginCredentials.Username, _config.LoginCredentials.Password + ); + + await _context.Pipelines.UserOnPacketCheckPassword.Process(new UserOnPacketCheckPasswordFlipped( + message.User, + _config.LoginCredentials.Username, + _config.LoginCredentials.Password + )); + } + } +} diff --git a/src/plugin/Edelstein.Plugin.Rue/RueGamePlugin.cs b/src/plugin/Edelstein.Plugin.Rue/RueGamePlugin.cs index 65780c26f..db3242237 100644 --- a/src/plugin/Edelstein.Plugin.Rue/RueGamePlugin.cs +++ b/src/plugin/Edelstein.Plugin.Rue/RueGamePlugin.cs @@ -12,7 +12,7 @@ namespace Edelstein.Plugin.Rue; public class RueGamePlugin : IGamePlugin { - public string ID => "Rue"; + public string ID => "RueGame"; private ILogger? Logger { get; set; } public Task OnInit(IPluginHost host, GameContext ctx) @@ -48,15 +48,12 @@ public Task OnStart(IPluginHost host, GameContext ctx) commandManager.Insert(new StatCommand()); commandManager.Insert(new TemporaryStatCommand()); commandManager.Insert(new MobTemporaryStatCommand()); - commandManager.Insert(new DebugCommand()); ctx.Pipelines.FieldOnPacketUserChat.Add(PipelinePriority.High, new FieldOnPacketUserChatCommandPlug(commandManager)); return Task.CompletedTask; } - + public Task OnStop() - { - return Task.CompletedTask; - } + => Task.CompletedTask; } diff --git a/src/plugin/Edelstein.Plugin.Rue/RueLoginPlugin.cs b/src/plugin/Edelstein.Plugin.Rue/RueLoginPlugin.cs new file mode 100644 index 000000000..f85185bfd --- /dev/null +++ b/src/plugin/Edelstein.Plugin.Rue/RueLoginPlugin.cs @@ -0,0 +1,50 @@ +using Edelstein.Plugin.Rue.Configs; +using Edelstein.Plugin.Rue.Plugs; +using Edelstein.Protocol.Gameplay.Login.Contexts; +using Edelstein.Protocol.Plugin; +using Edelstein.Protocol.Plugin.Login; +using Edelstein.Protocol.Utilities.Pipelines; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; + +namespace Edelstein.Plugin.Rue; + +public class RueLoginPlugin : ILoginPlugin +{ + public string ID => "RueLogin"; + + private ILogger? Logger { get; set; } + private RueConfigLogin? Config { get; set; } + + public Task OnInit(IPluginHost host, LoginContext ctx) + { + Logger = host.Logger; + Config = new RueConfigLogin(); + return Task.CompletedTask; + } + + public Task OnStart(IPluginHost host, LoginContext ctx) + { + host.Config.Bind(Config); + + ctx.Pipelines.UserOnPacketCreateSecurityHandle.Add(PipelinePriority.High, new UserOnPacketCreateSecurityHandleAutoRegisterPlug( + Logger, + Config, + ctx + )); + ctx.Pipelines.UserOnPacketCheckPassword.Add(PipelinePriority.High, new UserOnPacketCheckPasswordAutoLoginPlug( + Logger, + Config, + ctx + )); + ctx.Pipelines.UserOnPacketCheckPassword.Add(PipelinePriority.Highest, new UserOnPacketCheckPasswordFlippedPlug( + Logger, + Config, + ctx + )); + return Task.CompletedTask; + } + + public Task OnStop() + => Task.CompletedTask; +} diff --git a/src/plugin/Edelstein.Plugin.Rue/appsettings.json b/src/plugin/Edelstein.Plugin.Rue/appsettings.json index 077404aaa..6f514891e 100644 --- a/src/plugin/Edelstein.Plugin.Rue/appsettings.json +++ b/src/plugin/Edelstein.Plugin.Rue/appsettings.json @@ -1,3 +1,10 @@ { + "IsAutoRegister": true, + "IsAutoLogin": false, + "IsFlippedUsername": false, + "LoginCredentials": { + "Username": "username", + "Password": "password" + } } \ No newline at end of file diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Game/Contexts/GameContext.cs b/src/protocol/Edelstein.Protocol.Gameplay.Game/Contexts/GameContext.cs index 587858223..8122f61de 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay.Game/Contexts/GameContext.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay.Game/Contexts/GameContext.cs @@ -1,6 +1,7 @@ namespace Edelstein.Protocol.Gameplay.Game.Contexts; public record GameContext( + IGameStage Stage, IGameStageOptions Options, GameContextManagers Managers, GameContextServices Services, diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Login/Contexts/LoginContext.cs b/src/protocol/Edelstein.Protocol.Gameplay.Login/Contexts/LoginContext.cs index b64f98983..b285aab3b 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay.Login/Contexts/LoginContext.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay.Login/Contexts/LoginContext.cs @@ -1,6 +1,7 @@ namespace Edelstein.Protocol.Gameplay.Login.Contexts; public record LoginContext( + ILoginStage Stage, ILoginStageOptions Options, LoginContextManagers Managers, LoginContextServices Services, diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Login/Contexts/LoginContextPipelines.cs b/src/protocol/Edelstein.Protocol.Gameplay.Login/Contexts/LoginContextPipelines.cs index 449db4160..15a152a86 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay.Login/Contexts/LoginContextPipelines.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay.Login/Contexts/LoginContextPipelines.cs @@ -12,6 +12,7 @@ public record LoginContextPipelines( IPipeline> UserOnException, IPipeline> UserOnDisconnect, IPipeline> UserOnPacketAliveAck, + IPipeline UserOnPacketCreateSecurityHandle, IPipeline UserOnPacketCheckPassword, IPipeline UserOnPacketSelectWorld, IPipeline UserOnPacketCheckUserLimit, diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Login/Contracts/UserOnPacketCreateSecurityHandle.cs b/src/protocol/Edelstein.Protocol.Gameplay.Login/Contracts/UserOnPacketCreateSecurityHandle.cs new file mode 100644 index 000000000..90c3e24e5 --- /dev/null +++ b/src/protocol/Edelstein.Protocol.Gameplay.Login/Contracts/UserOnPacketCreateSecurityHandle.cs @@ -0,0 +1,5 @@ +namespace Edelstein.Protocol.Gameplay.Login.Contracts; + +public record UserOnPacketCreateSecurityHandle( + ILoginStageUser User +); diff --git a/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageOptions.cs b/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageOptions.cs index 7d9abc55a..b1525969f 100644 --- a/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageOptions.cs +++ b/src/protocol/Edelstein.Protocol.Gameplay.Login/ILoginStageOptions.cs @@ -5,8 +5,4 @@ namespace Edelstein.Protocol.Gameplay.Login; public interface ILoginStageOptions : IIdentifiable { byte[] Worlds { get; } - - // TODO move this to plugins - bool IsAutoRegister { get; } - bool IsFlippedUsername { get; } }