cap

package module
v0.0.0-...-058c7cc Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 27, 2025 License: MIT Imports: 12 Imported by: 1

Documentation

Index

Constants

View Source
const DefaultIPv4SignificantBits = 32
View Source
const DefaultIPv6SignificantBits = 64
View Source
const DefaultMaxChallengesPerIP = 60
View Source
const DefaultMaxChallengesWindow = 1 * time.Minute
View Source
const DefaultValidDuration = 10 * time.Minute

DefaultValidDuration is the default duration that a Cap challenge is valid before it expires.

Variables

View Source
var DefaultChallengeParams = ChallengeParams{
	Difficulty: 4,
	Count:      50,
	SaltSize:   32,
}

DefaultChallengeParams are the default parameters to use for challenges.

View Source
var ErrChallengeNotFound = errors.New("challenge not found (or is expired or already redeemed)")

ErrChallengeNotFound is returned when a challenge is not found, expired, or already redeemed.

View Source
var ErrInsufficientSolutions = errors.New("insufficient solutions provided for challenge")

ErrInsufficientSolutions is returned when not enough solutions were provided for a challenge.

View Source
var ErrInvalidSolution = errors.New("invalid solution provided for challenge")

ErrInvalidSolution is returned when a solution is invalid.

View Source
var ErrRateLimited = errors.New("captcha could not be created because a rate limit was hit")

ErrRateLimited is returned when a rate limit for an IP has been reached. This can be returned by Driver.Store when an IP address is specified. Rate limits are defined by driver implementations.

Functions

func Int64ToHex

func Int64ToHex(v int64) string

Int64ToHex converts an int64 into a hex string. It uses little endian byte order.

func IpToInt64

func IpToInt64(addr *netip.Addr, ipV4SignificantBits int, ipV6SignificantBits int) (version int, integer int64)

IpToInt64 converts an IP address to an integer, containing the significant bits specified. The ipV4SignificantBits parameter must be between 0 and 32 (inclusive), and the ipV6SignificantBits parameter must be between 0 and 64 (inclusive). IPv6 significant bits are capped to 64 instead of 128 because properly configured IPv6 networks tend not to provide smaller than /64 blocks. We also want to be able to store the IP in a 64 bit integer.

If the significant bits parameters are out of bounds, this function panics.

func Prng

func Prng(seed string, length int) string

Prng generates a deterministic hex string of given length from a string seed. `seed` is the initial seed value. `length` is the output hex string length.

func WithIPv4SignificantBits

func WithIPv4SignificantBits(bits int) func(rl *RateLimitOptions)

WithIPv4SignificantBits sets the significant bits (netmask) to use for rate limit counting on IPv4 addresses. When not specified, uses DefaultIPv4SignificantBits.

func WithIPv6SignificantBits

func WithIPv6SignificantBits(bits int) func(rl *RateLimitOptions)

WithIPv6SignificantBits sets the significant bits (netmask) to use for rate limit counting on IPv6 addresses. When not specified, uses DefaultIPv6SignificantBits.

func WithMaxChallengesPerIP

func WithMaxChallengesPerIP(max int) func(rl *RateLimitOptions)

WithMaxChallengesPerIP sets the maximum allowed challenges that can be generated per IP. The underlying window algorithm (e.g. sliding window, fixed window, etc.) is determined by the specific driver. When not specified, uses DefaultMaxChallengesPerIP.

func WithMaxChallengesWindow

func WithMaxChallengesWindow(window time.Duration) func(rl *RateLimitOptions)

WithMaxChallengesWindow sets the window of time in which challenge creations are counted. The underlying window algorithm (e.g. sliding window, fixed window, etc.) is determined by the specific driver. When not specified, uses DefaultMaxChallengesWindow.

Types

type Cap

type Cap struct {
	// contains filtered or unexported fields
}

Cap is an implementation of the Cap server. It can create challenges, accept solutions, and redeem tokens. It uses a driver for storing challenges (and optional rate limiting).

func NewCap

func NewCap(driver Driver) *Cap

NewCap creates a new Cap instance with the specified driver.

func (*Cap) CreateChallenge

func (s *Cap) CreateChallenge(ctx context.Context, req ChallengeRequest) (*Challenge, error)

CreateChallenge generates a new challenge. If the request IP is set and the driver has rate limiting enabled, the function may return ErrRateLimited.

func (*Cap) UseRedeemToken

func (s *Cap) UseRedeemToken(ctx context.Context, token string) (bool, error)

UseRedeemToken uses up a redeem token and returns whether it was valid, invalidating it either way.

func (*Cap) VerifyChallengeSolutions

func (s *Cap) VerifyChallengeSolutions(ctx context.Context, req VerifySolutionsRequest) (*RedeemData, error)

