package jdenticon import ( "fmt" ) // Error types for structured error handling following Go best practices. // ErrInvalidInput represents an error due to invalid input parameters. type ErrInvalidInput struct { Field string // The field or parameter that was invalid Value string // The invalid value (may be truncated for display) Reason string // Human-readable explanation of why it's invalid } func (e *ErrInvalidInput) Error() string { if e.Field != "" { return fmt.Sprintf("jdenticon: invalid input for %s: %s (got: %s)", e.Field, e.Reason, e.Value) } return fmt.Sprintf("jdenticon: invalid input: %s", e.Reason) } // NewErrInvalidInput creates a new ErrInvalidInput. func NewErrInvalidInput(field, value, reason string) *ErrInvalidInput { return &ErrInvalidInput{ Field: field, Value: value, Reason: reason, } } // ErrInvalidSize represents an error due to invalid size parameter. type ErrInvalidSize int func (e ErrInvalidSize) Error() string { return fmt.Sprintf("jdenticon: invalid size: must be positive, got %d", int(e)) } // ErrInvalidIcon represents an error due to invalid icon state. type ErrInvalidIcon string func (e ErrInvalidIcon) Error() string { return fmt.Sprintf("jdenticon: invalid icon: %s", string(e)) } // ErrRenderFailed represents an error during rendering. type ErrRenderFailed struct { Format string // The format being rendered (SVG, PNG) Cause error // The underlying error } func (e *ErrRenderFailed) Error() string { return fmt.Sprintf("jdenticon: %s rendering failed: %v", e.Format, e.Cause) } func (e *ErrRenderFailed) Unwrap() error { return e.Cause } // NewErrRenderFailed creates a new ErrRenderFailed. func NewErrRenderFailed(format string, cause error) *ErrRenderFailed { return &ErrRenderFailed{ Format: format, Cause: cause, } } // ErrGenerationFailed represents an error during identicon generation. type ErrGenerationFailed struct { Input string // The input string that failed to generate (may be truncated) Size int // The requested size Cause error // The underlying error } func (e *ErrGenerationFailed) Error() string { return fmt.Sprintf("jdenticon: generation failed for input %q (size %d): %v", e.Input, e.Size, e.Cause) } func (e *ErrGenerationFailed) Unwrap() error { return e.Cause } // NewErrGenerationFailed creates a new ErrGenerationFailed. func NewErrGenerationFailed(input string, size int, cause error) *ErrGenerationFailed { // Truncate long inputs for display displayInput := input if len(input) > 50 { displayInput = input[:47] + "..." } return &ErrGenerationFailed{ Input: displayInput, Size: size, Cause: cause, } } // ErrCacheCreationFailed represents an error during cache creation. type ErrCacheCreationFailed struct { Size int // The requested cache size Cause error // The underlying error } func (e *ErrCacheCreationFailed) Error() string { return fmt.Sprintf("jdenticon: cache creation failed (size %d): %v", e.Size, e.Cause) } func (e *ErrCacheCreationFailed) Unwrap() error { return e.Cause } // NewErrCacheCreationFailed creates a new ErrCacheCreationFailed. func NewErrCacheCreationFailed(size int, cause error) *ErrCacheCreationFailed { return &ErrCacheCreationFailed{ Size: size, Cause: cause, } } // ErrValueTooLarge is returned when a numeric input exceeds a configured limit. // This supports the configurable DoS protection system. type ErrValueTooLarge struct { ParameterName string // The name of the parameter being validated (e.g., "IconSize", "InputLength") Limit int // The configured limit that was exceeded Actual int // The actual value that was provided } func (e *ErrValueTooLarge) Error() string { return fmt.Sprintf("jdenticon: %s of %d exceeds configured limit of %d", e.ParameterName, e.Actual, e.Limit) } // NewErrValueTooLarge creates a new ErrValueTooLarge. func NewErrValueTooLarge(parameterName string, limit, actual int) *ErrValueTooLarge { return &ErrValueTooLarge{ ParameterName: parameterName, Limit: limit, Actual: actual, } } // ErrEffectiveSizeTooLarge is returned when the effective PNG size (size * supersampling) exceeds limits. // This provides specific context for PNG rendering with supersampling. type ErrEffectiveSizeTooLarge struct { Limit int // The configured size limit Actual int // The calculated effective size (size * supersampling) Size int // The requested icon size Supersampling int // The supersampling factor applied } func (e *ErrEffectiveSizeTooLarge) Error() string { return fmt.Sprintf("jdenticon: effective PNG size of %d (size %d × supersampling %d) exceeds limit of %d", e.Actual, e.Size, e.Supersampling, e.Limit) } // NewErrEffectiveSizeTooLarge creates a new ErrEffectiveSizeTooLarge. func NewErrEffectiveSizeTooLarge(limit, actual, size, supersampling int) *ErrEffectiveSizeTooLarge { return &ErrEffectiveSizeTooLarge{ Limit: limit, Actual: actual, Size: size, Supersampling: supersampling, } } // ErrComplexityLimitExceeded is returned when the calculated geometric complexity exceeds the configured limit. // This prevents resource exhaustion attacks through extremely complex identicon generation. type ErrComplexityLimitExceeded struct { Limit int // The configured complexity limit Actual int // The calculated complexity score InputHash string // The input hash that caused the high complexity (truncated for display) } func (e *ErrComplexityLimitExceeded) Error() string { return fmt.Sprintf("jdenticon: complexity score of %d exceeds limit of %d for input hash %s", e.Actual, e.Limit, e.InputHash) } // NewErrComplexityLimitExceeded creates a new ErrComplexityLimitExceeded. func NewErrComplexityLimitExceeded(limit, actual int, inputHash string) *ErrComplexityLimitExceeded { // Truncate long hash for display displayHash := inputHash if len(inputHash) > 16 { displayHash = inputHash[:13] + "..." } return &ErrComplexityLimitExceeded{ Limit: limit, Actual: actual, InputHash: displayHash, } }