github.com/lestrrat-go/jwx/v2@v2.0.21/internal/base64/base64.go (about) 1 package base64 2 3 import ( 4 "bytes" 5 "encoding/base64" 6 "encoding/binary" 7 "fmt" 8 "sync" 9 ) 10 11 type Decoder interface { 12 Decode([]byte) ([]byte, error) 13 } 14 15 type Encoder interface { 16 Encode([]byte, []byte) 17 EncodedLen(int) int 18 EncodeToString([]byte) string 19 } 20 21 var muEncoder sync.RWMutex 22 var encoder Encoder = base64.RawURLEncoding 23 var muDecoder sync.RWMutex 24 var decoder Decoder = defaultDecoder{} 25 26 func SetEncoder(enc Encoder) { 27 muEncoder.Lock() 28 defer muEncoder.Unlock() 29 encoder = enc 30 } 31 32 func getEncoder() Encoder { 33 muEncoder.RLock() 34 defer muEncoder.RUnlock() 35 return encoder 36 } 37 38 func SetDecoder(dec Decoder) { 39 muDecoder.Lock() 40 defer muDecoder.Unlock() 41 decoder = dec 42 } 43 44 func getDecoder() Decoder { 45 muDecoder.RLock() 46 defer muDecoder.RUnlock() 47 return decoder 48 } 49 50 func Encode(src []byte) []byte { 51 encoder := getEncoder() 52 dst := make([]byte, encoder.EncodedLen(len(src))) 53 encoder.Encode(dst, src) 54 return dst 55 } 56 57 func EncodeToString(src []byte) string { 58 return getEncoder().EncodeToString(src) 59 } 60 61 func EncodeUint64ToString(v uint64) string { 62 data := make([]byte, 8) 63 binary.BigEndian.PutUint64(data, v) 64 65 i := 0 66 for ; i < len(data); i++ { 67 if data[i] != 0x0 { 68 break 69 } 70 } 71 72 return EncodeToString(data[i:]) 73 } 74 75 const ( 76 InvalidEncoding = iota 77 Std 78 URL 79 RawStd 80 RawURL 81 ) 82 83 func Guess(src []byte) int { 84 var isRaw = !bytes.HasSuffix(src, []byte{'='}) 85 var isURL = !bytes.ContainsAny(src, "+/") 86 switch { 87 case isRaw && isURL: 88 return RawURL 89 case isURL: 90 return URL 91 case isRaw: 92 return RawStd 93 default: 94 return Std 95 } 96 } 97 98 // defaultDecoder is a Decoder that detects the encoding of the source and 99 // decodes it accordingly. This shouldn't really be required per the spec, but 100 // it exist because we have seen in the wild JWTs that are encoded using 101 // various versions of the base64 encoding. 102 type defaultDecoder struct{} 103 104 func (defaultDecoder) Decode(src []byte) ([]byte, error) { 105 var enc *base64.Encoding 106 107 switch Guess(src) { 108 case RawURL: 109 enc = base64.RawURLEncoding 110 case URL: 111 enc = base64.URLEncoding 112 case RawStd: 113 enc = base64.RawStdEncoding 114 case Std: 115 enc = base64.StdEncoding 116 default: 117 return nil, fmt.Errorf(`invalid encoding`) 118 } 119 120 dst := make([]byte, enc.DecodedLen(len(src))) 121 n, err := enc.Decode(dst, src) 122 if err != nil { 123 return nil, fmt.Errorf(`failed to decode source: %w`, err) 124 } 125 return dst[:n], nil 126 } 127 128 func Decode(src []byte) ([]byte, error) { 129 return getDecoder().Decode(src) 130 } 131 132 func DecodeString(src string) ([]byte, error) { 133 return getDecoder().Decode([]byte(src)) 134 }