The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/services/store/validate.go

101 lines
2.5 KiB

package store
import (
"context"
"encoding/json"
"fmt"
"net/http"
"path/filepath"
"strings"
"github.com/grafana/grafana/pkg/infra/filestorage"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util"
)
var (
allowedImageExtensions = map[string]bool{
".jpg": true,
".jpeg": true,
".svg": true,
".gif": true,
".png": true,
".webp": true,
}
imageExtensionsToMatchingMimeTypes = map[string]map[string]bool{
".jpg": {"image/jpg": true, "image/jpeg": true},
".jpeg": {"image/jpg": true, "image/jpeg": true},
".gif": {"image/gif": true},
".png": {"image/png": true},
".webp": {"image/webp": true},
".svg": {"image/svg+xml": true},
}
)
type validationResult struct {
ok bool
reason string
}
func success() validationResult {
return validationResult{
ok: true,
}
}
func fail(reason string) validationResult {
return validationResult{
ok: false,
reason: reason,
}
}
func (s *standardStorageService) detectMimeType(ctx context.Context, user *user.SignedInUser, uploadRequest *UploadRequest) string {
if strings.HasSuffix(uploadRequest.Path, ".svg") {
if util.IsSVG(uploadRequest.Contents) {
return "image/svg+xml"
}
}
return http.DetectContentType(uploadRequest.Contents)
}
func (s *standardStorageService) validateImage(ctx context.Context, user *user.SignedInUser, uploadRequest *UploadRequest) validationResult {
ext := filepath.Ext(uploadRequest.Path)
if !allowedImageExtensions[ext] {
return fail(fmt.Sprintf("unsupported extension: %s", ext))
}
mimeType := s.detectMimeType(ctx, user, uploadRequest)
if !imageExtensionsToMatchingMimeTypes[ext][mimeType] {
return fail(fmt.Sprintf("extension '%s' does not match the detected MimeType: %s", ext, mimeType))
}
return success()
}
func (s *standardStorageService) validateUploadRequest(ctx context.Context, user *user.SignedInUser, req *UploadRequest, storagePath string) validationResult {
// TODO: validateSize
// TODO: validateProperties
if err := filestorage.ValidatePath(storagePath); err != nil {
return fail(fmt.Sprintf("path validation failed. error: %s. path: %s", err.Error(), storagePath))
}
switch req.EntityType {
case EntityTypeJSON:
fallthrough
case EntityTypeFolder:
fallthrough
case EntityTypeDashboard:
// TODO: add proper validation
if !json.Valid(req.Contents) {
return fail("invalid json")
}
return success()
case EntityTypeImage:
return s.validateImage(ctx, user, req)
default:
return fail("unknown entity")
}
}