1// Package buffer provides a very thin wrapper around []byte buffer called 2// `Buffer`, to provide functionalities that are often used within the jwx 3// related packages 4package buffer 5 6import ( 7 "encoding/base64" 8 "encoding/binary" 9 "encoding/json" 10 11 "github.com/pkg/errors" 12) 13 14// Buffer wraps `[]byte` and provides functions that are often used in 15// the jwx related packages. One notable difference is that while 16// encoding/json marshalls `[]byte` using base64.StdEncoding, this 17// module uses base64.RawURLEncoding as mandated by the spec 18type Buffer []byte 19 20// FromUint creates a `Buffer` from an unsigned int 21func FromUint(v uint64) Buffer { 22 data := make([]byte, 8) 23 binary.BigEndian.PutUint64(data, v) 24 25 i := 0 26 for ; i < len(data); i++ { 27 if data[i] != 0x0 { 28 break 29 } 30 } 31 return Buffer(data[i:]) 32} 33 34// FromBase64 constructs a new Buffer from a base64 encoded data 35func FromBase64(v []byte) (Buffer, error) { 36 b := Buffer{} 37 if err := b.Base64Decode(v); err != nil { 38 return Buffer(nil), errors.Wrap(err, "failed to decode from base64") 39 } 40 41 return b, nil 42} 43 44// FromNData constructs a new Buffer from a "n:data" format 45// (I made that name up) 46func FromNData(v []byte) (Buffer, error) { 47 size := binary.BigEndian.Uint32(v) 48 buf := make([]byte, int(size)) 49 copy(buf, v[4:4+size]) 50 return Buffer(buf), nil 51} 52 53// Bytes returns the raw bytes that comprises the Buffer 54func (b Buffer) Bytes() []byte { 55 return []byte(b) 56} 57 58// NData returns Datalen || Data, where Datalen is a 32 bit counter for 59// the length of the following data, and Data is the octets that comprise 60// the buffer data 61func (b Buffer) NData() []byte { 62 buf := make([]byte, 4+b.Len()) 63 binary.BigEndian.PutUint32(buf, uint32(b.Len())) 64 65 copy(buf[4:], b.Bytes()) 66 return buf 67} 68 69// Len returns the number of bytes that the Buffer holds 70func (b Buffer) Len() int { 71 return len(b) 72} 73 74func (b *Buffer) SetBytes(b2 []byte) { 75 *b = make([]byte, len(b2)) 76 copy(*b, b2) 77} 78 79// Base64Encode encodes the contents of the Buffer using base64.RawURLEncoding 80func (b Buffer) Base64Encode() ([]byte, error) { 81 enc := base64.RawURLEncoding 82 out := make([]byte, enc.EncodedLen(len(b))) 83 enc.Encode(out, b) 84 return out, nil 85} 86 87// Base64Decode decodes the contents of the Buffer using base64.RawURLEncoding 88func (b *Buffer) Base64Decode(v []byte) error { 89 enc := base64.RawURLEncoding 90 out := make([]byte, enc.DecodedLen(len(v))) 91 n, err := enc.Decode(out, v) 92 if err != nil { 93 return errors.Wrap(err, "failed to decode from base64") 94 } 95 out = out[:n] 96 *b = Buffer(out) 97 return nil 98} 99 100// MarshalJSON marshals the buffer into JSON format after encoding the buffer 101// with base64.RawURLEncoding 102func (b Buffer) MarshalJSON() ([]byte, error) { 103 v, err := b.Base64Encode() 104 if err != nil { 105 return nil, errors.Wrap(err, "failed to encode to base64") 106 } 107 return json.Marshal(string(v)) 108} 109 110// UnmarshalJSON unmarshals from a JSON string into a Buffer, after decoding it 111// with base64.RawURLEncoding 112func (b *Buffer) UnmarshalJSON(data []byte) error { 113 var x string 114 if err := json.Unmarshal(data, &x); err != nil { 115 return errors.Wrap(err, "failed to unmarshal JSON") 116 } 117 return b.Base64Decode([]byte(x)) 118} 119