finish migration to Pilz.NET

This commit is contained in:
Schedel Pascal
2024-08-23 11:18:46 +02:00
parent 90283ff5df
commit 4cd52de441
10 changed files with 103 additions and 110 deletions

View File

@@ -1,6 +1,6 @@
namespace OwnChar.Server.Api.Endpoint; namespace OwnChar.Server.Api.Endpoint;
internal class CharactersApi(IServer server) : IApiEndpoint internal class CharactersApi(IOwnCharServer server) : IApiEndpoint
{ {
public void Initialize(IApiBuilder builder) public void Initialize(IApiBuilder builder)
{ {

View File

@@ -1,44 +1,33 @@
using OwnChar.Api.Packets; using OwnChar.Api.Packets.General;
using OwnChar.Api.Packets.General;
using OwnChar.Api.Packets.Groups; using OwnChar.Api.Packets.Groups;
using OwnChar.Api.Updates; using OwnChar.Api.Updates;
using OwnChar.Data; using OwnChar.Data;
using OwnChar.Data.Model.Client; using OwnChar.Data.Model.Client;
using OwnChar.Server.Data.Model; using OwnChar.Server.Data.Model;
using OwnChar.Server.Extensions; using OwnChar.Server.Extensions;
using Pilz.Net.Api;
namespace OwnChar.Server.Api.Endpoint; namespace OwnChar.Server.Api.Endpoint;
internal class GroupsApi(IServer server) : IApiEndpoint internal class GroupsApi(IOwnCharServer server)
{ {
public void Initialize(IApiBuilder builder) [MessageHandler("/group/get/byid")]
public ApiResult GetById(GetSinlgeObjectRequest request, ApiRequestInfo info)
{ {
builder.Map("/groups/get/byid", GetById); if (!server.CheckLogin(info, UserType.Guest, out UserAccountDb? user))
builder.Map("/groups/get", Get); return ApiResult.Unauthorized();
builder.Map("/groups/create", Create);
builder.Map("/groups/update", Update);
builder.Map("/groups/delete", Delete);
builder.Map("/groups/members/get", GetMembers);
builder.Map("/groups/members/add", AddMembers);
builder.Map("/groups/members/update", UpdateMember);
builder.Map("/groups/members/remove", RemoveMembers);
}
private IResult GetById(GetSinlgeObjectRequest request)
{
if (!server.CheckLogin(request, UserType.Guest, out UserAccountDb? user))
return TypedResults.Unauthorized();
if (server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.ObjectId && n.Members.Any(m => m.User != null && m.User.Id == user.Id)) is not GroupDb group) if (server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.ObjectId && n.Members.Any(m => m.User != null && m.User.Id == user.Id)) is not GroupDb group)
return TypedResults.Ok(new GetSingleObjectResponse<Group>(null).With(OwnCharResponseError.NotFound)); return ApiResult.NotFound();
return TypedResults.Ok(new GetSingleObjectResponse<Group>(group.ToClient())); return ApiResult.Ok(new GetSingleObjectResponse<Group>(group.ToClient()));
} }
private IResult Get(GetGroupsRequest request) [MessageHandler("/group/get", RequiesAuth = true)]
public ApiResult Get(GetGroupsRequest request, ApiRequestInfo info)
{ {
if (!server.CheckLogin(request, UserType.Guest, out UserAccountDb? user)) if (!server.CheckLogin(info, UserType.Guest, out UserAccountDb? user))
return TypedResults.Unauthorized(); return ApiResult.Unauthorized();
IQueryable<GroupDb> groups; IQueryable<GroupDb> groups;
@@ -49,13 +38,14 @@ internal class GroupsApi(IServer server) : IApiEndpoint
else else
groups = Array.Empty<GroupDb>().AsQueryable(); // Currently not supported. groups = Array.Empty<GroupDb>().AsQueryable(); // Currently not supported.
return TypedResults.Ok(new GetGroupsResponse([.. groups.Select(g => g.ToClient())])); return ApiResult.Ok(new GetGroupsResponse([.. groups.Select(g => g.ToClient())]));
} }
private IResult Create(CreateGroupRequest request) [MessageHandler("/group/create", RequiesAuth = true)]
public ApiResult Create(CreateGroupRequest request, ApiRequestInfo info)
{ {
if (!server.CheckLogin(request, UserType.User, out UserAccountDb? user)) if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user))
return TypedResults.Unauthorized(); return ApiResult.Unauthorized();
var group = new GroupDb(); var group = new GroupDb();
@@ -71,19 +61,20 @@ internal class GroupsApi(IServer server) : IApiEndpoint
server.Data!.Update(group); server.Data!.Update(group);
server.Data.SaveChanges(); server.Data.SaveChanges();
return TypedResults.Ok(new CreateGroupResponse(group.ToClient())); return ApiResult.Ok(new CreateGroupResponse(group.ToClient()));
} }
private IResult Update(UpdateRequest request) [MessageHandler("/group/update", RequiesAuth = true)]
public ApiResult Update(UpdateRequest request, ApiRequestInfo info)
{ {
if (!server.CheckLogin(request, UserType.User, out UserAccountDb? user) if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.Update.Id) is not GroupDb group || server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.Update.Id) is not GroupDb group
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin || !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin
|| user.IsNot(UserType.Admin))) || user.IsNot(UserType.Admin)))
return TypedResults.Unauthorized(); return ApiResult.Unauthorized();
if (request.Update is not GroupUpdate update) if (request.Update is not GroupUpdate update)
return TypedResults.Ok(new UpdateResponse().With(OwnCharResponseError.Default)); return ApiResult.NotFound();
group.Name = update.Name; group.Name = update.Name;
group.Fandom = update.Fandom; group.Fandom = update.Fandom;
@@ -91,42 +82,45 @@ internal class GroupsApi(IServer server) : IApiEndpoint
server.Data.Update(group); server.Data.Update(group);
server.Data.SaveChanges(); server.Data.SaveChanges();
return TypedResults.Ok(new UpdateResponse()); return ApiResult.Ok();
} }
private IResult Delete(DeleteObjectRequest request) [MessageHandler("/group/delete", RequiesAuth = true)]
public ApiResult Delete(DeleteObjectRequest request, ApiRequestInfo info)
{ {
if (!server.CheckLogin(request, UserType.User, out UserAccountDb? user) if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.ObjectId) is not GroupDb group || server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.ObjectId) is not GroupDb group
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Owner) || !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Owner)
|| user.IsNot(UserType.Admin)) || user.IsNot(UserType.Admin))
return TypedResults.Unauthorized(); return ApiResult.Unauthorized();
server.Data.Remove(group); server.Data.Remove(group);
server.Data.SaveChanges(); server.Data.SaveChanges();
return TypedResults.Ok(new DeleteObjectResponse()); return ApiResult.Ok();
} }
private IResult GetMembers(GetGroupMembersRequest request) [MessageHandler("/group/members/get", RequiesAuth = true)]
public ApiResult GetMembers(GetGroupMembersRequest request, ApiRequestInfo info)
{ {
if (!server.CheckLogin(request, UserType.User, out UserAccountDb? user) if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.GroupId) is not GroupDb group || server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.GroupId) is not GroupDb group
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Member) || !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Member)
|| user.IsNot(UserType.Admin)) || user.IsNot(UserType.Admin))
return TypedResults.Unauthorized(); return ApiResult.Unauthorized();
var members = group.Members.Select(n => n.ToClient()); var members = group.Members.Select(n => n.ToClient());
return TypedResults.Ok(new GetGroupMembersResponse(members.ToList())); return ApiResult.Ok(new GetGroupMembersResponse(members.ToList()));
} }
private IResult AddMembers(GroupMemberAddRequest request) [MessageHandler("/group/members/add", RequiesAuth = true)]
public ApiResult AddMembers(GroupMemberAddRequest request, ApiRequestInfo info)
{ {
if (!server.CheckLogin(request, UserType.User, out UserAccountDb? user) if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.GroupId) is not GroupDb group || server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.GroupId) is not GroupDb group
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin) || !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin)
|| user.IsNot(UserType.Admin)) || user.IsNot(UserType.Admin))
return TypedResults.Unauthorized(); return ApiResult.Unauthorized();
var addedMembers = new List<MemberEntryDb>(); var addedMembers = new List<MemberEntryDb>();
@@ -146,43 +140,45 @@ internal class GroupsApi(IServer server) : IApiEndpoint
} }
} }
return TypedResults.Ok(new GroupMemberAddResponse(addedMembers.Select(m => m.ToClient()).ToList())); return ApiResult.Ok(new GroupMemberAddResponse(addedMembers.Select(m => m.ToClient()).ToList()));
} }
private IResult UpdateMember(UpdateRequest request) [MessageHandler("/group/members/update", RequiesAuth = true)]
public ApiResult UpdateMember(UpdateRequest request, ApiRequestInfo info)
{ {
if (!server.CheckLogin(request, UserType.User, out UserAccountDb? user) if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.Update.Id) is not GroupDb group || server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Id == request.Update.Id) is not GroupDb group
|| group.Members.FirstOrDefault(m => m.Id == request.Update.Id) is not MemberEntryDb member || group.Members.FirstOrDefault(m => m.Id == request.Update.Id) is not MemberEntryDb member
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin || !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin
|| user.IsNot(UserType.Admin))) || user.IsNot(UserType.Admin)))
return TypedResults.Unauthorized(); return ApiResult.Unauthorized();
if (request.Update is not MemberUpdate update) if (request.Update is not MemberUpdate update)
return TypedResults.Ok(new UpdateResponse().With(OwnCharResponseError.Default)); return ApiResult.NotFound();
member.Level = update.Level; member.Level = update.Level;
server.Data.Update(member); server.Data.Update(member);
server.Data.SaveChanges(); server.Data.SaveChanges();
return TypedResults.Ok(new UpdateResponse()); return ApiResult.Ok();
} }
private IResult RemoveMembers(DeleteObjectRequest request) [MessageHandler("/group/members/remove", RequiesAuth = true)]
public ApiResult RemoveMembers(DeleteObjectRequest request, ApiRequestInfo info)
{ {
if (!server.CheckLogin(request, UserType.User, out UserAccountDb? user) if (!server.CheckLogin(info, UserType.User, out UserAccountDb? user)
|| server.Data?.Set<MemberEntryDb>().FirstOrDefault(m => m.Id == request.ObjectId) is not MemberEntryDb member || server.Data?.Set<MemberEntryDb>().FirstOrDefault(m => m.Id == request.ObjectId) is not MemberEntryDb member
|| server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Members.Contains(member)) is not GroupDb group || server.Data?.Set<GroupDb>().FirstOrDefault(n => n.Members.Contains(member)) is not GroupDb group
|| !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin || !group.Members.Any(m => m.Id == user.Profile!.Id && m.Level >= MemberLevel.Admin
|| user.IsNot(UserType.Admin))) || user.IsNot(UserType.Admin)))
return TypedResults.Unauthorized(); return ApiResult.Unauthorized();
group.Members.Remove(member); group.Members.Remove(member);
server.Data.Remove(member); server.Data.Remove(member);
server.Data.Update(group); server.Data.Update(group);
server.Data.SaveChanges(); server.Data.SaveChanges();
return TypedResults.Ok(new DeleteObjectResponse()); return ApiResult.Ok();
} }
} }

