Initial release: Go Jdenticon library v0.1.0
- Core library with SVG and PNG generation - CLI tool with generate and batch commands - Cross-platform path handling for Windows compatibility - Comprehensive test suite with integration tests
This commit is contained in:
@@ -3,103 +3,232 @@ package jdenticon
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/ungluedlabs/go-jdenticon/internal/constants"
|
||||
"github.com/ungluedlabs/go-jdenticon/internal/engine"
|
||||
)
|
||||
|
||||
// Config holds configuration options for identicon generation.
|
||||
type Config struct {
|
||||
// HueRestrictions specifies the hues (in degrees) that are allowed for the identicon.
|
||||
// If empty, any hue can be used. Values should be between 0 and 360.
|
||||
HueRestrictions []float64
|
||||
|
||||
// ColorLightnessRange specifies the lightness range for colored shapes [min, max].
|
||||
// Values should be between 0.0 and 1.0. Default: [0.4, 0.8]
|
||||
ColorLightnessRange [2]float64
|
||||
|
||||
// GrayscaleLightnessRange specifies the lightness range for grayscale shapes [min, max].
|
||||
// Values should be between 0.0 and 1.0. Default: [0.3, 0.9]
|
||||
GrayscaleLightnessRange [2]float64
|
||||
|
||||
// ColorSaturation controls the saturation of colored shapes.
|
||||
// Values should be between 0.0 and 1.0. Default: 0.5
|
||||
ColorSaturation float64
|
||||
|
||||
// GrayscaleSaturation controls the saturation of grayscale shapes.
|
||||
// Values should be between 0.0 and 1.0. Default: 0.0
|
||||
GrayscaleSaturation float64
|
||||
|
||||
// BackgroundColor sets the background color for the identicon.
|
||||
// Accepts hex colors like "#fff", "#ffffff", "#ffffff80" (with alpha).
|
||||
// If empty, the background will be transparent.
|
||||
BackgroundColor string
|
||||
|
||||
// Padding controls the padding around the identicon as a percentage of the size.
|
||||
// Values should be between 0.0 and 0.5. Default: 0.08
|
||||
Padding float64
|
||||
// hexColorRegex validates hex color strings in #RGB or #RRGGBB format.
|
||||
// It's compiled once at package initialization for efficiency.
|
||||
var hexColorRegex = regexp.MustCompile(`^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$`)
|
||||
|
||||
// isValidHexColor checks if the given string is a valid hex color code.
|
||||
// It accepts both #RGB and #RRGGBB formats, case-insensitive.
|
||||
// Returns true for empty strings, which are treated as "transparent background".
|
||||
func isValidHexColor(color string) bool {
|
||||
if color == "" {
|
||||
return true // Empty string means transparent background
|
||||
}
|
||||
return hexColorRegex.MatchString(color)
|
||||
}
|
||||
|
||||
// DefaultConfig returns a default configuration that matches jdenticon-js defaults.
|
||||
// Config holds the configuration options for identicon generation.
|
||||
// This is the public API configuration that wraps the internal engine config.
|
||||
type Config struct {
|
||||
// Color configuration
|
||||
ColorSaturation float64 // Saturation for colored shapes (0.0-1.0)
|
||||
GrayscaleSaturation float64 // Saturation for grayscale shapes (0.0-1.0)
|
||||
ColorLightnessRange [2]float64 // Lightness range for colored shapes [min, max] (0.0-1.0)
|
||||
GrayscaleLightnessRange [2]float64 // Lightness range for grayscale shapes [min, max] (0.0-1.0)
|
||||
|
||||
// Hue restrictions - if specified, only these hues will be used
|
||||
HueRestrictions []float64 // Specific hue values in degrees (0-360)
|
||||
|
||||
// Layout configuration
|
||||
Padding float64 // Padding as percentage of icon size (0.0-0.5)
|
||||
BackgroundColor string // Background color in hex format (e.g., "#ffffff") or empty for transparent
|
||||
|
||||
// PNG rendering configuration
|
||||
PNGSupersampling int // Supersampling factor for PNG rendering (1-16)
|
||||
|
||||
// Security limits for DoS protection.
|
||||
//
|
||||
// MaxIconSize sets the maximum icon dimension in pixels to prevent memory exhaustion.
|
||||
// - 0 (default): Use library default of 4096 pixels (64MB max memory)
|
||||
// - Positive value: Use custom pixel limit
|
||||
// - -1: Disable size limits entirely (use with caution in server environments)
|
||||
MaxIconSize int
|
||||
|
||||
// MaxInputLength sets the maximum input string length in bytes to prevent hash DoS.
|
||||
// - 0 (default): Use library default of 1MB
|
||||
// - Positive value: Use custom byte limit
|
||||
// - -1: Disable input length limits entirely
|
||||
MaxInputLength int
|
||||
|
||||
// MaxComplexity sets the maximum geometric complexity score to prevent resource exhaustion.
|
||||
// This is calculated as the sum of complexity scores for all shapes in an identicon.
|
||||
// - 0 (default): Use library default complexity limit
|
||||
// - Positive value: Use custom complexity limit
|
||||
// - -1: Disable complexity limits entirely (use with caution)
|
||||
MaxComplexity int
|
||||
}
|
||||
|
||||
// DefaultConfig returns a Config with sensible default values.
|
||||
func DefaultConfig() Config {
|
||||
return Config{
|
||||
HueRestrictions: nil, // No restrictions
|
||||
ColorLightnessRange: [2]float64{0.4, 0.8},
|
||||
GrayscaleLightnessRange: [2]float64{0.3, 0.9},
|
||||
ColorSaturation: 0.5,
|
||||
GrayscaleSaturation: 0.0,
|
||||
BackgroundColor: "", // Transparent
|
||||
ColorLightnessRange: [2]float64{0.4, 0.8},
|
||||
GrayscaleLightnessRange: [2]float64{0.3, 0.9},
|
||||
HueRestrictions: nil, // No restrictions by default
|
||||
Padding: 0.08,
|
||||
BackgroundColor: "", // Transparent background
|
||||
PNGSupersampling: 8,
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigOption represents a configuration option function.
|
||||
// Validate checks if the configuration values are valid.
|
||||
func (c *Config) Validate() error {
|
||||
// Validate saturation ranges
|
||||
if c.ColorSaturation < 0.0 || c.ColorSaturation > 1.0 {
|
||||
return fmt.Errorf("color saturation must be between 0.0 and 1.0, got %f", c.ColorSaturation)
|
||||
}
|
||||
if c.GrayscaleSaturation < 0.0 || c.GrayscaleSaturation > 1.0 {
|
||||
return fmt.Errorf("grayscale saturation must be between 0.0 and 1.0, got %f", c.GrayscaleSaturation)
|
||||
}
|
||||
|
||||
// Validate lightness ranges
|
||||
if c.ColorLightnessRange[0] < 0.0 || c.ColorLightnessRange[0] > 1.0 ||
|
||||
c.ColorLightnessRange[1] < 0.0 || c.ColorLightnessRange[1] > 1.0 {
|
||||
return fmt.Errorf("color lightness range values must be between 0.0 and 1.0, got [%f, %f]",
|
||||
c.ColorLightnessRange[0], c.ColorLightnessRange[1])
|
||||
}
|
||||
if c.ColorLightnessRange[0] >= c.ColorLightnessRange[1] {
|
||||
return fmt.Errorf("color lightness range min must be less than max, got [%f, %f]",
|
||||
c.ColorLightnessRange[0], c.ColorLightnessRange[1])
|
||||
}
|
||||
|
||||
if c.GrayscaleLightnessRange[0] < 0.0 || c.GrayscaleLightnessRange[0] > 1.0 ||
|
||||
c.GrayscaleLightnessRange[1] < 0.0 || c.GrayscaleLightnessRange[1] > 1.0 {
|
||||
return fmt.Errorf("grayscale lightness range values must be between 0.0 and 1.0, got [%f, %f]",
|
||||
c.GrayscaleLightnessRange[0], c.GrayscaleLightnessRange[1])
|
||||
}
|
||||
if c.GrayscaleLightnessRange[0] >= c.GrayscaleLightnessRange[1] {
|
||||
return fmt.Errorf("grayscale lightness range min must be less than max, got [%f, %f]",
|
||||
c.GrayscaleLightnessRange[0], c.GrayscaleLightnessRange[1])
|
||||
}
|
||||
|
||||
// Validate padding
|
||||
if c.Padding < 0.0 || c.Padding > 0.5 {
|
||||
return fmt.Errorf("padding must be between 0.0 and 0.5, got %f", c.Padding)
|
||||
}
|
||||
|
||||
// Validate hue restrictions
|
||||
for i, hue := range c.HueRestrictions {
|
||||
if hue < 0.0 || hue > 360.0 {
|
||||
return fmt.Errorf("hue restriction at index %d must be between 0.0 and 360.0, got %f", i, hue)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate PNG supersampling
|
||||
if c.PNGSupersampling < 1 || c.PNGSupersampling > 16 {
|
||||
return fmt.Errorf("PNG supersampling must be between 1 and 16, got %d", c.PNGSupersampling)
|
||||
}
|
||||
|
||||
// Validate background color format
|
||||
if !isValidHexColor(c.BackgroundColor) {
|
||||
return NewErrInvalidInput("background_color", c.BackgroundColor, "must be a valid hex color in #RGB or #RRGGBB format")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// effectiveMaxIconSize resolves the configured icon size limit, applying the default if necessary.
|
||||
// Returns -1 if the limit is disabled.
|
||||
func (c *Config) effectiveMaxIconSize() int {
|
||||
if c.MaxIconSize < 0 {
|
||||
return -1 // Disabled
|
||||
}
|
||||
if c.MaxIconSize == 0 {
|
||||
return constants.DefaultMaxIconSize
|
||||
}
|
||||
return c.MaxIconSize
|
||||
}
|
||||
|
||||
// effectiveMaxInputLength resolves the configured input length limit, applying the default if necessary.
|
||||
// Returns -1 if the limit is disabled.
|
||||
func (c *Config) effectiveMaxInputLength() int {
|
||||
if c.MaxInputLength < 0 {
|
||||
return -1 // Disabled
|
||||
}
|
||||
if c.MaxInputLength == 0 {
|
||||
return constants.DefaultMaxInputLength
|
||||
}
|
||||
return c.MaxInputLength
|
||||
}
|
||||
|
||||
// effectiveMaxComplexity resolves the configured complexity limit, applying the default if necessary.
|
||||
// Returns -1 if the limit is disabled.
|
||||
func (c *Config) effectiveMaxComplexity() int {
|
||||
if c.MaxComplexity < 0 {
|
||||
return -1 // Disabled
|
||||
}
|
||||
if c.MaxComplexity == 0 {
|
||||
return constants.DefaultMaxComplexity
|
||||
}
|
||||
return c.MaxComplexity
|
||||
}
|
||||
|
||||
// toEngineColorConfig converts the public Config to the internal engine.ColorConfig.
|
||||
func (c *Config) toEngineColorConfig() (engine.ColorConfig, error) {
|
||||
if err := c.Validate(); err != nil {
|
||||
return engine.ColorConfig{}, fmt.Errorf("invalid configuration: %w", err)
|
||||
}
|
||||
|
||||
colorConfig := engine.ColorConfig{
|
||||
ColorSaturation: c.ColorSaturation,
|
||||
GrayscaleSaturation: c.GrayscaleSaturation,
|
||||
ColorLightness: engine.LightnessRange{
|
||||
Min: c.ColorLightnessRange[0],
|
||||
Max: c.ColorLightnessRange[1],
|
||||
},
|
||||
GrayscaleLightness: engine.LightnessRange{
|
||||
Min: c.GrayscaleLightnessRange[0],
|
||||
Max: c.GrayscaleLightnessRange[1],
|
||||
},
|
||||
Hues: c.HueRestrictions,
|
||||
BackColor: nil, // Will be set below if background color is specified
|
||||
IconPadding: c.Padding,
|
||||
}
|
||||
|
||||
// Handle background color conversion from hex string to engine.Color
|
||||
if c.BackgroundColor != "" {
|
||||
// Validation is already handled by c.Validate() above.
|
||||
bgColor, err := engine.ParseHexColorToEngine(c.BackgroundColor)
|
||||
if err != nil {
|
||||
return colorConfig, fmt.Errorf("failed to parse background color: %w", err)
|
||||
}
|
||||
colorConfig.BackColor = &bgColor
|
||||
}
|
||||
|
||||
return colorConfig, nil
|
||||
}
|
||||
|
||||
// ConfigOption represents a functional option for configuring identicon generation.
|
||||
type ConfigOption func(*Config) error
|
||||
|
||||
// WithHueRestrictions sets the allowed hues in degrees (0-360).
|
||||
func WithHueRestrictions(hues []float64) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
for _, hue := range hues {
|
||||
if hue < 0 || hue >= 360 {
|
||||
return fmt.Errorf("hue must be between 0 and 360, got %f", hue)
|
||||
}
|
||||
// Configure applies configuration options to create a new Config.
|
||||
func Configure(options ...ConfigOption) (Config, error) {
|
||||
config := DefaultConfig()
|
||||
|
||||
for _, option := range options {
|
||||
if err := option(&config); err != nil {
|
||||
return config, fmt.Errorf("configuration option failed: %w", err)
|
||||
}
|
||||
c.HueRestrictions = make([]float64, len(hues))
|
||||
copy(c.HueRestrictions, hues)
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := config.Validate(); err != nil {
|
||||
return config, fmt.Errorf("invalid configuration after applying options: %w", err)
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// WithColorLightnessRange sets the lightness range for colored shapes.
|
||||
func WithColorLightnessRange(min, max float64) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if min < 0 || min > 1 || max < 0 || max > 1 {
|
||||
return fmt.Errorf("lightness values must be between 0 and 1, got min=%f max=%f", min, max)
|
||||
}
|
||||
if min > max {
|
||||
return fmt.Errorf("minimum lightness cannot be greater than maximum, got min=%f max=%f", min, max)
|
||||
}
|
||||
c.ColorLightnessRange = [2]float64{min, max}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithGrayscaleLightnessRange sets the lightness range for grayscale shapes.
|
||||
func WithGrayscaleLightnessRange(min, max float64) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if min < 0 || min > 1 || max < 0 || max > 1 {
|
||||
return fmt.Errorf("lightness values must be between 0 and 1, got min=%f max=%f", min, max)
|
||||
}
|
||||
if min > max {
|
||||
return fmt.Errorf("minimum lightness cannot be greater than maximum, got min=%f max=%f", min, max)
|
||||
}
|
||||
c.GrayscaleLightnessRange = [2]float64{min, max}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithColorSaturation sets the saturation for colored shapes.
|
||||
// WithColorSaturation sets the color saturation for colored shapes.
|
||||
func WithColorSaturation(saturation float64) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if saturation < 0 || saturation > 1 {
|
||||
return fmt.Errorf("saturation must be between 0 and 1, got %f", saturation)
|
||||
if saturation < 0.0 || saturation > 1.0 {
|
||||
return fmt.Errorf("color saturation must be between 0.0 and 1.0, got %f", saturation)
|
||||
}
|
||||
c.ColorSaturation = saturation
|
||||
return nil
|
||||
@@ -109,127 +238,122 @@ func WithColorSaturation(saturation float64) ConfigOption {
|
||||
// WithGrayscaleSaturation sets the saturation for grayscale shapes.
|
||||
func WithGrayscaleSaturation(saturation float64) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if saturation < 0 || saturation > 1 {
|
||||
return fmt.Errorf("saturation must be between 0 and 1, got %f", saturation)
|
||||
if saturation < 0.0 || saturation > 1.0 {
|
||||
return fmt.Errorf("grayscale saturation must be between 0.0 and 1.0, got %f", saturation)
|
||||
}
|
||||
c.GrayscaleSaturation = saturation
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithBackgroundColor sets the background color.
|
||||
func WithBackgroundColor(color string) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if color != "" {
|
||||
if err := validateHexColor(color); err != nil {
|
||||
return fmt.Errorf("invalid background color: %w", err)
|
||||
}
|
||||
}
|
||||
c.BackgroundColor = color
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithPadding sets the padding around the identicon.
|
||||
// WithPadding sets the padding as a percentage of the icon size.
|
||||
func WithPadding(padding float64) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if padding < 0 || padding > 0.5 {
|
||||
return fmt.Errorf("padding must be between 0 and 0.5, got %f", padding)
|
||||
if padding < 0.0 || padding > 0.5 {
|
||||
return fmt.Errorf("padding must be between 0.0 and 0.5, got %f", padding)
|
||||
}
|
||||
c.Padding = padding
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Configure creates a new configuration with the given options.
|
||||
func Configure(options ...ConfigOption) (Config, error) {
|
||||
config := DefaultConfig()
|
||||
|
||||
for _, option := range options {
|
||||
if err := option(&config); err != nil {
|
||||
return Config{}, err
|
||||
// WithBackgroundColor sets the background color (hex format like "#ffffff").
|
||||
// The color must be in #RGB or #RRGGBB format. An empty string means transparent background.
|
||||
func WithBackgroundColor(color string) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if !isValidHexColor(color) {
|
||||
return NewErrInvalidInput("background_color", color, "must be a valid hex color in #RGB or #RRGGBB format")
|
||||
}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// validateHexColor validates that a color string is a valid hex color.
|
||||
func validateHexColor(color string) error {
|
||||
hexColorPattern := regexp.MustCompile(`^#[0-9a-fA-F]{3,8}$`)
|
||||
if !hexColorPattern.MatchString(color) {
|
||||
return fmt.Errorf("color must be a hex color like #fff, #ffffff, or #ffffff80")
|
||||
}
|
||||
|
||||
// Validate length - must be 3, 4, 6, or 8 characters after #
|
||||
length := len(color) - 1
|
||||
if length != 3 && length != 4 && length != 6 && length != 8 {
|
||||
return fmt.Errorf("hex color must be 3, 4, 6, or 8 characters after #")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ParseColor normalizes a hex color string to the full #RRGGBB or #RRGGBBAA format.
|
||||
func ParseColor(color string) (string, error) {
|
||||
if color == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if err := validateHexColor(color); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Normalize short forms to full forms
|
||||
switch len(color) {
|
||||
case 4: // #RGB -> #RRGGBB
|
||||
r, g, b := color[1], color[2], color[3]
|
||||
return fmt.Sprintf("#%c%c%c%c%c%c", r, r, g, g, b, b), nil
|
||||
case 5: // #RGBA -> #RRGGBBAA
|
||||
r, g, b, a := color[1], color[2], color[3], color[4]
|
||||
return fmt.Sprintf("#%c%c%c%c%c%c%c%c", r, r, g, g, b, b, a, a), nil
|
||||
case 7, 9: // #RRGGBB or #RRGGBBAA - already normalized
|
||||
return color, nil
|
||||
default:
|
||||
return "", fmt.Errorf("unsupported color format")
|
||||
c.BackgroundColor = color
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetHue returns the hue for the given original hue value, taking into account hue restrictions.
|
||||
func (c *Config) GetHue(originalHue float64) float64 {
|
||||
if len(c.HueRestrictions) == 0 {
|
||||
return originalHue
|
||||
// WithColorLightnessRange sets the lightness range for colored shapes.
|
||||
func WithColorLightnessRange(min, max float64) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if min < 0.0 || min > 1.0 || max < 0.0 || max > 1.0 {
|
||||
return fmt.Errorf("lightness values must be between 0.0 and 1.0, got min=%f, max=%f", min, max)
|
||||
}
|
||||
if min >= max {
|
||||
return fmt.Errorf("lightness min must be less than max, got min=%f, max=%f", min, max)
|
||||
}
|
||||
c.ColorLightnessRange = [2]float64{min, max}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Map originalHue [0,1] to one of the restricted hues
|
||||
index := int(originalHue * 0.999 * float64(len(c.HueRestrictions)))
|
||||
if index >= len(c.HueRestrictions) {
|
||||
index = len(c.HueRestrictions) - 1
|
||||
}
|
||||
|
||||
hue := c.HueRestrictions[index]
|
||||
// Convert degrees to [0,1] range and normalize
|
||||
return ((hue/360.0)+1.0) - float64(int((hue/360.0)+1.0))
|
||||
}
|
||||
|
||||
// GetColorLightness returns a lightness value within the color lightness range.
|
||||
func (c *Config) GetColorLightness(value float64) float64 {
|
||||
return c.getLightness(value, c.ColorLightnessRange)
|
||||
// WithGrayscaleLightnessRange sets the lightness range for grayscale shapes.
|
||||
func WithGrayscaleLightnessRange(min, max float64) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if min < 0.0 || min > 1.0 || max < 0.0 || max > 1.0 {
|
||||
return fmt.Errorf("lightness values must be between 0.0 and 1.0, got min=%f, max=%f", min, max)
|
||||
}
|
||||
if min >= max {
|
||||
return fmt.Errorf("lightness min must be less than max, got min=%f, max=%f", min, max)
|
||||
}
|
||||
c.GrayscaleLightnessRange = [2]float64{min, max}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// GetGrayscaleLightness returns a lightness value within the grayscale lightness range.
|
||||
func (c *Config) GetGrayscaleLightness(value float64) float64 {
|
||||
return c.getLightness(value, c.GrayscaleLightnessRange)
|
||||
// WithHueRestrictions restricts hues to specific values in degrees (0-360).
|
||||
func WithHueRestrictions(hues []float64) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
for i, hue := range hues {
|
||||
if hue < 0.0 || hue > 360.0 {
|
||||
return fmt.Errorf("hue at index %d must be between 0.0 and 360.0, got %f", i, hue)
|
||||
}
|
||||
}
|
||||
c.HueRestrictions = make([]float64, len(hues))
|
||||
copy(c.HueRestrictions, hues)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// getLightness maps a value [0,1] to the specified lightness range.
|
||||
func (c *Config) getLightness(value float64, lightnessRange [2]float64) float64 {
|
||||
result := lightnessRange[0] + value*(lightnessRange[1]-lightnessRange[0])
|
||||
if result < 0 {
|
||||
return 0
|
||||
// WithPNGSupersampling sets the PNG supersampling factor (1-16).
|
||||
func WithPNGSupersampling(factor int) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if factor < 1 || factor > 16 {
|
||||
return fmt.Errorf("PNG supersampling must be between 1 and 16, got %d", factor)
|
||||
}
|
||||
c.PNGSupersampling = factor
|
||||
return nil
|
||||
}
|
||||
if result > 1 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// WithMaxComplexity sets the maximum geometric complexity limit for resource protection.
|
||||
// Use -1 to disable complexity limits entirely (use with caution).
|
||||
func WithMaxComplexity(maxComplexity int) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if maxComplexity < -1 {
|
||||
return fmt.Errorf("max complexity must be >= -1, got %d", maxComplexity)
|
||||
}
|
||||
c.MaxComplexity = maxComplexity
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxIconSize sets the maximum icon dimension in pixels for DoS protection.
|
||||
// Use 0 for the library default (4096 pixels), or -1 to disable limits entirely.
|
||||
func WithMaxIconSize(maxSize int) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if maxSize < -1 {
|
||||
return fmt.Errorf("max icon size must be >= -1, got %d", maxSize)
|
||||
}
|
||||
c.MaxIconSize = maxSize
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithMaxInputLength sets the maximum input string length in bytes for DoS protection.
|
||||
// Use 0 for the library default (1MB), or -1 to disable limits entirely.
|
||||
func WithMaxInputLength(maxLength int) ConfigOption {
|
||||
return func(c *Config) error {
|
||||
if maxLength < -1 {
|
||||
return fmt.Errorf("max input length must be >= -1, got %d", maxLength)
|
||||
}
|
||||
c.MaxInputLength = maxLength
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user