~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
110 lines · 2.8 KB Raw History
package main

import (
	"context"
	"encoding/json"
	"sync"
	"time"

	"github.com/go-jose/go-jose/v4"
	"github.com/openbao/openbao/sdk/v2/logical"
)

const (
	sessionPrefix  = "session/"
	statusActive   = "active"
	statusExpired  = "expired"
	refreshLeeway  = 60 * time.Second
	refreshTimeout = 30 * time.Second
)

type sessionEntry struct {
	DID                string          `json:"did"`
	Handle             string          `json:"handle"`
	PDS                string          `json:"pds"`
	Issuer             string          `json:"issuer"`
	TokenEndpoint      string          `json:"token_endpoint"`
	RevocationEndpoint string          `json:"revocation_endpoint"`
	Scope              string          `json:"scope"`
	AccessToken        string          `json:"access_token"`
	RefreshToken       string          `json:"refresh_token"`
	ExpiresAt          time.Time       `json:"expires_at"`
	DPoPJWK            json.RawMessage `json:"dpop_jwk"`
	Status             string          `json:"status"`
	StatusReason       string          `json:"status_reason,omitempty"`
	CreatedAt          time.Time       `json:"created_at"`
	UpdatedAt          time.Time       `json:"updated_at"`
}

func (s *sessionEntry) dpopKey() (*jose.JSONWebKey, error) {
	var jwk jose.JSONWebKey
	if err := json.Unmarshal(s.DPoPJWK, &jwk); err != nil {
		return nil, err
	}
	return &jwk, nil
}

func getSession(ctx context.Context, st logical.Storage, did string) (*sessionEntry, error) {
	raw, err := st.Get(ctx, sessionPrefix+did)
	if err != nil || raw == nil {
		return nil, err
	}
	var s sessionEntry
	if err := raw.DecodeJSON(&s); err != nil {
		return nil, err
	}
	return &s, nil
}

func putSession(ctx context.Context, st logical.Storage, s *sessionEntry) error {
	s.UpdatedAt = time.Now().UTC()
	entry, err := logical.StorageEntryJSON(sessionPrefix+s.DID, s)
	if err != nil {
		return err
	}
	return st.Put(ctx, entry)
}

type sessionLocks struct {
	mu    sync.Mutex
	locks map[string]*sync.Mutex
}

func newSessionLocks() *sessionLocks { return &sessionLocks{locks: map[string]*sync.Mutex{}} }

func (l *sessionLocks) forDID(did string) *sync.Mutex {
	l.mu.Lock()
	defer l.mu.Unlock()
	m, ok := l.locks[did]
	if !ok {
		m = &sync.Mutex{}
		l.locks[did] = m
	}
	return m
}

type nonceCache struct {
	mu     sync.Mutex
	nonces map[string]string
}

func newNonceCache() *nonceCache { return &nonceCache{nonces: map[string]string{}} }

type didNonces struct {
	cache *nonceCache
	did   string
}

func (n *nonceCache) forDID(did string) nonceStore { return didNonces{cache: n, did: did} }

func (d didNonces) get(origin string) string {
	d.cache.mu.Lock()
	defer d.cache.mu.Unlock()
	return d.cache.nonces[d.did+"|"+origin]
}

func (d didNonces) set(origin, nonce string) {
	d.cache.mu.Lock()
	defer d.cache.mu.Unlock()
	d.cache.nonces[d.did+"|"+origin] = nonce
}