View File

@@ -1,6 +0,0 @@
namespace OwnChar.Server.Api.Endpoint;
internal interface IApiEndpoint
{
void Initialize(IApiBuilder builder);
}

View File

@@ -2,41 +2,29 @@
using OwnChar.Api.Packets.General; using OwnChar.Api.Packets.General;
using OwnChar.Server.Data.Model; using OwnChar.Server.Data.Model;
using OwnChar.Server.Extensions; using OwnChar.Server.Extensions;
using Pilz.Net.Api;
namespace OwnChar.Server.Api.Endpoint; namespace OwnChar.Server.Api.Endpoint;
internal class LoginApi(ServerContext server) : IApiEndpoint internal class LoginApi(ServerContext server)
{ {
public void Initialize(IApiBuilder builder) [MessageHandler("/auth/login")]
public ApiResult Login(LoginRequest request, ApiRequestInfo info)
{ {
builder.Map("/auth/login", Login); if (server.Data?.Set<UserAccountDb>()?.FirstOrDefault(n => n.Username == request.Username && n.Password == request.Password) is UserAccountDb acc && acc.Profile != null)
builder.Map("/auth/logout", Logout); {
if (info.IsAuthenticated)
server.Logout(info.AuthKey);
return ApiResult.Ok(new LoginResponse(acc.ToClient(), acc.Profile.ToClient(), server.Login(acc)));
}
return ApiResult.NotFound();
} }
private IResult Login(LoginRequest request) [MessageHandler("/auth/logout")]
public ApiResult Logout(ApiRequestInfo info)
{ {
LoginResponse? result; if (info.IsAuthenticated)
server.Logout(info.AuthKey);
if (server.Data != null return ApiResult.Ok();
&& server.Data.Set<UserAccountDb>()?.FirstOrDefault(n => n.Username == request.Username && n.Password == request.Password) is UserAccountDb acc
&& acc.Profile != null)
{
result = new(acc.ToClient(), acc.Profile.ToClient(), server.Login(acc));
}
else
{
result = new(null, null, null)
{
ErrorCode = OwnCharResponseError.NotFound,
};
}
return TypedResults.Ok(result);
}
private IResult Logout(LogoutRequest request)
{
server.Logout(request.AuthSecret);
return TypedResults.Ok(new LogoutResponse());
} }
} }

