// Package session owns opaque server sessions: minting bearer tokens, resolving
// them to accounts through a write-through in-memory cache, and revoking them.
// Only the SHA-256 hash of a token is persisted; the plaintext is returned to
// the caller once and never stored. Sessions are revoke-only (no TTL).
package session

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"fmt"
)

// tokenBytes is the entropy of an opaque session token: 256 bits.
const tokenBytes = 32

// GenerateToken returns a fresh random opaque token (URL-safe base64, 256-bit)
// together with its hex-encoded SHA-256 hash for storage. The plaintext token
// is handed to the caller once and is never persisted.
func GenerateToken() (token, tokenHash string, err error) {
	buf := make([]byte, tokenBytes)
	if _, err := rand.Read(buf); err != nil {
		return "", "", fmt.Errorf("session: read random token: %w", err)
	}
	token = base64.RawURLEncoding.EncodeToString(buf)
	return token, HashToken(token), nil
}

// HashToken returns the hex-encoded SHA-256 of token. Lookups hash the presented
// token and compare against the stored hash.
func HashToken(token string) string {
	sum := sha256.Sum256([]byte(token))
	return hex.EncodeToString(sum[:])
}
