config.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. package config
  2. import (
  3. "flag"
  4. "fmt"
  5. "math"
  6. "os"
  7. "regexp"
  8. "runtime"
  9. log "github.com/sirupsen/logrus"
  10. "github.com/imgproxy/imgproxy/v3/config/configurators"
  11. "github.com/imgproxy/imgproxy/v3/imagetype"
  12. "github.com/imgproxy/imgproxy/v3/version"
  13. )
  14. var (
  15. Network string
  16. Bind string
  17. ReadTimeout int
  18. WriteTimeout int
  19. KeepAliveTimeout int
  20. DownloadTimeout int
  21. Concurrency int
  22. MaxClients int
  23. TTL int
  24. CacheControlPassthrough bool
  25. SetCanonicalHeader bool
  26. SoReuseport bool
  27. PathPrefix string
  28. MaxSrcResolution int
  29. MaxSrcFileSize int
  30. MaxAnimationFrames int
  31. MaxSvgCheckBytes int
  32. JpegProgressive bool
  33. PngInterlaced bool
  34. PngQuantize bool
  35. PngQuantizationColors int
  36. AvifSpeed int
  37. Quality int
  38. FormatQuality map[imagetype.Type]int
  39. StripMetadata bool
  40. StripColorProfile bool
  41. AutoRotate bool
  42. EnableWebpDetection bool
  43. EnforceWebp bool
  44. EnableAvifDetection bool
  45. EnforceAvif bool
  46. EnableClientHints bool
  47. SkipProcessingFormats []imagetype.Type
  48. UseLinearColorspace bool
  49. DisableShrinkOnLoad bool
  50. Keys [][]byte
  51. Salts [][]byte
  52. SignatureSize int
  53. Secret string
  54. AllowOrigin string
  55. UserAgent string
  56. IgnoreSslVerification bool
  57. DevelopmentErrorsMode bool
  58. AllowedSources []*regexp.Regexp
  59. CookiePassthrough bool
  60. CookieBaseURL string
  61. LocalFileSystemRoot string
  62. S3Enabled bool
  63. S3Region string
  64. S3Endpoint string
  65. GCSEnabled bool
  66. GCSKey string
  67. ABSEnabled bool
  68. ABSName string
  69. ABSKey string
  70. ABSEndpoint string
  71. ETagEnabled bool
  72. ETagBuster string
  73. BaseURL string
  74. Presets []string
  75. OnlyPresets bool
  76. WatermarkData string
  77. WatermarkPath string
  78. WatermarkURL string
  79. WatermarkOpacity float64
  80. FallbackImageData string
  81. FallbackImagePath string
  82. FallbackImageURL string
  83. FallbackImageHTTPCode int
  84. DataDogEnable bool
  85. NewRelicAppName string
  86. NewRelicKey string
  87. PrometheusBind string
  88. PrometheusNamespace string
  89. BugsnagKey string
  90. BugsnagStage string
  91. HoneybadgerKey string
  92. HoneybadgerEnv string
  93. SentryDSN string
  94. SentryEnvironment string
  95. SentryRelease string
  96. AirbrakeProjecID int
  97. AirbrakeProjecKey string
  98. AirbrakeEnv string
  99. ReportDownloadingErrors bool
  100. EnableDebugHeaders bool
  101. FreeMemoryInterval int
  102. DownloadBufferSize int
  103. BufferPoolCalibrationThreshold int
  104. )
  105. var (
  106. keyPath string
  107. saltPath string
  108. presetsPath string
  109. )
  110. func init() {
  111. Reset()
  112. flag.StringVar(&keyPath, "keypath", "", "path of the file with hex-encoded key")
  113. flag.StringVar(&saltPath, "saltpath", "", "path of the file with hex-encoded salt")
  114. flag.StringVar(&presetsPath, "presets", "", "path of the file with presets")
  115. }
  116. func Reset() {
  117. Network = "tcp"
  118. Bind = ":8080"
  119. ReadTimeout = 10
  120. WriteTimeout = 10
  121. KeepAliveTimeout = 10
  122. DownloadTimeout = 5
  123. Concurrency = runtime.NumCPU() * 2
  124. MaxClients = 0
  125. TTL = 3600
  126. CacheControlPassthrough = false
  127. SetCanonicalHeader = false
  128. SoReuseport = false
  129. PathPrefix = ""
  130. MaxSrcResolution = 16800000
  131. MaxSrcFileSize = 0
  132. MaxAnimationFrames = 1
  133. MaxSvgCheckBytes = 32 * 1024
  134. JpegProgressive = false
  135. PngInterlaced = false
  136. PngQuantize = false
  137. PngQuantizationColors = 256
  138. AvifSpeed = 5
  139. Quality = 80
  140. FormatQuality = map[imagetype.Type]int{imagetype.AVIF: 50}
  141. StripMetadata = true
  142. StripColorProfile = true
  143. AutoRotate = true
  144. EnableWebpDetection = false
  145. EnforceWebp = false
  146. EnableAvifDetection = false
  147. EnforceAvif = false
  148. EnableClientHints = false
  149. SkipProcessingFormats = make([]imagetype.Type, 0)
  150. UseLinearColorspace = false
  151. DisableShrinkOnLoad = false
  152. Keys = make([][]byte, 0)
  153. Salts = make([][]byte, 0)
  154. SignatureSize = 32
  155. Secret = ""
  156. AllowOrigin = ""
  157. UserAgent = fmt.Sprintf("imgproxy/%s", version.Version())
  158. IgnoreSslVerification = false
  159. DevelopmentErrorsMode = false
  160. AllowedSources = make([]*regexp.Regexp, 0)
  161. CookiePassthrough = false
  162. CookieBaseURL = ""
  163. LocalFileSystemRoot = ""
  164. S3Enabled = false
  165. S3Region = ""
  166. S3Endpoint = ""
  167. GCSEnabled = false
  168. GCSKey = ""
  169. ABSEnabled = false
  170. ABSName = ""
  171. ABSKey = ""
  172. ABSEndpoint = ""
  173. ETagEnabled = false
  174. ETagBuster = ""
  175. BaseURL = ""
  176. Presets = make([]string, 0)
  177. OnlyPresets = false
  178. WatermarkData = ""
  179. WatermarkPath = ""
  180. WatermarkURL = ""
  181. WatermarkOpacity = 1
  182. FallbackImageData = ""
  183. FallbackImagePath = ""
  184. FallbackImageURL = ""
  185. FallbackImageHTTPCode = 200
  186. DataDogEnable = false
  187. NewRelicAppName = ""
  188. NewRelicKey = ""
  189. PrometheusBind = ""
  190. PrometheusNamespace = ""
  191. BugsnagKey = ""
  192. BugsnagStage = "production"
  193. HoneybadgerKey = ""
  194. HoneybadgerEnv = "production"
  195. SentryDSN = ""
  196. SentryEnvironment = "production"
  197. SentryRelease = fmt.Sprintf("imgproxy@%s", version.Version())
  198. AirbrakeProjecID = 0
  199. AirbrakeProjecKey = ""
  200. AirbrakeEnv = "production"
  201. ReportDownloadingErrors = true
  202. EnableDebugHeaders = false
  203. FreeMemoryInterval = 10
  204. DownloadBufferSize = 0
  205. BufferPoolCalibrationThreshold = 1024
  206. }
  207. func Configure() error {
  208. if port := os.Getenv("PORT"); len(port) > 0 {
  209. Bind = fmt.Sprintf(":%s", port)
  210. }
  211. configurators.String(&Network, "IMGPROXY_NETWORK")
  212. configurators.String(&Bind, "IMGPROXY_BIND")
  213. configurators.Int(&ReadTimeout, "IMGPROXY_READ_TIMEOUT")
  214. configurators.Int(&WriteTimeout, "IMGPROXY_WRITE_TIMEOUT")
  215. configurators.Int(&KeepAliveTimeout, "IMGPROXY_KEEP_ALIVE_TIMEOUT")
  216. configurators.Int(&DownloadTimeout, "IMGPROXY_DOWNLOAD_TIMEOUT")
  217. configurators.Int(&Concurrency, "IMGPROXY_CONCURRENCY")
  218. configurators.Int(&MaxClients, "IMGPROXY_MAX_CLIENTS")
  219. configurators.Int(&TTL, "IMGPROXY_TTL")
  220. configurators.Bool(&CacheControlPassthrough, "IMGPROXY_CACHE_CONTROL_PASSTHROUGH")
  221. configurators.Bool(&SetCanonicalHeader, "IMGPROXY_SET_CANONICAL_HEADER")
  222. configurators.Bool(&SoReuseport, "IMGPROXY_SO_REUSEPORT")
  223. configurators.String(&PathPrefix, "IMGPROXY_PATH_PREFIX")
  224. configurators.MegaInt(&MaxSrcResolution, "IMGPROXY_MAX_SRC_RESOLUTION")
  225. configurators.Int(&MaxSrcFileSize, "IMGPROXY_MAX_SRC_FILE_SIZE")
  226. configurators.Int(&MaxSvgCheckBytes, "IMGPROXY_MAX_SVG_CHECK_BYTES")
  227. configurators.Int(&MaxAnimationFrames, "IMGPROXY_MAX_ANIMATION_FRAMES")
  228. configurators.Patterns(&AllowedSources, "IMGPROXY_ALLOWED_SOURCES")
  229. configurators.Bool(&JpegProgressive, "IMGPROXY_JPEG_PROGRESSIVE")
  230. configurators.Bool(&PngInterlaced, "IMGPROXY_PNG_INTERLACED")
  231. configurators.Bool(&PngQuantize, "IMGPROXY_PNG_QUANTIZE")
  232. configurators.Int(&PngQuantizationColors, "IMGPROXY_PNG_QUANTIZATION_COLORS")
  233. configurators.Int(&AvifSpeed, "IMGPROXY_AVIF_SPEED")
  234. configurators.Int(&Quality, "IMGPROXY_QUALITY")
  235. if err := configurators.ImageTypesQuality(FormatQuality, "IMGPROXY_FORMAT_QUALITY"); err != nil {
  236. return err
  237. }
  238. configurators.Bool(&StripMetadata, "IMGPROXY_STRIP_METADATA")
  239. configurators.Bool(&StripColorProfile, "IMGPROXY_STRIP_COLOR_PROFILE")
  240. configurators.Bool(&AutoRotate, "IMGPROXY_AUTO_ROTATE")
  241. configurators.Bool(&EnableWebpDetection, "IMGPROXY_ENABLE_WEBP_DETECTION")
  242. configurators.Bool(&EnforceWebp, "IMGPROXY_ENFORCE_WEBP")
  243. configurators.Bool(&EnableAvifDetection, "IMGPROXY_ENABLE_AVIF_DETECTION")
  244. configurators.Bool(&EnforceAvif, "IMGPROXY_ENFORCE_AVIF")
  245. configurators.Bool(&EnableClientHints, "IMGPROXY_ENABLE_CLIENT_HINTS")
  246. if err := configurators.ImageTypes(&SkipProcessingFormats, "IMGPROXY_SKIP_PROCESSING_FORMATS"); err != nil {
  247. return err
  248. }
  249. configurators.Bool(&UseLinearColorspace, "IMGPROXY_USE_LINEAR_COLORSPACE")
  250. configurators.Bool(&DisableShrinkOnLoad, "IMGPROXY_DISABLE_SHRINK_ON_LOAD")
  251. if err := configurators.Hex(&Keys, "IMGPROXY_KEY"); err != nil {
  252. return err
  253. }
  254. if err := configurators.Hex(&Salts, "IMGPROXY_SALT"); err != nil {
  255. return err
  256. }
  257. configurators.Int(&SignatureSize, "IMGPROXY_SIGNATURE_SIZE")
  258. if err := configurators.HexFile(&Keys, keyPath); err != nil {
  259. return err
  260. }
  261. if err := configurators.HexFile(&Salts, saltPath); err != nil {
  262. return err
  263. }
  264. configurators.String(&Secret, "IMGPROXY_SECRET")
  265. configurators.String(&AllowOrigin, "IMGPROXY_ALLOW_ORIGIN")
  266. configurators.String(&UserAgent, "IMGPROXY_USER_AGENT")
  267. configurators.Bool(&IgnoreSslVerification, "IMGPROXY_IGNORE_SSL_VERIFICATION")
  268. configurators.Bool(&DevelopmentErrorsMode, "IMGPROXY_DEVELOPMENT_ERRORS_MODE")
  269. configurators.Bool(&CookiePassthrough, "IMGPROXY_COOKIE_PASSTHROUGH")
  270. configurators.String(&CookieBaseURL, "IMGPROXY_COOKIE_BASE_URL")
  271. configurators.String(&LocalFileSystemRoot, "IMGPROXY_LOCAL_FILESYSTEM_ROOT")
  272. configurators.Bool(&S3Enabled, "IMGPROXY_USE_S3")
  273. configurators.String(&S3Region, "IMGPROXY_S3_REGION")
  274. configurators.String(&S3Endpoint, "IMGPROXY_S3_ENDPOINT")
  275. configurators.Bool(&GCSEnabled, "IMGPROXY_USE_GCS")
  276. configurators.String(&GCSKey, "IMGPROXY_GCS_KEY")
  277. configurators.Bool(&ABSEnabled, "IMGPROXY_USE_ABS")
  278. configurators.String(&ABSName, "IMGPROXY_ABS_NAME")
  279. configurators.String(&ABSKey, "IMGPROXY_ABS_KEY")
  280. configurators.String(&ABSEndpoint, "IMGPROXY_ABS_ENDPOINT")
  281. configurators.Bool(&ETagEnabled, "IMGPROXY_USE_ETAG")
  282. configurators.String(&ETagBuster, "IMGPROXY_ETAG_BUSTER")
  283. configurators.String(&BaseURL, "IMGPROXY_BASE_URL")
  284. configurators.StringSlice(&Presets, "IMGPROXY_PRESETS")
  285. if err := configurators.StringSliceFile(&Presets, presetsPath); err != nil {
  286. return err
  287. }
  288. configurators.Bool(&OnlyPresets, "IMGPROXY_ONLY_PRESETS")
  289. configurators.String(&WatermarkData, "IMGPROXY_WATERMARK_DATA")
  290. configurators.String(&WatermarkPath, "IMGPROXY_WATERMARK_PATH")
  291. configurators.String(&WatermarkURL, "IMGPROXY_WATERMARK_URL")
  292. configurators.Float(&WatermarkOpacity, "IMGPROXY_WATERMARK_OPACITY")
  293. configurators.String(&FallbackImageData, "IMGPROXY_FALLBACK_IMAGE_DATA")
  294. configurators.String(&FallbackImagePath, "IMGPROXY_FALLBACK_IMAGE_PATH")
  295. configurators.String(&FallbackImageURL, "IMGPROXY_FALLBACK_IMAGE_URL")
  296. configurators.Int(&FallbackImageHTTPCode, "IMGPROXY_FALLBACK_IMAGE_HTTP_CODE")
  297. configurators.Bool(&DataDogEnable, "IMGPROXY_DATADOG_ENABLE")
  298. configurators.String(&NewRelicAppName, "IMGPROXY_NEW_RELIC_APP_NAME")
  299. configurators.String(&NewRelicKey, "IMGPROXY_NEW_RELIC_KEY")
  300. configurators.String(&PrometheusBind, "IMGPROXY_PROMETHEUS_BIND")
  301. configurators.String(&PrometheusNamespace, "IMGPROXY_PROMETHEUS_NAMESPACE")
  302. configurators.String(&BugsnagKey, "IMGPROXY_BUGSNAG_KEY")
  303. configurators.String(&BugsnagStage, "IMGPROXY_BUGSNAG_STAGE")
  304. configurators.String(&HoneybadgerKey, "IMGPROXY_HONEYBADGER_KEY")
  305. configurators.String(&HoneybadgerEnv, "IMGPROXY_HONEYBADGER_ENV")
  306. configurators.String(&SentryDSN, "IMGPROXY_SENTRY_DSN")
  307. configurators.String(&SentryEnvironment, "IMGPROXY_SENTRY_ENVIRONMENT")
  308. configurators.String(&SentryRelease, "IMGPROXY_SENTRY_RELEASE")
  309. configurators.Int(&AirbrakeProjecID, "IMGPROXY_AIRBRAKE_PROJECT_ID")
  310. configurators.String(&AirbrakeProjecKey, "IMGPROXY_AIRBRAKE_PROJECT_KEY")
  311. configurators.String(&AirbrakeEnv, "IMGPROXY_AIRBRAKE_ENVIRONMENT")
  312. configurators.Bool(&ReportDownloadingErrors, "IMGPROXY_REPORT_DOWNLOADING_ERRORS")
  313. configurators.Bool(&EnableDebugHeaders, "IMGPROXY_ENABLE_DEBUG_HEADERS")
  314. configurators.Int(&FreeMemoryInterval, "IMGPROXY_FREE_MEMORY_INTERVAL")
  315. configurators.Int(&DownloadBufferSize, "IMGPROXY_DOWNLOAD_BUFFER_SIZE")
  316. configurators.Int(&BufferPoolCalibrationThreshold, "IMGPROXY_BUFFER_POOL_CALIBRATION_THRESHOLD")
  317. if len(Keys) != len(Salts) {
  318. return fmt.Errorf("Number of keys and number of salts should be equal. Keys: %d, salts: %d", len(Keys), len(Salts))
  319. }
  320. if len(Keys) == 0 {
  321. log.Warning("No keys defined, so signature checking is disabled")
  322. }
  323. if len(Salts) == 0 {
  324. log.Warning("No salts defined, so signature checking is disabled")
  325. }
  326. if SignatureSize < 1 || SignatureSize > 32 {
  327. return fmt.Errorf("Signature size should be within 1 and 32, now - %d\n", SignatureSize)
  328. }
  329. if len(Bind) == 0 {
  330. return fmt.Errorf("Bind address is not defined")
  331. }
  332. if ReadTimeout <= 0 {
  333. return fmt.Errorf("Read timeout should be greater than 0, now - %d\n", ReadTimeout)
  334. }
  335. if WriteTimeout <= 0 {
  336. return fmt.Errorf("Write timeout should be greater than 0, now - %d\n", WriteTimeout)
  337. }
  338. if KeepAliveTimeout < 0 {
  339. return fmt.Errorf("KeepAlive timeout should be greater than or equal to 0, now - %d\n", KeepAliveTimeout)
  340. }
  341. if DownloadTimeout <= 0 {
  342. return fmt.Errorf("Download timeout should be greater than 0, now - %d\n", DownloadTimeout)
  343. }
  344. if Concurrency <= 0 {
  345. return fmt.Errorf("Concurrency should be greater than 0, now - %d\n", Concurrency)
  346. }
  347. if MaxClients <= 0 {
  348. MaxClients = Concurrency * 10
  349. }
  350. if TTL <= 0 {
  351. return fmt.Errorf("TTL should be greater than 0, now - %d\n", TTL)
  352. }
  353. if MaxSrcResolution <= 0 {
  354. return fmt.Errorf("Max src resolution should be greater than 0, now - %d\n", MaxSrcResolution)
  355. }
  356. if MaxSrcFileSize < 0 {
  357. return fmt.Errorf("Max src file size should be greater than or equal to 0, now - %d\n", MaxSrcFileSize)
  358. }
  359. if MaxAnimationFrames <= 0 {
  360. return fmt.Errorf("Max animation frames should be greater than 0, now - %d\n", MaxAnimationFrames)
  361. }
  362. if PngQuantizationColors < 2 {
  363. return fmt.Errorf("Png quantization colors should be greater than 1, now - %d\n", PngQuantizationColors)
  364. } else if PngQuantizationColors > 256 {
  365. return fmt.Errorf("Png quantization colors can't be greater than 256, now - %d\n", PngQuantizationColors)
  366. }
  367. if AvifSpeed < 0 {
  368. return fmt.Errorf("Avif speed should be greater than 0, now - %d\n", AvifSpeed)
  369. } else if AvifSpeed > 8 {
  370. return fmt.Errorf("Avif speed can't be greater than 8, now - %d\n", AvifSpeed)
  371. }
  372. if Quality <= 0 {
  373. return fmt.Errorf("Quality should be greater than 0, now - %d\n", Quality)
  374. } else if Quality > 100 {
  375. return fmt.Errorf("Quality can't be greater than 100, now - %d\n", Quality)
  376. }
  377. if IgnoreSslVerification {
  378. log.Warning("Ignoring SSL verification is very unsafe")
  379. }
  380. if LocalFileSystemRoot != "" {
  381. stat, err := os.Stat(LocalFileSystemRoot)
  382. if err != nil {
  383. return fmt.Errorf("Cannot use local directory: %s", err)
  384. }
  385. if !stat.IsDir() {
  386. return fmt.Errorf("Cannot use local directory: not a directory")
  387. }
  388. if LocalFileSystemRoot == "/" {
  389. log.Warning("Exposing root via IMGPROXY_LOCAL_FILESYSTEM_ROOT is unsafe")
  390. }
  391. }
  392. if _, ok := os.LookupEnv("IMGPROXY_USE_GCS"); !ok && len(GCSKey) > 0 {
  393. log.Warning("Set IMGPROXY_USE_GCS to true since it may be required by future versions to enable GCS support")
  394. GCSEnabled = true
  395. }
  396. if WatermarkOpacity <= 0 {
  397. return fmt.Errorf("Watermark opacity should be greater than 0")
  398. } else if WatermarkOpacity > 1 {
  399. return fmt.Errorf("Watermark opacity should be less than or equal to 1")
  400. }
  401. if FallbackImageHTTPCode < 100 || FallbackImageHTTPCode > 599 {
  402. return fmt.Errorf("Fallback image HTTP code should be between 100 and 599")
  403. }
  404. if len(PrometheusBind) > 0 && PrometheusBind == Bind {
  405. return fmt.Errorf("Can't use the same binding for the main server and Prometheus")
  406. }
  407. if FreeMemoryInterval <= 0 {
  408. return fmt.Errorf("Free memory interval should be greater than zero")
  409. }
  410. if DownloadBufferSize < 0 {
  411. return fmt.Errorf("Download buffer size should be greater than or equal to 0")
  412. } else if DownloadBufferSize > math.MaxInt32 {
  413. return fmt.Errorf("Download buffer size can't be greater than %d", math.MaxInt32)
  414. }
  415. if BufferPoolCalibrationThreshold < 64 {
  416. return fmt.Errorf("Buffer pool calibration threshold should be greater than or equal to 64")
  417. }
  418. return nil
  419. }