141 lines
3.6 KiB
Go
141 lines
3.6 KiB
Go
package lib
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"strings"
|
|
)
|
|
|
|
// Permission constants (bitmask)
|
|
const (
|
|
PermRead = 1 // Read access
|
|
PermWrite = 2 // Create/update
|
|
PermDelete = 4 // Delete
|
|
PermManage = 8 // Grant/revoke access to others
|
|
)
|
|
|
|
// CheckAccess checks if accessor has permission to access an entry/category/dossier.
|
|
// Returns true if access is granted, false otherwise.
|
|
func CheckAccess(accessorID, dossierID, entryID string, perm int) bool {
|
|
if accessorID == "" || accessorID == SystemAccessorID {
|
|
return true
|
|
}
|
|
if accessorID == dossierID {
|
|
return true
|
|
}
|
|
|
|
var grants []Access
|
|
if err := dbQuery(
|
|
"SELECT AccessID, DossierID, GranteeID, EntryID, Ops FROM access WHERE GranteeID = ? AND DossierID = ?",
|
|
[]any{accessorID, dossierID},
|
|
&grants,
|
|
); err != nil {
|
|
return false
|
|
}
|
|
|
|
for _, grant := range grants {
|
|
if grant.EntryID == entryID {
|
|
return (grant.Ops & perm) != 0
|
|
}
|
|
if grant.EntryID == dossierID {
|
|
return (grant.Ops & perm) != 0
|
|
}
|
|
if entryID != dossierID && entryID != "" {
|
|
var entry Entry
|
|
if err := dbLoad("entries", entryID, &entry); err == nil {
|
|
if entry.ParentID == grant.EntryID || entry.ParentID == "" && grant.EntryID == dossierID {
|
|
return (grant.Ops & perm) != 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// OpsToString converts ops bitmask to string representation.
|
|
func OpsToString(ops int) string {
|
|
var parts []string
|
|
if ops&PermRead != 0 {
|
|
parts = append(parts, "r")
|
|
}
|
|
if ops&PermWrite != 0 {
|
|
parts = append(parts, "w")
|
|
}
|
|
if ops&PermDelete != 0 {
|
|
parts = append(parts, "d")
|
|
}
|
|
if ops&PermManage != 0 {
|
|
parts = append(parts, "m")
|
|
}
|
|
return strings.Join(parts, "")
|
|
}
|
|
|
|
// ============================================================================
|
|
// STUBS — will be rebuilt when sharing UI is wired
|
|
// ============================================================================
|
|
|
|
func GrantAccess(dossierID, granteeID, entryID string, ops, relation int) error {
|
|
access := &Access{
|
|
AccessID: NewID(),
|
|
DossierID: dossierID,
|
|
GranteeID: granteeID,
|
|
EntryID: entryID,
|
|
Ops: ops,
|
|
Relation: relation,
|
|
CreatedAt: nowUnix(),
|
|
}
|
|
return dbSave("access", access)
|
|
}
|
|
|
|
func RevokeAccess(dossierID, granteeID, entryID string) error {
|
|
var matches []Access
|
|
if err := dbQuery("SELECT * FROM access WHERE DossierID = ? AND GranteeID = ? AND EntryID = ?",
|
|
[]any{dossierID, granteeID, entryID}, &matches); err != nil {
|
|
return err
|
|
}
|
|
for _, a := range matches {
|
|
dbDelete("access", "AccessID", a.AccessID)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func RevokeAllAccess(dossierID, granteeID string) error {
|
|
log.Printf("[STUB] RevokeAllAccess(dossier=%s, grantee=%s)", dossierID, granteeID)
|
|
return nil
|
|
}
|
|
|
|
func ListGrants(dossierID, granteeID string) ([]*Access, error) {
|
|
log.Printf("[STUB] ListGrants(dossier=%s, grantee=%s)", dossierID, granteeID)
|
|
return nil, nil
|
|
}
|
|
|
|
func ListGrantees(dossierID string) ([]*Access, error) {
|
|
log.Printf("[STUB] ListGrantees(dossier=%s)", dossierID)
|
|
return nil, nil
|
|
}
|
|
|
|
func CanManageDossier(accessorID, dossierID string) bool {
|
|
return CheckAccess(accessorID, dossierID, dossierID, PermManage)
|
|
}
|
|
|
|
// ============================================================================
|
|
// DEPRECATED — kept for compilation, will be removed
|
|
// ============================================================================
|
|
|
|
type AccessContext struct {
|
|
DossierID string
|
|
AccessorID string
|
|
IsSystem bool
|
|
}
|
|
|
|
var SystemContext = &AccessContext{DossierID: "system", AccessorID: SystemAccessorID, IsSystem: true}
|
|
|
|
var ErrAccessDenied = fmt.Errorf("access denied")
|
|
|
|
func InvalidateCacheForAccessor(accessorID string) {}
|
|
|
|
func EnsureCategoryRoot(dossierID string, category int) (string, error) {
|
|
return dossierID, nil
|
|
}
|