Initial QSfera import
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
load("@rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "base64",
|
||||
srcs = ["base64.go"],
|
||||
importpath = "github.com/lestrrat-go/jwx/v3/internal/base64",
|
||||
visibility = ["//:__subpackages__"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "base64_test",
|
||||
srcs = ["base64_test.go"],
|
||||
embed = [":base64"],
|
||||
deps = ["@com_github_stretchr_testify//require"],
|
||||
)
|
||||
|
||||
alias(
|
||||
name = "go_default_library",
|
||||
actual = ":base64",
|
||||
visibility = ["//:__subpackages__"],
|
||||
)
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
//go:build jwx_asmbase64
|
||||
|
||||
package base64
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
asmbase64 "github.com/segmentio/asm/base64"
|
||||
)
|
||||
|
||||
func init() {
|
||||
SetEncoder(asmEncoder{asmbase64.RawURLEncoding})
|
||||
SetDecoder(asmDecoder{})
|
||||
}
|
||||
|
||||
type asmEncoder struct {
|
||||
*asmbase64.Encoding
|
||||
}
|
||||
|
||||
func (e asmEncoder) AppendEncode(dst, src []byte) []byte {
|
||||
n := e.Encoding.EncodedLen(len(src))
|
||||
dst = slices.Grow(dst, n)
|
||||
e.Encoding.Encode(dst[len(dst):][:n], src)
|
||||
return dst[:len(dst)+n]
|
||||
}
|
||||
|
||||
type asmDecoder struct{}
|
||||
|
||||
func (d asmDecoder) Decode(src []byte) ([]byte, error) {
|
||||
var enc *asmbase64.Encoding
|
||||
switch Guess(src) {
|
||||
case Std:
|
||||
enc = asmbase64.StdEncoding
|
||||
case RawStd:
|
||||
enc = asmbase64.RawStdEncoding
|
||||
case URL:
|
||||
enc = asmbase64.URLEncoding
|
||||
case RawURL:
|
||||
enc = asmbase64.RawURLEncoding
|
||||
default:
|
||||
return nil, fmt.Errorf(`invalid encoding`)
|
||||
}
|
||||
|
||||
dst := make([]byte, enc.DecodedLen(len(src)))
|
||||
n, err := enc.Decode(dst, src)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`failed to decode source: %w`, err)
|
||||
}
|
||||
return dst[:n], nil
|
||||
}
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
package base64
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Decoder interface {
|
||||
Decode([]byte) ([]byte, error)
|
||||
}
|
||||
|
||||
type Encoder interface {
|
||||
Encode([]byte, []byte)
|
||||
EncodedLen(int) int
|
||||
EncodeToString([]byte) string
|
||||
AppendEncode([]byte, []byte) []byte
|
||||
}
|
||||
|
||||
var muEncoder sync.RWMutex
|
||||
var encoder Encoder = base64.RawURLEncoding
|
||||
var muDecoder sync.RWMutex
|
||||
var decoder Decoder = defaultDecoder{}
|
||||
|
||||
func SetEncoder(enc Encoder) {
|
||||
muEncoder.Lock()
|
||||
defer muEncoder.Unlock()
|
||||
encoder = enc
|
||||
}
|
||||
|
||||
func getEncoder() Encoder {
|
||||
muEncoder.RLock()
|
||||
defer muEncoder.RUnlock()
|
||||
return encoder
|
||||
}
|
||||
|
||||
func DefaultEncoder() Encoder {
|
||||
return getEncoder()
|
||||
}
|
||||
|
||||
func SetDecoder(dec Decoder) {
|
||||
muDecoder.Lock()
|
||||
defer muDecoder.Unlock()
|
||||
decoder = dec
|
||||
}
|
||||
|
||||
func getDecoder() Decoder {
|
||||
muDecoder.RLock()
|
||||
defer muDecoder.RUnlock()
|
||||
return decoder
|
||||
}
|
||||
|
||||
func Encode(src []byte) []byte {
|
||||
encoder := getEncoder()
|
||||
dst := make([]byte, encoder.EncodedLen(len(src)))
|
||||
encoder.Encode(dst, src)
|
||||
return dst
|
||||
}
|
||||
|
||||
func EncodeToString(src []byte) string {
|
||||
return getEncoder().EncodeToString(src)
|
||||
}
|
||||
|
||||
func EncodeUint64ToString(v uint64) string {
|
||||
data := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(data, v)
|
||||
|
||||
i := 0
|
||||
for ; i < len(data); i++ {
|
||||
if data[i] != 0x0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return EncodeToString(data[i:])
|
||||
}
|
||||
|
||||
const (
|
||||
InvalidEncoding = iota
|
||||
Std
|
||||
URL
|
||||
RawStd
|
||||
RawURL
|
||||
)
|
||||
|
||||
func Guess(src []byte) int {
|
||||
var isRaw = !bytes.HasSuffix(src, []byte{'='})
|
||||
var isURL = !bytes.ContainsAny(src, "+/")
|
||||
switch {
|
||||
case isRaw && isURL:
|
||||
return RawURL
|
||||
case isURL:
|
||||
return URL
|
||||
case isRaw:
|
||||
return RawStd
|
||||
default:
|
||||
return Std
|
||||
}
|
||||
}
|
||||
|
||||
// defaultDecoder is a Decoder that detects the encoding of the source and
|
||||
// decodes it accordingly. This shouldn't really be required per the spec, but
|
||||
// it exist because we have seen in the wild JWTs that are encoded using
|
||||
// various versions of the base64 encoding.
|
||||
type defaultDecoder struct{}
|
||||
|
||||
func (defaultDecoder) Decode(src []byte) ([]byte, error) {
|
||||
var enc *base64.Encoding
|
||||
|
||||
switch Guess(src) {
|
||||
case RawURL:
|
||||
enc = base64.RawURLEncoding
|
||||
case URL:
|
||||
enc = base64.URLEncoding
|
||||
case RawStd:
|
||||
enc = base64.RawStdEncoding
|
||||
case Std:
|
||||
enc = base64.StdEncoding
|
||||
default:
|
||||
return nil, fmt.Errorf(`invalid encoding`)
|
||||
}
|
||||
|
||||
dst := make([]byte, enc.DecodedLen(len(src)))
|
||||
n, err := enc.Decode(dst, src)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(`failed to decode source: %w`, err)
|
||||
}
|
||||
return dst[:n], nil
|
||||
}
|
||||
|
||||
func Decode(src []byte) ([]byte, error) {
|
||||
return getDecoder().Decode(src)
|
||||
}
|
||||
|
||||
func DecodeString(src string) ([]byte, error) {
|
||||
return getDecoder().Decode([]byte(src))
|
||||
}
|
||||
Reference in New Issue
Block a user