From aabb8848289d006b8559b270bb5ec87b51ff698d Mon Sep 17 00:00:00 2001 From: Neeraj Gupta <254676+ua741@users.noreply.github.com> Date: Wed, 17 Apr 2024 15:19:20 +0530 Subject: [PATCH] [server] Add validation logic for file copy --- server/pkg/controller/collection.go | 35 +++++++++++++++++++++++++++++ server/pkg/repo/collection.go | 24 ++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/server/pkg/controller/collection.go b/server/pkg/controller/collection.go index 15c06fa331..455e240194 100644 --- a/server/pkg/controller/collection.go +++ b/server/pkg/controller/collection.go @@ -464,6 +464,41 @@ func (c *CollectionController) isRemoveAllowed(ctx *gin.Context, actorUserID int return nil } +func (c *CollectionController) isCopyAllowed(ctx *gin.Context, actorUserID int64, req ente.CopyFileSyncRequest) error { + // verify that srcCollectionID is accessible by actorUserID + if _, err := c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{ + CollectionID: req.SrcCollectionID, + ActorUserID: actorUserID, + }); err != nil { + return stacktrace.Propagate(err, "failed to verify srcCollection access") + } + // verify that dstCollectionID is owned by actorUserID + if _, err := c.AccessCtrl.GetCollection(ctx, &access.GetCollectionParams{ + CollectionID: req.DstCollection, + ActorUserID: actorUserID, + VerifyOwner: true, + }); err != nil { + return stacktrace.Propagate(err, "failed to ownership of the dstCollection access") + } + // verify that all FileIDs exists in the srcCollection + fileIDs := make([]int64, len(req.Files)) + for idx, file := range req.Files { + fileIDs[idx] = file.ID + } + if err := c.CollectionRepo.VerifyAllFileIDsExistsInCollection(ctx, req.SrcCollectionID, fileIDs); err != nil { + return stacktrace.Propagate(err, "failed to verify fileIDs in srcCollection") + } + dsMap, err := c.FileRepo.GetOwnerToFileIDsMap(ctx, fileIDs) + if err != nil { + return err + } + // verify that none of the file belongs to actorUserID + if _, ok := dsMap[actorUserID]; ok { + return ente.NewBadRequestWithMessage("can not copy files owned by actor") + } + return nil +} + // GetDiffV2 returns the changes in user's collections since a timestamp, along with hasMore bool flag. func (c *CollectionController) GetDiffV2(ctx *gin.Context, cID int64, userID int64, sinceTime int64) ([]ente.File, bool, error) { reqContextLogger := log.WithFields(log.Fields{ diff --git a/server/pkg/repo/collection.go b/server/pkg/repo/collection.go index 16ae853244..1ab54903bf 100644 --- a/server/pkg/repo/collection.go +++ b/server/pkg/repo/collection.go @@ -374,6 +374,30 @@ func (repo *CollectionRepository) DoesFileExistInCollections(fileID int64, cIDs return exists, stacktrace.Propagate(err, "") } +// VerifyAllFileIDsExistsInCollection returns error if the fileIDs don't exist in the collection +func (repo *CollectionRepository) VerifyAllFileIDsExistsInCollection(ctx context.Context, cID int64, fileIDs []int64) error { + fileIdMap := make(map[int64]bool) + rows, err := repo.DB.QueryContext(ctx, `SELECT file_id FROM collection_files WHERE collection_id = $1 AND is_deleted = $2 AND file_id = ALL ($3)`, + cID, false, pq.Array(fileIDs)) + if err != nil { + return stacktrace.Propagate(err, "") + } + for rows.Next() { + var fileID int64 + if err := rows.Scan(&fileID); err != nil { + return stacktrace.Propagate(err, "") + } + fileIdMap[fileID] = true + } + // find fileIds that are not present in the collection + for _, fileID := range fileIDs { + if _, ok := fileIdMap[fileID]; !ok { + return stacktrace.Propagate(fmt.Errorf("fileID %d not found in collection %d", fileID, cID), "") + } + } + return nil +} + // GetCollectionShareeRole returns true if the collection is shared with the user func (repo *CollectionRepository) GetCollectionShareeRole(cID int64, userID int64) (*ente.CollectionParticipantRole, error) { var role *ente.CollectionParticipantRole