diff options
Diffstat (limited to 'Services/SecurityService.cs')
| -rw-r--r-- | Services/SecurityService.cs | 70 |
1 files changed, 67 insertions, 3 deletions
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<HBContext> dbFactory; - private Acl[] acls; + private Group[] groups; + private Acl[] acls; public SecurityService(IDbContextFactory<HBContext> 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<HBObject> Filter(IEnumerable<HBObject> objects, ulong permissions) { + public IEnumerable<HBObject> Filter( + IEnumerable<HBObject> 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<HBObject> Filter<T>( + IEnumerable<HBObject> 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<HBPrincipal>() + .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<Group> 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<HBObject>(); + return groups; } } |
