json.go 2.5 KB

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