Files
SaraView/Backend/Locks.py
T

106 lines
2.8 KiB
Python

from __future__ import annotations
import tomllib
from typing import Any
import tomli_w
from fastapi import HTTPException
from Settings import GetDataDirectory
def GetLocksPath():
return GetDataDirectory() / "LockedDirectories.toml"
def LoadLocks() -> list[dict[str, Any]]:
LocksPath = GetLocksPath()
if not LocksPath.is_file():
return []
with LocksPath.open("rb") as LocksFile:
Loaded = tomllib.load(LocksFile)
return Loaded.get("Locks", [])
def SaveLocks(Locks: list[dict[str, Any]]) -> None:
GetDataDirectory().mkdir(parents=True, exist_ok=True)
with GetLocksPath().open("wb") as LocksFile:
tomli_w.dump({"Locks": Locks}, LocksFile)
def GetLockForPath(RootName: str, RelativePath: str) -> dict[str, Any] | None:
for Lock in LoadLocks():
if Lock.get("Root") == RootName and Lock.get("Path") == RelativePath:
return Lock
return None
def SetLock(RootName: str, RelativePath: str, Usernames: list[str], GroupNames: list[str]) -> None:
if not RelativePath:
raise ValueError("Can't lock an entire root - pick a specific file or directory.")
if not Usernames and not GroupNames:
RemoveLock(RootName, RelativePath)
return
Locks = LoadLocks()
for Lock in Locks:
if Lock.get("Root") == RootName and Lock.get("Path") == RelativePath:
Lock["Users"] = Usernames
Lock["Groups"] = GroupNames
SaveLocks(Locks)
return
Locks.append({"Root": RootName, "Path": RelativePath, "Users": Usernames, "Groups": GroupNames})
SaveLocks(Locks)
def RemoveLock(RootName: str, RelativePath: str) -> None:
Locks = [
Lock
for Lock in LoadLocks()
if not (Lock.get("Root") == RootName and Lock.get("Path") == RelativePath)
]
SaveLocks(Locks)
def IsPathAccessible(
RootName: str, RelativePath: str, Username: str, UserGroups: list[str]
) -> bool:
for Lock in LoadLocks():
if Lock.get("Root") != RootName:
continue
LockPath = Lock.get("Path", "")
if not LockPath:
continue
if RelativePath == LockPath or RelativePath.startswith(f"{LockPath}/"):
PermittedUsers = Lock.get("Users", [])
PermittedGroups = Lock.get("Groups", [])
IsPermittedByUser = Username in PermittedUsers
IsPermittedByGroup = any(Group in PermittedGroups for Group in UserGroups)
if not IsPermittedByUser and not IsPermittedByGroup:
return False
return True
def RequirePathAccessible(RootName: str, RelativePath: str, CurrentUser: dict[str, Any]) -> None:
if not IsPathAccessible(
RootName,
RelativePath,
CurrentUser["Username"],
CurrentUser.get("Groups", []),
):
raise HTTPException(status_code=404, detail="Not found.")