move ACL to Dict field

This commit is contained in:
evilchili 2025-10-07 23:30:23 -07:00
parent 2064890ea5
commit b395940d2d
2 changed files with 19 additions and 29 deletions

View File

@ -1,10 +1,9 @@
from __future__ import annotations from __future__ import annotations
from datetime import datetime from datetime import datetime
from functools import cache
from typing import List from typing import List
from grung.types import BackReference, Collection, DateTime, Field, Password, Pointer, Record, Timestamp from grung.types import BackReference, Collection, DateTime, Dict, Field, Password, Pointer, Record, Timestamp
from tinydb import where from tinydb import where
@ -27,7 +26,7 @@ class Page(Record):
Pointer("author", value_type=User), # The last user to touch the page. Pointer("author", value_type=User), # The last user to touch the page.
DateTime("created"), # When the page was created DateTime("created"), # When the page was created
Timestamp("last_modified"), # The last time the page was modified. Timestamp("last_modified"), # The last time the page was modified.
Collection("acl", Permissions), # The access control list Dict("acl"),
] ]
# fmt: on # fmt: on
@ -79,18 +78,17 @@ class Page(Record):
return page return page
return None return None
def set_permissions(self, entity: Entity, permissions: List) -> Record: def set_permissions(self, entity: Entity, permissions: List) -> str:
from ttfrog import app from ttfrog import app
app.check_state() app.check_state()
perms = app.db.save(Permissions(entity=entity, grants="".join(permissions))) perms = "".join(permissions)
self.acl = list(set(self.acl + [perms])) self.acl[entity.reference] = perms
app.db.save(self) app.db.save(self)
return perms return perms
@cache def get_acl_for_entity(self, entity) -> (str, str | None):
def get_acl_for_entity(self, entity) -> list:
""" """
Search upward through the page hierarchy looking for one with an ACL that either Search upward through the page hierarchy looking for one with an ACL that either
has a grant for the entity we care about, or at least one group in which the entity is a member. has a grant for the entity we care about, or at least one group in which the entity is a member.
@ -101,36 +99,29 @@ class Page(Record):
def find_acl(obj): def find_acl(obj):
if hasattr(obj, "acl"): if hasattr(obj, "acl"):
# examine each entry in the ACL and see if one refers to the entity we care about if entity.reference in obj.acl:
group_grants = [] return {entity.reference: obj.acl[entity.reference]}
for entry in obj.acl:
if type(entry) == str:
entry = app.db.Permissions.get(where("uid") == entry.split("::")[1], recurse=False)
# grants specific to the entity always take precedence group_grants = {}
if entry.entity.uid == entity.uid: for ref, grant in obj.acl.items():
return [entry] if ref.startswith("Group::"):
group = app.db.Group.get(where("uid") == ref.split("::")[1], recurse=False)
# keep track of grants to groups containing the entity if entity.reference in group.members:
elif entity.reference in getattr(entry.entity, "members", []): group_grants[ref] = grant
group_grants.append(entry)
# if we found group grants, return them
if group_grants: if group_grants:
return group_grants return group_grants
# no ACL on this object, so check its parent, if there is one if hasattr(obj, "parent"):
if not hasattr(obj, "parent"):
return []
return find_acl(obj.parent) return find_acl(obj.parent)
return {"": ""}
return find_acl(self) return find_acl(self)
class Entity(Page): class Entity(Page):
def has_permission(self, record: Record, requested: str) -> bool | None: def has_permission(self, record: Record, requested: str) -> bool | None:
for acl in record.get_acl_for_entity(self): for entity, grants in record.get_acl_for_entity(self).items():
if requested in acl.grants: if requested in grants:
return True return True
return False return False

View File

@ -58,7 +58,6 @@ def test_permissions(app):
# set to rw, no delete # set to rw, no delete
notes.set_permissions(players, [schema.Permissions.READ, schema.Permissions.WRITE]) notes.set_permissions(players, [schema.Permissions.READ, schema.Permissions.WRITE])
notes = app.db.Page.get(doc_id=notes.doc_id) notes = app.db.Page.get(doc_id=notes.doc_id)
assert players.can_read(notes) assert players.can_read(notes)
assert players.can_write(notes) assert players.can_write(notes)
assert not players.can_delete(notes) assert not players.can_delete(notes)