mirror of
https://github.com/imgproxy/imgproxy.git
synced 2024-11-24 08:12:38 +02:00
546 lines
15 KiB
Go
546 lines
15 KiB
Go
package config
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
"regexp"
|
|
"runtime"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"github.com/imgproxy/imgproxy/v3/config/configurators"
|
|
"github.com/imgproxy/imgproxy/v3/imagetype"
|
|
"github.com/imgproxy/imgproxy/v3/version"
|
|
)
|
|
|
|
var (
|
|
Network string
|
|
Bind string
|
|
ReadTimeout int
|
|
WriteTimeout int
|
|
KeepAliveTimeout int
|
|
DownloadTimeout int
|
|
Concurrency int
|
|
MaxClients int
|
|
|
|
TTL int
|
|
CacheControlPassthrough bool
|
|
SetCanonicalHeader bool
|
|
|
|
SoReuseport bool
|
|
|
|
PathPrefix string
|
|
|
|
MaxSrcResolution int
|
|
MaxSrcFileSize int
|
|
MaxAnimationFrames int
|
|
MaxSvgCheckBytes int
|
|
|
|
JpegProgressive bool
|
|
PngInterlaced bool
|
|
PngQuantize bool
|
|
PngQuantizationColors int
|
|
AvifSpeed int
|
|
Quality int
|
|
FormatQuality map[imagetype.Type]int
|
|
StripMetadata bool
|
|
StripColorProfile bool
|
|
AutoRotate bool
|
|
|
|
EnableWebpDetection bool
|
|
EnforceWebp bool
|
|
EnableAvifDetection bool
|
|
EnforceAvif bool
|
|
EnableClientHints bool
|
|
|
|
SkipProcessingFormats []imagetype.Type
|
|
|
|
UseLinearColorspace bool
|
|
DisableShrinkOnLoad bool
|
|
|
|
Keys [][]byte
|
|
Salts [][]byte
|
|
SignatureSize int
|
|
|
|
Secret string
|
|
|
|
AllowOrigin string
|
|
|
|
UserAgent string
|
|
|
|
IgnoreSslVerification bool
|
|
DevelopmentErrorsMode bool
|
|
|
|
AllowedSources []*regexp.Regexp
|
|
|
|
CookiePassthrough bool
|
|
CookieBaseURL string
|
|
|
|
LocalFileSystemRoot string
|
|
S3Enabled bool
|
|
S3Region string
|
|
S3Endpoint string
|
|
GCSEnabled bool
|
|
GCSKey string
|
|
ABSEnabled bool
|
|
ABSName string
|
|
ABSKey string
|
|
ABSEndpoint string
|
|
|
|
ETagEnabled bool
|
|
|
|
BaseURL string
|
|
|
|
Presets []string
|
|
OnlyPresets bool
|
|
|
|
WatermarkData string
|
|
WatermarkPath string
|
|
WatermarkURL string
|
|
WatermarkOpacity float64
|
|
|
|
FallbackImageData string
|
|
FallbackImagePath string
|
|
FallbackImageURL string
|
|
FallbackImageHTTPCode int
|
|
|
|
DataDogEnable bool
|
|
|
|
NewRelicAppName string
|
|
NewRelicKey string
|
|
|
|
PrometheusBind string
|
|
PrometheusNamespace string
|
|
|
|
BugsnagKey string
|
|
BugsnagStage string
|
|
|
|
HoneybadgerKey string
|
|
HoneybadgerEnv string
|
|
|
|
SentryDSN string
|
|
SentryEnvironment string
|
|
SentryRelease string
|
|
|
|
AirbrakeProjecID int
|
|
AirbrakeProjecKey string
|
|
AirbrakeEnv string
|
|
|
|
ReportDownloadingErrors bool
|
|
|
|
EnableDebugHeaders bool
|
|
|
|
FreeMemoryInterval int
|
|
DownloadBufferSize int
|
|
BufferPoolCalibrationThreshold int
|
|
)
|
|
|
|
var (
|
|
keyPath = flag.String("keypath", "", "path of the file with hex-encoded key")
|
|
saltPath = flag.String("saltpath", "", "path of the file with hex-encoded salt")
|
|
presetsPath = flag.String("presets", "", "path of the file with presets")
|
|
)
|
|
|
|
func init() {
|
|
Reset()
|
|
}
|
|
|
|
func Reset() {
|
|
Network = "tcp"
|
|
Bind = ":8080"
|
|
ReadTimeout = 10
|
|
WriteTimeout = 10
|
|
KeepAliveTimeout = 10
|
|
DownloadTimeout = 5
|
|
Concurrency = runtime.NumCPU() * 2
|
|
MaxClients = 0
|
|
|
|
TTL = 3600
|
|
CacheControlPassthrough = false
|
|
SetCanonicalHeader = false
|
|
|
|
SoReuseport = false
|
|
|
|
PathPrefix = ""
|
|
|
|
MaxSrcResolution = 16800000
|
|
MaxSrcFileSize = 0
|
|
MaxAnimationFrames = 1
|
|
MaxSvgCheckBytes = 32 * 1024
|
|
|
|
JpegProgressive = false
|
|
PngInterlaced = false
|
|
PngQuantize = false
|
|
PngQuantizationColors = 256
|
|
AvifSpeed = 5
|
|
Quality = 80
|
|
FormatQuality = map[imagetype.Type]int{imagetype.AVIF: 50}
|
|
StripMetadata = true
|
|
StripColorProfile = true
|
|
AutoRotate = true
|
|
|
|
EnableWebpDetection = false
|
|
EnforceWebp = false
|
|
EnableAvifDetection = false
|
|
EnforceAvif = false
|
|
EnableClientHints = false
|
|
|
|
SkipProcessingFormats = make([]imagetype.Type, 0)
|
|
|
|
UseLinearColorspace = false
|
|
DisableShrinkOnLoad = false
|
|
|
|
Keys = make([][]byte, 0)
|
|
Salts = make([][]byte, 0)
|
|
SignatureSize = 32
|
|
|
|
Secret = ""
|
|
|
|
AllowOrigin = ""
|
|
|
|
UserAgent = fmt.Sprintf("imgproxy/%s", version.Version())
|
|
|
|
IgnoreSslVerification = false
|
|
DevelopmentErrorsMode = false
|
|
|
|
AllowedSources = make([]*regexp.Regexp, 0)
|
|
|
|
CookiePassthrough = false
|
|
CookieBaseURL = ""
|
|
|
|
LocalFileSystemRoot = ""
|
|
S3Enabled = false
|
|
S3Region = ""
|
|
S3Endpoint = ""
|
|
GCSEnabled = false
|
|
GCSKey = ""
|
|
ABSEnabled = false
|
|
ABSName = ""
|
|
ABSKey = ""
|
|
ABSEndpoint = ""
|
|
|
|
ETagEnabled = false
|
|
|
|
BaseURL = ""
|
|
|
|
Presets = make([]string, 0)
|
|
OnlyPresets = false
|
|
|
|
WatermarkData = ""
|
|
WatermarkPath = ""
|
|
WatermarkURL = ""
|
|
WatermarkOpacity = 1
|
|
|
|
FallbackImageData = ""
|
|
FallbackImagePath = ""
|
|
FallbackImageURL = ""
|
|
FallbackImageHTTPCode = 200
|
|
|
|
DataDogEnable = false
|
|
|
|
NewRelicAppName = ""
|
|
NewRelicKey = ""
|
|
|
|
PrometheusBind = ""
|
|
PrometheusNamespace = ""
|
|
|
|
BugsnagKey = ""
|
|
BugsnagStage = "production"
|
|
|
|
HoneybadgerKey = ""
|
|
HoneybadgerEnv = "production"
|
|
|
|
SentryDSN = ""
|
|
SentryEnvironment = "production"
|
|
SentryRelease = fmt.Sprintf("imgproxy/%s", version.Version())
|
|
|
|
AirbrakeProjecID = 0
|
|
AirbrakeProjecKey = ""
|
|
AirbrakeEnv = "production"
|
|
|
|
ReportDownloadingErrors = true
|
|
|
|
EnableDebugHeaders = false
|
|
|
|
FreeMemoryInterval = 10
|
|
DownloadBufferSize = 0
|
|
BufferPoolCalibrationThreshold = 1024
|
|
}
|
|
|
|
func Configure() error {
|
|
flag.Parse()
|
|
|
|
if port := os.Getenv("PORT"); len(port) > 0 {
|
|
Bind = fmt.Sprintf(":%s", port)
|
|
}
|
|
|
|
configurators.String(&Network, "IMGPROXY_NETWORK")
|
|
configurators.String(&Bind, "IMGPROXY_BIND")
|
|
configurators.Int(&ReadTimeout, "IMGPROXY_READ_TIMEOUT")
|
|
configurators.Int(&WriteTimeout, "IMGPROXY_WRITE_TIMEOUT")
|
|
configurators.Int(&KeepAliveTimeout, "IMGPROXY_KEEP_ALIVE_TIMEOUT")
|
|
configurators.Int(&DownloadTimeout, "IMGPROXY_DOWNLOAD_TIMEOUT")
|
|
configurators.Int(&Concurrency, "IMGPROXY_CONCURRENCY")
|
|
configurators.Int(&MaxClients, "IMGPROXY_MAX_CLIENTS")
|
|
|
|
configurators.Int(&TTL, "IMGPROXY_TTL")
|
|
configurators.Bool(&CacheControlPassthrough, "IMGPROXY_CACHE_CONTROL_PASSTHROUGH")
|
|
configurators.Bool(&SetCanonicalHeader, "IMGPROXY_SET_CANONICAL_HEADER")
|
|
|
|
configurators.Bool(&SoReuseport, "IMGPROXY_SO_REUSEPORT")
|
|
|
|
configurators.String(&PathPrefix, "IMGPROXY_PATH_PREFIX")
|
|
|
|
configurators.MegaInt(&MaxSrcResolution, "IMGPROXY_MAX_SRC_RESOLUTION")
|
|
configurators.Int(&MaxSrcFileSize, "IMGPROXY_MAX_SRC_FILE_SIZE")
|
|
configurators.Int(&MaxSvgCheckBytes, "IMGPROXY_MAX_SVG_CHECK_BYTES")
|
|
|
|
configurators.Int(&MaxAnimationFrames, "IMGPROXY_MAX_ANIMATION_FRAMES")
|
|
|
|
configurators.Patterns(&AllowedSources, "IMGPROXY_ALLOWED_SOURCES")
|
|
|
|
configurators.Bool(&JpegProgressive, "IMGPROXY_JPEG_PROGRESSIVE")
|
|
configurators.Bool(&PngInterlaced, "IMGPROXY_PNG_INTERLACED")
|
|
configurators.Bool(&PngQuantize, "IMGPROXY_PNG_QUANTIZE")
|
|
configurators.Int(&PngQuantizationColors, "IMGPROXY_PNG_QUANTIZATION_COLORS")
|
|
configurators.Int(&AvifSpeed, "IMGPROXY_AVIF_SPEED")
|
|
configurators.Int(&Quality, "IMGPROXY_QUALITY")
|
|
if err := configurators.ImageTypesQuality(FormatQuality, "IMGPROXY_FORMAT_QUALITY"); err != nil {
|
|
return err
|
|
}
|
|
configurators.Bool(&StripMetadata, "IMGPROXY_STRIP_METADATA")
|
|
configurators.Bool(&StripColorProfile, "IMGPROXY_STRIP_COLOR_PROFILE")
|
|
configurators.Bool(&AutoRotate, "IMGPROXY_AUTO_ROTATE")
|
|
|
|
configurators.Bool(&EnableWebpDetection, "IMGPROXY_ENABLE_WEBP_DETECTION")
|
|
configurators.Bool(&EnforceWebp, "IMGPROXY_ENFORCE_WEBP")
|
|
configurators.Bool(&EnableAvifDetection, "IMGPROXY_ENABLE_AVIF_DETECTION")
|
|
configurators.Bool(&EnforceAvif, "IMGPROXY_ENFORCE_AVIF")
|
|
configurators.Bool(&EnableClientHints, "IMGPROXY_ENABLE_CLIENT_HINTS")
|
|
|
|
if err := configurators.ImageTypes(&SkipProcessingFormats, "IMGPROXY_SKIP_PROCESSING_FORMATS"); err != nil {
|
|
return err
|
|
}
|
|
|
|
configurators.Bool(&UseLinearColorspace, "IMGPROXY_USE_LINEAR_COLORSPACE")
|
|
configurators.Bool(&DisableShrinkOnLoad, "IMGPROXY_DISABLE_SHRINK_ON_LOAD")
|
|
|
|
if err := configurators.Hex(&Keys, "IMGPROXY_KEY"); err != nil {
|
|
return err
|
|
}
|
|
if err := configurators.Hex(&Salts, "IMGPROXY_SALT"); err != nil {
|
|
return err
|
|
}
|
|
configurators.Int(&SignatureSize, "IMGPROXY_SIGNATURE_SIZE")
|
|
|
|
if err := configurators.HexFile(&Keys, *keyPath); err != nil {
|
|
return err
|
|
}
|
|
if err := configurators.HexFile(&Salts, *saltPath); err != nil {
|
|
return err
|
|
}
|
|
|
|
configurators.String(&Secret, "IMGPROXY_SECRET")
|
|
|
|
configurators.String(&AllowOrigin, "IMGPROXY_ALLOW_ORIGIN")
|
|
|
|
configurators.String(&UserAgent, "IMGPROXY_USER_AGENT")
|
|
|
|
configurators.Bool(&IgnoreSslVerification, "IMGPROXY_IGNORE_SSL_VERIFICATION")
|
|
configurators.Bool(&DevelopmentErrorsMode, "IMGPROXY_DEVELOPMENT_ERRORS_MODE")
|
|
|
|
configurators.Bool(&CookiePassthrough, "IMGPROXY_COOKIE_PASSTHROUGH")
|
|
configurators.String(&CookieBaseURL, "IMGPROXY_COOKIE_BASE_URL")
|
|
|
|
configurators.String(&LocalFileSystemRoot, "IMGPROXY_LOCAL_FILESYSTEM_ROOT")
|
|
|
|
configurators.Bool(&S3Enabled, "IMGPROXY_USE_S3")
|
|
configurators.String(&S3Region, "IMGPROXY_S3_REGION")
|
|
configurators.String(&S3Endpoint, "IMGPROXY_S3_ENDPOINT")
|
|
|
|
configurators.Bool(&GCSEnabled, "IMGPROXY_USE_GCS")
|
|
configurators.String(&GCSKey, "IMGPROXY_GCS_KEY")
|
|
|
|
configurators.Bool(&ABSEnabled, "IMGPROXY_USE_ABS")
|
|
configurators.String(&ABSName, "IMGPROXY_ABS_NAME")
|
|
configurators.String(&ABSKey, "IMGPROXY_ABS_KEY")
|
|
configurators.String(&ABSEndpoint, "IMGPROXY_ABS_ENDPOINT")
|
|
|
|
configurators.Bool(&ETagEnabled, "IMGPROXY_USE_ETAG")
|
|
|
|
configurators.String(&BaseURL, "IMGPROXY_BASE_URL")
|
|
|
|
configurators.StringSlice(&Presets, "IMGPROXY_PRESETS")
|
|
if err := configurators.StringSliceFile(&Presets, *presetsPath); err != nil {
|
|
return err
|
|
}
|
|
configurators.Bool(&OnlyPresets, "IMGPROXY_ONLY_PRESETS")
|
|
|
|
configurators.String(&WatermarkData, "IMGPROXY_WATERMARK_DATA")
|
|
configurators.String(&WatermarkPath, "IMGPROXY_WATERMARK_PATH")
|
|
configurators.String(&WatermarkURL, "IMGPROXY_WATERMARK_URL")
|
|
configurators.Float(&WatermarkOpacity, "IMGPROXY_WATERMARK_OPACITY")
|
|
|
|
configurators.String(&FallbackImageData, "IMGPROXY_FALLBACK_IMAGE_DATA")
|
|
configurators.String(&FallbackImagePath, "IMGPROXY_FALLBACK_IMAGE_PATH")
|
|
configurators.String(&FallbackImageURL, "IMGPROXY_FALLBACK_IMAGE_URL")
|
|
configurators.Int(&FallbackImageHTTPCode, "IMGPROXY_FALLBACK_IMAGE_HTTP_CODE")
|
|
|
|
configurators.Bool(&DataDogEnable, "IMGPROXY_DATADOG_ENABLE")
|
|
|
|
configurators.String(&NewRelicAppName, "IMGPROXY_NEW_RELIC_APP_NAME")
|
|
configurators.String(&NewRelicKey, "IMGPROXY_NEW_RELIC_KEY")
|
|
|
|
configurators.String(&PrometheusBind, "IMGPROXY_PROMETHEUS_BIND")
|
|
configurators.String(&PrometheusNamespace, "IMGPROXY_PROMETHEUS_NAMESPACE")
|
|
|
|
configurators.String(&BugsnagKey, "IMGPROXY_BUGSNAG_KEY")
|
|
configurators.String(&BugsnagStage, "IMGPROXY_BUGSNAG_STAGE")
|
|
configurators.String(&HoneybadgerKey, "IMGPROXY_HONEYBADGER_KEY")
|
|
configurators.String(&HoneybadgerEnv, "IMGPROXY_HONEYBADGER_ENV")
|
|
configurators.String(&SentryDSN, "IMGPROXY_SENTRY_DSN")
|
|
configurators.String(&SentryEnvironment, "IMGPROXY_SENTRY_ENVIRONMENT")
|
|
configurators.String(&SentryRelease, "IMGPROXY_SENTRY_RELEASE")
|
|
configurators.Int(&AirbrakeProjecID, "IMGPROXY_AIRBRAKE_PROJECT_ID")
|
|
configurators.String(&AirbrakeProjecKey, "IMGPROXY_AIRBRAKE_PROJECT_KEY")
|
|
configurators.String(&AirbrakeEnv, "IMGPROXY_AIRBRAKE_ENVIRONMENT")
|
|
configurators.Bool(&ReportDownloadingErrors, "IMGPROXY_REPORT_DOWNLOADING_ERRORS")
|
|
configurators.Bool(&EnableDebugHeaders, "IMGPROXY_ENABLE_DEBUG_HEADERS")
|
|
|
|
configurators.Int(&FreeMemoryInterval, "IMGPROXY_FREE_MEMORY_INTERVAL")
|
|
configurators.Int(&DownloadBufferSize, "IMGPROXY_DOWNLOAD_BUFFER_SIZE")
|
|
configurators.Int(&BufferPoolCalibrationThreshold, "IMGPROXY_BUFFER_POOL_CALIBRATION_THRESHOLD")
|
|
|
|
if len(Keys) != len(Salts) {
|
|
return fmt.Errorf("Number of keys and number of salts should be equal. Keys: %d, salts: %d", len(Keys), len(Salts))
|
|
}
|
|
if len(Keys) == 0 {
|
|
log.Warning("No keys defined, so signature checking is disabled")
|
|
}
|
|
if len(Salts) == 0 {
|
|
log.Warning("No salts defined, so signature checking is disabled")
|
|
}
|
|
|
|
if SignatureSize < 1 || SignatureSize > 32 {
|
|
return fmt.Errorf("Signature size should be within 1 and 32, now - %d\n", SignatureSize)
|
|
}
|
|
|
|
if len(Bind) == 0 {
|
|
return fmt.Errorf("Bind address is not defined")
|
|
}
|
|
|
|
if ReadTimeout <= 0 {
|
|
return fmt.Errorf("Read timeout should be greater than 0, now - %d\n", ReadTimeout)
|
|
}
|
|
|
|
if WriteTimeout <= 0 {
|
|
return fmt.Errorf("Write timeout should be greater than 0, now - %d\n", WriteTimeout)
|
|
}
|
|
if KeepAliveTimeout < 0 {
|
|
return fmt.Errorf("KeepAlive timeout should be greater than or equal to 0, now - %d\n", KeepAliveTimeout)
|
|
}
|
|
|
|
if DownloadTimeout <= 0 {
|
|
return fmt.Errorf("Download timeout should be greater than 0, now - %d\n", DownloadTimeout)
|
|
}
|
|
|
|
if Concurrency <= 0 {
|
|
return fmt.Errorf("Concurrency should be greater than 0, now - %d\n", Concurrency)
|
|
}
|
|
|
|
if MaxClients <= 0 {
|
|
MaxClients = Concurrency * 10
|
|
}
|
|
|
|
if TTL <= 0 {
|
|
return fmt.Errorf("TTL should be greater than 0, now - %d\n", TTL)
|
|
}
|
|
|
|
if MaxSrcResolution <= 0 {
|
|
return fmt.Errorf("Max src resolution should be greater than 0, now - %d\n", MaxSrcResolution)
|
|
}
|
|
|
|
if MaxSrcFileSize < 0 {
|
|
return fmt.Errorf("Max src file size should be greater than or equal to 0, now - %d\n", MaxSrcFileSize)
|
|
}
|
|
|
|
if MaxAnimationFrames <= 0 {
|
|
return fmt.Errorf("Max animation frames should be greater than 0, now - %d\n", MaxAnimationFrames)
|
|
}
|
|
|
|
if PngQuantizationColors < 2 {
|
|
return fmt.Errorf("Png quantization colors should be greater than 1, now - %d\n", PngQuantizationColors)
|
|
} else if PngQuantizationColors > 256 {
|
|
return fmt.Errorf("Png quantization colors can't be greater than 256, now - %d\n", PngQuantizationColors)
|
|
}
|
|
|
|
if AvifSpeed <= 0 {
|
|
return fmt.Errorf("Avif speed should be greater than 0, now - %d\n", AvifSpeed)
|
|
} else if AvifSpeed > 8 {
|
|
return fmt.Errorf("Avif speed can't be greater than 8, now - %d\n", AvifSpeed)
|
|
}
|
|
|
|
if Quality <= 0 {
|
|
return fmt.Errorf("Quality should be greater than 0, now - %d\n", Quality)
|
|
} else if Quality > 100 {
|
|
return fmt.Errorf("Quality can't be greater than 100, now - %d\n", Quality)
|
|
}
|
|
|
|
if IgnoreSslVerification {
|
|
log.Warning("Ignoring SSL verification is very unsafe")
|
|
}
|
|
|
|
if LocalFileSystemRoot != "" {
|
|
stat, err := os.Stat(LocalFileSystemRoot)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Cannot use local directory: %s", err)
|
|
}
|
|
|
|
if !stat.IsDir() {
|
|
return fmt.Errorf("Cannot use local directory: not a directory")
|
|
}
|
|
|
|
if LocalFileSystemRoot == "/" {
|
|
log.Warning("Exposing root via IMGPROXY_LOCAL_FILESYSTEM_ROOT is unsafe")
|
|
}
|
|
}
|
|
|
|
if _, ok := os.LookupEnv("IMGPROXY_USE_GCS"); !ok && len(GCSKey) > 0 {
|
|
log.Warning("Set IMGPROXY_USE_GCS to true since it may be required by future versions to enable GCS support")
|
|
GCSEnabled = true
|
|
}
|
|
|
|
if WatermarkOpacity <= 0 {
|
|
return fmt.Errorf("Watermark opacity should be greater than 0")
|
|
} else if WatermarkOpacity > 1 {
|
|
return fmt.Errorf("Watermark opacity should be less than or equal to 1")
|
|
}
|
|
|
|
if FallbackImageHTTPCode < 100 || FallbackImageHTTPCode > 599 {
|
|
return fmt.Errorf("Fallback image HTTP code should be between 100 and 599")
|
|
}
|
|
|
|
if len(PrometheusBind) > 0 && PrometheusBind == Bind {
|
|
return fmt.Errorf("Can't use the same binding for the main server and Prometheus")
|
|
}
|
|
|
|
if FreeMemoryInterval <= 0 {
|
|
return fmt.Errorf("Free memory interval should be greater than zero")
|
|
}
|
|
|
|
if DownloadBufferSize < 0 {
|
|
return fmt.Errorf("Download buffer size should be greater than or equal to 0")
|
|
} else if DownloadBufferSize > math.MaxInt32 {
|
|
return fmt.Errorf("Download buffer size can't be greater than %d", math.MaxInt32)
|
|
}
|
|
|
|
if BufferPoolCalibrationThreshold < 64 {
|
|
return fmt.Errorf("Buffer pool calibration threshold should be greater than or equal to 64")
|
|
}
|
|
|
|
return nil
|
|
}
|