mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-05 11:10:47 -06:00
[server][core][db] Inline fs_permissions.sql
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
86
server/internal/core/fs/permissions.go
Normal file
86
server/internal/core/fs/permissions.go
Normal file
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user