diff --git a/src/Gml.Core b/src/Gml.Core index 20fa9fc..3da3c8d 160000 --- a/src/Gml.Core +++ b/src/Gml.Core @@ -1 +1 @@ -Subproject commit 20fa9fc8826e1a687e11ca659611111d912603d1 +Subproject commit 3da3c8dae2d4213fab47afb24ddbc1004c5af81a diff --git a/src/Gml.Web.Api.Domains/Integrations/AzuriomAuthResult.cs b/src/Gml.Web.Api.Domains/Integrations/AzuriomAuthResult.cs index 548b7c0..5eb628d 100644 --- a/src/Gml.Web.Api.Domains/Integrations/AzuriomAuthResult.cs +++ b/src/Gml.Web.Api.Domains/Integrations/AzuriomAuthResult.cs @@ -18,7 +18,7 @@ public class AzuriomAuthResult public bool EmailVerified { get; set; } [JsonProperty("money")] - public int Money { get; set; } + public decimal Money { get; set; } [JsonProperty("banned")] public bool Banned { get; set; } diff --git a/src/Gml.Web.Api.Domains/Integrations/UnicoreAuthResult.cs b/src/Gml.Web.Api.Domains/Integrations/UnicoreAuthResult.cs index 62e453c..0dcb62b 100644 --- a/src/Gml.Web.Api.Domains/Integrations/UnicoreAuthResult.cs +++ b/src/Gml.Web.Api.Domains/Integrations/UnicoreAuthResult.cs @@ -60,10 +60,10 @@ public class User public string TwoFactorSecretTemp { get; set; } [JsonProperty("real")] - public int Real { get; set; } + public decimal Real { get; set; } [JsonProperty("virtual")] - public int Virtual { get; set; } + public decimal Virtual { get; set; } [JsonProperty("perms")] public object Perms { get; set; } diff --git a/src/Gml.Web.Api.Dto/Minecraft/AuthLib/Textures.cs b/src/Gml.Web.Api.Dto/Minecraft/AuthLib/Textures.cs index 354063e..89ba98c 100644 --- a/src/Gml.Web.Api.Dto/Minecraft/AuthLib/Textures.cs +++ b/src/Gml.Web.Api.Dto/Minecraft/AuthLib/Textures.cs @@ -4,7 +4,7 @@ namespace Gml.Web.Api.Dto.Minecraft.AuthLib; public class Textures { - [JsonProperty("SKIN")] public SkinCape Skin { get; set; } + [JsonProperty("SKIN", NullValueHandling = NullValueHandling.Ignore)] public SkinCape Skin { get; set; } [JsonProperty("CAPE", NullValueHandling = NullValueHandling.Ignore)] public SkinCape Cape { get; set; } } diff --git a/src/Gml.Web.Api.Dto/Player/AuthUserHistoryDto.cs b/src/Gml.Web.Api.Dto/Player/AuthUserHistoryDto.cs new file mode 100644 index 0000000..1c19cc4 --- /dev/null +++ b/src/Gml.Web.Api.Dto/Player/AuthUserHistoryDto.cs @@ -0,0 +1,12 @@ +using System; + +namespace Gml.Web.Api.Dto.Player; + +public class AuthUserHistoryDto +{ + public DateTime Date { get; set; } + public string Device { get; set; } + public string? Address { get; set; } + public string Protocol { get; set; } + public string? Hwid { get; set; } +} diff --git a/src/Gml.Web.Api.Dto/Player/ExtendedPlayerReadDto.cs b/src/Gml.Web.Api.Dto/Player/ExtendedPlayerReadDto.cs new file mode 100644 index 0000000..4003739 --- /dev/null +++ b/src/Gml.Web.Api.Dto/Player/ExtendedPlayerReadDto.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; + +namespace Gml.Web.Api.Dto.Player; + +public class ExtendedPlayerReadDto : PlayerReadDto +{ + public bool IsBanned { get; set; } + public List AuthHistory { get; set; } = new(); + public List ServerJoinHistory { get; set; } = new(); +} diff --git a/src/Gml.Web.Api.Dto/Player/PlayerReadDto.cs b/src/Gml.Web.Api.Dto/Player/PlayerReadDto.cs index e0ec5bd..ab0f1ca 100644 --- a/src/Gml.Web.Api.Dto/Player/PlayerReadDto.cs +++ b/src/Gml.Web.Api.Dto/Player/PlayerReadDto.cs @@ -4,8 +4,8 @@ namespace Gml.Web.Api.Dto.Player; public class PlayerReadDto : PlayerTextureDto { + public string Uuid { get; set; } public string Name { get; set; } = null!; public string AccessToken { get; set; } - public string Uuid { get; set; } public DateTime ExpiredDate { get; set; } } diff --git a/src/Gml.Web.Api.Dto/Player/ServerJoinHistoryDto.cs b/src/Gml.Web.Api.Dto/Player/ServerJoinHistoryDto.cs new file mode 100644 index 0000000..f8239e5 --- /dev/null +++ b/src/Gml.Web.Api.Dto/Player/ServerJoinHistoryDto.cs @@ -0,0 +1,9 @@ +using System; + +namespace Gml.Web.Api.Dto.Player; + +public record ServerJoinHistoryDto +{ + public string ServerUuid { get; set; } + public DateTime Date { get; set; } +} diff --git a/src/Gml.Web.Api.Dto/Profile/ProfileReadInfoDto.cs b/src/Gml.Web.Api.Dto/Profile/ProfileReadInfoDto.cs index e9b5c0f..813e80d 100644 --- a/src/Gml.Web.Api.Dto/Profile/ProfileReadInfoDto.cs +++ b/src/Gml.Web.Api.Dto/Profile/ProfileReadInfoDto.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Gml.Web.Api.Dto.Files; +using Gml.Web.Api.Dto.Player; using GmlCore.Interfaces.Enums; using GmlCore.Interfaces.System; @@ -15,7 +16,7 @@ public class ProfileReadInfoDto public string IconBase64 { get; set; } public string Description { get; set; } public string Arguments { get; set; } - public string IsEnabled { get; set; } + public bool IsEnabled { get; set; } public string JvmArguments { get; set; } public string GameArguments { get; set; } public bool HasUpdate { get; set; } @@ -23,5 +24,6 @@ public class ProfileReadInfoDto public List Files { get; set; } public List WhiteListFolders { get; set; } public List WhiteListFiles { get; set; } + public List UsersWhiteList { get; set; } public string Background { get; set; } } diff --git a/src/Gml.Web.Api/Core/Extensions/EndpointsExtensions.cs b/src/Gml.Web.Api/Core/Extensions/EndpointsExtensions.cs index 17eeb89..78830cb 100644 --- a/src/Gml.Web.Api/Core/Extensions/EndpointsExtensions.cs +++ b/src/Gml.Web.Api/Core/Extensions/EndpointsExtensions.cs @@ -12,6 +12,7 @@ using Gml.Web.Api.Dto.Settings; using Gml.Web.Api.Dto.User; using GmlCore.Interfaces.Notifications; +using GmlCore.Interfaces.User; namespace Gml.Web.Api.Core.Extensions; @@ -37,7 +38,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Integration/GitHub/Launcher") .Produces>>() .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/v1/integrations/github/launcher/download", GitHubIntegrationHandler.DownloadLauncher) .WithOpenApi(generatedOperation => @@ -49,7 +50,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Integration/GitHub/Launcher") .Produces>() .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/integrations/github/launcher/download/{version}", GitHubIntegrationHandler.ReturnLauncherSolution) @@ -61,17 +62,21 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Download launcher solution") .WithTags("Integration/GitHub/Launcher") .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion #region SignalR Hubs - app.MapHub("/ws/profiles/restore").RequireAuthorization(); - app.MapHub("/ws/launcher/build").RequireAuthorization(); - app.MapHub("/ws/gameServer").RequireAuthorization(); + app.MapHub("/ws/profiles/restore") + .RequireAuthorization(c => c.RequireRole("Admin")); + app.MapHub("/ws/launcher/build") + .RequireAuthorization(c => c.RequireRole("Admin")); + app.MapHub("/ws/gameServer") + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapHub("/ws/launcher").RequireAuthorization(); - app.MapHub("/ws/notifications").RequireAuthorization(); + app.MapHub("/ws/notifications") + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion @@ -139,7 +144,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Update dsn sentry service url") .WithTags("Integration/Sentry") .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/{projectId}/envelope", SentryHandler.CreateBugInfo) .WithOpenApi(generatedOperation => @@ -149,7 +154,8 @@ public static WebApplication RegisterEndpoints(this WebApplication app) }) .WithDescription("Добавление ошибок Sentry") .WithName("Get sentry message") - .WithTags("Integration/Sentry"); + .WithTags("Integration/Sentry") + .RequireAuthorization(c => c.RequireRole("Admin", "Player")); app.MapPost("/api/v1/sentry", SentryHandler.GetBugs) .WithOpenApi(generatedOperation => @@ -160,7 +166,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Получение всех ошибок Sentry") .WithName("Get all bugs sentry") .WithTags("Integration/Sentry") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/v1/sentry/filter", SentryHandler.GetFilterSentry) .WithOpenApi(generatedOperation => @@ -171,7 +177,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Получение отфильтрованного списка ошибок") .WithName("Get filtered bugs sentry") .WithTags("Integration/Sentry") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/v1/sentry/filter/list", SentryHandler.GetFilterListSentry) .WithOpenApi(generatedOperation => @@ -182,7 +188,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Получение отфильтрованного списка по ошибок") .WithName("Get filtered on bugs sentry") .WithTags("Integration/Sentry") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/sentry/stats/last", SentryHandler.GetLastSentryErrors) .WithOpenApi(generatedOperation => @@ -193,7 +199,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Получение списка ошибок за последние 3 месяца") .WithName("Get last bugs sentry") .WithTags("Integration/Sentry") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/sentry/stats/summary", SentryHandler.GetSummarySentryErrors) .WithOpenApi(generatedOperation => @@ -204,7 +210,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Получить сводку ошибок") .WithName("Get summary bugs sentry") .WithTags("Integration/Sentry") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/sentry/{exception}", SentryHandler.GetByException) .WithOpenApi(generatedOperation => @@ -215,7 +221,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Получение exception в Sentry") .WithName("Get exception on sentry") .WithTags("Integration/Sentry") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/sentry/bug/{id}", SentryHandler.GetBugId) .WithOpenApi(generatedOperation => @@ -226,7 +232,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Получение бага по Guid Sentry") .WithName("Get bug or id sentry") .WithTags("Integration/Sentry") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion @@ -253,7 +259,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Update discord RPC data") .WithTags("Integration/Discord") .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion @@ -280,7 +286,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Update skin texture url") .WithTags("Integration/Textures") .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/integrations/texture/skins/{textureGuid}", TextureIntegrationHandler.GetUserSkin) .WithOpenApi(generatedOperation => @@ -304,6 +310,17 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Integration/Textures") .Produces((int)HttpStatusCode.BadRequest); + app.MapGet("/api/v1/integrations/texture/head/{userUuid}", TextureIntegrationHandler.GetUserHead) + .WithOpenApi(generatedOperation => + { + generatedOperation.Summary = "Получение текстуры лица пользователя"; + return generatedOperation; + }) + .WithDescription("Получение текстуры лица пользователя") + .WithName("Get user head texture url") + .WithTags("Integration/Textures") + .Produces((int)HttpStatusCode.BadRequest); + app.MapGet("/api/v1/integrations/texture/cloaks", TextureIntegrationHandler.GetCloakUrl) .WithOpenApi(generatedOperation => { @@ -325,7 +342,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Update cloak texture url") .WithTags("Integration/Textures") .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/v1/integrations/texture/skins/load", TextureIntegrationHandler.UpdateUserSkin) .WithOpenApi(generatedOperation => @@ -462,7 +479,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Integration/Auth") .Produces() .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/integrations/auth", AuthIntegrationHandler.GetIntegrationServices) .WithOpenApi(generatedOperation => @@ -475,7 +492,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Integration/Auth") .Produces>>() .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/integrations/auth/active", AuthIntegrationHandler.GetAuthService) .WithOpenApi(generatedOperation => @@ -487,7 +504,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Get active auth service") .WithTags("Integration/Auth") .Produces>() - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapDelete("/api/v1/integrations/auth/active", AuthIntegrationHandler.RemoveAuthService) .WithOpenApi(generatedOperation => @@ -500,7 +517,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Integration/Auth") .Produces>() .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion @@ -511,14 +528,15 @@ public static WebApplication RegisterEndpoints(this WebApplication app) app.MapGet("/api/v1/profiles", ProfileHandler.GetProfiles) .WithOpenApi(generatedOperation => { - generatedOperation.Summary = "Получение списка профилилей"; + generatedOperation.Summary = "Получение списка профилей"; return generatedOperation; }) .WithDescription("Получение списка профиля") .WithName("Profiles list") .WithTags("Profiles") .Produces>>() - .Produces((int)HttpStatusCode.BadRequest); + .Produces((int)HttpStatusCode.BadRequest) + .RequireAuthorization(c => c.RequireRole("Player", "Admin")); app.MapGet("/api/v1/profiles/versions/{gameLoader}/{minecraftVersion}", ProfileHandler.GetMinecraftVersions) .WithOpenApi(generatedOperation => @@ -531,7 +549,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Profiles") .Produces>>() .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/v1/profiles", ProfileHandler.CreateProfile) .WithOpenApi(generatedOperation => @@ -545,7 +563,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .Produces>() .Produces((int)HttpStatusCode.NotFound) .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPut("/api/v1/profiles", ProfileHandler.UpdateProfile) .WithOpenApi(generatedOperation => @@ -559,7 +577,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .Produces>() .Produces((int)HttpStatusCode.NotFound) .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/v1/profiles/restore", ProfileHandler.RestoreProfile) .WithOpenApi(generatedOperation => @@ -572,7 +590,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Profiles") .Produces((int)HttpStatusCode.NotFound) .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapDelete("/api/v1/profiles/{profileNames}", ProfileHandler.RemoveProfile) .WithOpenApi(generatedOperation => @@ -585,7 +603,33 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Profiles") .Produces((int)HttpStatusCode.NotFound) .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); + + app.MapPost("/api/v1/profiles/{profileName}/players/whitelist/{userUuid}", ProfileHandler.AddPlayerToWhiteList) + .WithOpenApi(generatedOperation => + { + generatedOperation.Summary = "Добавление игрока в белый список профиля"; + return generatedOperation; + }) + .WithDescription("Добавление игрока в белый список профиля") + .WithName("Add users white list profile") + .WithTags("Profiles") + .Produces((int)HttpStatusCode.NotFound) + .Produces((int)HttpStatusCode.BadRequest) + .RequireAuthorization(c => c.RequireRole("Admin")); + + app.MapDelete("/api/v1/profiles/{profileName}/players/whitelist/{userUuid}", ProfileHandler.RemovePlayerFromWhiteList) + .WithOpenApi(generatedOperation => + { + generatedOperation.Summary = "Удаление игрока из белого списка профиля"; + return generatedOperation; + }) + .WithDescription("Удаление игрока из белого списка профиля") + .WithName("Remove user from profile white list") + .WithTags("Profiles") + .Produces((int)HttpStatusCode.NotFound) + .Produces((int)HttpStatusCode.BadRequest) + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/v1/profiles/info", ProfileHandler.GetProfileInfo) .WithOpenApi(generatedOperation => @@ -610,7 +654,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Profiles") .Produces>() .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/v1/profiles/compile", ProfileHandler.CompileProfile) .WithOpenApi(generatedOperation => @@ -623,7 +667,47 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Profiles") .Produces>() .Produces((int)HttpStatusCode.BadRequest) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); + + #endregion + + #region Players + + app.MapGet("/api/v1/players", PlayersHandler.GetPlayers) + .WithOpenApi(generatedOperation => + { + generatedOperation.Summary = "Получение списка игроков"; + return generatedOperation; + }) + .WithDescription("Получение списка игроков") + .WithName("Players list") + .WithTags("Players") + .Produces>>() + .Produces((int)HttpStatusCode.BadRequest); + + app.MapPost("/api/v1/players/ban", PlayersHandler.BanPlayer) + .WithOpenApi(generatedOperation => + { + generatedOperation.Summary = "Блокировка списка игроков"; + return generatedOperation; + }) + .WithDescription("Блокировка списка игроков") + .WithName("Ban players") + .WithTags("Players") + .Produces>>() + .Produces((int)HttpStatusCode.BadRequest); + + app.MapPost("/api/v1/players/pardon", PlayersHandler.PardonPlayer) + .WithOpenApi(generatedOperation => + { + generatedOperation.Summary = "Разблокировка списка игроков"; + return generatedOperation; + }) + .WithDescription("Разблокировка списка игроков") + .WithName("Pardon players") + .WithTags("Players") + .Produces>>() + .Produces((int)HttpStatusCode.BadRequest); #endregion @@ -650,7 +734,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Add file to white list") .WithTags("Files") .Produces((int)HttpStatusCode.NotFound) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapDelete("/api/v1/file/whiteList", FileHandler.RemoveFileWhiteList) .WithOpenApi(generatedOperation => @@ -662,7 +746,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Remove file from white list") .WithTags("Files") .Produces((int)HttpStatusCode.NotFound) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/v1/folder/whiteList", FileHandler.AddFolderWhiteList) .WithOpenApi(generatedOperation => @@ -674,7 +758,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Add folder to white list") .WithTags("Files") .Produces((int)HttpStatusCode.NotFound) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapDelete("/api/v1/folder/whiteList", FileHandler.RemoveFolderWhiteList) .WithOpenApi(generatedOperation => @@ -686,7 +770,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Remove folder from white list") .WithTags("Files") .Produces((int)HttpStatusCode.NotFound) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion @@ -703,7 +787,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithTags("Settings") .Produces>() .Produces((int)HttpStatusCode.NotFound) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPut("/api/v1/settings/platform", SettingsHandler.UpdateSettings) @@ -716,7 +800,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Update settings") .WithTags("Settings") .Produces((int)HttpStatusCode.NotFound) - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion @@ -732,7 +816,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Установка плагина в систему") .WithName("Install plugin") .WithTags("Plugins") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/plugins", PluginHandler.GetInstalledPlugins) @@ -745,7 +829,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Get installed plugin") .WithTags("Plugins") .Produces>() - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapDelete("/api/v1/plugins/{name}/{version}", PluginHandler.RemovePlugin) @@ -757,7 +841,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Удаление плагина из системы") .WithName("Remove plugin") .WithTags("Plugins") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion @@ -772,7 +856,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Загрузка новой версии лаунчера") .WithName("Upload launcher version") .WithTags("Launcher") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/launcher", LauncherUpdateHandler.GetActualVersion) .WithOpenApi(generatedOperation => @@ -793,7 +877,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Получение списка сборок") .WithName("Get launcher builds") .WithTags("Launcher") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapGet("/api/v1/launcher/platforms", LauncherUpdateHandler.GetPlatforms) .WithOpenApi(generatedOperation => @@ -804,7 +888,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Получение списка платформ для сборки") .WithName("Get launcher platforms") .WithTags("Launcher") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion @@ -820,7 +904,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Get profile game servers") .WithTags("MinecraftServers") .Produces>>() - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapPost("/api/v1/servers/{profileName}", ServersHandler.CreateServer) .WithOpenApi(generatedOperation => @@ -831,7 +915,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Создание сервера у профиля") .WithName("Create server to game profile") .WithTags("MinecraftServers") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapDelete("/api/v1/servers/{profileName}/{serverNamesString}", ServersHandler.RemoveServer) .WithOpenApi(generatedOperation => @@ -842,7 +926,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithDescription("Удаление сервера в игровом профиле") .WithName("Remove server from game profile") .WithTags("MinecraftServers") - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion @@ -858,7 +942,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Get profile notifications") .WithTags("Notifications") .Produces>>() - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); app.MapDelete("/api/v1/notifications", NotificationHandler.ClearNotification) .WithOpenApi(generatedOperation => @@ -870,7 +954,7 @@ public static WebApplication RegisterEndpoints(this WebApplication app) .WithName("Delete all notifications") .WithTags("Notifications") .Produces() - .RequireAuthorization(); + .RequireAuthorization(c => c.RequireRole("Admin")); #endregion diff --git a/src/Gml.Web.Api/Core/Handlers/AuthIntegrationHandler.cs b/src/Gml.Web.Api/Core/Handlers/AuthIntegrationHandler.cs index c14dc22..f971e30 100644 --- a/src/Gml.Web.Api/Core/Handlers/AuthIntegrationHandler.cs +++ b/src/Gml.Web.Api/Core/Handlers/AuthIntegrationHandler.cs @@ -60,6 +60,13 @@ public static async Task Auth( authResult.Uuid, context.Request.Headers["X-HWID"]); + if (player.IsBanned) + { + return Results.BadRequest(ResponseMessage.Create( + "Пользователь заблокирован!", + HttpStatusCode.BadRequest)); + } + await gmlManager.Profiles.CreateUserSessionAsync(null, player); player.TextureSkinUrl ??= (await gmlManager.Integrations.GetSkinServiceAsync()) @@ -116,6 +123,13 @@ public static async Task AuthWithToken( { var player = user; + if (player.IsBanned) + { + return Results.BadRequest(ResponseMessage.Create( + "Пользователь заблокирован!", + HttpStatusCode.BadRequest)); + } + player.TextureSkinUrl ??= (await gmlManager.Integrations.GetSkinServiceAsync()) .Replace("{userName}", player.Name) .Replace("{userUuid}", player.Uuid); diff --git a/src/Gml.Web.Api/Core/Handlers/IPlayersHandler.cs b/src/Gml.Web.Api/Core/Handlers/IPlayersHandler.cs new file mode 100644 index 0000000..5513e59 --- /dev/null +++ b/src/Gml.Web.Api/Core/Handlers/IPlayersHandler.cs @@ -0,0 +1,6 @@ +namespace Gml.Web.Api.Core.Handlers; + +public interface IPlayersHandler +{ + +} diff --git a/src/Gml.Web.Api/Core/Handlers/MinecraftHandler.cs b/src/Gml.Web.Api/Core/Handlers/MinecraftHandler.cs index deb42b3..10461fc 100644 --- a/src/Gml.Web.Api/Core/Handlers/MinecraftHandler.cs +++ b/src/Gml.Web.Api/Core/Handlers/MinecraftHandler.cs @@ -72,7 +72,7 @@ public static async Task HasJoined(HttpContext context, IGmlManager gml { var user = await gmlManager.Users.GetUserByName(userName); - if (user is null || string.IsNullOrEmpty(userName) || await gmlManager.Users.CanJoinToServer(user, serverId) == false) + if (user is null || string.IsNullOrEmpty(userName) || user.IsBanned || await gmlManager.Users.CanJoinToServer(user, serverId) == false) return Results.NoContent(); var profile = new Profile @@ -147,7 +147,7 @@ public static async Task GetProfile(HttpContext context, IGmlManager gm var user = await gmlManager.Users.GetUserByUuid(guidUuid); - if (user is null || string.IsNullOrEmpty(guidUuid)) return Results.NoContent(); + if (user is null || string.IsNullOrEmpty(guidUuid) || user.IsBanned) return Results.NoContent(); var profile = new Profile { diff --git a/src/Gml.Web.Api/Core/Handlers/PlayersHandler.cs b/src/Gml.Web.Api/Core/Handlers/PlayersHandler.cs new file mode 100644 index 0000000..13a8ead --- /dev/null +++ b/src/Gml.Web.Api/Core/Handlers/PlayersHandler.cs @@ -0,0 +1,64 @@ +using System.Net; +using AutoMapper; +using Gml.Web.Api.Dto.Messages; +using Gml.Web.Api.Dto.Player; +using GmlCore.Interfaces; + +namespace Gml.Web.Api.Core.Handlers; + +public class PlayersHandler : IPlayersHandler +{ + public static async Task GetPlayers(IGmlManager gmlManager, IMapper mapper, int? take, int? offset, string? findName) + { + var players = await gmlManager.Users.GetUsers(take ?? 20, offset ?? 0, findName ?? string.Empty); + + return Results.Ok(ResponseMessage.Create(mapper.Map>(players), "Список пользователей успешно получен", HttpStatusCode.OK)); + } + + public static async Task BanPlayer( + IGmlManager gmlManager, + IMapper mapper, + IList playerUuids, + bool deviceBlock = false) + { + if (!playerUuids.Any()) + { + return Results.BadRequest(ResponseMessage.Create("Не передан ни один пользователь для блокировки", + HttpStatusCode.BadRequest)); + } + + foreach (var playerUuid in playerUuids) + { + var player = await gmlManager.Users.GetUserByUuid(playerUuid); + + if (player is null) continue; + player.IsBanned = true; + await gmlManager.Users.UpdateUser(player); + } + + return Results.Ok(ResponseMessage.Create("Пользователь(и) успешно заблокированы", HttpStatusCode.OK)); + } + + public static async Task PardonPlayer( + IGmlManager gmlManager, + IMapper mapper, + IList playerUuids) + { + if (!playerUuids.Any()) + { + return Results.BadRequest(ResponseMessage.Create("Не передан ни один пользователь для блокировки", + HttpStatusCode.BadRequest)); + } + + foreach (var playerUuid in playerUuids) + { + var player = await gmlManager.Users.GetUserByUuid(playerUuid); + + if (player is null) continue; + player.IsBanned = false; + await gmlManager.Users.UpdateUser(player); + } + + return Results.Ok(ResponseMessage.Create("Пользователь(и) успешно разблокированы", HttpStatusCode.OK)); + } +} diff --git a/src/Gml.Web.Api/Core/Handlers/ProfileHandler.cs b/src/Gml.Web.Api/Core/Handlers/ProfileHandler.cs index b1a2073..f8d0491 100644 --- a/src/Gml.Web.Api/Core/Handlers/ProfileHandler.cs +++ b/src/Gml.Web.Api/Core/Handlers/ProfileHandler.cs @@ -10,6 +10,7 @@ using Gml.Web.Api.Domains.Exceptions; using Gml.Web.Api.Domains.System; using Gml.Web.Api.Dto.Messages; +using Gml.Web.Api.Dto.Player; using Gml.Web.Api.Dto.Profile; using GmlCore.Interfaces; using GmlCore.Interfaces.Enums; @@ -27,7 +28,36 @@ public static async Task GetProfiles( IMapper mapper, IGmlManager gmlManager) { - var profiles = await gmlManager.Profiles.GetProfiles(); + IEnumerable profiles = []; + + if (context.User.IsInRole("Player")) + { + var userName = context.User.Identity?.Name; + + if (string.IsNullOrEmpty(userName)) + { + return Results.BadRequest(ResponseMessage.Create("Не удалось идентифицировать пользователя", + HttpStatusCode.BadRequest)); + } + + var user = await gmlManager.Users.GetUserByName(userName); + + if (user is null) + { + return Results.BadRequest(ResponseMessage.Create("Не удалось идентифицировать пользователя", + HttpStatusCode.BadRequest)); + } + + profiles = (await gmlManager.Profiles.GetProfiles()) + .Where(c => + c is { IsEnabled: true, UserWhiteListGuid.Count: 0 } || + c.UserWhiteListGuid.Any(g => g.Equals(user.Uuid))); + + }else if (context.User.IsInRole("Admin")) + { + profiles = await gmlManager.Profiles.GetProfiles(); + } + var gameProfiles = profiles as IGameProfile[] ?? profiles.ToArray(); var dtoProfiles = mapper.Map(profiles); @@ -270,11 +300,14 @@ public static async Task GetProfileInfo( var user = await gmlManager.Users.GetUserByName(createInfoDto.UserName); - if (user is null || user.AccessToken != token) + if (user is null || user.AccessToken != token || user.IsBanned) { return Results.StatusCode(StatusCodes.Status403Forbidden); } + if (profile.UserWhiteListGuid.Count != 0 && !profile.UserWhiteListGuid.Any(c => c.Equals(user.Uuid, StringComparison.OrdinalIgnoreCase))) + return Results.Forbid(); + user.Manager = gmlManager; var profileInfo = await gmlManager.Profiles.GetProfileInfo(profile.Name, new StartupOptions @@ -341,11 +374,15 @@ public static async Task GetProfileDetails( MinimumRamMb = createInfoDto.RamSize, OsName = osName, OsArch = createInfoDto.OsArchitecture - },user); + }, user); + + var whiteListPlayers = await gmlManager.Users.GetUsers(profile.UserWhiteListGuid); var profileDto = mapper.Map(profileInfo); profileDto.Background = $"{context.Request.Scheme}://{context.Request.Host}/api/v1/file/{profile.BackgroundImageKey}"; + profileDto.IsEnabled = profile.IsEnabled; + profileDto.UsersWhiteList = mapper.Map>(whiteListPlayers); return Results.Ok(ResponseMessage.Create(profileDto, string.Empty, HttpStatusCode.OK)); } @@ -384,4 +421,63 @@ public static async Task RemoveProfile( return Results.Ok(ResponseMessage.Create(message, HttpStatusCode.OK)); } + + [Authorize] + public static async Task AddPlayerToWhiteList( + IGmlManager gmlManager, + IMapper mapper, + string profileName, + string userUuid) + { + var profile = await gmlManager.Profiles.GetProfile(profileName); + + if (profile is null) + return Results.NotFound(ResponseMessage.Create($"Профиль \"{profileName}\" не найден", + HttpStatusCode.NotFound)); + + var user = await gmlManager.Users.GetUserByUuid(userUuid); + + if (user is null) + return Results.NotFound(ResponseMessage.Create($"Пользователь с UUID: \"{userUuid}\" не найден", + HttpStatusCode.NotFound)); + + if (profile.UserWhiteListGuid.Any(c => c.Equals(userUuid))) + return Results.BadRequest(ResponseMessage.Create($"Пользователь с UUID: \"{userUuid}\" уже находится белом списке пользователей профиля", + HttpStatusCode.BadRequest)); + + profile.UserWhiteListGuid.Add(user.Uuid); + await gmlManager.Profiles.SaveProfiles(); + + var mappedUser = mapper.Map(user); + + return Results.Ok(ResponseMessage.Create(mappedUser, "Пользователь успешно добавлен в белый список профиля", HttpStatusCode.OK)); + } + + [Authorize] + public static async Task RemovePlayerFromWhiteList( + IGmlManager gmlManager, + string profileName, + string userUuid) + { + var profile = await gmlManager.Profiles.GetProfile(profileName); + + if (profile is null) + return Results.NotFound(ResponseMessage.Create($"Профиль \"{profileName}\" не найден", + HttpStatusCode.NotFound)); + + var user = await gmlManager.Users.GetUserByUuid(userUuid); + + if (user is null) + return Results.NotFound(ResponseMessage.Create($"Пользователь с UUID: \"{userUuid}\" не найден", + HttpStatusCode.NotFound)); + + if (!profile.UserWhiteListGuid.Any(c=> c.Equals(userUuid))) + return Results.BadRequest(ResponseMessage.Create($"Пользователь с UUID: \"{userUuid}\" не найден в белом списке пользователей профиля", + HttpStatusCode.BadRequest)); + + profile.UserWhiteListGuid.Remove(user.Uuid); + await gmlManager.Profiles.SaveProfiles(); + + return Results.Ok(ResponseMessage.Create("Пользователь успешно удален из белого списка профиля", HttpStatusCode.OK)); + } } diff --git a/src/Gml.Web.Api/Core/Handlers/TextureIntegrationHandler.cs b/src/Gml.Web.Api/Core/Handlers/TextureIntegrationHandler.cs index 03da34b..232f661 100644 --- a/src/Gml.Web.Api/Core/Handlers/TextureIntegrationHandler.cs +++ b/src/Gml.Web.Api/Core/Handlers/TextureIntegrationHandler.cs @@ -169,4 +169,15 @@ public static async Task GetUserCloak(IGmlManager gmlManager, string te return Results.Stream(await gmlManager.Users.GetCloak(user)); } + + public static async Task GetUserHead(IGmlManager gmlManager, string userUuid) + { + var user = await gmlManager.Users.GetUserByUuid(userUuid); + + if (user is null) + return Results.NotFound(ResponseMessage.Create($"Пользователь с UUID: \"{userUuid}\" не найден", + HttpStatusCode.NotFound)); + + return Results.Stream(await gmlManager.Users.GetHead(user).ConfigureAwait(false)); + } } diff --git a/src/Gml.Web.Api/Core/Hubs/Controllers/PlayersController.cs b/src/Gml.Web.Api/Core/Hubs/Controllers/PlayersController.cs index cff6469..ac37076 100644 --- a/src/Gml.Web.Api/Core/Hubs/Controllers/PlayersController.cs +++ b/src/Gml.Web.Api/Core/Hubs/Controllers/PlayersController.cs @@ -15,15 +15,12 @@ namespace Gml.Web.Api.Core.Hubs.Controllers; public class PlayersController : ConcurrentDictionary { private readonly IGmlManager _gmlManager; - private readonly HubEvents _hubEvents; public ConcurrentDictionary Timers = new(); - public ConcurrentDictionary Schedulers = new(); - public ConcurrentDictionary Servers = new(); - public ConcurrentDictionary LauncherConnections = new(); + public ConcurrentDictionary GameServersConnections = new(); + public ConcurrentDictionary LauncherInfos = new(); - public PlayersController(IGmlManager gmlManager, HubEvents hubEvents) + public PlayersController(IGmlManager gmlManager) { - _hubEvents = hubEvents; _gmlManager = gmlManager; } @@ -33,7 +30,7 @@ public async Task AddLauncherConnection(string connectionId, ISingleClientProxy var userName = contextUser.FindFirstValue(JwtRegisteredClaimNames.Name); if (!string.IsNullOrEmpty(userName) && await _gmlManager.Users.GetUserByName(userName) is AuthUser user) { - LauncherConnections.TryAdd(connectionId, new UserLauncherInfo + LauncherInfos.TryAdd(connectionId, new UserLauncherInfo { User = user, ExpiredDate = DateTimeOffset.Now.AddSeconds(30), @@ -45,7 +42,7 @@ public async Task AddLauncherConnection(string connectionId, ISingleClientProxy var timer = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(5)) .Subscribe(_ => { - if (!LauncherConnections.TryGetValue(connectionId, out var userInfo) + if (!LauncherInfos.TryGetValue(connectionId, out var userInfo) || DateTimeOffset.Now > userInfo.ExpiredDate) { RemoveLauncherConnection(connectionId); @@ -64,7 +61,7 @@ public async Task AddLauncherConnection(string connectionId, ISingleClientProxy public void RemoveLauncherConnection(string connectionId) { - if (LauncherConnections.TryRemove(connectionId, out var user)) + if (LauncherInfos.TryRemove(connectionId, out var user)) { // Останавливаем таймер для данного лаунчера if (Timers.TryRemove(connectionId, out var timer)) @@ -74,15 +71,15 @@ public void RemoveLauncherConnection(string connectionId) } Debug.WriteLine($"{user.User.Name} | {user.User.Uuid} | Disconnected"); - _hubEvents.KickUser.OnNext(user.User.Name); + _ = OnKickUser(user.User.Name, "Потеряно соединение с сервером"); } } public void ConfirmLauncherHash(string connectionId, string hash) { - if (LauncherConnections.TryGetValue(connectionId, out var user)) + if (LauncherInfos.TryGetValue(connectionId, out var user)) { - Debug.WriteLine($"{user.User.Name} | {user.User.Uuid} | Session active"); + Debug.WriteLine($"{user.User.Name} | {user.User.Uuid} | Session active | hash: {hash}"); user.ExpiredDate = DateTimeOffset.Now.AddSeconds(30); } } @@ -90,7 +87,7 @@ public void ConfirmLauncherHash(string connectionId, string hash) public bool GetLauncherConnection(string userName, out UserLauncherInfo? launcherInfo) { var userConnection = - LauncherConnections.FirstOrDefault(c => c.Value.User.Name == userName); + LauncherInfos.FirstOrDefault(c => c.Value.User.Name == userName); if (userConnection.Key is null) { @@ -98,6 +95,22 @@ public bool GetLauncherConnection(string userName, out UserLauncherInfo? launche return false; } - return LauncherConnections.TryGetValue(userConnection.Key, out launcherInfo); + return LauncherInfos.TryGetValue(userConnection.Key, out launcherInfo); + } + + internal async Task OnKickUser(string userName, string message) + { + foreach (var caller in GameServersConnections.Values) + { + try + { + await caller.SendAsync("KickUser", userName, message); + Debug.WriteLine($"User Kicked: {userName}"); + } + catch (Exception e) + { + Debug.WriteLine($"Ошибка при отправке сообщения на удаление: {e}"); + } + } } } diff --git a/src/Gml.Web.Api/Core/Hubs/GameServerHub.cs b/src/Gml.Web.Api/Core/Hubs/GameServerHub.cs index 462d5f3..a513dd4 100644 --- a/src/Gml.Web.Api/Core/Hubs/GameServerHub.cs +++ b/src/Gml.Web.Api/Core/Hubs/GameServerHub.cs @@ -7,55 +7,40 @@ namespace Gml.Web.Api.Core.Hubs; -public class GameServerHub : BaseHub +public class GameServerHub( + IGmlManager gmlManager, + PlayersController playerController, + HubEvents hubEvents) + : BaseHub { - private readonly IGmlManager _gmlManager; - private readonly PlayersController _playerController; - private readonly HubEvents _hubEvents; - - public GameServerHub( - IGmlManager gmlManager, - PlayersController playerController, - HubEvents hubEvents) - { - _gmlManager = gmlManager; - _hubEvents = hubEvents; - _playerController = playerController; - - hubEvents.KickUser.Subscribe(async userName => await KickUser(userName)); - } - public override Task OnConnectedAsync() { - _playerController.Servers.TryAdd(Context.ConnectionId, Clients.Caller); + playerController.GameServersConnections.TryAdd(Context.ConnectionId, Clients.Caller); return base.OnConnectedAsync(); } public override Task OnDisconnectedAsync(Exception? exception) { - _playerController.Servers.TryRemove(Context.ConnectionId, out _); + playerController.GameServersConnections.TryRemove(Context.ConnectionId, out _); return base.OnDisconnectedAsync(exception); } - private async Task KickUser(string userName) - { - await KickUser(userName, "Не удалось идентифицировать пользователя. Перезапустите игру вместе с лаунчером!"); - } + public async Task OnJoin(string userName) { try { - if (!_playerController.GetLauncherConnection(userName, out var launcherInfo) || launcherInfo!.ExpiredDate < DateTimeOffset.Now) + if (!playerController.GetLauncherConnection(userName, out var launcherInfo) || launcherInfo!.ExpiredDate < DateTimeOffset.Now) { - await KickUser(userName); + hubEvents.KickUser.OnNext((userName, "Не удалось идентифицировать пользователя. Перезапустите игру вместе с лаунчером!")); return; } Debug.WriteLine($"OnJoin: {userName}; ExpiredTime: {launcherInfo.ExpiredDate - DateTimeOffset.Now:g}"); - var user = await _gmlManager.Users.GetUserByName(userName); + var user = await gmlManager.Users.GetUserByName(userName); if (user is null) { @@ -63,41 +48,25 @@ public async Task OnJoin(string userName) return; } - await _gmlManager.Users.StartSession(user); + await gmlManager.Users.StartSession(user); } catch (Exception e) { - await KickUser(userName, "Произошла ошибка при попытке подключения к серверу"); + hubEvents.KickUser.OnNext((userName, "Произошла ошибка при попытке подключения к серверу")); Console.WriteLine(e); } } - private async Task KickUser(string userName, string message) - { - foreach (var caller in _playerController.Servers.Values) - { - try - { - await caller.SendAsync("KickUser", userName, message); - Debug.WriteLine($"User Kicked: {userName}"); - } - catch (Exception e) - { - Debug.WriteLine($"Ошибка при отправке сообщения на удаление: {e}"); - } - } - } - public async Task OnLeft(string userName) { try { - if (!_playerController.GetLauncherConnection(userName, out var launcherInfo) || launcherInfo!.ExpiredDate < DateTimeOffset.Now) + if (!playerController.GetLauncherConnection(userName, out var launcherInfo) || launcherInfo!.ExpiredDate < DateTimeOffset.Now) { return; } - var user = await _gmlManager.Users.GetUserByName(userName); + var user = await gmlManager.Users.GetUserByName(userName); if (user is null) { @@ -106,11 +75,11 @@ public async Task OnLeft(string userName) } Debug.WriteLine($"OnLeft: {userName}"); - await _gmlManager.Users.EndSession(user); + await gmlManager.Users.EndSession(user); } catch (Exception e) { - await KickUser(userName, "Произошла ошибка при попытке подключения к серверу"); + hubEvents.KickUser.OnNext((userName, "Произошла ошибка при попытке подключения к серверу")); Console.WriteLine(e); } diff --git a/src/Gml.Web.Api/Core/Hubs/HubEvents.cs b/src/Gml.Web.Api/Core/Hubs/HubEvents.cs index 1daa54b..efde2bf 100644 --- a/src/Gml.Web.Api/Core/Hubs/HubEvents.cs +++ b/src/Gml.Web.Api/Core/Hubs/HubEvents.cs @@ -1,8 +1,25 @@ +using System.Diagnostics; using System.Reactive.Subjects; +using Gml.Web.Api.Core.Hubs.Controllers; namespace Gml.Web.Api.Core.Hubs; public class HubEvents { - public ISubject KickUser { get; } = new Subject(); + public Subject<(string UserName, string Reason)> KickUser { get; } = new(); + + public HubEvents(PlayersController playersController) + { + KickUser.Subscribe(async void (user) => + { + try + { + await playersController.OnKickUser(user.UserName, user.Reason); + } + catch (Exception e) + { + //ToDo Add Sentry Log + } + }); + } } diff --git a/src/Gml.Web.Api/Core/Hubs/LauncherHub.cs b/src/Gml.Web.Api/Core/Hubs/LauncherHub.cs index ad55629..9663390 100644 --- a/src/Gml.Web.Api/Core/Hubs/LauncherHub.cs +++ b/src/Gml.Web.Api/Core/Hubs/LauncherHub.cs @@ -26,7 +26,7 @@ public LauncherHub( _profilesChangedEvent ??= gmlManager.Profiles.ProfilesChanged.Subscribe(eventType => { - foreach (var connection in _playerController.LauncherConnections.Values.Select(c => c.Connection).OfType()) + foreach (var connection in _playerController.LauncherInfos.Values.Select(c => c.Connection).OfType()) { connection?.SendAsync("RefreshProfiles"); } diff --git a/src/Gml.Web.Api/Core/MappingProfiles/PlayerMapper.cs b/src/Gml.Web.Api/Core/MappingProfiles/PlayerMapper.cs index ee99066..ce59b8a 100644 --- a/src/Gml.Web.Api/Core/MappingProfiles/PlayerMapper.cs +++ b/src/Gml.Web.Api/Core/MappingProfiles/PlayerMapper.cs @@ -9,6 +9,9 @@ public class PlayerMapper : Profile public PlayerMapper() { CreateMap(); + CreateMap(); CreateMap(); + CreateMap(); + CreateMap(); } } diff --git a/src/Gml.Web.Api/Core/Middlewares/PluginMiddleware.cs b/src/Gml.Web.Api/Core/Middlewares/PluginMiddleware.cs index bdaa52a..aff90e6 100644 --- a/src/Gml.Web.Api/Core/Middlewares/PluginMiddleware.cs +++ b/src/Gml.Web.Api/Core/Middlewares/PluginMiddleware.cs @@ -1,10 +1,12 @@ using System.Diagnostics; +using System.Net; using System.Reactive.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Loader; using Gml.Web.Api.Core.Services; +using Gml.Web.Api.Dto.Messages; using Gml.Web.Api.EndpointSDK; using GmlCore.Interfaces; using Spectre.Console; @@ -26,24 +28,32 @@ public PluginMiddleware(RequestDelegate next, AccessTokenService accessTokenServ public async Task Invoke(HttpContext context) { - var reference = await Process(context); - - if (reference is null) + try { - return; - } + var reference = await Process(context); - if (!context.Response.HasStarted) - { - await _next(context); - } + if (reference is null) + { + return; + } - for (int i = 0; i < 10 && reference.IsAlive; i++) - { - GC.Collect(); - GC.WaitForPendingFinalizers(); + if (!context.Response.HasStarted) + { + await _next(context); + } + + for (int i = 0; i < 10 && reference.IsAlive; i++) + { + GC.Collect(); + GC.WaitForPendingFinalizers(); - // Debug.WriteLine($"Clean GC: {i}/10"); + // Debug.WriteLine($"Clean GC: {i}/10"); + } + } + catch (Exception exeption) + { + _gmlManager.BugTracker.CaptureException(exeption); + await context.Response.WriteAsJsonAsync(ResponseMessage.Create("Сервер обработал принял запрос, но не смог его обработать", HttpStatusCode.UnprocessableContent)); } // Debug.WriteLine($"Unload successful: {!reference.IsAlive}"); diff --git a/src/Gml.Web.Api/Core/Middlewares/TestAuthenticationHandler.cs b/src/Gml.Web.Api/Core/Middlewares/TestAuthenticationHandler.cs index 65ddfd8..3c6a364 100644 --- a/src/Gml.Web.Api/Core/Middlewares/TestAuthenticationHandler.cs +++ b/src/Gml.Web.Api/Core/Middlewares/TestAuthenticationHandler.cs @@ -19,7 +19,7 @@ public TestAuthenticationHandler(IOptionsMonitor op protected override Task HandleAuthenticateAsync() { - var identity = new ClaimsIdentity(Array.Empty(), "Test"); + var identity = new ClaimsIdentity([new Claim(ClaimTypes.Role, "Admin")], "Test"); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, "TestScheme"); diff --git a/src/Gml.Web.Api/Core/Repositories/UserRepository.cs b/src/Gml.Web.Api/Core/Repositories/UserRepository.cs index c52f007..52dbec2 100644 --- a/src/Gml.Web.Api/Core/Repositories/UserRepository.cs +++ b/src/Gml.Web.Api/Core/Repositories/UserRepository.cs @@ -70,7 +70,11 @@ private string GetAccessToken(string userId) var tokenHandler = new JwtSecurityTokenHandler(); var tokenDescriptor = new SecurityTokenDescriptor { - Subject = new ClaimsIdentity(new[] { new Claim("id", userId) }), + Subject = new ClaimsIdentity(new[] + { + new Claim("id", userId), + new Claim(ClaimTypes.Role, "Admin"), + }), Expires = DateTime.UtcNow.AddDays(3), SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.SecurityKey)), diff --git a/src/Gml.Web.Api/Gml.Web.Api.csproj b/src/Gml.Web.Api/Gml.Web.Api.csproj index a2c3f13..7d1b703 100644 --- a/src/Gml.Web.Api/Gml.Web.Api.csproj +++ b/src/Gml.Web.Api/Gml.Web.Api.csproj @@ -142,6 +142,9 @@ ISentryHandler.cs + + IPlayersHandler.cs +