From 19bd47d0f40b0672eece2d10d5396d5ba44a4ed7 Mon Sep 17 00:00:00 2001 From: RaidMax Date: Mon, 4 Apr 2022 22:16:40 -0500 Subject: [PATCH] initial permissions based webfront access implementation --- SharedLibraryCore/BaseController.cs | 9 +++- .../Configuration/ApplicationConfiguration.cs | 12 ++++- SharedLibraryCore/Utilities.cs | 39 ++++++++++++++ WebfrontCore/Controllers/ActionController.cs | 11 +++- .../Controllers/Client/ClientController.cs | 25 +++++---- WebfrontCore/Permissions/WebfrontEntity.cs | 15 ++++++ .../ProfileMetaListViewComponent.cs | 54 ++++++++++--------- .../Profile/Meta/_UpdatedAliasResponse.cshtml | 1 - 8 files changed, 125 insertions(+), 41 deletions(-) create mode 100644 WebfrontCore/Permissions/WebfrontEntity.cs diff --git a/SharedLibraryCore/BaseController.cs b/SharedLibraryCore/BaseController.cs index ef4c674ff..628fe11ab 100644 --- a/SharedLibraryCore/BaseController.cs +++ b/SharedLibraryCore/BaseController.cs @@ -30,6 +30,7 @@ namespace SharedLibraryCore private static string SocialTitle; protected readonly DatabaseContext Context; protected List Pages; + protected List PermissionsSet; public BaseController(IManager manager) { @@ -43,7 +44,6 @@ namespace SharedLibraryCore SocialTitle = AppConfig.SocialLinkTitle; } - Pages = Manager.GetPageList().Pages .Select(page => new Page { @@ -135,6 +135,11 @@ namespace SharedLibraryCore var claimsIdentity = new ClaimsIdentity(claims, "login"); SignInAsync(new ClaimsPrincipal(claimsIdentity)).Wait(); } + + if (AppConfig.PermissionSets.ContainsKey(Client.Level.ToString())) + { + PermissionsSet = AppConfig.PermissionSets[Client.Level.ToString()]; + } var communityName = AppConfig.CommunityInformation?.Name; var shouldUseCommunityName = !string.IsNullOrWhiteSpace(communityName) @@ -160,4 +165,4 @@ namespace SharedLibraryCore base.OnActionExecuting(context); } } -} \ No newline at end of file +} diff --git a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs index 83f3074b9..fecf191e7 100644 --- a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs +++ b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs @@ -115,7 +115,7 @@ namespace SharedLibraryCore.Configuration [LocalizedDisplayName("WEBFRONT_CONFIGURATION_ENABLE_COLOR_CODES")] public bool EnableColorCodes { get; set; } - + [ConfigurationIgnore] public string IngameAccentColorKey { get; set; } = "Cyan"; [LocalizedDisplayName("WEBFRONT_CONFIGURATION_AUTOMESSAGE_PERIOD")] @@ -144,6 +144,16 @@ namespace SharedLibraryCore.Configuration TimeSpan.FromDays(30) }; + public Dictionary> PermissionSets { get; set; } = new() + { + { Permission.Trusted.ToString(), new List { "*" } }, + { Permission.Moderator.ToString(), new List { "*" } }, + { Permission.Administrator.ToString(), new List { "*" } }, + { Permission.SeniorAdmin.ToString(), new List { "*" } }, + { Permission.Owner.ToString(), new List { "*" } }, + { Permission.Console.ToString(), new List { "*" } } + }; + [ConfigurationIgnore] [LocalizedDisplayName("WEBFRONT_CONFIGURATION_PRESET_BAN_REASONS")] public Dictionary PresetPenaltyReasons { get; set; } = new Dictionary diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index 4e37c29d0..e4b15f308 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -525,6 +525,45 @@ namespace SharedLibraryCore return new TimeSpan(1, 0, 0); } + public static bool HasPermission(this IEnumerable permissionsSet, TEntity entity, + TPermission permission) where TEntity : Enum where TPermission : Enum + { + return permissionsSet?.Any(raw => + { + if (raw == "*") + { + return true; + } + + var split = raw.Split("."); + + if (split.Length != 2) + { + return false; + } + + if (!Enum.TryParse(typeof(TEntity), split[0], out var e)) + { + return false; + } + + if (!Enum.TryParse(typeof(TPermission), split[1], out var p)) + { + return false; + } + + return (e?.Equals(entity) ?? false) && (p?.Equals(permission) ?? false); + }) ?? false; + } + + public static bool HasPermission(this ApplicationConfiguration appConfig, + Permission permissionLevel, TEntity entity, + TPermission permission) where TEntity : Enum where TPermission : Enum + { + return appConfig.PermissionSets.ContainsKey(permissionLevel.ToString()) && + HasPermission(appConfig.PermissionSets[permissionLevel.ToString()], entity, permission); + } + /// /// returns a list of penalty types that should be shown across all profiles /// diff --git a/WebfrontCore/Controllers/ActionController.cs b/WebfrontCore/Controllers/ActionController.cs index 8eb7fa755..c0d7241b6 100644 --- a/WebfrontCore/Controllers/ActionController.cs +++ b/WebfrontCore/Controllers/ActionController.cs @@ -10,6 +10,7 @@ using SharedLibraryCore; using SharedLibraryCore.Commands; using SharedLibraryCore.Configuration; using SharedLibraryCore.Interfaces; +using WebfrontCore.Permissions; using WebfrontCore.ViewModels; namespace WebfrontCore.Controllers @@ -314,6 +315,14 @@ namespace WebfrontCore.Controllers public async Task RecentClientsForm() { var clients = await Manager.GetClientService().GetRecentClients(); + foreach (var client in clients) + { + client.IPAddress = + _appConfig.HasPermission(Client.Level, WebfrontEntity.IPAddress, WebfrontPermission.Read) + ? client.IPAddress + : null; + } + return View("~/Views/Shared/Components/Client/_RecentClients.cshtml", clients); } @@ -453,4 +462,4 @@ namespace WebfrontCore.Controllers }) .ToDictionary(item => item.Value, item => item.Value); } -} \ No newline at end of file +} diff --git a/WebfrontCore/Controllers/Client/ClientController.cs b/WebfrontCore/Controllers/Client/ClientController.cs index 96f37ac39..9a80733bd 100644 --- a/WebfrontCore/Controllers/Client/ClientController.cs +++ b/WebfrontCore/Controllers/Client/ClientController.cs @@ -7,11 +7,13 @@ using SharedLibraryCore.Interfaces; using SharedLibraryCore.QueryHelper; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Threading; using System.Threading.Tasks; using Data.Models; using Stats.Config; +using WebfrontCore.Permissions; using WebfrontCore.ViewComponents; namespace WebfrontCore.Controllers @@ -79,7 +81,7 @@ namespace WebfrontCore.Controllers Level = displayLevel, LevelInt = displayLevelInt, ClientId = client.ClientId, - IPAddress = client.IPAddressString, + IPAddress = PermissionsSet.HasPermission(WebfrontEntity.IPAddress, WebfrontPermission.Read) ? client.IPAddressString : null, NetworkId = client.NetworkId, Meta = new List(), Aliases = client.AliasLink.Children @@ -90,13 +92,13 @@ namespace WebfrontCore.Controllers .Distinct() .OrderBy(a => a) .ToList(), - IPs = client.AliasLink.Children + IPs = PermissionsSet.HasPermission(WebfrontEntity.IPAddress, WebfrontPermission.Read) ? client.AliasLink.Children .Where(i => i.IPAddress != null) .OrderByDescending(i => i.DateAdded) .Select(i => i.IPAddress.ConvertIPtoString()) .Prepend(client.CurrentAlias.IPAddress.ConvertIPtoString()) .Distinct() - .ToList(), + .ToList() : new List(), HasActivePenalty = activePenalties.Any(_penalty => _penalty.Type != EFPenalty.PenaltyType.Flag), Online = Manager.GetActiveClients().FirstOrDefault(c => c.ClientId == client.ClientId) != null, TimeOnline = (DateTime.UtcNow - client.LastConnection).HumanizeForCurrentCulture(), @@ -191,7 +193,7 @@ namespace WebfrontCore.Controllers return View("Find/Index", clientsDto); } - public async Task Meta(int id, int count, int offset, long? startAt, MetaType? metaFilterType, CancellationToken token) + public IActionResult Meta(int id, int count, int offset, long? startAt, MetaType? metaFilterType, CancellationToken token) { var request = new ClientPaginationRequest { @@ -201,14 +203,15 @@ namespace WebfrontCore.Controllers Before = DateTime.FromFileTimeUtc(startAt ?? DateTime.UtcNow.ToFileTimeUtc()) }; - var meta = await ProfileMetaListViewComponent.GetClientMeta(_metaService, metaFilterType, Client.Level, request, token); - - if (!meta.Any()) + return ViewComponent(typeof(ProfileMetaListViewComponent), new { - return Ok(); - } - - return View("Components/ProfileMetaList/_List", meta); + clientId = request.ClientId, + count = request.Count, + offset = request.Offset, + startAt = request.Before, + metaType = metaFilterType, + token + }); } } } diff --git a/WebfrontCore/Permissions/WebfrontEntity.cs b/WebfrontCore/Permissions/WebfrontEntity.cs new file mode 100644 index 000000000..a7167b6c0 --- /dev/null +++ b/WebfrontCore/Permissions/WebfrontEntity.cs @@ -0,0 +1,15 @@ +namespace WebfrontCore.Permissions; + +public enum WebfrontEntity +{ + IPAddress, + MetaAliasUpdate +} + +public enum WebfrontPermission +{ + Read, + Create, + Update, + Delete +} diff --git a/WebfrontCore/ViewComponents/ProfileMetaListViewComponent.cs b/WebfrontCore/ViewComponents/ProfileMetaListViewComponent.cs index f6a24358c..a2fed6253 100644 --- a/WebfrontCore/ViewComponents/ProfileMetaListViewComponent.cs +++ b/WebfrontCore/ViewComponents/ProfileMetaListViewComponent.cs @@ -9,16 +9,21 @@ using System.Linq; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; +using SharedLibraryCore; +using SharedLibraryCore.Configuration; +using WebfrontCore.Permissions; namespace WebfrontCore.ViewComponents { public class ProfileMetaListViewComponent : ViewComponent { private readonly IMetaServiceV2 _metaService; + private readonly ApplicationConfiguration _appConfig; - public ProfileMetaListViewComponent(IMetaServiceV2 metaService) + public ProfileMetaListViewComponent(IMetaServiceV2 metaService, ApplicationConfiguration appConfig) { _metaService = metaService; + _appConfig = appConfig; } public async Task InvokeAsync(int clientId, int count, int offset, DateTime? startAt, MetaType? metaType, CancellationToken token) @@ -39,11 +44,16 @@ namespace WebfrontCore.ViewComponents return View("_List", meta); } - public static async Task> GetClientMeta(IMetaServiceV2 metaService, MetaType? metaType, + private async Task> GetClientMeta(IMetaServiceV2 metaService, MetaType? metaType, EFClient.Permission level, ClientPaginationRequest request, CancellationToken token) { IEnumerable meta = null; + if (!_appConfig.PermissionSets.TryGetValue(level.ToString(), out var permissionSet)) + { + permissionSet = new List(); + } + if (metaType is null or MetaType.All) { meta = await metaService.GetRuntimeMeta(request, token); @@ -51,30 +61,24 @@ namespace WebfrontCore.ViewComponents else { - switch (metaType) + meta = metaType switch { - case MetaType.Information: - meta = await metaService.GetRuntimeMeta(request, metaType.Value, token); - break; - case MetaType.AliasUpdate: - meta = await metaService.GetRuntimeMeta(request, metaType.Value, token); - break; - case MetaType.ChatMessage: - meta = await metaService.GetRuntimeMeta(request, metaType.Value, token); - break; - case MetaType.Penalized: - meta = await metaService.GetRuntimeMeta(request, metaType.Value, token); - break; - case MetaType.ReceivedPenalty: - meta = await metaService.GetRuntimeMeta(request, metaType.Value, token); - break; - case MetaType.ConnectionHistory: - meta = await metaService.GetRuntimeMeta(request, metaType.Value, token); - break; - case MetaType.PermissionLevel: - meta = await metaService.GetRuntimeMeta(request, metaType.Value, token); - break; - } + MetaType.Information => await metaService.GetRuntimeMeta(request, + metaType.Value, token), + MetaType.AliasUpdate => permissionSet.HasPermission(WebfrontEntity.MetaAliasUpdate, WebfrontPermission.Read) ? await metaService.GetRuntimeMeta(request, + metaType.Value, token) : new List(), + MetaType.ChatMessage => await metaService.GetRuntimeMeta(request, metaType.Value, + token), + MetaType.Penalized => await metaService.GetRuntimeMeta(request, + metaType.Value, token), + MetaType.ReceivedPenalty => await metaService.GetRuntimeMeta(request, + metaType.Value, token), + MetaType.ConnectionHistory => await metaService.GetRuntimeMeta(request, + metaType.Value, token), + MetaType.PermissionLevel => await metaService.GetRuntimeMeta( + request, metaType.Value, token), + _ => meta + }; } if (level < EFClient.Permission.Trusted) diff --git a/WebfrontCore/Views/Client/Profile/Meta/_UpdatedAliasResponse.cshtml b/WebfrontCore/Views/Client/Profile/Meta/_UpdatedAliasResponse.cshtml index e2feb2391..3eb7f4a76 100644 --- a/WebfrontCore/Views/Client/Profile/Meta/_UpdatedAliasResponse.cshtml +++ b/WebfrontCore/Views/Client/Profile/Meta/_UpdatedAliasResponse.cshtml @@ -1,5 +1,4 @@ @using SharedLibraryCore.Dtos.Meta.Responses -@using SharedLibraryCore @model UpdatedAliasResponse @foreach (var token in Utilities.SplitTranslationTokens("WEBFRONT_PROFILE_META_CONNECT_ALIAS"))