Files
QSfera/Server/vendor/github.com/lestrrat-go/jwx/v3/jwk/set.go
T
Курнат Андрей 2315f25754 Initial QSfera import
2026-06-07 10:20:04 +03:00

320 lines
6.2 KiB
Go

package jwk
import (
"bytes"
"fmt"
"maps"
"reflect"
"sort"
"github.com/lestrrat-go/blackmagic"
"github.com/lestrrat-go/jwx/v3/internal/json"
"github.com/lestrrat-go/jwx/v3/internal/pool"
"github.com/lestrrat-go/jwx/v3/internal/tokens"
)
const keysKey = `keys` // appease linter
func newSet() *set {
return &set{
privateParams: make(map[string]any),
}
}
// NewSet creates and empty `jwk.Set` object
func NewSet() Set {
return newSet()
}
func (s *set) Set(n string, v any) error {
s.mu.RLock()
defer s.mu.RUnlock()
if n == keysKey {
vl, ok := v.([]Key)
if !ok {
return fmt.Errorf(`value for field "keys" must be []jwk.Key`)
}
s.keys = vl
return nil
}
s.privateParams[n] = v
return nil
}
func (s *set) Get(name string, dst any) error {
s.mu.RLock()
defer s.mu.RUnlock()
v, ok := s.privateParams[name]
if !ok {
return fmt.Errorf(`field %q not found`, name)
}
if err := blackmagic.AssignIfCompatible(dst, v); err != nil {
return fmt.Errorf(`failed to assign value to dst: %w`, err)
}
return nil
}
func (s *set) Key(idx int) (Key, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
if idx >= 0 && idx < len(s.keys) {
return s.keys[idx], true
}
return nil, false
}
func (s *set) Len() int {
s.mu.RLock()
defer s.mu.RUnlock()
return len(s.keys)
}
// indexNL is Index(), but without the locking
func (s *set) indexNL(key Key) int {
for i, k := range s.keys {
if k == key {
return i
}
}
return -1
}
func (s *set) Index(key Key) int {
s.mu.RLock()
defer s.mu.RUnlock()
return s.indexNL(key)
}
func (s *set) AddKey(key Key) error {
s.mu.Lock()
defer s.mu.Unlock()
if reflect.ValueOf(key).IsNil() {
panic("nil key")
}
if i := s.indexNL(key); i > -1 {
return fmt.Errorf(`(jwk.Set).AddKey: key already exists`)
}
s.keys = append(s.keys, key)
return nil
}
func (s *set) Remove(name string) error {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.privateParams, name)
return nil
}
func (s *set) RemoveKey(key Key) error {
s.mu.Lock()
defer s.mu.Unlock()
for i, k := range s.keys {
if k == key {
switch i {
case 0:
s.keys = s.keys[1:]
case len(s.keys) - 1:
s.keys = s.keys[:i]
default:
s.keys = append(s.keys[:i], s.keys[i+1:]...)
}
return nil
}
}
return fmt.Errorf(`(jwk.Set).RemoveKey: specified key does not exist in set`)
}
func (s *set) Clear() error {
s.mu.Lock()
defer s.mu.Unlock()
s.keys = nil
s.privateParams = make(map[string]any)
return nil
}
func (s *set) Keys() []string {
ret := make([]string, len(s.privateParams))
var i int
for k := range s.privateParams {
ret[i] = k
i++
}
return ret
}
func (s *set) MarshalJSON() ([]byte, error) {
s.mu.RLock()
defer s.mu.RUnlock()
buf := pool.BytesBuffer().Get()
defer pool.BytesBuffer().Put(buf)
enc := json.NewEncoder(buf)
fields := []string{keysKey}
for k := range s.privateParams {
fields = append(fields, k)
}
sort.Strings(fields)
buf.WriteByte(tokens.OpenCurlyBracket)
for i, field := range fields {
if i > 0 {
buf.WriteByte(tokens.Comma)
}
fmt.Fprintf(buf, `%q:`, field)
if field != keysKey {
if err := enc.Encode(s.privateParams[field]); err != nil {
return nil, fmt.Errorf(`failed to marshal field %q: %w`, field, err)
}
} else {
buf.WriteByte(tokens.OpenSquareBracket)
for j, k := range s.keys {
if j > 0 {
buf.WriteByte(tokens.Comma)
}
if err := enc.Encode(k); err != nil {
return nil, fmt.Errorf(`failed to marshal key #%d: %w`, i, err)
}
}
buf.WriteByte(tokens.CloseSquareBracket)
}
}
buf.WriteByte(tokens.CloseCurlyBracket)
ret := make([]byte, buf.Len())
copy(ret, buf.Bytes())
return ret, nil
}
func (s *set) UnmarshalJSON(data []byte) error {
s.mu.Lock()
defer s.mu.Unlock()
s.privateParams = make(map[string]any)
s.keys = nil
var options []ParseOption
var ignoreParseError bool
if dc := s.dc; dc != nil {
if localReg := dc.Registry(); localReg != nil {
options = append(options, withLocalRegistry(localReg))
}
ignoreParseError = dc.IgnoreParseError()
}
var sawKeysField bool
dec := json.NewDecoder(bytes.NewReader(data))
LOOP:
for {
tok, err := dec.Token()
if err != nil {
return fmt.Errorf(`error reading token: %w`, err)
}
switch tok := tok.(type) {
case json.Delim:
// Assuming we're doing everything correctly, we should ONLY
// get either tokens.OpenCurlyBracket or tokens.CloseCurlyBracket here.
if tok == tokens.CloseCurlyBracket { // End of object
break LOOP
} else if tok != tokens.OpenCurlyBracket {
return fmt.Errorf(`expected '%c' but got '%c'`, tokens.OpenCurlyBracket, tok)
}
case string:
switch tok {
case "keys":
sawKeysField = true
var list []json.RawMessage
if err := dec.Decode(&list); err != nil {
return fmt.Errorf(`failed to decode "keys": %w`, err)
}
for i, keysrc := range list {
key, err := ParseKey(keysrc, options...)
if err != nil {
if !ignoreParseError {
return fmt.Errorf(`failed to decode key #%d in "keys": %w`, i, err)
}
continue
}
s.keys = append(s.keys, key)
}
default:
var v any
if err := dec.Decode(&v); err != nil {
return fmt.Errorf(`failed to decode value for key %q: %w`, tok, err)
}
s.privateParams[tok] = v
}
}
}
// This is really silly, but we can only detect the
// lack of the "keys" field after going through the
// entire object once
// Not checking for len(s.keys) == 0, because it could be
// an empty key set
if !sawKeysField {
key, err := ParseKey(data, options...)
if err != nil {
return fmt.Errorf(`failed to parse sole key in key set`)
}
s.keys = append(s.keys, key)
}
return nil
}
func (s *set) LookupKeyID(kid string) (Key, bool) {
s.mu.RLock()
defer s.mu.RUnlock()
for i := range s.Len() {
key, ok := s.Key(i)
if !ok {
return nil, false
}
gotkid, ok := key.KeyID()
if ok && gotkid == kid {
return key, true
}
}
return nil, false
}
func (s *set) DecodeCtx() DecodeCtx {
s.mu.RLock()
defer s.mu.RUnlock()
return s.dc
}
func (s *set) SetDecodeCtx(dc DecodeCtx) {
s.mu.Lock()
defer s.mu.Unlock()
s.dc = dc
}
func (s *set) Clone() (Set, error) {
s2 := newSet()
s.mu.RLock()
defer s.mu.RUnlock()
s2.keys = make([]Key, len(s.keys))
copy(s2.keys, s.keys)
maps.Copy(s2.privateParams, s.privateParams)
return s2, nil
}