View File

@@ -1,6 +1,6 @@
namespace OwnChar.Server.Api.Endpoint; namespace OwnChar.Server.Api.Endpoint;
internal class UsersApi(IServer server) : IApiEndpoint internal class UsersApi(IOwnCharServer server) : IApiEndpoint
{ {
public void Initialize(IApiBuilder builder) public void Initialize(IApiBuilder builder)
{ {

View File

@@ -6,7 +6,7 @@ using System.Diagnostics.CodeAnalysis;
namespace OwnChar.Server.Api; namespace OwnChar.Server.Api;
public interface IServer : IApiServer public interface IOwnCharServer : IApiServer
{ {
ISettings Settings { get; } ISettings Settings { get; }
DbContext? Data { get; } DbContext? Data { get; }

View File

@@ -1,5 +1,4 @@
using OwnChar.Server.Api.Endpoint; using Pilz.Plugins.Advanced;
using Pilz.Plugins.Advanced;
namespace OwnChar.Server.Api.Plugins; namespace OwnChar.Server.Api.Plugins;
@@ -7,5 +6,5 @@ public abstract class ApiEndpointFeature(string identifier) : PluginFeature(Feat
{ {
public static string FeatureType => "ownchar.server.apiep"; public static string FeatureType => "ownchar.server.apiep";
public abstract void OnServerInit(IServer init); public abstract void OnServerInit(IOwnCharServer init);
} }

View File

@@ -3,7 +3,7 @@ using OwnChar.Server.Api;
namespace OwnChar.Server.Api.Plugins; namespace OwnChar.Server.Api.Plugins;
public class OwnCharServerPluginInitParams(IServer server) : OwnCharPluginInitParams public class OwnCharServerPluginInitParams(IOwnCharServer server) : OwnCharPluginInitParams
{ {
public IServer Server { get; } = server; public IOwnCharServer Server { get; } = server;
} }

View File

@@ -3,31 +3,40 @@ using OwnChar.Data;
using OwnChar.Data.Model.Base; using OwnChar.Data.Model.Base;
using OwnChar.Server.Api; using OwnChar.Server.Api;
using OwnChar.Server.Data.Model; using OwnChar.Server.Data.Model;
using Pilz.Net.Api;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
namespace OwnChar.Server.Extensions; namespace OwnChar.Server.Extensions;
public static class GeneralExtensions public static class GeneralExtensions
{ {
public static bool CheckLogin(this IServer server, OwnCharRequest request, UserType userType) public static bool CheckLogin(this IOwnCharServer server, ApiRequestInfo request, UserType userType)
{ {
if (server.Data is null if (server.Data is null
|| string.IsNullOrWhiteSpace(request.Username) || !request.IsAuthenticated
|| string.IsNullOrWhiteSpace(request.AuthSecret) || request.AuthKey.Split(":") is not string[] authKey
|| !server.IsLoggedIn(request.AuthSecret) || authKey.ElementAtOrDefault(0) is not string username
|| server.GetUser(request.AuthSecret) is not UserAccountBase usr || authKey.ElementAtOrDefault(1) is not string secret
|| string.IsNullOrWhiteSpace(username)
|| string.IsNullOrWhiteSpace(secret)
|| !server.IsLoggedIn(secret)
|| server.GetUser(secret) is not UserAccountBase usr
|| usr.Type < userType) || usr.Type < userType)
return false; return false;
return true; return true;
} }
public static bool CheckLogin(this IServer server, OwnCharRequest request, UserType userType, [NotNullWhen(true)] out UserAccountDb? user) public static bool CheckLogin(this IOwnCharServer server, ApiRequestInfo request, UserType userType, [NotNullWhen(true)] out UserAccountDb? user)
{ {
if (server.Data is null if (server.Data is null
|| string.IsNullOrWhiteSpace(request.Username) || !request.IsAuthenticated
|| string.IsNullOrWhiteSpace(request.AuthSecret) || request.AuthKey.Split(":") is not string[] authKey
|| !server.IsLoggedIn(request.AuthSecret) || authKey.ElementAtOrDefault(0) is not string username
|| server.GetUser(request.AuthSecret) is not UserAccountDb usr || authKey.ElementAtOrDefault(1) is not string secret
|| string.IsNullOrWhiteSpace(username)
|| string.IsNullOrWhiteSpace(secret)
|| !server.IsLoggedIn(secret)
|| server.GetUser(secret) is not UserAccountDb usr
|| usr.Type < userType) || usr.Type < userType)
{ {
user = null; user = null;

View File

@@ -12,7 +12,7 @@ using Pilz.Plugins.Advanced;
namespace OwnChar.Server; namespace OwnChar.Server;
internal class ServerContext(ISettings settings) : ApiServer(settings.Get<ServerSettings>().ApiUrl!), IServer internal class ServerContext(ISettings settings) : ApiServer(settings.Get<ServerSettings>().ApiUrl!), IOwnCharServer
{ {
private readonly Dictionary<string, UserAccountBase> users = []; private readonly Dictionary<string, UserAccountBase> users = [];
@@ -47,12 +47,19 @@ internal class ServerContext(ISettings settings) : ApiServer(settings.Get<Server
protected override string? DecodeAuthKey(string authKey) protected override string? DecodeAuthKey(string authKey)
{ {
return base.DecodeAuthKey(new SecureString(authKey, true)); if (!string.IsNullOrWhiteSpace(authKey))
return new SecureString(authKey, true).Value;
return authKey;
} }
protected override bool CheckAuthentication(string authKey) protected override bool CheckAuthentication(string authKey)
{ {
return base.CheckAuthentication(authKey) || IsLoggedIn(authKey); return string.IsNullOrWhiteSpace(authKey)
|| authKey.Split(":") is not string[] authKeyParts
|| authKey.Length != 2
|| string.IsNullOrWhiteSpace(authKeyParts[0])
|| string.IsNullOrWhiteSpace(authKeyParts[1])
|| !IsLoggedIn(authKeyParts[1]);
} }
public string Login(UserAccountBase account) public string Login(UserAccountBase account)