options.go 26 KB

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