Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to new validation plugin #194

Merged
merged 27 commits into from
Mar 15, 2019
Merged
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b92c055
api: Use new validation options
Mar 7, 2019
6760a04
api: Add/fix validations
Mar 15, 2019
cfc05a9
api: Fix populators
Mar 15, 2019
3a4b0f4
api: Regenerate
Mar 7, 2019
c5775d2
api: Validate Set/Update requests using fieldmask
Mar 13, 2019
d50235d
api: Remove bounds validation on raw_payload
johanstokking Mar 14, 2019
85f388d
make: Update protoc image version
Mar 7, 2019
1ac7663
dev: Vendor validator dependencies
Mar 7, 2019
833ddeb
all: Migrate to new validation method signature
Mar 7, 2019
2faaa36
util: Support ValidateFields in validator middleware
Mar 6, 2019
3f214ab
util: Fix PingSlotChannel MAC command frequency encoding
Mar 8, 2019
0c52e16
util: Fix crypto package
Mar 12, 2019
26a2358
ns: Fix panics in application queue
Mar 6, 2019
1f559d4
ns: Harmonize tests, adapt to message validation
Mar 6, 2019
8d91552
js: Harmonize tests, adapt to message validation
Mar 7, 2019
5a8a37b
js: Ensure App/Dev IDs are set in registries
Mar 7, 2019
e899ff5
ns: Fix panic on message drops
Mar 8, 2019
a82632f
ns: Fix BeaconFreqReq MAC encoding
Mar 8, 2019
f1abfd4
ns: Adapt to API changes
Mar 9, 2019
7f5ab3e
js: Make device primary key uid and secondary key EUIs
johanstokking Mar 8, 2019
2c7fa8d
ns: Fix argument order
johanstokking Mar 8, 2019
240601e
js: Make SetByEUI atomic in Redis
Mar 9, 2019
97789d2
util: Do not change given uplink message when getting identifiers
johanstokking Mar 14, 2019
1df8842
util: Adapt to API changes
Mar 15, 2019
6c170e1
dev: Regenerate messages
Mar 12, 2019
1a04640
ns: Fix decoding of uplinks
Mar 15, 2019
7d0d128
js: Remove redundant checks
Mar 15, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
util: Support ValidateFields in validator middleware
Roman Volosatovs committed Mar 15, 2019

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 2faaa36241ac3533f5ca238cd4c073d9e45bb711
116 changes: 58 additions & 58 deletions pkg/rpcmiddleware/validator/validator.go
Original file line number Diff line number Diff line change
@@ -39,14 +39,6 @@ func RegisterAllowedFieldMaskPaths(rpcFullMethod string, allowedPaths ...string)
}
}

func getAllowedFieldMaskPaths(rpcFullMethod string) map[string]struct{} {
return allowedFieldMaskPaths[rpcFullMethod]
}

type fieldMaskGetter interface {
GetFieldMask() types.FieldMask
}

var errForbiddenFieldMaskPaths = errors.DefineInvalidArgument("field_mask_paths", "forbidden path(s) in field mask", "forbidden_paths")

func forbiddenPaths(requestedPaths []string, allowedPaths map[string]struct{}) (invalidPaths []string) {
@@ -60,25 +52,53 @@ nextRequestedPath:
return
}

type validatorWithContext interface {
ValidateContext(ctx context.Context) error
}

type validator interface {
Validate() error
}

func convertError(err error) error {
if ttnErr, ok := errors.From(err); ok {
return ttnErr
}
return grpc.Errorf(codes.InvalidArgument, err.Error())
}

func validateMessage(ctx context.Context, fullMethod string, msg interface{}) error {
if v, ok := msg.(interface {
GetFieldMask() types.FieldMask
}); ok {
if forbiddenPaths := forbiddenPaths(v.GetFieldMask().Paths, allowedFieldMaskPaths[fullMethod]); len(forbiddenPaths) > 0 {
return errForbiddenFieldMaskPaths.WithAttributes("forbidden_paths", forbiddenPaths)
}
}

switch v := msg.(type) {
case interface {
ValidateContext(context.Context) error
}:
if err := v.ValidateContext(ctx); err != nil {
return convertError(err)
}

case interface {
Validate() error
}:
if err := v.Validate(); err != nil {
return convertError(err)
}

case interface {
ValidateFields(...string) error
}:
if err := v.ValidateFields(); err != nil {
return convertError(err)
}

}
return nil
}

// UnaryServerInterceptor returns a new unary server interceptor that validates
// incoming messages if those incoming messages implement:
// (A) ValidateContext(ctx context.Context) error
// (B) Validate() error
// (C) ValidateFields(...string) error
// If a message implements both, then (A) should call (B).
//
// Invalid messages will be rejected with the error returned from the validator,
@@ -89,28 +109,33 @@ func convertError(err error) error {
// then the field mask paths are validated according to the registered list.
func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
if v, ok := req.(fieldMaskGetter); ok {
if forbiddenPaths := forbiddenPaths(v.GetFieldMask().Paths, getAllowedFieldMaskPaths(info.FullMethod)); len(forbiddenPaths) > 0 {
return nil, errForbiddenFieldMaskPaths.WithAttributes("forbidden_paths", forbiddenPaths)
}
}
if v, ok := req.(validatorWithContext); ok {
if err := v.ValidateContext(ctx); err != nil {
return nil, convertError(err)
}
} else if v, ok := req.(validator); ok {
if err := v.Validate(); err != nil {
return nil, convertError(err)
}
if err := validateMessage(ctx, info.FullMethod, req); err != nil {
return nil, err
}
return handler(ctx, req)
}
}

type recvWrapper struct {
grpc.ServerStream
fullMethod string
}

func (s *recvWrapper) RecvMsg(msg interface{}) error {
if err := s.ServerStream.RecvMsg(msg); err != nil {
return err
}
if err := validateMessage(s.Context(), s.fullMethod, msg); err != nil {
return err
}
return nil
}

// StreamServerInterceptor returns a new streaming server interceptor that validates
// incoming messages if those incoming messages implement:
// (A) ValidateContext(ctx context.Context) error
// (B) Validate() error
// (C) ValidateFields(...string) error
// If a message implements both, then (A) should call (B).
//
// Invalid messages will be rejected with the error returned from the validator,
@@ -126,34 +151,9 @@ func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
// then the field mask paths are validated according to the registered list.
func StreamServerInterceptor() grpc.StreamServerInterceptor {
return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
wrapper := &recvWrapper{ServerStream: stream, allowedFieldMaskPaths: getAllowedFieldMaskPaths(info.FullMethod)}
return handler(srv, wrapper)
}
}

type recvWrapper struct {
grpc.ServerStream
allowedFieldMaskPaths map[string]struct{}
}

func (s *recvWrapper) RecvMsg(m interface{}) error {
if err := s.ServerStream.RecvMsg(m); err != nil {
return err
}
if v, ok := m.(fieldMaskGetter); ok {
requested := v.GetFieldMask().Paths
if forbiddenPaths := forbiddenPaths(requested, s.allowedFieldMaskPaths); len(forbiddenPaths) > 0 {
return errForbiddenFieldMaskPaths.WithAttributes("forbidden_paths", forbiddenPaths)
}
return handler(srv, &recvWrapper{
ServerStream: stream,
fullMethod: info.FullMethod,
})
}
if v, ok := m.(validatorWithContext); ok {
if err := v.ValidateContext(s.Context()); err != nil {
return convertError(err)
}
} else if v, ok := m.(validator); ok {
if err := v.Validate(); err != nil {
return convertError(err)
}
}
return nil
}