VerifyChallengeSolutions verifies a challenge's solution in exchange for a redeem token. Returns ErrChallengeNotFound if no challenge with the specified token exists. Returns ErrInsufficientSolutions if not enough solutions were provided. Returns ErrInvalidSolution if any solution is invalid.

type Challenge

type Challenge struct {
	// The token used to identify the challenge.
	ChallengeToken string

	// The redeem token, returned for correct solutions.
	// This can be redeemed once by a client once received.
	RedeemToken string

	// The parameters used to generate the challenge and verify its solution.
	Params ChallengeParams

	// The expiration time, when solutions will no longer be accepted and the redeem token
	// will no longer be accepted.
	Expires time.Time
}

Challenge is a Cap challenge. It includes a challenge token, used to identify the challenge, a redeem token, which will be returned to clients who successfully solve the challenge, and params which are used to verify the challenge solution. The expiration time is the cutoff point where the challenge can no longer be solved, and its redeem token can no longer be redeemed.

func (*Challenge) ToResponse

func (c *Challenge) ToResponse() ChallengeResponse

ToResponse returns a ChallengeResponse with the data inside the Challenge struct.

type ChallengeParams

type ChallengeParams struct {
	// The difficulty level of the challenge.
	Difficulty int `json:"d"`

	// The number of challenges to generate.
	Count int `json:"c"`

	// The size of the salt in bytes.
	SaltSize int `json:"s"`
}

ChallengeParams are the parameters for creating and validating a challenge. This struct can be serialized into a valid JSON challenge response.

type ChallengeRequest

type ChallengeRequest struct {
	// The parameters for the challenge.
	Params ChallengeParams

	// The IP address that is requesting the challenge.
	// Can be nil.
	// Used by the driver for optional rate limiting.
	IP *netip.Addr

	// The duration for which the challenge is valid.
	ValidDuration time.Duration
}

ChallengeRequest is a request to create a challenge

type ChallengeResponse

type ChallengeResponse struct {
	// The challenge parameters.
	Params ChallengeParams `json:"challenge"`

	// The challenge hash/token.
	ChallengeHash string `json:"token"`

	// The UNIX millisecond timestamp when the challenge expires.
	ExpiresMs int64 `json:"expires"`
}

ChallengeResponse is a challenge response that can be sent to a client that requested one. It can be serialized to JSON and used as the JSON response for the challenge endpoint.

type Driver

type Driver interface {
	// Store stores a challenge.
	// The challenge must not be nil.
	// The driver is responsible for clearing expired challenges.
	//
	// If `ip` is not nil, it can be used for rate limiting, and the
	// driver may return ErrRateLimited.
	Store(ctx context.Context, challenge *Challenge, ip *netip.Addr) error

	// GetUnredeemedChallenge returns the unredeemed challenge with the specified challenge token.
	// Returns nil if the challenge does not exist, is expired, or is already redeemed.
	//
	// Will not return ErrRateLimited.
	GetUnredeemedChallenge(ctx context.Context, challengeToken string) (*Challenge, error)

	// UseRedeemToken redeems the specified redeem token.
	// If the challenge did not exist, was expired, or was already redeemed, returns false.
	// If the redemption was successful, returns true.
	// The redeem token must not be able to be re-used after calling this function with it.
	//
	// Will not return ErrRateLimited.
	UseRedeemToken(ctx context.Context, redeemToken string) (wasRedeemed bool, err error)
}

Driver is a driver for managing Cap challenges. A driver is responsible for storing, updating and retrieving challenges. It is also responsible for clearing expired challenges, and optionally enforcing rate limits.

type RateLimitOptions

type RateLimitOptions struct {
	IPv4SignificantBits int
	IPv6SignificantBits int

	MaxChallengesPerIP  int
	MaxChallengesWindow time.Duration
}

RateLimitOptions are options for applying rate limiting to the Cap drivers. It limits challenge creation based on IP address. The specific rate limit algorithm and implementation is defined by the driver. IP addresses are truncated to a specified number of bits. For example, you can limit based on the /24 subnet for IPv4 and /48 for IPv6 instead of the default /32 and /64.

func NewDefaultRateLimitOptions

func NewDefaultRateLimitOptions() *RateLimitOptions

NewDefaultRateLimitOptions returns a new RateLimitOptions with default values.

type RedeemData

type RedeemData struct {
	RedeemToken string
	Expires     time.Time
}

RedeemData is the redemption data returned after verifying a successful solution.

type VerifySolutionsRequest

type VerifySolutionsRequest struct {
	ChallengeToken string   `json:"token"`
	Solutions      []uint32 `json:"solutions"`
}

VerifySolutionsRequest is the request for verifying a challenge solution. It can be used to deserialize a JSON request body.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL