Add 'settings/' from commit '230545a4a75b0611988fbcea51336a6c316d6a3d'

git-subtree-dir: settings
git-subtree-mainline: c26f7b390a
git-subtree-split: 230545a4a7
This commit is contained in:
A.Unger
2020-09-18 12:43:43 +02:00
140 changed files with 28757 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
package svc
import (
"github.com/owncloud/ocis-settings/pkg/metrics"
)
// NewInstrument returns a service that instruments metrics.
func NewInstrument(next Service, metrics *metrics.Metrics) Service {
return Service{
manager: next.manager,
config: next.config,
}
}
+13
View File
@@ -0,0 +1,13 @@
package svc
import (
"github.com/owncloud/ocis-pkg/v2/log"
)
// NewLogging returns a service that logs messages.
func NewLogging(next Service, logger log.Logger) Service {
return Service{
manager: next.manager,
config: next.config,
}
}
+39
View File
@@ -0,0 +1,39 @@
package svc
import (
"net/http"
"github.com/owncloud/ocis-pkg/v2/log"
"github.com/owncloud/ocis-settings/pkg/config"
)
// Option defines a single option function.
type Option func(o *Options)
// Options defines the available options for this package.
type Options struct {
Logger log.Logger
Config *config.Config
Middleware []func(http.Handler) http.Handler
}
// Logger provides a function to set the logger option.
func Logger(val log.Logger) Option {
return func(o *Options) {
o.Logger = val
}
}
// Config provides a function to set the config option.
func Config(val *config.Config) Option {
return func(o *Options) {
o.Config = val
}
}
// Middleware provides a function to set the middleware option.
func Middleware(val ...func(http.Handler) http.Handler) Option {
return func(o *Options) {
o.Middleware = val
}
}
+57
View File
@@ -0,0 +1,57 @@
package svc
import "github.com/owncloud/ocis-settings/pkg/proto/v0"
func (g Service) hasPermission(
roleIDs []string,
resource *proto.Resource,
operations []proto.Permission_Operation,
constraint proto.Permission_Constraint,
) bool {
permissions, err := g.manager.ListPermissionsByResource(resource, roleIDs)
if err != nil {
g.logger.Debug().Err(err).
Str("resource-type", resource.Type.String()).
Str("resource-id", resource.Id).
Msg("permissions could not be loaded for resource")
return false
}
permissions = getFilteredPermissionsByOperations(permissions, operations)
return isConstraintFulfilled(permissions, constraint)
}
// filterPermissionsByOperations returns the subset of the given permissions, where at least one of the given operations is fulfilled.
func getFilteredPermissionsByOperations(permissions []*proto.Permission, operations []proto.Permission_Operation) []*proto.Permission {
var filteredPermissions []*proto.Permission
for _, permission := range permissions {
if isAnyOperationFulfilled(permission, operations) {
filteredPermissions = append(filteredPermissions, permission)
}
}
return filteredPermissions
}
// isAnyOperationFulfilled checks if the permissions is about any of the operations
func isAnyOperationFulfilled(permission *proto.Permission, operations []proto.Permission_Operation) bool {
for _, operation := range operations {
if operation == permission.Operation {
return true
}
}
return false
}
// isConstraintFulfilled checks if one of the permissions has the same or a parent of the constraint.
// this is only a comparison on ENUM level. More sophisticated checks cannot happen here...
func isConstraintFulfilled(permissions []*proto.Permission, constraint proto.Permission_Constraint) bool {
for _, permission := range permissions {
// comparing enum by order is not a feasible solution, because `SHARED` is not a superset of `OWN`.
if permission.Constraint == proto.Permission_CONSTRAINT_ALL {
return true
}
if permission.Constraint != proto.Permission_CONSTRAINT_UNKNOWN && permission.Constraint == constraint {
return true
}
}
return false
}
+388
View File
@@ -0,0 +1,388 @@
package svc
import (
"context"
"fmt"
"github.com/golang/protobuf/ptypes/empty"
merrors "github.com/micro/go-micro/v2/errors"
"github.com/micro/go-micro/v2/metadata"
"github.com/owncloud/ocis-pkg/v2/log"
"github.com/owncloud/ocis-pkg/v2/middleware"
"github.com/owncloud/ocis-pkg/v2/roles"
"github.com/owncloud/ocis-settings/pkg/config"
"github.com/owncloud/ocis-settings/pkg/proto/v0"
"github.com/owncloud/ocis-settings/pkg/settings"
store "github.com/owncloud/ocis-settings/pkg/store/filesystem"
)
// Service represents a service.
type Service struct {
id string
config *config.Config
logger log.Logger
manager settings.Manager
}
// NewService returns a service implementation for Service.
func NewService(cfg *config.Config, logger log.Logger) Service {
service := Service{
id: "ocis-settings",
config: cfg,
logger: logger,
manager: store.New(cfg),
}
service.RegisterDefaultRoles()
return service
}
// RegisterDefaultRoles composes default roles and saves them. Skipped if the roles already exist.
func (g Service) RegisterDefaultRoles() {
// FIXME: we're writing default roles per service start (i.e. twice at the moment, for http and grpc server). has to happen only once.
for _, role := range generateBundlesDefaultRoles() {
bundleID := role.Extension + "." + role.Id
// check if the role already exists
bundle, _ := g.manager.ReadBundle(role.Id)
if bundle != nil {
g.logger.Debug().Str("bundleID", bundleID).Msg("bundle already exists. skipping.")
continue
}
// create the role
_, err := g.manager.WriteBundle(role)
if err != nil {
g.logger.Error().Err(err).Str("bundleID", bundleID).Msg("failed to register bundle")
}
g.logger.Debug().Str("bundleID", bundleID).Msg("successfully registered bundle")
}
}
// TODO: check permissions on every request
// SaveBundle implements the BundleServiceHandler interface
func (g Service) SaveBundle(c context.Context, req *proto.SaveBundleRequest, res *proto.SaveBundleResponse) error {
cleanUpResource(c, req.Bundle.Resource)
if validationError := validateSaveBundle(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.WriteBundle(req.Bundle)
if err != nil {
return merrors.BadRequest(g.id, "%s", err)
}
res.Bundle = r
return nil
}
// GetBundle implements the BundleServiceHandler interface
func (g Service) GetBundle(c context.Context, req *proto.GetBundleRequest, res *proto.GetBundleResponse) error {
if validationError := validateGetBundle(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
bundle, err := g.manager.ReadBundle(req.BundleId)
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
filteredBundle := g.getFilteredBundle(g.getRoleIDs(c), bundle)
if len(filteredBundle.Settings) == 0 {
err = fmt.Errorf("could not read bundle: %s", req.BundleId)
return merrors.NotFound(g.id, "%s", err)
}
res.Bundle = filteredBundle
return nil
}
// ListBundles implements the BundleServiceHandler interface
func (g Service) ListBundles(c context.Context, req *proto.ListBundlesRequest, res *proto.ListBundlesResponse) error {
// fetch all bundles
if validationError := validateListBundles(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
bundles, err := g.manager.ListBundles(proto.Bundle_TYPE_DEFAULT, req.BundleIds)
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
roleIDs := g.getRoleIDs(c)
// filter settings in bundles that are allowed according to roles
var filteredBundles []*proto.Bundle
for _, bundle := range bundles {
filteredBundle := g.getFilteredBundle(roleIDs, bundle)
if len(filteredBundle.Settings) > 0 {
filteredBundles = append(filteredBundles, filteredBundle)
}
}
res.Bundles = filteredBundles
return nil
}
func (g Service) getFilteredBundle(roleIDs []string, bundle *proto.Bundle) *proto.Bundle {
// check if full bundle is whitelisted
bundleResource := &proto.Resource{
Type: proto.Resource_TYPE_BUNDLE,
Id: bundle.Id,
}
if g.hasPermission(
roleIDs,
bundleResource,
[]proto.Permission_Operation{proto.Permission_OPERATION_READ, proto.Permission_OPERATION_READWRITE},
proto.Permission_CONSTRAINT_OWN,
) {
return bundle
}
// filter settings based on permissions
var filteredSettings []*proto.Setting
for _, setting := range bundle.Settings {
settingResource := &proto.Resource{
Type: proto.Resource_TYPE_SETTING,
Id: setting.Id,
}
if g.hasPermission(
roleIDs,
settingResource,
[]proto.Permission_Operation{proto.Permission_OPERATION_READ, proto.Permission_OPERATION_READWRITE},
proto.Permission_CONSTRAINT_OWN,
) {
filteredSettings = append(filteredSettings, setting)
}
}
bundle.Settings = filteredSettings
return bundle
}
// AddSettingToBundle implements the BundleServiceHandler interface
func (g Service) AddSettingToBundle(c context.Context, req *proto.AddSettingToBundleRequest, res *proto.AddSettingToBundleResponse) error {
cleanUpResource(c, req.Setting.Resource)
if validationError := validateAddSettingToBundle(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.AddSettingToBundle(req.BundleId, req.Setting)
if err != nil {
return merrors.BadRequest(g.id, "%s", err)
}
res.Setting = r
return nil
}
// RemoveSettingFromBundle implements the BundleServiceHandler interface
func (g Service) RemoveSettingFromBundle(c context.Context, req *proto.RemoveSettingFromBundleRequest, _ *empty.Empty) error {
if validationError := validateRemoveSettingFromBundle(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
if err := g.manager.RemoveSettingFromBundle(req.BundleId, req.SettingId); err != nil {
return merrors.BadRequest(g.id, "%s", err)
}
return nil
}
// SaveValue implements the ValueServiceHandler interface
func (g Service) SaveValue(c context.Context, req *proto.SaveValueRequest, res *proto.SaveValueResponse) error {
req.Value.AccountUuid = getValidatedAccountUUID(c, req.Value.AccountUuid)
cleanUpResource(c, req.Value.Resource)
// TODO: we need to check, if the authenticated user has permission to write the value for the specified resource (e.g. global, file with id xy, ...)
if validationError := validateSaveValue(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.WriteValue(req.Value)
if err != nil {
return merrors.BadRequest(g.id, "%s", err)
}
valueWithIdentifier, err := g.getValueWithIdentifier(r)
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
res.Value = valueWithIdentifier
return nil
}
// GetValue implements the ValueServiceHandler interface
func (g Service) GetValue(c context.Context, req *proto.GetValueRequest, res *proto.GetValueResponse) error {
if validationError := validateGetValue(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.ReadValue(req.Id)
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
valueWithIdentifier, err := g.getValueWithIdentifier(r)
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
res.Value = valueWithIdentifier
return nil
}
// GetValueByUniqueIdentifiers implements the ValueService interface
func (g Service) GetValueByUniqueIdentifiers(ctx context.Context, req *proto.GetValueByUniqueIdentifiersRequest, res *proto.GetValueResponse) error {
if validationError := validateGetValueByUniqueIdentifiers(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
v, err := g.manager.ReadValueByUniqueIdentifiers(req.AccountUuid, req.SettingId)
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
if v.BundleId != "" {
valueWithIdentifier, err := g.getValueWithIdentifier(v)
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
res.Value = valueWithIdentifier
}
return nil
}
// ListValues implements the ValueServiceHandler interface
func (g Service) ListValues(c context.Context, req *proto.ListValuesRequest, res *proto.ListValuesResponse) error {
req.AccountUuid = getValidatedAccountUUID(c, req.AccountUuid)
if validationError := validateListValues(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.ListValues(req.BundleId, req.AccountUuid)
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
var result []*proto.ValueWithIdentifier
for _, value := range r {
valueWithIdentifier, err := g.getValueWithIdentifier(value)
if err == nil {
result = append(result, valueWithIdentifier)
}
}
res.Values = result
return nil
}
// ListRoles implements the RoleServiceHandler interface
func (g Service) ListRoles(c context.Context, req *proto.ListBundlesRequest, res *proto.ListBundlesResponse) error {
//accountUUID := getValidatedAccountUUID(c, "me")
if validationError := validateListRoles(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.ListBundles(proto.Bundle_TYPE_ROLE, req.BundleIds)
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
// TODO: only allow to list roles when user has account/role/... management permissions
res.Bundles = r
return nil
}
// ListRoleAssignments implements the RoleServiceHandler interface
func (g Service) ListRoleAssignments(c context.Context, req *proto.ListRoleAssignmentsRequest, res *proto.ListRoleAssignmentsResponse) error {
req.AccountUuid = getValidatedAccountUUID(c, req.AccountUuid)
if validationError := validateListRoleAssignments(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.ListRoleAssignments(req.AccountUuid)
if err != nil {
return merrors.NotFound(g.id, "%s", err)
}
res.Assignments = r
return nil
}
// AssignRoleToUser implements the RoleServiceHandler interface
func (g Service) AssignRoleToUser(c context.Context, req *proto.AssignRoleToUserRequest, res *proto.AssignRoleToUserResponse) error {
req.AccountUuid = getValidatedAccountUUID(c, req.AccountUuid)
if validationError := validateAssignRoleToUser(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
r, err := g.manager.WriteRoleAssignment(req.AccountUuid, req.RoleId)
if err != nil {
return merrors.BadRequest(g.id, "%s", err)
}
res.Assignment = r
return nil
}
// RemoveRoleFromUser implements the RoleServiceHandler interface
func (g Service) RemoveRoleFromUser(c context.Context, req *proto.RemoveRoleFromUserRequest, _ *empty.Empty) error {
if validationError := validateRemoveRoleFromUser(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
if err := g.manager.RemoveRoleAssignment(req.Id); err != nil {
return merrors.BadRequest(g.id, "%s", err)
}
return nil
}
// ListPermissionsByResource implements the PermissionServiceHandler interface
func (g Service) ListPermissionsByResource(c context.Context, req *proto.ListPermissionsByResourceRequest, res *proto.ListPermissionsByResourceResponse) error {
if validationError := validateListPermissionsByResource(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
permissions, err := g.manager.ListPermissionsByResource(req.Resource, g.getRoleIDs(c))
if err != nil {
return merrors.BadRequest(g.id, "%s", err)
}
res.Permissions = permissions
return nil
}
// GetPermissionByID implements the PermissionServiceHandler interface
func (g Service) GetPermissionByID(c context.Context, req *proto.GetPermissionByIDRequest, res *proto.GetPermissionByIDResponse) error {
if validationError := validateGetPermissionByID(req); validationError != nil {
return merrors.BadRequest(g.id, "%s", validationError)
}
permission, err := g.manager.ReadPermissionByID(req.PermissionId, g.getRoleIDs(c))
if err != nil {
return merrors.BadRequest(g.id, "%s", err)
}
if permission == nil {
return merrors.NotFound(g.id, "%s", fmt.Errorf("permission %s not found in roles", req.PermissionId))
}
res.Permission = permission
return nil
}
// cleanUpResource makes sure that the account uuid of the authenticated user is injected if needed.
func cleanUpResource(c context.Context, resource *proto.Resource) {
if resource != nil && resource.Type == proto.Resource_TYPE_USER {
resource.Id = getValidatedAccountUUID(c, resource.Id)
}
}
// getValidatedAccountUUID converts `me` into an actual account uuid from the context, if possible.
// the result of this function will always be a valid lower-case UUID or an empty string.
func getValidatedAccountUUID(c context.Context, accountUUID string) string {
if accountUUID == "me" {
if ownAccountUUID, ok := metadata.Get(c, middleware.AccountID); ok {
accountUUID = ownAccountUUID
}
}
if accountUUID == "me" {
// no matter what happens above, an accountUUID of `me` must not be passed on. Clear it instead.
accountUUID = ""
}
return accountUUID
}
// getRoleIDs extracts the roleIDs of the authenticated user from the context.
func (g Service) getRoleIDs(c context.Context) []string {
if ownRoleIDs, ok := roles.ReadRoleIDsFromContext(c); ok {
return ownRoleIDs
}
return []string{}
}
func (g Service) getValueWithIdentifier(value *proto.Value) (*proto.ValueWithIdentifier, error) {
bundle, err := g.manager.ReadBundle(value.BundleId)
if err != nil {
return nil, err
}
setting, err := g.manager.ReadSetting(value.SettingId)
if err != nil {
return nil, err
}
return &proto.ValueWithIdentifier{
Identifier: &proto.Identifier{
Extension: bundle.Extension,
Bundle: bundle.Name,
Setting: setting.Name,
},
Value: value,
}, nil
}
+61
View File
@@ -0,0 +1,61 @@
package svc
import (
"context"
"testing"
"github.com/micro/go-micro/v2/metadata"
"github.com/owncloud/ocis-pkg/v2/middleware"
"github.com/stretchr/testify/assert"
)
var (
ctxWithUUID = metadata.Set(context.Background(), middleware.AccountID, "61445573-4dbe-4d56-88dc-88ab47aceba7")
ctxWithEmptyUUID = metadata.Set(context.Background(), middleware.AccountID, "")
emptyCtx = context.Background()
scenarios = []struct {
name string
accountUUID string
ctx context.Context
expect string
}{
{
name: "context with UUID; identifier = 'me'",
ctx: ctxWithUUID,
accountUUID: "me",
expect: "61445573-4dbe-4d56-88dc-88ab47aceba7",
},
{
name: "context with empty UUID; identifier = 'me'",
ctx: ctxWithEmptyUUID,
accountUUID: "me",
expect: "",
},
{
name: "context without UUID; identifier = 'me'",
ctx: emptyCtx,
accountUUID: "me",
expect: "",
},
{
name: "context with UUID; identifier not 'me'",
ctx: ctxWithUUID,
accountUUID: "",
expect: "",
},
}
)
func TestGetValidatedAccountUUID(t *testing.T) {
for _, s := range scenarios {
scenario := s
t.Run(scenario.name, func(t *testing.T) {
got := getValidatedAccountUUID(scenario.ctx, scenario.accountUUID)
assert.NotPanics(t, func() {
getValidatedAccountUUID(emptyCtx, scenario.accountUUID)
})
assert.Equal(t, scenario.expect, got)
})
}
}
+65
View File
@@ -0,0 +1,65 @@
package svc
import settings "github.com/owncloud/ocis-settings/pkg/proto/v0"
const (
// BundleUUIDRoleAdmin represents the admin role
BundleUUIDRoleAdmin = "71881883-1768-46bd-a24d-a356a2afdf7f"
// BundleUUIDRoleUser represents the user role.
BundleUUIDRoleUser = "d7beeea8-8ff4-406b-8fb6-ab2dd81e6b11"
// BundleUUIDRoleGuest represents the guest role.
BundleUUIDRoleGuest = "38071a68-456a-4553-846a-fa67bf5596cc"
)
// generateBundlesDefaultRoles bootstraps the default roles.
func generateBundlesDefaultRoles() []*settings.Bundle {
return []*settings.Bundle{
generateBundleAdminRole(),
generateBundleUserRole(),
generateBundleGuestRole(),
}
}
func generateBundleAdminRole() *settings.Bundle {
return &settings.Bundle{
Id: BundleUUIDRoleAdmin,
Name: "admin",
Type: settings.Bundle_TYPE_ROLE,
Extension: "ocis-roles",
DisplayName: "Admin",
Resource: &settings.Resource{
Type: settings.Resource_TYPE_SYSTEM,
},
Settings: []*settings.Setting{},
}
}
func generateBundleUserRole() *settings.Bundle {
return &settings.Bundle{
Id: BundleUUIDRoleUser,
Name: "user",
Type: settings.Bundle_TYPE_ROLE,
Extension: "ocis-roles",
DisplayName: "User",
Resource: &settings.Resource{
Type: settings.Resource_TYPE_SYSTEM,
},
Settings: []*settings.Setting{},
}
}
func generateBundleGuestRole() *settings.Bundle {
return &settings.Bundle{
Id: BundleUUIDRoleGuest,
Name: "guest",
Type: settings.Bundle_TYPE_ROLE,
Extension: "ocis-roles",
DisplayName: "Guest",
Resource: &settings.Resource{
Type: settings.Resource_TYPE_SYSTEM,
},
Settings: []*settings.Setting{},
}
}
+9
View File
@@ -0,0 +1,9 @@
package svc
// NewTracing returns a service that instruments traces.
func NewTracing(next Service) Service {
return Service{
manager: next.manager,
config: next.config,
}
}
+163
View File
@@ -0,0 +1,163 @@
package svc
import (
"regexp"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/go-ozzo/ozzo-validation/v4/is"
"github.com/owncloud/ocis-settings/pkg/proto/v0"
)
var (
regexForAccountUUID = regexp.MustCompile(`^[A-Za-z0-9\-_.+@]+$`)
requireAccountID = []validation.Rule{
// use rule for validation error message consistency (".. must not be blank" on empty strings)
validation.Required,
validation.Match(regexForAccountUUID),
}
regexForKeys = regexp.MustCompile(`^[A-Za-z0-9\-_]*$`)
requireAlphanumeric = []validation.Rule{
validation.Required,
validation.Match(regexForKeys),
}
)
func validateSaveBundle(req *proto.SaveBundleRequest) error {
if err := validation.ValidateStruct(
req.Bundle,
validation.Field(&req.Bundle.Id, validation.When(req.Bundle.Id != "", is.UUID)),
validation.Field(&req.Bundle.Name, requireAlphanumeric...),
validation.Field(&req.Bundle.Type, validation.NotIn(proto.Bundle_TYPE_UNKNOWN)),
validation.Field(&req.Bundle.Extension, requireAlphanumeric...),
validation.Field(&req.Bundle.DisplayName, validation.Required),
validation.Field(&req.Bundle.Settings, validation.Required),
); err != nil {
return err
}
if err := validateResource(req.Bundle.Resource); err != nil {
return err
}
for i := range req.Bundle.Settings {
if err := validateSetting(req.Bundle.Settings[i]); err != nil {
return err
}
}
return nil
}
func validateGetBundle(req *proto.GetBundleRequest) error {
return validation.Validate(&req.BundleId, is.UUID)
}
func validateListBundles(req *proto.ListBundlesRequest) error {
return nil
}
func validateAddSettingToBundle(req *proto.AddSettingToBundleRequest) error {
if err := validation.ValidateStruct(req, validation.Field(&req.BundleId, is.UUID)); err != nil {
return err
}
return validateSetting(req.Setting)
}
func validateRemoveSettingFromBundle(req *proto.RemoveSettingFromBundleRequest) error {
return validation.ValidateStruct(
req,
validation.Field(&req.BundleId, is.UUID),
validation.Field(&req.SettingId, is.UUID),
)
}
func validateSaveValue(req *proto.SaveValueRequest) error {
if err := validation.ValidateStruct(
req.Value,
validation.Field(&req.Value.Id, validation.When(req.Value.Id != "", is.UUID)),
validation.Field(&req.Value.BundleId, is.UUID),
validation.Field(&req.Value.SettingId, is.UUID),
validation.Field(&req.Value.AccountUuid, requireAccountID...),
); err != nil {
return err
}
if err := validateResource(req.Value.Resource); err != nil {
return err
}
// TODO: validate values against the respective setting. need to check if constraints of the setting are fulfilled.
return nil
}
func validateGetValue(req *proto.GetValueRequest) error {
return validation.Validate(req.Id, is.UUID)
}
func validateGetValueByUniqueIdentifiers(req *proto.GetValueByUniqueIdentifiersRequest) error {
return validation.ValidateStruct(
req,
validation.Field(&req.SettingId, is.UUID),
validation.Field(&req.AccountUuid, requireAccountID...),
)
}
func validateListValues(req *proto.ListValuesRequest) error {
return validation.ValidateStruct(
req,
validation.Field(&req.BundleId, validation.When(req.BundleId != "", is.UUID)),
validation.Field(&req.AccountUuid, validation.When(req.AccountUuid != "", validation.Match(regexForAccountUUID))),
)
}
func validateListRoles(req *proto.ListBundlesRequest) error {
return nil
}
func validateListRoleAssignments(req *proto.ListRoleAssignmentsRequest) error {
return validation.Validate(req.AccountUuid, requireAccountID...)
}
func validateAssignRoleToUser(req *proto.AssignRoleToUserRequest) error {
return validation.ValidateStruct(
req,
validation.Field(&req.AccountUuid, requireAccountID...),
validation.Field(&req.RoleId, is.UUID),
)
}
func validateRemoveRoleFromUser(req *proto.RemoveRoleFromUserRequest) error {
return validation.ValidateStruct(
req,
validation.Field(&req.Id, is.UUID),
)
}
func validateListPermissionsByResource(req *proto.ListPermissionsByResourceRequest) error {
return validateResource(req.Resource)
}
func validateGetPermissionByID(req *proto.GetPermissionByIDRequest) error {
return validation.ValidateStruct(
req,
validation.Field(&req.PermissionId, requireAlphanumeric...),
)
}
// validateResource is an internal helper for validating the content of a resource.
func validateResource(resource *proto.Resource) error {
if err := validation.Validate(&resource, validation.Required); err != nil {
return err
}
return validation.Validate(&resource, validation.NotIn(proto.Resource_TYPE_UNKNOWN))
}
// validateSetting is an internal helper for validating the content of a setting.
func validateSetting(setting *proto.Setting) error {
// TODO: make sanity checks, like for int settings, min <= default <= max.
if err := validation.ValidateStruct(
setting,
validation.Field(&setting.Id, validation.When(setting.Id != "", is.UUID)),
validation.Field(&setting.Name, requireAlphanumeric...),
); err != nil {
return err
}
return validateResource(setting.Resource)
}