From ccad8db591129f5a9effb6469b477bb5c23ee229 Mon Sep 17 00:00:00 2001 From: Jake Mannens Date: Wed, 20 Sep 2023 11:45:46 +1000 Subject: Completed initial filter functionality --- Principal.cs | 7 ++--- Services/SecurityService.cs | 70 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/Principal.cs b/Principal.cs index d736bf2..18b82d0 100644 --- a/Principal.cs +++ b/Principal.cs @@ -4,13 +4,12 @@ namespace HyperBooru; [Index(nameof(Name))] public class HBPrincipal : HBObject { - public string Name { get; set; } + public string Name { get; set; } + public List MemberOf { get; set; } } public class User : HBPrincipal { public string PasswordHash { get; set; } } -public class Group : HBPrincipal { - public List Members { get; set; } -} \ No newline at end of file +public class Group : HBPrincipal {} \ No newline at end of file diff --git a/Services/SecurityService.cs b/Services/SecurityService.cs index 9695254..c8dafd5 100644 --- a/Services/SecurityService.cs +++ b/Services/SecurityService.cs @@ -1,11 +1,13 @@ using Microsoft.EntityFrameworkCore; +using System.Data; namespace HyperBooru.Services; public class SecurityService { private IDbContextFactory dbFactory; - private Acl[] acls; + private Group[] groups; + private Acl[] acls; public SecurityService(IDbContextFactory dbFactory) { this.dbFactory = dbFactory; @@ -14,16 +16,78 @@ public class SecurityService { public void Reload() { using var db = dbFactory.CreateDbContext(); + + groups = db.Groups + .Include(g => g.MemberOf) + .ToArray(); + acls = db.Acls .Include(a => a.Rules) .ThenInclude(r => r.Principal) .ToArray(); } - public IEnumerable Filter(IEnumerable objects, ulong permissions) { + public IEnumerable Filter( + IEnumerable objects, + HBPrincipal principal, + ulong permissions) { + foreach(var obj in objects) { + var perms = GetPermissions(obj.Acl, principal); + if((perms & permissions) == permissions) + yield return obj; + } + } + + public IEnumerable Filter( + IEnumerable objects, + HBPrincipal principal, + T permissions) where T : Enum => + Filter(objects, principal, permissions); + + private ulong GetPermissions(Acl? acl, HBPrincipal principal) { + if(acl is null) + return ulong.MaxValue; + + bool hasAllowRules = acl.Rules + .Any(r => r.Action == AclRuleAction.Allow); + + ulong permissions = hasAllowRules ? 0 : ulong.MaxValue; + + var principals = GetGroupMemberShip(principal) + .Cast() + .Concat(new[] { principal }) + .ToArray(); + + acl.Rules.IntersectBy(principals, r => r.Principal); + + foreach(var rule in acl.Rules) { + if(!principals.Contains(rule.Principal)) + continue; + + if(rule.Action == AclRuleAction.Allow) + permissions |= rule.Permissions; + else + permissions &= ~rule.Permissions; + } + + return permissions; + } + + private List GetGroupMemberShip(HBPrincipal principal) { + var groups = principal.MemberOf.ToList(); + + while(true) { + var toAdd = this.groups + .Where(g => !groups.Contains(g)) + .ToArray(); + + if(toAdd.Count() == 0) + break; + + groups.AddRange(toAdd); } - return Enumerable.Empty(); + return groups; } } -- cgit v1.3