Skip to content

Commit

Permalink
Add auto login, auto register, and flipped username handling to Rue (#80
Browse files Browse the repository at this point in the history
)

* 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 <[email protected]>
  • Loading branch information
Bia10 and Kaioru authored Sep 30, 2023
1 parent 77fae74 commit 10ae287
Show file tree
Hide file tree
Showing 20 changed files with 235 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
4 changes: 1 addition & 3 deletions src/app/Edelstein.Application.Server/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
"Worlds": [
0,
1
],
"IsAutoRegister": true,
"IsFlippedUsername": false
]
}
],
"GameStages": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,9 @@ public CheckPasswordHandler(IPipeline<UserOnPacketCheckPassword> 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()
);
}
}
Original file line number Diff line number Diff line change
@@ -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<ILoginStageUser, UserOnPacketCreateSecurityHandle>
{
public CreateSecurityHandleHandler(IPipeline<UserOnPacketCreateSecurityHandle> 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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 });

Expand Down
10 changes: 10 additions & 0 deletions src/plugin/Edelstein.Plugin.Rue/Configs/RueConfigLogin.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Edelstein.Plugin.Rue.Configs;

public record RueConfigLoginCredentials
{
public string Username { get; set; }
public string Password { get; set; }
}
Original file line number Diff line number Diff line change
@@ -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
);
3 changes: 3 additions & 0 deletions src/plugin/Edelstein.Plugin.Rue/Edelstein.Plugin.Rue.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@

<ItemGroup>
<ProjectReference Include="..\..\common\Edelstein.Common.Gameplay.Game\Edelstein.Common.Gameplay.Game.csproj" />
<ProjectReference Include="..\..\common\Edelstein.Common.Gameplay.Login\Edelstein.Common.Gameplay.Login.csproj" />
<ProjectReference Include="..\..\common\Edelstein.Common.Gameplay\Edelstein.Common.Gameplay.csproj" />
<ProjectReference Include="..\..\common\Edelstein.Common.Utilities\Edelstein.Common.Utilities.csproj" />
<ProjectReference Include="..\..\protocol\Edelstein.Protocol.Plugin.Game\Edelstein.Protocol.Plugin.Game.csproj" />
<ProjectReference Include="..\..\protocol\Edelstein.Protocol.Plugin.Login\Edelstein.Protocol.Plugin.Login.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="DotNet.Glob" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
<PackageReference Include="PowerArgs" Version="4.0.2" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -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<UserOnPacketCheckPassword>
{
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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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<UserOnPacketCheckPassword>
{
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();
}
}
}
Original file line number Diff line number Diff line change
@@ -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<UserOnPacketCreateSecurityHandle>
{
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
));
}
}
}
9 changes: 3 additions & 6 deletions src/plugin/Edelstein.Plugin.Rue/RueGamePlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<GameContext> host, GameContext ctx)
Expand Down Expand Up @@ -48,15 +48,12 @@ public Task OnStart(IPluginHost<GameContext> 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;
}
50 changes: 50 additions & 0 deletions src/plugin/Edelstein.Plugin.Rue/RueLoginPlugin.cs
Original file line number Diff line number Diff line change
@@ -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<LoginContext> host, LoginContext ctx)
{
Logger = host.Logger;
Config = new RueConfigLogin();
return Task.CompletedTask;
}

public Task OnStart(IPluginHost<LoginContext> 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;
}
7 changes: 7 additions & 0 deletions src/plugin/Edelstein.Plugin.Rue/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
{
"IsAutoRegister": true,
"IsAutoLogin": false,
"IsFlippedUsername": false,

"LoginCredentials": {
"Username": "username",
"Password": "password"
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Edelstein.Protocol.Gameplay.Game.Contexts;

public record GameContext(
IGameStage Stage,
IGameStageOptions Options,
GameContextManagers Managers,
GameContextServices Services,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace Edelstein.Protocol.Gameplay.Login.Contexts;

public record LoginContext(
ILoginStage Stage,
ILoginStageOptions Options,
LoginContextManagers Managers,
LoginContextServices Services,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public record LoginContextPipelines(
IPipeline<UserOnException<ILoginStageUser>> UserOnException,
IPipeline<UserOnDisconnect<ILoginStageUser>> UserOnDisconnect,
IPipeline<UserOnPacketAliveAck<ILoginStageUser>> UserOnPacketAliveAck,
IPipeline<UserOnPacketCreateSecurityHandle> UserOnPacketCreateSecurityHandle,
IPipeline<UserOnPacketCheckPassword> UserOnPacketCheckPassword,
IPipeline<UserOnPacketSelectWorld> UserOnPacketSelectWorld,
IPipeline<UserOnPacketCheckUserLimit> UserOnPacketCheckUserLimit,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Edelstein.Protocol.Gameplay.Login.Contracts;

public record UserOnPacketCreateSecurityHandle(
ILoginStageUser User
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,4 @@ namespace Edelstein.Protocol.Gameplay.Login;
public interface ILoginStageOptions : IIdentifiable<string>
{
byte[] Worlds { get; }

// TODO move this to plugins
bool IsAutoRegister { get; }
bool IsFlippedUsername { get; }
}

0 comments on commit 10ae287

Please sign in to comment.