From e9f4fc3f0be74f13b7cf4c84bf54f02489708f62 Mon Sep 17 00:00:00 2001 From: Abhishek Shroff Date: Sun, 30 Mar 2025 00:03:01 +0530 Subject: [PATCH] [server][core][db] Inline fs_permissions.sql --- server/internal/core/fs/copy_move.go | 6 +- server/internal/core/fs/create.go | 2 +- server/internal/core/fs/permission.go | 11 --- server/internal/core/fs/permissions.go | 86 ++++++++++++++++++++++ server/internal/core/fs/resource_delete.go | 9 +-- server/internal/core/fs/update.go | 58 --------------- server/sql/queries/fs_permissions.sql | 18 +---- 7 files changed, 95 insertions(+), 95 deletions(-) delete mode 100644 server/internal/core/fs/permission.go create mode 100644 server/internal/core/fs/permissions.go delete mode 100644 server/internal/core/fs/update.go diff --git a/server/internal/core/fs/copy_move.go b/server/internal/core/fs/copy_move.go index 16416afc..696b88d2 100644 --- a/server/internal/core/fs/copy_move.go +++ b/server/internal/core/fs/copy_move.go @@ -62,13 +62,13 @@ func (r Resource) Move(target string, conflictResolution ResourceBindConflictRes return err } } - if result, err := f.db.UpdateResourceNameParent(f.ctx, db.UpdateResourceNameParentParams{ID: r.ID(), Name: destName, Parent: destParent.ID()}); err != nil { + if result, err := f.db.UpdateResourceNameParent(f.ctx, db.UpdateResourceNameParentParams{ID: r.id, Name: destName, Parent: destParent.ID()}); err != nil { if strings.Contains(err.Error(), "unique_member_resource_name") { return ErrResourceNameConflict } return err } else { - if err := f.db.RecomputePermissions(r.f.ctx, r.ID()); err != nil { + if err := f.recomputePermissions(r.id); err != nil { return err } res = ResourceFromDB(result) @@ -167,7 +167,7 @@ func (r Resource) Copy(target string, id uuid.UUID, recursive bool, conflictReso if _, err := f.db.CreateResources(f.ctx, children); err != nil { return err } - if err := f.db.RecomputePermissions(r.f.ctx, id); err != nil { + if err := f.recomputePermissions(id); err != nil { return err } if created { diff --git a/server/internal/core/fs/create.go b/server/internal/core/fs/create.go index 64afa36e..51950109 100644 --- a/server/internal/core/fs/create.go +++ b/server/internal/core/fs/create.go @@ -57,7 +57,7 @@ func (r Resource) CreateMemberResource(name string, id uuid.UUID, dir bool, conf if res, created, _, err = f.createResource(id, r.id, name, dir, 0, emptyContentType, emptyContentSHA256, conflictResolution, r.permissions); err != nil { return err } else if created { - if err := f.db.RecomputePermissions(f.ctx, id); err != nil { + if err := f.recomputePermissions(r.id); err != nil { return err } return f.db.UpdateResourceModified(f.ctx, r.id) diff --git a/server/internal/core/fs/permission.go b/server/internal/core/fs/permission.go deleted file mode 100644 index f3a283e9..00000000 --- a/server/internal/core/fs/permission.go +++ /dev/null @@ -1,11 +0,0 @@ -package fs - -type Permission = int32 - -const ( - PermissionNone = Permission(0) - PermissionRead = Permission(4) - PermissionWrite = Permission(32) - PermissionShare = Permission(128) - PermissionSU = Permission(-1) -) diff --git a/server/internal/core/fs/permissions.go b/server/internal/core/fs/permissions.go new file mode 100644 index 00000000..185ca800 --- /dev/null +++ b/server/internal/core/fs/permissions.go @@ -0,0 +1,86 @@ +package fs + +import ( + "encoding/json" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5" +) + +type Permission = int32 + +const ( + PermissionNone = Permission(0) + PermissionRead = Permission(4) + PermissionWrite = Permission(32) + PermissionShare = Permission(128) + PermissionSU = Permission(-1) +) + +func (r Resource) UpdatePermissions(username string, permission Permission) (Resource, error) { + if !r.hasPermission(PermissionShare) { + return Resource{}, ErrInsufficientPermissions + } + // Do not grant more than what you have + permission = permission & r.userPermission + const q = ` +UPDATE resources SET + grants[@username::TEXT] = jsonb_build_object('p', @permission::INT, 't', EXTRACT(EPOCH FROM NOW())::INTEGER)" + grants = (CASE permissions WHEN 0 THEN grants - @username::TEXT ELSE grants END) + modified = NOW() +WHERE id = @resource_id::UUID` + + err := r.f.runInTx(func(f filesystem) error { + if _, err := f.db.Exec(f.ctx, q, pgx.NamedArgs{ + "resource_id": r.id, + "username": username, + "permission": permission, + }); err != nil { + return err + } + + return f.recomputePermissions(r.id) + }) + if err != nil { + return Resource{}, err + } + p := make(map[string]Permission) + if r.permissions != nil { + if err := json.Unmarshal(r.permissions, &p); err != nil { + return Resource{}, err + } + } + if permission == 0 { + delete(p, username) + } else { + p[username] = permission + } + res, err := json.Marshal(p) + if err != nil { + return Resource{}, err + } + + r.permissions = res + return r, nil +} + +func (f filesystem) recomputePermissions(id uuid.UUID) error { + const q = ` +WITH RECURSIVE nodes(id, parent, permissions) AS ( + SELECT r.id, r.parent, phylum_merge_permission_grants(COALESCE(p.permissions, '{}'::JSONB), r.grants) END + FROM resources r + LEFT JOIN resources p + ON r.parent = p.id + WHERE r.id = $1::UUID + UNION ALL + SELECT r.id, r.parent, phylum_merge_permission_grants(n.permissions, r.grants) + FROM resources r JOIN nodes n on r.parent = n.id +) +UPDATE resources + SET permissions = nodes.permissions + FROM nodes + WHERE resources.id = nodes.id` + + _, err := f.db.Exec(f.ctx, q, id) + return err +} diff --git a/server/internal/core/fs/resource_delete.go b/server/internal/core/fs/resource_delete.go index 451ca577..97374e16 100644 --- a/server/internal/core/fs/resource_delete.go +++ b/server/internal/core/fs/resource_delete.go @@ -1,7 +1,6 @@ package fs import ( - "context" "errors" "fmt" "path" @@ -118,7 +117,7 @@ func (r Resource) RestoreDeleted(parentPathOrUUID string, name string, autoRenam r.parentID = update.Parent } } - if del, err := f.markNotDeleted(f.ctx, r.id); err != nil { + if del, err := f.markNotDeleted(r.id); err != nil { return err } else { count = len(del) @@ -127,7 +126,7 @@ func (r Resource) RestoreDeleted(parentPathOrUUID string, name string, autoRenam } } - return f.db.RecomputePermissions(f.ctx, r.ID()) + return f.recomputePermissions(r.id) }) res = r return @@ -180,7 +179,7 @@ func (f filesystem) markDeleted(id uuid.UUID, softDelete, excludeRoot bool) (int return collectNonDirResourceIDs(f.db.Query(f.ctx, query, params...)) } -func (f filesystem) markNotDeleted(ctx context.Context, id uuid.UUID) ([]int64, error) { +func (f filesystem) markNotDeleted(id uuid.UUID) ([]int64, error) { r, _, s := selectResourceTree(id, false, false) q := s.Update().Set( goqu.Record{ @@ -191,7 +190,7 @@ func (f filesystem) markNotDeleted(ctx context.Context, id uuid.UUID) ([]int64, query, params, _ := q.ToSQL() - rows, err := f.db.Query(ctx, query, params...) + rows, err := f.db.Query(f.ctx, query, params...) if err != nil { return nil, err } diff --git a/server/internal/core/fs/update.go b/server/internal/core/fs/update.go deleted file mode 100644 index 1388f2a3..00000000 --- a/server/internal/core/fs/update.go +++ /dev/null @@ -1,58 +0,0 @@ -package fs - -import ( - "encoding/json" - - "github.com/shroff/phylum/server/internal/core/db" -) - -func (r Resource) UpdatePermissions(username string, permission Permission) (Resource, error) { - if !r.hasPermission(PermissionShare) { - return Resource{}, ErrInsufficientPermissions - } - // Do not grant more than what you have - permission = permission & r.userPermission - - ctx := r.f.ctx - err := r.f.db.WithTx(ctx, func(dbh *db.DbHandler) error { - if permission == PermissionNone { - if err := dbh.RevokeUserPermissionForResource(ctx, db.RevokeUserPermissionForResourceParams{ - ResourceID: r.ID(), - Username: username, - }); err != nil { - return err - } - } else { - if err := dbh.GrantUserPermissionForResource(ctx, db.GrantUserPermissionForResourceParams{ - ResourceID: r.ID(), - Username: username, - Permission: permission, - }); err != nil { - return err - } - } - - return dbh.RecomputePermissions(ctx, r.ID()) - }) - if err != nil { - return Resource{}, err - } - p := make(map[string]Permission) - if r.permissions != nil { - if err := json.Unmarshal(r.permissions, &p); err != nil { - return Resource{}, err - } - } - if permission == 0 { - delete(p, username) - } else { - p[username] = permission - } - res, err := json.Marshal(p) - if err != nil { - return Resource{}, err - } - - r.permissions = res - return r, nil -} diff --git a/server/sql/queries/fs_permissions.sql b/server/sql/queries/fs_permissions.sql index a7ec727f..7d5b6be8 100644 --- a/server/sql/queries/fs_permissions.sql +++ b/server/sql/queries/fs_permissions.sql @@ -12,20 +12,4 @@ SET grants = grants - @username::TEXT, modified = NOW() WHERE id = @resource_id::uuid -RETURNING permissions; - --- name: RecomputePermissions :exec -WITH RECURSIVE nodes(id, parent, permissions) AS ( - SELECT r.id, r.parent, phylum_merge_permission_grants(COALESCE(p.permissions, '{}'::JSONB), r.grants) END - FROM resources r - LEFT JOIN resources p - ON r.parent = p.id - WHERE r.id = @resource_id::uuid - UNION ALL - SELECT r.id, r.parent, phylum_merge_permission_grants(n.permissions, r.grants) - FROM resources r JOIN nodes n on r.parent = n.id -) -UPDATE resources - SET permissions = nodes.permissions - FROM nodes - WHERE resources.id = nodes.id; +RETURNING permissions; \ No newline at end of file