From e2ed42c2a338d0a6902b8c424f38106aec7f90ff Mon Sep 17 00:00:00 2001 From: Sofia Papagiannaki <1632407+papagian@users.noreply.github.com> Date: Fri, 6 Jan 2023 16:04:17 +0200 Subject: [PATCH] Nested folders: Do not expose the sequential ID from the folder store (#60702) * Nested folders: Do not expose the sequential ID from the folder store --- pkg/services/folder/folderimpl/folder.go | 134 +++++++++++++-------- pkg/services/folder/folderimpl/sqlstore.go | 4 +- 2 files changed, 86 insertions(+), 52 deletions(-) diff --git a/pkg/services/folder/folderimpl/folder.go b/pkg/services/folder/folderimpl/folder.go index f7984c872ac..3890db59bc1 100644 --- a/pkg/services/folder/folderimpl/folder.go +++ b/pkg/services/folder/folderimpl/folder.go @@ -97,41 +97,61 @@ func (s *Service) Get(ctx context.Context, cmd *folder.GetFolderQuery) (*folder. return nil, folder.ErrBadRequest.Errorf("missing signed in user") } - if s.features.IsEnabled(featuremgmt.FlagNestedFolders) { - f, err := s.store.Get(ctx, *cmd) - - if err != nil { - return nil, err - } - - // do not get guardian by the folder ID because it differs from the nested folder ID - // and the legacy folder ID has been associated with the permissions: - // use the folde UID instead that is the same for both - g, err := guardian.NewByUID(ctx, f.UID, f.OrgID, cmd.SignedInUser) - if err != nil { - return nil, err - } - - if canView, err := g.CanView(); err != nil || !canView { - if err != nil { - return nil, toFolderError(err) - } - return nil, dashboards.ErrFolderAccessDenied - } - - return f, err - } - + var dashFolder *folder.Folder + var err error switch { case cmd.UID != nil: - return s.getFolderByUID(ctx, cmd.SignedInUser, cmd.OrgID, *cmd.UID) + dashFolder, err = s.getFolderByUID(ctx, cmd.SignedInUser, cmd.OrgID, *cmd.UID) + if err != nil { + return nil, err + } case cmd.ID != nil: - return s.getFolderByID(ctx, cmd.SignedInUser, *cmd.ID, cmd.OrgID) + dashFolder, err = s.getFolderByID(ctx, cmd.SignedInUser, *cmd.ID, cmd.OrgID) + if err != nil { + return nil, err + } case cmd.Title != nil: - return s.getFolderByTitle(ctx, cmd.SignedInUser, cmd.OrgID, *cmd.Title) + dashFolder, err = s.getFolderByTitle(ctx, cmd.SignedInUser, cmd.OrgID, *cmd.Title) + if err != nil { + return nil, err + } default: return nil, folder.ErrBadRequest.Errorf("either on of UID, ID, Title fields must be present") } + + if !s.features.IsEnabled(featuremgmt.FlagNestedFolders) { + return dashFolder, nil + } + + if cmd.ID != nil { + cmd.ID = nil + cmd.UID = &dashFolder.UID + } + f, err := s.store.Get(ctx, *cmd) + + if err != nil { + return nil, err + } + + // do not get guardian by the folder ID because it differs from the nested folder ID + // and the legacy folder ID has been associated with the permissions: + // use the folde UID instead that is the same for both + g, err := guardian.NewByUID(ctx, f.UID, f.OrgID, cmd.SignedInUser) + if err != nil { + return nil, err + } + + if canView, err := g.CanView(); err != nil || !canView { + if err != nil { + return nil, toFolderError(err) + } + return nil, dashboards.ErrFolderAccessDenied + } + + // always expose the dashboard store sequential ID + f.ID = dashFolder.ID + + return f, err } func (s *Service) GetChildren(ctx context.Context, cmd *folder.GetChildrenQuery) ([]*folder.Folder, error) { @@ -147,12 +167,21 @@ func (s *Service) GetChildren(ctx context.Context, cmd *folder.GetChildrenQuery) filtered := make([]*folder.Folder, 0, len(children)) for _, f := range children { + // fetch folder from dashboard store + dashFolder, err := s.dashboardStore.GetFolderByUID(ctx, f.OrgID, f.UID) + if err != nil { + s.log.Error("failed to fetch folder by UID: %s from dashboard store", f.UID, err) + continue + } + g, err := guardian.New(ctx, f.ID, f.OrgID, cmd.SignedInUser) if err != nil { return nil, err } canView, err := g.CanView() if err != nil || canView { + // always expose the dashboard store sequential ID + f.ID = dashFolder.ID filtered = append(filtered, f) } } @@ -372,33 +401,38 @@ func (s *Service) Update(ctx context.Context, cmd *folder.UpdateFolderCommand) ( } user := cmd.SignedInUser - foldr, err := s.legacyUpdate(ctx, cmd) + dashFolder, err := s.legacyUpdate(ctx, cmd) if err != nil { return nil, err } - if s.features.IsEnabled(featuremgmt.FlagNestedFolders) { - if cmd.NewUID != nil && *cmd.NewUID != "" { - if !util.IsValidShortUID(*cmd.NewUID) { - return nil, dashboards.ErrDashboardInvalidUid - } else if util.IsShortUIDTooLong(*cmd.NewUID) { - return nil, dashboards.ErrDashboardUidTooLong - } - } - - foldr, err := s.store.Update(ctx, folder.UpdateFolderCommand{ - UID: cmd.UID, - OrgID: cmd.OrgID, - NewUID: cmd.NewUID, - NewTitle: cmd.NewTitle, - NewDescription: cmd.NewDescription, - SignedInUser: user, - }) - if err != nil { - return nil, err - } - return foldr, nil + if !s.features.IsEnabled(featuremgmt.FlagNestedFolders) { + return dashFolder, nil } + + if cmd.NewUID != nil && *cmd.NewUID != "" { + if !util.IsValidShortUID(*cmd.NewUID) { + return nil, dashboards.ErrDashboardInvalidUid + } else if util.IsShortUIDTooLong(*cmd.NewUID) { + return nil, dashboards.ErrDashboardUidTooLong + } + } + + foldr, err := s.store.Update(ctx, folder.UpdateFolderCommand{ + UID: cmd.UID, + OrgID: cmd.OrgID, + NewUID: cmd.NewUID, + NewTitle: cmd.NewTitle, + NewDescription: cmd.NewDescription, + SignedInUser: user, + }) + if err != nil { + return nil, err + } + + // always expose the dashboard store sequential ID + foldr.ID = dashFolder.ID + return foldr, nil } diff --git a/pkg/services/folder/folderimpl/sqlstore.go b/pkg/services/folder/folderimpl/sqlstore.go index 91e9f057a16..241d711d36b 100644 --- a/pkg/services/folder/folderimpl/sqlstore.go +++ b/pkg/services/folder/folderimpl/sqlstore.go @@ -163,12 +163,12 @@ func (ss *sqlStore) Get(ctx context.Context, q folder.GetFolderQuery) (*folder.F exists := false var err error switch { + case q.UID != nil: + exists, err = sess.SQL("SELECT * FROM folder WHERE uid = ? AND org_id = ?", q.UID, q.OrgID).Get(foldr) case q.ID != nil: exists, err = sess.SQL("SELECT * FROM folder WHERE id = ?", q.ID).Get(foldr) case q.Title != nil: exists, err = sess.SQL("SELECT * FROM folder WHERE title = ? AND org_id = ?", q.Title, q.OrgID).Get(foldr) - case q.UID != nil: - exists, err = sess.SQL("SELECT * FROM folder WHERE uid = ? AND org_id = ?", q.UID, q.OrgID).Get(foldr) default: return folder.ErrBadRequest.Errorf("one of ID, UID, or Title must be included in the command") }