Ctrl K
ComunidadGuías…

internal/auth/revoke.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package auth

import (
	"context"
	"log/slog"
	"maps"
	"sync"
	"time"
)

type RevocationStore interface {
	Revoke(ctx context.Context, session string, until, now time.Time) error
	Revocations(ctx context.Context, now time.Time) (map[string]time.Time, error)
}

type revocations struct {
	mu     sync.Mutex
	gone   map[string]time.Time
	within time.Duration
	now    func() time.Time
	kept   RevocationStore
}

func newRevocations(within time.Duration) *revocations {
	return &revocations{gone: map[string]time.Time{}, within: within, now: time.Now}
}

func (rv *revocations) keep(ctx context.Context, kept RevocationStore) error {
	held, err := kept.Revocations(ctx, rv.now())
	if err != nil {
		return err
	}
	rv.mu.Lock()
	defer rv.mu.Unlock()
	rv.kept = kept
	maps.Copy(rv.gone, held)
	return nil
}

func (rv *revocations) revoke(ctx context.Context, session string) {
	if session == "" {
		return
	}
	rv.mu.Lock()
	rv.sweep()
	now := rv.now()
	until := now.Add(rv.within)
	rv.gone[session] = until
	kept := rv.kept
	rv.mu.Unlock()
	if kept == nil {
		return
	}
	err := kept.Revoke(ctx, session, until, now)
	if err != nil {
		slog.Warn("a revoked session could not be written down, so it would be accepted again after a restart", "session", session, "error", err)
	}
}

func (rv *revocations) revoked(session string) bool {
	if session == "" {
		return false
	}
	rv.mu.Lock()
	defer rv.mu.Unlock()
	until, held := rv.gone[session]
	if !held {
		return false
	}
	if !rv.now().Before(until) {
		delete(rv.gone, session)
		return false
	}
	return true
}

func (rv *revocations) sweep() {
	now := rv.now()
	for session, until := range rv.gone {
		if !now.Before(until) {
			delete(rv.gone, session)
		}
	}
}