1package json 2 3import ( 4 "bytes" 5 "sync" 6 "sync/atomic" 7 8 "github.com/lestrrat-go/jwx/internal/base64" 9 "github.com/pkg/errors" 10) 11 12var muGlobalConfig sync.RWMutex 13var useNumber bool 14 15// Sets the global configuration for json decoding 16func DecoderSettings(inUseNumber bool) { 17 muGlobalConfig.Lock() 18 useNumber = inUseNumber 19 muGlobalConfig.Unlock() 20} 21 22// Unmarshal respects the values specified in DecoderSettings, 23// and uses a Decoder that has certain features turned on/off 24func Unmarshal(b []byte, v interface{}) error { 25 dec := NewDecoder(bytes.NewReader(b)) 26 return dec.Decode(v) 27} 28 29func AssignNextBytesToken(dst *[]byte, dec *Decoder) error { 30 var val string 31 if err := dec.Decode(&val); err != nil { 32 return errors.Wrap(err, `error reading next value`) 33 } 34 35 buf, err := base64.DecodeString(val) 36 if err != nil { 37 return errors.Errorf(`expected base64 encoded []byte (%T)`, val) 38 } 39 *dst = buf 40 return nil 41} 42 43func ReadNextStringToken(dec *Decoder) (string, error) { 44 var val string 45 if err := dec.Decode(&val); err != nil { 46 return "", errors.Wrap(err, `error reading next value`) 47 } 48 return val, nil 49} 50 51func AssignNextStringToken(dst **string, dec *Decoder) error { 52 val, err := ReadNextStringToken(dec) 53 if err != nil { 54 return err 55 } 56 *dst = &val 57 return nil 58} 59 60// FlattenAudience is a flag to specify if we should flatten the "aud" 61// entry to a string when there's only one entry. 62// In jwx < 1.1.8 we just dumped everything as an array of strings, 63// but apparently AWS Cognito doesn't handle this well. 64// 65// So now we have the ability to dump "aud" as a string if there's 66// only one entry, but we need to retain the old behavior so that 67// we don't accidentally break somebody else's code. (e.g. messing 68// up how signatures are calculated) 69var FlattenAudience uint32 70 71func EncodeAudience(enc *Encoder, aud []string) error { 72 var val interface{} 73 if len(aud) == 1 && atomic.LoadUint32(&FlattenAudience) == 1 { 74 val = aud[0] 75 } else { 76 val = aud 77 } 78 return enc.Encode(val) 79} 80 81// DecodeCtx is an interface for objects that needs that extra something 82// when decoding JSON into an object. 83type DecodeCtx interface { 84 Registry() *Registry 85} 86 87// DecodeCtxContainer is used to differentiate objects that can carry extra 88// decoding hints and those who can't. 89type DecodeCtxContainer interface { 90 DecodeCtx() DecodeCtx 91 SetDecodeCtx(DecodeCtx) 92} 93 94// stock decodeCtx. should cover 80% of the cases 95type decodeCtx struct { 96 registry *Registry 97} 98 99func NewDecodeCtx(r *Registry) DecodeCtx { 100 return &decodeCtx{registry: r} 101} 102 103func (dc *decodeCtx) Registry() *Registry { 104 return dc.registry 105} 106