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

View File

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