summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Mannens <jake@asger.xyz>2023-09-20 11:45:46 +1000
committerJake Mannens <jake@asger.xyz>2023-09-20 11:45:46 +1000
commitccad8db591129f5a9effb6469b477bb5c23ee229 (patch)
tree3eb9aa30261575280d7668e541bb334e1524e116
parentcb8179b5e5a8d5253d063ed607205f52643410fa (diff)
Completed initial filter functionality
-rw-r--r--Principal.cs7
-rw-r--r--Services/SecurityService.cs70
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<Group> MemberOf { get; set; }
}
public class User : HBPrincipal {
public string PasswordHash { get; set; }
}
-public class Group : HBPrincipal {
- public List<HBPrincipal> 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<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;
}
}