diff options
| author | mo khan <mo@mokhan.ca> | 2025-05-20 14:28:06 -0600 |
|---|---|---|
| committer | mo khan <mo@mokhan.ca> | 2025-05-23 14:49:19 -0600 |
| commit | 4beee46dc6c7642316e118a4d3aa51e4b407256e (patch) | |
| tree | 039bdf57b99061844aeb0fe55ad0bc1c864166af /vendor/github.com/jhump/protoreflect/internal/codec/decode.go | |
| parent | 0ba49bfbde242920d8675a193d7af89420456fc0 (diff) | |
feat: add external authorization service (authzd) with JWT authentication
- Add new authzd gRPC service implementing Envoy's external authorization API
- Integrate JWT authentication filter in Envoy configuration with claim extraction
- Update middleware to support both cookie-based and header-based user authentication
- Add comprehensive test coverage for authorization service and server
- Configure proper service orchestration with authzd, sparkled, and Envoy
- Update build system and Docker configuration for multi-service deployment
- Add grpcurl tool for gRPC service debugging and testing
This enables fine-grained authorization control through Envoy's ext_authz filter
while maintaining backward compatibility with existing cookie-based authentication.
Diffstat (limited to 'vendor/github.com/jhump/protoreflect/internal/codec/decode.go')
| -rw-r--r-- | vendor/github.com/jhump/protoreflect/internal/codec/decode.go | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/vendor/github.com/jhump/protoreflect/internal/codec/decode.go b/vendor/github.com/jhump/protoreflect/internal/codec/decode.go new file mode 100644 index 0000000..a25f680 --- /dev/null +++ b/vendor/github.com/jhump/protoreflect/internal/codec/decode.go @@ -0,0 +1,346 @@ +package codec + +import ( + "errors" + "fmt" + "io" + "math" + + "github.com/golang/protobuf/proto" +) + +// ErrOverflow is returned when an integer is too large to be represented. +var ErrOverflow = errors.New("proto: integer overflow") + +// ErrBadWireType is returned when decoding a wire-type from a buffer that +// is not valid. +var ErrBadWireType = errors.New("proto: bad wiretype") + +func (cb *Buffer) decodeVarintSlow() (x uint64, err error) { + i := cb.index + l := len(cb.buf) + + for shift := uint(0); shift < 64; shift += 7 { + if i >= l { + err = io.ErrUnexpectedEOF + return + } + b := cb.buf[i] + i++ + x |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + cb.index = i + return + } + } + + // The number is too large to represent in a 64-bit value. + err = ErrOverflow + return +} + +// DecodeVarint reads a varint-encoded integer from the Buffer. +// This is the format for the +// int32, int64, uint32, uint64, bool, and enum +// protocol buffer types. +func (cb *Buffer) DecodeVarint() (uint64, error) { + i := cb.index + buf := cb.buf + + if i >= len(buf) { + return 0, io.ErrUnexpectedEOF + } else if buf[i] < 0x80 { + cb.index++ + return uint64(buf[i]), nil + } else if len(buf)-i < 10 { + return cb.decodeVarintSlow() + } + + var b uint64 + // we already checked the first byte + x := uint64(buf[i]) - 0x80 + i++ + + b = uint64(buf[i]) + i++ + x += b << 7 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 7 + + b = uint64(buf[i]) + i++ + x += b << 14 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 14 + + b = uint64(buf[i]) + i++ + x += b << 21 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 21 + + b = uint64(buf[i]) + i++ + x += b << 28 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 28 + + b = uint64(buf[i]) + i++ + x += b << 35 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 35 + + b = uint64(buf[i]) + i++ + x += b << 42 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 42 + + b = uint64(buf[i]) + i++ + x += b << 49 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 49 + + b = uint64(buf[i]) + i++ + x += b << 56 + if b&0x80 == 0 { + goto done + } + x -= 0x80 << 56 + + b = uint64(buf[i]) + i++ + x += b << 63 + if b&0x80 == 0 { + goto done + } + // x -= 0x80 << 63 // Always zero. + + return 0, ErrOverflow + +done: + cb.index = i + return x, nil +} + +// DecodeTagAndWireType decodes a field tag and wire type from input. +// This reads a varint and then extracts the two fields from the varint +// value read. +func (cb *Buffer) DecodeTagAndWireType() (tag int32, wireType int8, err error) { + var v uint64 + v, err = cb.DecodeVarint() + if err != nil { + return + } + // low 7 bits is wire type + wireType = int8(v & 7) + // rest is int32 tag number + v = v >> 3 + if v > math.MaxInt32 { + err = fmt.Errorf("tag number out of range: %d", v) + return + } + tag = int32(v) + return +} + +// DecodeFixed64 reads a 64-bit integer from the Buffer. +// This is the format for the +// fixed64, sfixed64, and double protocol buffer types. +func (cb *Buffer) DecodeFixed64() (x uint64, err error) { + // x, err already 0 + i := cb.index + 8 + if i < 0 || i > len(cb.buf) { + err = io.ErrUnexpectedEOF + return + } + cb.index = i + + x = uint64(cb.buf[i-8]) + x |= uint64(cb.buf[i-7]) << 8 + x |= uint64(cb.buf[i-6]) << 16 + x |= uint64(cb.buf[i-5]) << 24 + x |= uint64(cb.buf[i-4]) << 32 + x |= uint64(cb.buf[i-3]) << 40 + x |= uint64(cb.buf[i-2]) << 48 + x |= uint64(cb.buf[i-1]) << 56 + return +} + +// DecodeFixed32 reads a 32-bit integer from the Buffer. +// This is the format for the +// fixed32, sfixed32, and float protocol buffer types. +func (cb *Buffer) DecodeFixed32() (x uint64, err error) { + // x, err already 0 + i := cb.index + 4 + if i < 0 || i > len(cb.buf) { + err = io.ErrUnexpectedEOF + return + } + cb.index = i + + x = uint64(cb.buf[i-4]) + x |= uint64(cb.buf[i-3]) << 8 + x |= uint64(cb.buf[i-2]) << 16 + x |= uint64(cb.buf[i-1]) << 24 + return +} + +// DecodeRawBytes reads a count-delimited byte buffer from the Buffer. +// This is the format used for the bytes protocol buffer +// type and for embedded messages. +func (cb *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err error) { + n, err := cb.DecodeVarint() + if err != nil { + return nil, err + } + + nb := int(n) + if nb < 0 { + return nil, fmt.Errorf("proto: bad byte length %d", nb) + } + end := cb.index + nb + if end < cb.index || end > len(cb.buf) { + return nil, io.ErrUnexpectedEOF + } + + if !alloc { + buf = cb.buf[cb.index:end] + cb.index = end + return + } + + buf = make([]byte, nb) + copy(buf, cb.buf[cb.index:]) + cb.index = end + return +} + +// ReadGroup reads the input until a "group end" tag is found +// and returns the data up to that point. Subsequent reads from +// the buffer will read data after the group end tag. If alloc +// is true, the data is copied to a new slice before being returned. +// Otherwise, the returned slice is a view into the buffer's +// underlying byte slice. +// +// This function correctly handles nested groups: if a "group start" +// tag is found, then that group's end tag will be included in the +// returned data. +func (cb *Buffer) ReadGroup(alloc bool) ([]byte, error) { + var groupEnd, dataEnd int + groupEnd, dataEnd, err := cb.findGroupEnd() + if err != nil { + return nil, err + } + var results []byte + if !alloc { + results = cb.buf[cb.index:dataEnd] + } else { + results = make([]byte, dataEnd-cb.index) + copy(results, cb.buf[cb.index:]) + } + cb.index = groupEnd + return results, nil +} + +// SkipGroup is like ReadGroup, except that it discards the +// data and just advances the buffer to point to the input +// right *after* the "group end" tag. +func (cb *Buffer) SkipGroup() error { + groupEnd, _, err := cb.findGroupEnd() + if err != nil { + return err + } + cb.index = groupEnd + return nil +} + +// SkipField attempts to skip the value of a field with the given wire +// type. When consuming a protobuf-encoded stream, it can be called immediately +// after DecodeTagAndWireType to discard the subsequent data for the field. +func (cb *Buffer) SkipField(wireType int8) error { + switch wireType { + case proto.WireFixed32: + if err := cb.Skip(4); err != nil { + return err + } + case proto.WireFixed64: + if err := cb.Skip(8); err != nil { + return err + } + case proto.WireVarint: + // skip varint by finding last byte (has high bit unset) + i := cb.index + limit := i + 10 // varint cannot be >10 bytes + for { + if i >= limit { + return ErrOverflow + } + if i >= len(cb.buf) { + return io.ErrUnexpectedEOF + } + if cb.buf[i]&0x80 == 0 { + break + } + i++ + } + // TODO: This would only overflow if buffer length was MaxInt and we + // read the last byte. This is not a real/feasible concern on 64-bit + // systems. Something to worry about for 32-bit systems? Do we care? + cb.index = i + 1 + case proto.WireBytes: + l, err := cb.DecodeVarint() + if err != nil { + return err + } + if err := cb.Skip(int(l)); err != nil { + return err + } + case proto.WireStartGroup: + if err := cb.SkipGroup(); err != nil { + return err + } + default: + return ErrBadWireType + } + return nil +} + +func (cb *Buffer) findGroupEnd() (groupEnd int, dataEnd int, err error) { + start := cb.index + defer func() { + cb.index = start + }() + for { + fieldStart := cb.index + // read a field tag + _, wireType, err := cb.DecodeTagAndWireType() + if err != nil { + return 0, 0, err + } + if wireType == proto.WireEndGroup { + return cb.index, fieldStart, nil + } + // skip past the field's data + if err := cb.SkipField(wireType); err != nil { + return 0, 0, err + } + } +} |
