options.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  1. // Copyright 2019 Frédéric Guillot. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package config // import "miniflux.app/config"
  5. import (
  6. "crypto/rand"
  7. "fmt"
  8. "sort"
  9. "strings"
  10. "time"
  11. "miniflux.app/version"
  12. )
  13. const (
  14. defaultHTTPS = false
  15. defaultLogDateTime = false
  16. defaultHSTS = true
  17. defaultHTTPService = true
  18. defaultSchedulerService = true
  19. defaultDebug = false
  20. defaultTiming = false
  21. defaultBaseURL = "http://localhost"
  22. defaultRootURL = "http://localhost"
  23. defaultBasePath = ""
  24. defaultWorkerPoolSize = 5
  25. defaultPollingFrequency = 60
  26. defaultBatchSize = 100
  27. defaultPollingScheduler = "round_robin"
  28. defaultSchedulerEntryFrequencyMinInterval = 5
  29. defaultSchedulerEntryFrequencyMaxInterval = 24 * 60
  30. defaultPollingParsingErrorLimit = 3
  31. defaultRunMigrations = false
  32. defaultDatabaseURL = "user=postgres password=postgres dbname=miniflux2 sslmode=disable"
  33. defaultDatabaseMaxConns = 20
  34. defaultDatabaseMinConns = 1
  35. defaultDatabaseConnectionLifetime = 5
  36. defaultListenAddr = "127.0.0.1:8080"
  37. defaultCertFile = ""
  38. defaultKeyFile = ""
  39. defaultCertDomain = ""
  40. defaultCleanupFrequencyHours = 24
  41. defaultCleanupArchiveReadDays = 60
  42. defaultCleanupArchiveUnreadDays = 180
  43. defaultCleanupArchiveBatchSize = 10000
  44. defaultCleanupRemoveSessionsDays = 30
  45. defaultProxyImages = "http-only"
  46. defaultProxyImageUrl = ""
  47. defaultFetchYouTubeWatchTime = false
  48. defaultCreateAdmin = false
  49. defaultAdminUsername = ""
  50. defaultAdminPassword = ""
  51. defaultOAuth2UserCreation = false
  52. defaultOAuth2ClientID = ""
  53. defaultOAuth2ClientSecret = ""
  54. defaultOAuth2RedirectURL = ""
  55. defaultOAuth2OidcDiscoveryEndpoint = ""
  56. defaultOAuth2Provider = ""
  57. defaultPocketConsumerKey = ""
  58. defaultHTTPClientTimeout = 20
  59. defaultHTTPClientMaxBodySize = 15
  60. defaultHTTPClientProxy = ""
  61. defaultAuthProxyHeader = ""
  62. defaultAuthProxyUserCreation = false
  63. defaultMaintenanceMode = false
  64. defaultMaintenanceMessage = "Miniflux is currently under maintenance"
  65. defaultMetricsCollector = false
  66. defaultMetricsRefreshInterval = 60
  67. defaultMetricsAllowedNetworks = "127.0.0.1/8"
  68. defaultWatchdog = true
  69. defaultInvidiousInstance = "yewtu.be"
  70. )
  71. var defaultHTTPClientUserAgent = "Mozilla/5.0 (compatible; Miniflux/" + version.Version + "; +https://miniflux.app)"
  72. // Option contains a key to value map of a single option. It may be used to output debug strings.
  73. type Option struct {
  74. Key string
  75. Value interface{}
  76. }
  77. // Options contains configuration options.
  78. type Options struct {
  79. HTTPS bool
  80. logDateTime bool
  81. hsts bool
  82. httpService bool
  83. schedulerService bool
  84. debug bool
  85. serverTimingHeader bool
  86. baseURL string
  87. rootURL string
  88. basePath string
  89. databaseURL string
  90. databaseMaxConns int
  91. databaseMinConns int
  92. databaseConnectionLifetime int
  93. runMigrations bool
  94. listenAddr string
  95. certFile string
  96. certDomain string
  97. certKeyFile string
  98. cleanupFrequencyHours int
  99. cleanupArchiveReadDays int
  100. cleanupArchiveUnreadDays int
  101. cleanupArchiveBatchSize int
  102. cleanupRemoveSessionsDays int
  103. pollingFrequency int
  104. batchSize int
  105. pollingScheduler string
  106. schedulerEntryFrequencyMinInterval int
  107. schedulerEntryFrequencyMaxInterval int
  108. pollingParsingErrorLimit int
  109. workerPoolSize int
  110. createAdmin bool
  111. adminUsername string
  112. adminPassword string
  113. proxyImages string
  114. proxyImageUrl string
  115. fetchYouTubeWatchTime bool
  116. oauth2UserCreationAllowed bool
  117. oauth2ClientID string
  118. oauth2ClientSecret string
  119. oauth2RedirectURL string
  120. oauth2OidcDiscoveryEndpoint string
  121. oauth2Provider string
  122. pocketConsumerKey string
  123. httpClientTimeout int
  124. httpClientMaxBodySize int64
  125. httpClientProxy string
  126. httpClientUserAgent string
  127. authProxyHeader string
  128. authProxyUserCreation bool
  129. maintenanceMode bool
  130. maintenanceMessage string
  131. metricsCollector bool
  132. metricsRefreshInterval int
  133. metricsAllowedNetworks []string
  134. watchdog bool
  135. invidiousInstance string
  136. proxyPrivateKey []byte
  137. }
  138. // NewOptions returns Options with default values.
  139. func NewOptions() *Options {
  140. randomKey := make([]byte, 16)
  141. rand.Read(randomKey)
  142. return &Options{
  143. HTTPS: defaultHTTPS,
  144. logDateTime: defaultLogDateTime,
  145. hsts: defaultHSTS,
  146. httpService: defaultHTTPService,
  147. schedulerService: defaultSchedulerService,
  148. debug: defaultDebug,
  149. serverTimingHeader: defaultTiming,
  150. baseURL: defaultBaseURL,
  151. rootURL: defaultRootURL,
  152. basePath: defaultBasePath,
  153. databaseURL: defaultDatabaseURL,
  154. databaseMaxConns: defaultDatabaseMaxConns,
  155. databaseMinConns: defaultDatabaseMinConns,
  156. databaseConnectionLifetime: defaultDatabaseConnectionLifetime,
  157. runMigrations: defaultRunMigrations,
  158. listenAddr: defaultListenAddr,
  159. certFile: defaultCertFile,
  160. certDomain: defaultCertDomain,
  161. certKeyFile: defaultKeyFile,
  162. cleanupFrequencyHours: defaultCleanupFrequencyHours,
  163. cleanupArchiveReadDays: defaultCleanupArchiveReadDays,
  164. cleanupArchiveUnreadDays: defaultCleanupArchiveUnreadDays,
  165. cleanupArchiveBatchSize: defaultCleanupArchiveBatchSize,
  166. cleanupRemoveSessionsDays: defaultCleanupRemoveSessionsDays,
  167. pollingFrequency: defaultPollingFrequency,
  168. batchSize: defaultBatchSize,
  169. pollingScheduler: defaultPollingScheduler,
  170. schedulerEntryFrequencyMinInterval: defaultSchedulerEntryFrequencyMinInterval,
  171. schedulerEntryFrequencyMaxInterval: defaultSchedulerEntryFrequencyMaxInterval,
  172. pollingParsingErrorLimit: defaultPollingParsingErrorLimit,
  173. workerPoolSize: defaultWorkerPoolSize,
  174. createAdmin: defaultCreateAdmin,
  175. proxyImages: defaultProxyImages,
  176. proxyImageUrl: defaultProxyImageUrl,
  177. fetchYouTubeWatchTime: defaultFetchYouTubeWatchTime,
  178. oauth2UserCreationAllowed: defaultOAuth2UserCreation,
  179. oauth2ClientID: defaultOAuth2ClientID,
  180. oauth2ClientSecret: defaultOAuth2ClientSecret,
  181. oauth2RedirectURL: defaultOAuth2RedirectURL,
  182. oauth2OidcDiscoveryEndpoint: defaultOAuth2OidcDiscoveryEndpoint,
  183. oauth2Provider: defaultOAuth2Provider,
  184. pocketConsumerKey: defaultPocketConsumerKey,
  185. httpClientTimeout: defaultHTTPClientTimeout,
  186. httpClientMaxBodySize: defaultHTTPClientMaxBodySize * 1024 * 1024,
  187. httpClientProxy: defaultHTTPClientProxy,
  188. httpClientUserAgent: defaultHTTPClientUserAgent,
  189. authProxyHeader: defaultAuthProxyHeader,
  190. authProxyUserCreation: defaultAuthProxyUserCreation,
  191. maintenanceMode: defaultMaintenanceMode,
  192. maintenanceMessage: defaultMaintenanceMessage,
  193. metricsCollector: defaultMetricsCollector,
  194. metricsRefreshInterval: defaultMetricsRefreshInterval,
  195. metricsAllowedNetworks: []string{defaultMetricsAllowedNetworks},
  196. watchdog: defaultWatchdog,
  197. invidiousInstance: defaultInvidiousInstance,
  198. proxyPrivateKey: randomKey,
  199. }
  200. }
  201. // LogDateTime returns true if the date/time should be displayed in log messages.
  202. func (o *Options) LogDateTime() bool {
  203. return o.logDateTime
  204. }
  205. // HasMaintenanceMode returns true if maintenance mode is enabled.
  206. func (o *Options) HasMaintenanceMode() bool {
  207. return o.maintenanceMode
  208. }
  209. // MaintenanceMessage returns maintenance message.
  210. func (o *Options) MaintenanceMessage() string {
  211. return o.maintenanceMessage
  212. }
  213. // HasDebugMode returns true if debug mode is enabled.
  214. func (o *Options) HasDebugMode() bool {
  215. return o.debug
  216. }
  217. // HasServerTimingHeader returns true if server-timing headers enabled.
  218. func (o *Options) HasServerTimingHeader() bool {
  219. return o.serverTimingHeader
  220. }
  221. // BaseURL returns the application base URL with path.
  222. func (o *Options) BaseURL() string {
  223. return o.baseURL
  224. }
  225. // RootURL returns the base URL without path.
  226. func (o *Options) RootURL() string {
  227. return o.rootURL
  228. }
  229. // BasePath returns the application base path according to the base URL.
  230. func (o *Options) BasePath() string {
  231. return o.basePath
  232. }
  233. // IsDefaultDatabaseURL returns true if the default database URL is used.
  234. func (o *Options) IsDefaultDatabaseURL() bool {
  235. return o.databaseURL == defaultDatabaseURL
  236. }
  237. // DatabaseURL returns the database URL.
  238. func (o *Options) DatabaseURL() string {
  239. return o.databaseURL
  240. }
  241. // DatabaseMaxConns returns the maximum number of database connections.
  242. func (o *Options) DatabaseMaxConns() int {
  243. return o.databaseMaxConns
  244. }
  245. // DatabaseMinConns returns the minimum number of database connections.
  246. func (o *Options) DatabaseMinConns() int {
  247. return o.databaseMinConns
  248. }
  249. // DatabaseConnectionLifetime returns the maximum amount of time a connection may be reused.
  250. func (o *Options) DatabaseConnectionLifetime() time.Duration {
  251. return time.Duration(o.databaseConnectionLifetime) * time.Minute
  252. }
  253. // ListenAddr returns the listen address for the HTTP server.
  254. func (o *Options) ListenAddr() string {
  255. return o.listenAddr
  256. }
  257. // CertFile returns the SSL certificate filename if any.
  258. func (o *Options) CertFile() string {
  259. return o.certFile
  260. }
  261. // CertKeyFile returns the private key filename for custom SSL certificate.
  262. func (o *Options) CertKeyFile() string {
  263. return o.certKeyFile
  264. }
  265. // CertDomain returns the domain to use for Let's Encrypt certificate.
  266. func (o *Options) CertDomain() string {
  267. return o.certDomain
  268. }
  269. // CleanupFrequencyHours returns the interval in hours for cleanup jobs.
  270. func (o *Options) CleanupFrequencyHours() int {
  271. return o.cleanupFrequencyHours
  272. }
  273. // CleanupArchiveReadDays returns the number of days after which marking read items as removed.
  274. func (o *Options) CleanupArchiveReadDays() int {
  275. return o.cleanupArchiveReadDays
  276. }
  277. // CleanupArchiveUnreadDays returns the number of days after which marking unread items as removed.
  278. func (o *Options) CleanupArchiveUnreadDays() int {
  279. return o.cleanupArchiveUnreadDays
  280. }
  281. // CleanupArchiveBatchSize returns the number of entries to archive for each interval.
  282. func (o *Options) CleanupArchiveBatchSize() int {
  283. return o.cleanupArchiveBatchSize
  284. }
  285. // CleanupRemoveSessionsDays returns the number of days after which to remove sessions.
  286. func (o *Options) CleanupRemoveSessionsDays() int {
  287. return o.cleanupRemoveSessionsDays
  288. }
  289. // WorkerPoolSize returns the number of background worker.
  290. func (o *Options) WorkerPoolSize() int {
  291. return o.workerPoolSize
  292. }
  293. // PollingFrequency returns the interval to refresh feeds in the background.
  294. func (o *Options) PollingFrequency() int {
  295. return o.pollingFrequency
  296. }
  297. // BatchSize returns the number of feeds to send for background processing.
  298. func (o *Options) BatchSize() int {
  299. return o.batchSize
  300. }
  301. // PollingScheduler returns the scheduler used for polling feeds.
  302. func (o *Options) PollingScheduler() string {
  303. return o.pollingScheduler
  304. }
  305. // SchedulerEntryFrequencyMaxInterval returns the maximum interval in minutes for the entry frequency scheduler.
  306. func (o *Options) SchedulerEntryFrequencyMaxInterval() int {
  307. return o.schedulerEntryFrequencyMaxInterval
  308. }
  309. // SchedulerEntryFrequencyMinInterval returns the minimum interval in minutes for the entry frequency scheduler.
  310. func (o *Options) SchedulerEntryFrequencyMinInterval() int {
  311. return o.schedulerEntryFrequencyMinInterval
  312. }
  313. // PollingParsingErrorLimit returns the limit of errors when to stop polling.
  314. func (o *Options) PollingParsingErrorLimit() int {
  315. return o.pollingParsingErrorLimit
  316. }
  317. // IsOAuth2UserCreationAllowed returns true if user creation is allowed for OAuth2 users.
  318. func (o *Options) IsOAuth2UserCreationAllowed() bool {
  319. return o.oauth2UserCreationAllowed
  320. }
  321. // OAuth2ClientID returns the OAuth2 Client ID.
  322. func (o *Options) OAuth2ClientID() string {
  323. return o.oauth2ClientID
  324. }
  325. // OAuth2ClientSecret returns the OAuth2 client secret.
  326. func (o *Options) OAuth2ClientSecret() string {
  327. return o.oauth2ClientSecret
  328. }
  329. // OAuth2RedirectURL returns the OAuth2 redirect URL.
  330. func (o *Options) OAuth2RedirectURL() string {
  331. return o.oauth2RedirectURL
  332. }
  333. // OAuth2OidcDiscoveryEndpoint returns the OAuth2 OIDC discovery endpoint.
  334. func (o *Options) OAuth2OidcDiscoveryEndpoint() string {
  335. return o.oauth2OidcDiscoveryEndpoint
  336. }
  337. // OAuth2Provider returns the name of the OAuth2 provider configured.
  338. func (o *Options) OAuth2Provider() string {
  339. return o.oauth2Provider
  340. }
  341. // HasHSTS returns true if HTTP Strict Transport Security is enabled.
  342. func (o *Options) HasHSTS() bool {
  343. return o.hsts
  344. }
  345. // RunMigrations returns true if the environment variable RUN_MIGRATIONS is not empty.
  346. func (o *Options) RunMigrations() bool {
  347. return o.runMigrations
  348. }
  349. // CreateAdmin returns true if the environment variable CREATE_ADMIN is not empty.
  350. func (o *Options) CreateAdmin() bool {
  351. return o.createAdmin
  352. }
  353. // AdminUsername returns the admin username if defined.
  354. func (o *Options) AdminUsername() string {
  355. return o.adminUsername
  356. }
  357. // AdminPassword returns the admin password if defined.
  358. func (o *Options) AdminPassword() string {
  359. return o.adminPassword
  360. }
  361. // FetchYouTubeWatchTime returns true if the YouTube video duration
  362. // should be fetched and used as a reading time.
  363. func (o *Options) FetchYouTubeWatchTime() bool {
  364. return o.fetchYouTubeWatchTime
  365. }
  366. // ProxyImages returns "none" to never proxy, "http-only" to proxy non-HTTPS, "all" to always proxy.
  367. func (o *Options) ProxyImages() string {
  368. return o.proxyImages
  369. }
  370. // ProxyImageUrl returns a string of a URL to use to proxy image requests
  371. func (o *Options) ProxyImageUrl() string {
  372. return o.proxyImageUrl
  373. }
  374. // HasHTTPService returns true if the HTTP service is enabled.
  375. func (o *Options) HasHTTPService() bool {
  376. return o.httpService
  377. }
  378. // HasSchedulerService returns true if the scheduler service is enabled.
  379. func (o *Options) HasSchedulerService() bool {
  380. return o.schedulerService
  381. }
  382. // PocketConsumerKey returns the Pocket Consumer Key if configured.
  383. func (o *Options) PocketConsumerKey(defaultValue string) string {
  384. if o.pocketConsumerKey != "" {
  385. return o.pocketConsumerKey
  386. }
  387. return defaultValue
  388. }
  389. // HTTPClientTimeout returns the time limit in seconds before the HTTP client cancel the request.
  390. func (o *Options) HTTPClientTimeout() int {
  391. return o.httpClientTimeout
  392. }
  393. // HTTPClientMaxBodySize returns the number of bytes allowed for the HTTP client to transfer.
  394. func (o *Options) HTTPClientMaxBodySize() int64 {
  395. return o.httpClientMaxBodySize
  396. }
  397. // HTTPClientProxy returns the proxy URL for HTTP client.
  398. func (o *Options) HTTPClientProxy() string {
  399. return o.httpClientProxy
  400. }
  401. // HasHTTPClientProxyConfigured returns true if the HTTP proxy is configured.
  402. func (o *Options) HasHTTPClientProxyConfigured() bool {
  403. return o.httpClientProxy != ""
  404. }
  405. // AuthProxyHeader returns an HTTP header name that contains username for
  406. // authentication using auth proxy.
  407. func (o *Options) AuthProxyHeader() string {
  408. return o.authProxyHeader
  409. }
  410. // IsAuthProxyUserCreationAllowed returns true if user creation is allowed for
  411. // users authenticated using auth proxy.
  412. func (o *Options) IsAuthProxyUserCreationAllowed() bool {
  413. return o.authProxyUserCreation
  414. }
  415. // HasMetricsCollector returns true if metrics collection is enabled.
  416. func (o *Options) HasMetricsCollector() bool {
  417. return o.metricsCollector
  418. }
  419. // MetricsRefreshInterval returns the refresh interval in seconds.
  420. func (o *Options) MetricsRefreshInterval() int {
  421. return o.metricsRefreshInterval
  422. }
  423. // MetricsAllowedNetworks returns the list of networks allowed to connect to the metrics endpoint.
  424. func (o *Options) MetricsAllowedNetworks() []string {
  425. return o.metricsAllowedNetworks
  426. }
  427. // HTTPClientUserAgent returns the global User-Agent header for miniflux.
  428. func (o *Options) HTTPClientUserAgent() string {
  429. return o.httpClientUserAgent
  430. }
  431. // HasWatchdog returns true if the systemd watchdog is enabled.
  432. func (o *Options) HasWatchdog() bool {
  433. return o.watchdog
  434. }
  435. // InvidiousInstance returns the invidious instance used by miniflux
  436. func (o *Options) InvidiousInstance() string {
  437. return o.invidiousInstance
  438. }
  439. // ProxyPrivateKey returns the private key used by the media proxy
  440. func (o *Options) ProxyPrivateKey() []byte {
  441. return o.proxyPrivateKey
  442. }
  443. // SortedOptions returns options as a list of key value pairs, sorted by keys.
  444. func (o *Options) SortedOptions(redactSecret bool) []*Option {
  445. var keyValues = map[string]interface{}{
  446. "ADMIN_PASSWORD": redactSecretValue(o.adminPassword, redactSecret),
  447. "ADMIN_USERNAME": o.adminUsername,
  448. "AUTH_PROXY_HEADER": o.authProxyHeader,
  449. "AUTH_PROXY_USER_CREATION": o.authProxyUserCreation,
  450. "BASE_PATH": o.basePath,
  451. "BASE_URL": o.baseURL,
  452. "BATCH_SIZE": o.batchSize,
  453. "CERT_DOMAIN": o.certDomain,
  454. "CERT_FILE": o.certFile,
  455. "CLEANUP_ARCHIVE_READ_DAYS": o.cleanupArchiveReadDays,
  456. "CLEANUP_ARCHIVE_UNREAD_DAYS": o.cleanupArchiveUnreadDays,
  457. "CLEANUP_ARCHIVE_BATCH_SIZE": o.cleanupArchiveBatchSize,
  458. "CLEANUP_FREQUENCY_HOURS": o.cleanupFrequencyHours,
  459. "CLEANUP_REMOVE_SESSIONS_DAYS": o.cleanupRemoveSessionsDays,
  460. "CREATE_ADMIN": o.createAdmin,
  461. "DATABASE_MAX_CONNS": o.databaseMaxConns,
  462. "DATABASE_MIN_CONNS": o.databaseMinConns,
  463. "DATABASE_CONNECTION_LIFETIME": o.databaseConnectionLifetime,
  464. "DATABASE_URL": redactSecretValue(o.databaseURL, redactSecret),
  465. "DEBUG": o.debug,
  466. "DISABLE_HSTS": !o.hsts,
  467. "DISABLE_SCHEDULER_SERVICE": !o.schedulerService,
  468. "DISABLE_HTTP_SERVICE": !o.httpService,
  469. "FETCH_YOUTUBE_WATCH_TIME": o.fetchYouTubeWatchTime,
  470. "HTTPS": o.HTTPS,
  471. "HTTP_CLIENT_MAX_BODY_SIZE": o.httpClientMaxBodySize,
  472. "HTTP_CLIENT_PROXY": o.httpClientProxy,
  473. "HTTP_CLIENT_TIMEOUT": o.httpClientTimeout,
  474. "HTTP_CLIENT_USER_AGENT": o.httpClientUserAgent,
  475. "HTTP_SERVICE": o.httpService,
  476. "KEY_FILE": o.certKeyFile,
  477. "INVIDIOUS_INSTANCE": o.invidiousInstance,
  478. "LISTEN_ADDR": o.listenAddr,
  479. "LOG_DATE_TIME": o.logDateTime,
  480. "MAINTENANCE_MESSAGE": o.maintenanceMessage,
  481. "MAINTENANCE_MODE": o.maintenanceMode,
  482. "METRICS_ALLOWED_NETWORKS": strings.Join(o.metricsAllowedNetworks, ","),
  483. "METRICS_COLLECTOR": o.metricsCollector,
  484. "METRICS_REFRESH_INTERVAL": o.metricsRefreshInterval,
  485. "OAUTH2_CLIENT_ID": o.oauth2ClientID,
  486. "OAUTH2_CLIENT_SECRET": redactSecretValue(o.oauth2ClientSecret, redactSecret),
  487. "OAUTH2_OIDC_DISCOVERY_ENDPOINT": o.oauth2OidcDiscoveryEndpoint,
  488. "OAUTH2_PROVIDER": o.oauth2Provider,
  489. "OAUTH2_REDIRECT_URL": o.oauth2RedirectURL,
  490. "OAUTH2_USER_CREATION": o.oauth2UserCreationAllowed,
  491. "POCKET_CONSUMER_KEY": redactSecretValue(o.pocketConsumerKey, redactSecret),
  492. "POLLING_FREQUENCY": o.pollingFrequency,
  493. "POLLING_PARSING_ERROR_LIMIT": o.pollingParsingErrorLimit,
  494. "POLLING_SCHEDULER": o.pollingScheduler,
  495. "PROXY_IMAGES": o.proxyImages,
  496. "PROXY_IMAGE_URL": o.proxyImageUrl,
  497. "PROXY_PRIVATE_KEY": redactSecretValue(string(o.proxyPrivateKey), redactSecret),
  498. "ROOT_URL": o.rootURL,
  499. "RUN_MIGRATIONS": o.runMigrations,
  500. "SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL": o.schedulerEntryFrequencyMaxInterval,
  501. "SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL": o.schedulerEntryFrequencyMinInterval,
  502. "SCHEDULER_SERVICE": o.schedulerService,
  503. "SERVER_TIMING_HEADER": o.serverTimingHeader,
  504. "WORKER_POOL_SIZE": o.workerPoolSize,
  505. "WATCHDOG": o.watchdog,
  506. }
  507. keys := make([]string, 0, len(keyValues))
  508. for key := range keyValues {
  509. keys = append(keys, key)
  510. }
  511. sort.Strings(keys)
  512. var sortedOptions []*Option
  513. for _, key := range keys {
  514. sortedOptions = append(sortedOptions, &Option{Key: key, Value: keyValues[key]})
  515. }
  516. return sortedOptions
  517. }
  518. func (o *Options) String() string {
  519. var builder strings.Builder
  520. for _, option := range o.SortedOptions(false) {
  521. fmt.Fprintf(&builder, "%s=%v\n", option.Key, option.Value)
  522. }
  523. return builder.String()
  524. }
  525. func redactSecretValue(value string, redactSecret bool) string {
  526. if redactSecret && value != "" {
  527. return "******"
  528. }
  529. return value
  530. }