mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PublicDashboards: moved tokens service and new repository method (#61806)
This commit is contained in:
parent
89ef62f163
commit
a128944471
@ -13,8 +13,8 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ func (api *Api) ListPublicDashboards(c *contextmodel.ReqContext) response.Respon
|
|||||||
func (api *Api) GetPublicDashboard(c *contextmodel.ReqContext) response.Response {
|
func (api *Api) GetPublicDashboard(c *contextmodel.ReqContext) response.Response {
|
||||||
// exit if we don't have a valid dashboardUid
|
// exit if we don't have a valid dashboardUid
|
||||||
dashboardUid := web.Params(c.Req)[":dashboardUid"]
|
dashboardUid := web.Params(c.Req)[":dashboardUid"]
|
||||||
if !tokens.IsValidShortUID(dashboardUid) {
|
if !validation.IsValidShortUID(dashboardUid) {
|
||||||
return response.Err(ErrPublicDashboardIdentifierNotSet.Errorf("GetPublicDashboard: no dashboard Uid for public dashboard specified"))
|
return response.Err(ErrPublicDashboardIdentifierNotSet.Errorf("GetPublicDashboard: no dashboard Uid for public dashboard specified"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ func (api *Api) GetPublicDashboard(c *contextmodel.ReqContext) response.Response
|
|||||||
func (api *Api) CreatePublicDashboard(c *contextmodel.ReqContext) response.Response {
|
func (api *Api) CreatePublicDashboard(c *contextmodel.ReqContext) response.Response {
|
||||||
// exit if we don't have a valid dashboardUid
|
// exit if we don't have a valid dashboardUid
|
||||||
dashboardUid := web.Params(c.Req)[":dashboardUid"]
|
dashboardUid := web.Params(c.Req)[":dashboardUid"]
|
||||||
if !tokens.IsValidShortUID(dashboardUid) {
|
if !validation.IsValidShortUID(dashboardUid) {
|
||||||
return response.Err(ErrInvalidUid.Errorf("CreatePublicDashboard: invalid Uid %s", dashboardUid))
|
return response.Err(ErrInvalidUid.Errorf("CreatePublicDashboard: invalid Uid %s", dashboardUid))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,12 +155,12 @@ func (api *Api) CreatePublicDashboard(c *contextmodel.ReqContext) response.Respo
|
|||||||
func (api *Api) UpdatePublicDashboard(c *contextmodel.ReqContext) response.Response {
|
func (api *Api) UpdatePublicDashboard(c *contextmodel.ReqContext) response.Response {
|
||||||
// exit if we don't have a valid dashboardUid
|
// exit if we don't have a valid dashboardUid
|
||||||
dashboardUid := web.Params(c.Req)[":dashboardUid"]
|
dashboardUid := web.Params(c.Req)[":dashboardUid"]
|
||||||
if !tokens.IsValidShortUID(dashboardUid) {
|
if !validation.IsValidShortUID(dashboardUid) {
|
||||||
return response.Err(ErrInvalidUid.Errorf("UpdatePublicDashboard: invalid dashboard Uid %s", dashboardUid))
|
return response.Err(ErrInvalidUid.Errorf("UpdatePublicDashboard: invalid dashboard Uid %s", dashboardUid))
|
||||||
}
|
}
|
||||||
|
|
||||||
uid := web.Params(c.Req)[":uid"]
|
uid := web.Params(c.Req)[":uid"]
|
||||||
if !tokens.IsValidShortUID(uid) {
|
if !validation.IsValidShortUID(uid) {
|
||||||
return response.Err(ErrInvalidUid.Errorf("UpdatePublicDashboard: invalid Uid %s", uid))
|
return response.Err(ErrInvalidUid.Errorf("UpdatePublicDashboard: invalid Uid %s", uid))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +192,7 @@ func (api *Api) UpdatePublicDashboard(c *contextmodel.ReqContext) response.Respo
|
|||||||
// DELETE /api/dashboards/uid/:dashboardUid/public-dashboards/:uid
|
// DELETE /api/dashboards/uid/:dashboardUid/public-dashboards/:uid
|
||||||
func (api *Api) DeletePublicDashboard(c *contextmodel.ReqContext) response.Response {
|
func (api *Api) DeletePublicDashboard(c *contextmodel.ReqContext) response.Response {
|
||||||
uid := web.Params(c.Req)[":uid"]
|
uid := web.Params(c.Req)[":uid"]
|
||||||
if !tokens.IsValidShortUID(uid) {
|
if !validation.IsValidShortUID(uid) {
|
||||||
return response.Err(ErrInvalidUid.Errorf("UpdatePublicDashboard: invalid Uid %s", uid))
|
return response.Err(ErrInvalidUid.Errorf("UpdatePublicDashboard: invalid Uid %s", uid))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/infra/metrics"
|
"github.com/grafana/grafana/pkg/infra/metrics"
|
||||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ import (
|
|||||||
func SetPublicDashboardOrgIdOnContext(publicDashboardService publicdashboards.Service) func(c *contextmodel.ReqContext) {
|
func SetPublicDashboardOrgIdOnContext(publicDashboardService publicdashboards.Service) func(c *contextmodel.ReqContext) {
|
||||||
return func(c *contextmodel.ReqContext) {
|
return func(c *contextmodel.ReqContext) {
|
||||||
accessToken, ok := web.Params(c.Req)[":accessToken"]
|
accessToken, ok := web.Params(c.Req)[":accessToken"]
|
||||||
if !ok || !tokens.IsValidAccessToken(accessToken) {
|
if !ok || !validation.IsValidAccessToken(accessToken) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ func RequiresExistingAccessToken(publicDashboardService publicdashboards.Service
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tokens.IsValidAccessToken(accessToken) {
|
if !validation.IsValidAccessToken(accessToken) {
|
||||||
c.JsonApiErr(http.StatusBadRequest, "Invalid access token", nil)
|
c.JsonApiErr(http.StatusBadRequest, "Invalid access token", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -18,7 +18,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
var validAccessToken, _ = tokens.GenerateAccessToken()
|
var validAccessToken, _ = service.GenerateAccessToken()
|
||||||
|
|
||||||
func TestRequiresExistingAccessToken(t *testing.T) {
|
func TestRequiresExistingAccessToken(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/api/response"
|
"github.com/grafana/grafana/pkg/api/response"
|
||||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||||
"github.com/grafana/grafana/pkg/web"
|
"github.com/grafana/grafana/pkg/web"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ import (
|
|||||||
// GET /api/public/dashboards/:accessToken
|
// GET /api/public/dashboards/:accessToken
|
||||||
func (api *Api) ViewPublicDashboard(c *contextmodel.ReqContext) response.Response {
|
func (api *Api) ViewPublicDashboard(c *contextmodel.ReqContext) response.Response {
|
||||||
accessToken := web.Params(c.Req)[":accessToken"]
|
accessToken := web.Params(c.Req)[":accessToken"]
|
||||||
if !tokens.IsValidAccessToken(accessToken) {
|
if !validation.IsValidAccessToken(accessToken) {
|
||||||
return response.Err(ErrInvalidAccessToken.Errorf("ViewPublicDashboard: invalid access token"))
|
return response.Err(ErrInvalidAccessToken.Errorf("ViewPublicDashboard: invalid access token"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ func (api *Api) ViewPublicDashboard(c *contextmodel.ReqContext) response.Respons
|
|||||||
// POST /api/public/dashboard/:accessToken/panels/:panelId/query
|
// POST /api/public/dashboard/:accessToken/panels/:panelId/query
|
||||||
func (api *Api) QueryPublicDashboard(c *contextmodel.ReqContext) response.Response {
|
func (api *Api) QueryPublicDashboard(c *contextmodel.ReqContext) response.Response {
|
||||||
accessToken := web.Params(c.Req)[":accessToken"]
|
accessToken := web.Params(c.Req)[":accessToken"]
|
||||||
if !tokens.IsValidAccessToken(accessToken) {
|
if !validation.IsValidAccessToken(accessToken) {
|
||||||
return response.Err(ErrInvalidAccessToken.Errorf("QueryPublicDashboard: invalid access token"))
|
return response.Err(ErrInvalidAccessToken.Errorf("QueryPublicDashboard: invalid access token"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ func (api *Api) QueryPublicDashboard(c *contextmodel.ReqContext) response.Respon
|
|||||||
// GET /api/public/dashboards/:accessToken/annotations
|
// GET /api/public/dashboards/:accessToken/annotations
|
||||||
func (api *Api) GetAnnotations(c *contextmodel.ReqContext) response.Response {
|
func (api *Api) GetAnnotations(c *contextmodel.ReqContext) response.Response {
|
||||||
accessToken := web.Params(c.Req)[":accessToken"]
|
accessToken := web.Params(c.Req)[":accessToken"]
|
||||||
if !tokens.IsValidAccessToken(accessToken) {
|
if !validation.IsValidAccessToken(accessToken) {
|
||||||
return response.Err(ErrInvalidAccessToken.Errorf("GetAnnotations: invalid access token"))
|
return response.Err(ErrInvalidAccessToken.Errorf("GetAnnotations: invalid access token"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database"
|
dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
@ -693,7 +693,7 @@ func insertPublicDashboard(t *testing.T, publicdashboardStore *PublicDashboardSt
|
|||||||
|
|
||||||
uid := util.GenerateShortUID()
|
uid := util.GenerateShortUID()
|
||||||
|
|
||||||
accessToken, err := tokens.GenerateAccessToken()
|
accessToken, err := service.GenerateAccessToken()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
cmd := SavePublicDashboardCommand{
|
cmd := SavePublicDashboardCommand{
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
package tokens
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/grafana/grafana/pkg/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GenerateAccessToken generates an uuid formatted without dashes to use as access token
|
|
||||||
func GenerateAccessToken() (string, error) {
|
|
||||||
token, err := uuid.NewRandom()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%x", token[:]), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsValidAccessToken asserts that an accessToken is a valid uuid
|
|
||||||
func IsValidAccessToken(token string) bool {
|
|
||||||
_, err := uuid.Parse(token)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsValidShortUID checks that the uid is not blank and contains valid
|
|
||||||
// characters. Wraps utils.IsValidShortUID
|
|
||||||
func IsValidShortUID(uid string) bool {
|
|
||||||
return uid != "" && util.IsValidShortUID(uid)
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
package tokens
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGenerateAccessToken(t *testing.T) {
|
|
||||||
accessToken, err := GenerateAccessToken()
|
|
||||||
|
|
||||||
t.Run("length", func(t *testing.T) {
|
|
||||||
require.NoError(t, err)
|
|
||||||
assert.Equal(t, 32, len(accessToken))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("no - ", func(t *testing.T) {
|
|
||||||
assert.False(t, strings.Contains("-", accessToken))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidAccessToken(t *testing.T) {
|
|
||||||
t.Run("true", func(t *testing.T) {
|
|
||||||
uuid, _ := GenerateAccessToken()
|
|
||||||
assert.True(t, IsValidAccessToken(uuid))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("false when blank", func(t *testing.T) {
|
|
||||||
assert.False(t, IsValidAccessToken(""))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("false when can't be parsed by uuid lib", func(t *testing.T) {
|
|
||||||
// too long
|
|
||||||
assert.False(t, IsValidAccessToken("0123456789012345678901234567890123456789"))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// we just check base cases since this wraps utils.IsValidShortUID which has
|
|
||||||
// test coverage
|
|
||||||
func TestValidUid(t *testing.T) {
|
|
||||||
t.Run("true", func(t *testing.T) {
|
|
||||||
assert.True(t, IsValidShortUID("afqrz7jZZ"))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("false when blank", func(t *testing.T) {
|
|
||||||
assert.False(t, IsValidShortUID(""))
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("false when invalid chars", func(t *testing.T) {
|
|
||||||
assert.False(t, IsValidShortUID("afqrz7j%%"))
|
|
||||||
})
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
// Code generated by mockery v2.16.0. DO NOT EDIT.
|
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
||||||
|
|
||||||
package publicdashboards
|
package publicdashboards
|
||||||
|
|
||||||
@ -102,6 +102,29 @@ func (_m *FakePublicDashboardService) ExistsEnabledByDashboardUid(ctx context.Co
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find provides a mock function with given fields: ctx, uid
|
||||||
|
func (_m *FakePublicDashboardService) Find(ctx context.Context, uid string) (*models.PublicDashboard, error) {
|
||||||
|
ret := _m.Called(ctx, uid)
|
||||||
|
|
||||||
|
var r0 *models.PublicDashboard
|
||||||
|
if rf, ok := ret.Get(0).(func(context.Context, string) *models.PublicDashboard); ok {
|
||||||
|
r0 = rf(ctx, uid)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*models.PublicDashboard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
|
||||||
|
r1 = rf(ctx, uid)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// FindAll provides a mock function with given fields: ctx, u, orgId
|
// FindAll provides a mock function with given fields: ctx, u, orgId
|
||||||
func (_m *FakePublicDashboardService) FindAll(ctx context.Context, u *user.SignedInUser, orgId int64) ([]models.PublicDashboardListResponse, error) {
|
func (_m *FakePublicDashboardService) FindAll(ctx context.Context, u *user.SignedInUser, orgId int64) ([]models.PublicDashboardListResponse, error) {
|
||||||
ret := _m.Called(ctx, u, orgId)
|
ret := _m.Called(ctx, u, orgId)
|
||||||
|
@ -21,6 +21,7 @@ type Service interface {
|
|||||||
FindAnnotations(ctx context.Context, reqDTO AnnotationsQueryDTO, accessToken string) ([]AnnotationEvent, error)
|
FindAnnotations(ctx context.Context, reqDTO AnnotationsQueryDTO, accessToken string) ([]AnnotationEvent, error)
|
||||||
FindDashboard(ctx context.Context, orgId int64, dashboardUid string) (*dashboards.Dashboard, error)
|
FindDashboard(ctx context.Context, orgId int64, dashboardUid string) (*dashboards.Dashboard, error)
|
||||||
FindAll(ctx context.Context, u *user.SignedInUser, orgId int64) ([]PublicDashboardListResponse, error)
|
FindAll(ctx context.Context, u *user.SignedInUser, orgId int64) ([]PublicDashboardListResponse, error)
|
||||||
|
Find(ctx context.Context, uid string) (*PublicDashboard, error)
|
||||||
Create(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
|
Create(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
|
||||||
Update(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
|
Update(ctx context.Context, u *user.SignedInUser, dto *SavePublicDashboardDTO) (*PublicDashboard, error)
|
||||||
Delete(ctx context.Context, orgId int64, uid string) error
|
Delete(ctx context.Context, orgId int64, uid string) error
|
||||||
|
@ -3,15 +3,16 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||||
"github.com/grafana/grafana/pkg/infra/log"
|
"github.com/grafana/grafana/pkg/infra/log"
|
||||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||||
"github.com/grafana/grafana/pkg/services/annotations"
|
"github.com/grafana/grafana/pkg/services/annotations"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||||
"github.com/grafana/grafana/pkg/services/query"
|
"github.com/grafana/grafana/pkg/services/query"
|
||||||
@ -60,6 +61,14 @@ func ProvideService(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pd *PublicDashboardServiceImpl) Find(ctx context.Context, uid string) (*PublicDashboard, error) {
|
||||||
|
pubdash, err := pd.store.Find(ctx, uid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, ErrInternalServerError.Errorf("Find: failed to find public dashboard%w", err)
|
||||||
|
}
|
||||||
|
return pubdash, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FindDashboard Gets a dashboard by Uid
|
// FindDashboard Gets a dashboard by Uid
|
||||||
func (pd *PublicDashboardServiceImpl) FindDashboard(ctx context.Context, orgId int64, dashboardUid string) (*dashboards.Dashboard, error) {
|
func (pd *PublicDashboardServiceImpl) FindDashboard(ctx context.Context, orgId int64, dashboardUid string) (*dashboards.Dashboard, error) {
|
||||||
dash, err := pd.store.FindDashboard(ctx, orgId, dashboardUid)
|
dash, err := pd.store.FindDashboard(ctx, orgId, dashboardUid)
|
||||||
@ -281,7 +290,7 @@ func (pd *PublicDashboardServiceImpl) NewPublicDashboardAccessToken(ctx context.
|
|||||||
var accessToken string
|
var accessToken string
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
var err error
|
var err error
|
||||||
accessToken, err = tokens.GenerateAccessToken()
|
accessToken, err = GenerateAccessToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -396,3 +405,12 @@ func publicDashboardIsEnabledChanged(existingPubdash *PublicDashboard, newPubdas
|
|||||||
isEnabledChanged := existingPubdash != nil && newPubdash.IsEnabled != existingPubdash.IsEnabled
|
isEnabledChanged := existingPubdash != nil && newPubdash.IsEnabled != existingPubdash.IsEnabled
|
||||||
return newDashCreated || isEnabledChanged
|
return newDashCreated || isEnabledChanged
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenerateAccessToken generates an uuid formatted without dashes to use as access token
|
||||||
|
func GenerateAccessToken() (string, error) {
|
||||||
|
token, err := uuid.NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%x", token[:]), nil
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -18,8 +19,8 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
"github.com/grafana/grafana/pkg/services/publicdashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/publicdashboards/internal/tokens"
|
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||||
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts/tests"
|
||||||
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
|
||||||
@ -914,7 +915,7 @@ func TestPublicDashboardServiceImpl_NewPublicDashboardAccessToken(t *testing.T)
|
|||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
assert.NotEqual(t, got, tt.want, "NewPublicDashboardAccessToken(%v)", tt.args.ctx)
|
assert.NotEqual(t, got, tt.want, "NewPublicDashboardAccessToken(%v)", tt.args.ctx)
|
||||||
assert.True(t, tokens.IsValidAccessToken(got), "NewPublicDashboardAccessToken(%v)", tt.args.ctx)
|
assert.True(t, validation.IsValidAccessToken(got), "NewPublicDashboardAccessToken(%v)", tt.args.ctx)
|
||||||
store.AssertNumberOfCalls(t, "FindByAccessToken", 1)
|
store.AssertNumberOfCalls(t, "FindByAccessToken", 1)
|
||||||
} else {
|
} else {
|
||||||
store.AssertNumberOfCalls(t, "FindByAccessToken", 3)
|
store.AssertNumberOfCalls(t, "FindByAccessToken", 3)
|
||||||
@ -1028,3 +1029,16 @@ func insertTestDashboard(t *testing.T, dashboardStore *dashboardsDB.DashboardSto
|
|||||||
dash.Data.Set("uid", dash.UID)
|
dash.Data.Set("uid", dash.UID)
|
||||||
return dash
|
return dash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenerateAccessToken(t *testing.T) {
|
||||||
|
accessToken, err := GenerateAccessToken()
|
||||||
|
|
||||||
|
t.Run("length", func(t *testing.T) {
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, 32, len(accessToken))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("no - ", func(t *testing.T) {
|
||||||
|
assert.False(t, strings.Contains("-", accessToken))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
"github.com/grafana/grafana/pkg/tsdb/legacydata"
|
||||||
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ValidatePublicDashboard(dto *SavePublicDashboardDTO, dashboard *dashboards.Dashboard) error {
|
func ValidatePublicDashboard(dto *SavePublicDashboardDTO, dashboard *dashboards.Dashboard) error {
|
||||||
@ -44,3 +46,15 @@ func ValidateQueryPublicDashboardRequest(req PublicDashboardQueryDTO, pd *Public
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsValidAccessToken asserts that an accessToken is a valid uuid
|
||||||
|
func IsValidAccessToken(token string) bool {
|
||||||
|
_, err := uuid.Parse(token)
|
||||||
|
return err == nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsValidShortUID checks that the uid is not blank and contains valid
|
||||||
|
// characters. Wraps utils.IsValidShortUID
|
||||||
|
func IsValidShortUID(uid string) bool {
|
||||||
|
return uid != "" && util.IsValidShortUID(uid)
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -157,3 +158,35 @@ func TestValidateQueryPublicDashboardRequest(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestValidAccessToken(t *testing.T) {
|
||||||
|
t.Run("true", func(t *testing.T) {
|
||||||
|
uuid := "da82510c2aa64d78a2e87fef36c58e89"
|
||||||
|
assert.True(t, IsValidAccessToken(uuid))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("false when blank", func(t *testing.T) {
|
||||||
|
assert.False(t, IsValidAccessToken(""))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("false when can't be parsed by uuid lib", func(t *testing.T) {
|
||||||
|
// too long
|
||||||
|
assert.False(t, IsValidAccessToken("0123456789012345678901234567890123456789"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// we just check base cases since this wraps utils.IsValidShortUID which has
|
||||||
|
// test coverage
|
||||||
|
func TestValidUid(t *testing.T) {
|
||||||
|
t.Run("true", func(t *testing.T) {
|
||||||
|
assert.True(t, IsValidShortUID("afqrz7jZZ"))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("false when blank", func(t *testing.T) {
|
||||||
|
assert.False(t, IsValidShortUID(""))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("false when invalid chars", func(t *testing.T) {
|
||||||
|
assert.False(t, IsValidShortUID("afqrz7j%%"))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user