options.go 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package config // import "miniflux.app/v2/internal/config"
  4. import (
  5. "fmt"
  6. "maps"
  7. "net/url"
  8. "slices"
  9. "strings"
  10. "time"
  11. "miniflux.app/v2/internal/crypto"
  12. "miniflux.app/v2/internal/version"
  13. )
  14. const (
  15. defaultHTTPS = false
  16. defaultLogFile = "stderr"
  17. defaultLogDateTime = false
  18. defaultLogFormat = "text"
  19. defaultLogLevel = "info"
  20. defaultHSTS = true
  21. defaultHTTPService = true
  22. defaultSchedulerService = true
  23. defaultBaseURL = "http://localhost"
  24. defaultRootURL = "http://localhost"
  25. defaultBasePath = ""
  26. defaultWorkerPoolSize = 16
  27. defaultPollingFrequency = 60
  28. defaultForceRefreshInterval = 30 * time.Second
  29. defaultBatchSize = 100
  30. defaultPollingScheduler = "round_robin"
  31. defaultSchedulerEntryFrequencyMinInterval = 5 * time.Minute
  32. defaultSchedulerEntryFrequencyMaxInterval = 24 * time.Hour
  33. defaultSchedulerEntryFrequencyFactor = 1
  34. defaultSchedulerRoundRobinMinInterval = 1 * time.Hour
  35. defaultSchedulerRoundRobinMaxInterval = 24 * time.Hour
  36. defaultPollingParsingErrorLimit = 3
  37. defaultRunMigrations = false
  38. defaultDatabaseURL = "user=postgres password=postgres dbname=miniflux2 sslmode=disable"
  39. defaultDatabaseMaxConns = 20
  40. defaultDatabaseMinConns = 1
  41. defaultDatabaseConnectionLifetime = 5
  42. defaultListenAddr = "127.0.0.1:8080"
  43. defaultCertFile = ""
  44. defaultKeyFile = ""
  45. defaultCertDomain = ""
  46. defaultCleanupFrequencyHours = 24
  47. defaultCleanupArchiveReadDays = 60
  48. defaultCleanupArchiveUnreadDays = 180
  49. defaultCleanupArchiveBatchSize = 10000
  50. defaultCleanupRemoveSessionsDays = 30
  51. defaultMediaProxyHTTPClientTimeout = 120 * time.Second
  52. defaultMediaProxyMode = "http-only"
  53. defaultMediaResourceTypes = "image"
  54. defaultMediaProxyURL = ""
  55. defaultFilterEntryMaxAgeDays = 0
  56. defaultFetchBilibiliWatchTime = false
  57. defaultFetchNebulaWatchTime = false
  58. defaultFetchOdyseeWatchTime = false
  59. defaultFetchYouTubeWatchTime = false
  60. defaultYouTubeApiKey = ""
  61. defaultYouTubeEmbedUrlOverride = "https://www.youtube-nocookie.com/embed/"
  62. defaultCreateAdmin = false
  63. defaultAdminUsername = ""
  64. defaultAdminPassword = ""
  65. defaultOAuth2UserCreation = false
  66. defaultOAuth2ClientID = ""
  67. defaultOAuth2ClientSecret = ""
  68. defaultOAuth2RedirectURL = ""
  69. defaultOAuth2OidcDiscoveryEndpoint = ""
  70. defaultOauth2OidcProviderName = "OpenID Connect"
  71. defaultOAuth2Provider = ""
  72. defaultDisableLocalAuth = false
  73. defaultHTTPClientTimeout = 20 * time.Second
  74. defaultHTTPClientMaxBodySize = 15
  75. defaultHTTPClientProxy = ""
  76. defaultHTTPServerTimeout = 300 * time.Second
  77. defaultAuthProxyHeader = ""
  78. defaultAuthProxyUserCreation = false
  79. defaultMaintenanceMode = false
  80. defaultMaintenanceMessage = "Miniflux is currently under maintenance"
  81. defaultMetricsCollector = false
  82. defaultMetricsRefreshInterval = 60 * time.Second
  83. defaultMetricsAllowedNetworks = "127.0.0.1/8"
  84. defaultMetricsUsername = ""
  85. defaultMetricsPassword = ""
  86. defaultWatchdog = true
  87. defaultInvidiousInstance = "yewtu.be"
  88. defaultWebAuthn = false
  89. )
  90. var defaultHTTPClientUserAgent = "Mozilla/5.0 (compatible; Miniflux/" + version.Version + "; +https://miniflux.app)"
  91. // option contains a key to value map of a single option. It may be used to output debug strings.
  92. type option struct {
  93. Key string
  94. Value any
  95. }
  96. // Opts holds parsed configuration options.
  97. var Opts *options
  98. // options contains configuration options.
  99. type options struct {
  100. HTTPS bool
  101. logFile string
  102. logDateTime bool
  103. logFormat string
  104. logLevel string
  105. hsts bool
  106. httpService bool
  107. schedulerService bool
  108. baseURL string
  109. rootURL string
  110. basePath string
  111. databaseURL string
  112. databaseMaxConns int
  113. databaseMinConns int
  114. databaseConnectionLifetime int
  115. runMigrations bool
  116. listenAddr []string
  117. certFile string
  118. certDomain string
  119. certKeyFile string
  120. cleanupFrequencyHours int
  121. cleanupArchiveReadDays int
  122. cleanupArchiveUnreadDays int
  123. cleanupArchiveBatchSize int
  124. cleanupRemoveSessionsDays int
  125. forceRefreshInterval time.Duration
  126. batchSize int
  127. schedulerEntryFrequencyMinInterval time.Duration
  128. schedulerEntryFrequencyMaxInterval time.Duration
  129. schedulerEntryFrequencyFactor int
  130. schedulerRoundRobinMinInterval time.Duration
  131. schedulerRoundRobinMaxInterval time.Duration
  132. pollingFrequency int
  133. pollingLimitPerHost int
  134. pollingParsingErrorLimit int
  135. pollingScheduler string
  136. workerPoolSize int
  137. createAdmin bool
  138. adminUsername string
  139. adminPassword string
  140. mediaProxyHTTPClientTimeout time.Duration
  141. mediaProxyMode string
  142. mediaProxyResourceTypes []string
  143. mediaProxyCustomURL *url.URL
  144. fetchBilibiliWatchTime bool
  145. fetchNebulaWatchTime bool
  146. fetchOdyseeWatchTime bool
  147. fetchYouTubeWatchTime bool
  148. filterEntryMaxAgeDays int
  149. youTubeApiKey string
  150. youTubeEmbedUrlOverride string
  151. youTubeEmbedDomain string
  152. oauth2UserCreationAllowed bool
  153. oauth2ClientID string
  154. oauth2ClientSecret string
  155. oauth2RedirectURL string
  156. oidcDiscoveryEndpoint string
  157. oidcProviderName string
  158. oauth2Provider string
  159. disableLocalAuth bool
  160. httpClientTimeout time.Duration
  161. httpClientMaxBodySize int64
  162. httpClientProxyURL *url.URL
  163. httpClientProxies []string
  164. httpClientUserAgent string
  165. httpServerTimeout time.Duration
  166. authProxyHeader string
  167. authProxyUserCreation bool
  168. maintenanceMode bool
  169. maintenanceMessage string
  170. metricsCollector bool
  171. metricsRefreshInterval time.Duration
  172. metricsAllowedNetworks []string
  173. metricsUsername string
  174. metricsPassword string
  175. watchdog bool
  176. invidiousInstance string
  177. mediaProxyPrivateKey []byte
  178. webAuthn bool
  179. }
  180. // NewOptions returns Options with default values.
  181. func NewOptions() *options {
  182. return &options{
  183. HTTPS: defaultHTTPS,
  184. logFile: defaultLogFile,
  185. logDateTime: defaultLogDateTime,
  186. logFormat: defaultLogFormat,
  187. logLevel: defaultLogLevel,
  188. hsts: defaultHSTS,
  189. httpService: defaultHTTPService,
  190. schedulerService: defaultSchedulerService,
  191. baseURL: defaultBaseURL,
  192. rootURL: defaultRootURL,
  193. basePath: defaultBasePath,
  194. databaseURL: defaultDatabaseURL,
  195. databaseMaxConns: defaultDatabaseMaxConns,
  196. databaseMinConns: defaultDatabaseMinConns,
  197. databaseConnectionLifetime: defaultDatabaseConnectionLifetime,
  198. runMigrations: defaultRunMigrations,
  199. listenAddr: []string{defaultListenAddr},
  200. certFile: defaultCertFile,
  201. certDomain: defaultCertDomain,
  202. certKeyFile: defaultKeyFile,
  203. cleanupFrequencyHours: defaultCleanupFrequencyHours,
  204. cleanupArchiveReadDays: defaultCleanupArchiveReadDays,
  205. cleanupArchiveUnreadDays: defaultCleanupArchiveUnreadDays,
  206. cleanupArchiveBatchSize: defaultCleanupArchiveBatchSize,
  207. cleanupRemoveSessionsDays: defaultCleanupRemoveSessionsDays,
  208. pollingFrequency: defaultPollingFrequency,
  209. forceRefreshInterval: defaultForceRefreshInterval,
  210. batchSize: defaultBatchSize,
  211. pollingScheduler: defaultPollingScheduler,
  212. schedulerEntryFrequencyMinInterval: defaultSchedulerEntryFrequencyMinInterval,
  213. schedulerEntryFrequencyMaxInterval: defaultSchedulerEntryFrequencyMaxInterval,
  214. schedulerEntryFrequencyFactor: defaultSchedulerEntryFrequencyFactor,
  215. schedulerRoundRobinMinInterval: defaultSchedulerRoundRobinMinInterval,
  216. schedulerRoundRobinMaxInterval: defaultSchedulerRoundRobinMaxInterval,
  217. pollingParsingErrorLimit: defaultPollingParsingErrorLimit,
  218. workerPoolSize: defaultWorkerPoolSize,
  219. createAdmin: defaultCreateAdmin,
  220. mediaProxyHTTPClientTimeout: defaultMediaProxyHTTPClientTimeout,
  221. mediaProxyMode: defaultMediaProxyMode,
  222. mediaProxyResourceTypes: []string{defaultMediaResourceTypes},
  223. mediaProxyCustomURL: nil,
  224. filterEntryMaxAgeDays: defaultFilterEntryMaxAgeDays,
  225. fetchBilibiliWatchTime: defaultFetchBilibiliWatchTime,
  226. fetchNebulaWatchTime: defaultFetchNebulaWatchTime,
  227. fetchOdyseeWatchTime: defaultFetchOdyseeWatchTime,
  228. fetchYouTubeWatchTime: defaultFetchYouTubeWatchTime,
  229. youTubeApiKey: defaultYouTubeApiKey,
  230. youTubeEmbedUrlOverride: defaultYouTubeEmbedUrlOverride,
  231. oauth2UserCreationAllowed: defaultOAuth2UserCreation,
  232. oauth2ClientID: defaultOAuth2ClientID,
  233. oauth2ClientSecret: defaultOAuth2ClientSecret,
  234. oauth2RedirectURL: defaultOAuth2RedirectURL,
  235. oidcDiscoveryEndpoint: defaultOAuth2OidcDiscoveryEndpoint,
  236. oidcProviderName: defaultOauth2OidcProviderName,
  237. oauth2Provider: defaultOAuth2Provider,
  238. disableLocalAuth: defaultDisableLocalAuth,
  239. httpClientTimeout: defaultHTTPClientTimeout,
  240. httpClientMaxBodySize: defaultHTTPClientMaxBodySize * 1024 * 1024,
  241. httpClientProxyURL: nil,
  242. httpClientProxies: []string{},
  243. httpClientUserAgent: defaultHTTPClientUserAgent,
  244. httpServerTimeout: defaultHTTPServerTimeout,
  245. authProxyHeader: defaultAuthProxyHeader,
  246. authProxyUserCreation: defaultAuthProxyUserCreation,
  247. maintenanceMode: defaultMaintenanceMode,
  248. maintenanceMessage: defaultMaintenanceMessage,
  249. metricsCollector: defaultMetricsCollector,
  250. metricsRefreshInterval: defaultMetricsRefreshInterval,
  251. metricsAllowedNetworks: []string{defaultMetricsAllowedNetworks},
  252. metricsUsername: defaultMetricsUsername,
  253. metricsPassword: defaultMetricsPassword,
  254. watchdog: defaultWatchdog,
  255. invidiousInstance: defaultInvidiousInstance,
  256. mediaProxyPrivateKey: crypto.GenerateRandomBytes(16),
  257. webAuthn: defaultWebAuthn,
  258. }
  259. }
  260. func (o *options) LogFile() string {
  261. return o.logFile
  262. }
  263. // LogDateTime returns true if the date/time should be displayed in log messages.
  264. func (o *options) LogDateTime() bool {
  265. return o.logDateTime
  266. }
  267. // LogFormat returns the log format.
  268. func (o *options) LogFormat() string {
  269. return o.logFormat
  270. }
  271. // LogLevel returns the log level.
  272. func (o *options) LogLevel() string {
  273. return o.logLevel
  274. }
  275. // SetLogLevel sets the log level.
  276. func (o *options) SetLogLevel(level string) {
  277. o.logLevel = level
  278. }
  279. // HasMaintenanceMode returns true if maintenance mode is enabled.
  280. func (o *options) HasMaintenanceMode() bool {
  281. return o.maintenanceMode
  282. }
  283. // MaintenanceMessage returns maintenance message.
  284. func (o *options) MaintenanceMessage() string {
  285. return o.maintenanceMessage
  286. }
  287. // BaseURL returns the application base URL with path.
  288. func (o *options) BaseURL() string {
  289. return o.baseURL
  290. }
  291. // RootURL returns the base URL without path.
  292. func (o *options) RootURL() string {
  293. return o.rootURL
  294. }
  295. // BasePath returns the application base path according to the base URL.
  296. func (o *options) BasePath() string {
  297. return o.basePath
  298. }
  299. // IsDefaultDatabaseURL returns true if the default database URL is used.
  300. func (o *options) IsDefaultDatabaseURL() bool {
  301. return o.databaseURL == defaultDatabaseURL
  302. }
  303. // DatabaseURL returns the database URL.
  304. func (o *options) DatabaseURL() string {
  305. return o.databaseURL
  306. }
  307. // DatabaseMaxConns returns the maximum number of database connections.
  308. func (o *options) DatabaseMaxConns() int {
  309. return o.databaseMaxConns
  310. }
  311. // DatabaseMinConns returns the minimum number of database connections.
  312. func (o *options) DatabaseMinConns() int {
  313. return o.databaseMinConns
  314. }
  315. // DatabaseConnectionLifetime returns the maximum amount of time a connection may be reused.
  316. func (o *options) DatabaseConnectionLifetime() time.Duration {
  317. return time.Duration(o.databaseConnectionLifetime) * time.Minute
  318. }
  319. // ListenAddr returns the listen address for the HTTP server.
  320. func (o *options) ListenAddr() []string {
  321. return o.listenAddr
  322. }
  323. // CertFile returns the SSL certificate filename if any.
  324. func (o *options) CertFile() string {
  325. return o.certFile
  326. }
  327. // CertKeyFile returns the private key filename for custom SSL certificate.
  328. func (o *options) CertKeyFile() string {
  329. return o.certKeyFile
  330. }
  331. // CertDomain returns the domain to use for Let's Encrypt certificate.
  332. func (o *options) CertDomain() string {
  333. return o.certDomain
  334. }
  335. // CleanupFrequencyHours returns the interval in hours for cleanup jobs.
  336. func (o *options) CleanupFrequencyHours() int {
  337. return o.cleanupFrequencyHours
  338. }
  339. // CleanupArchiveReadDays returns the number of days after which marking read items as removed.
  340. func (o *options) CleanupArchiveReadDays() int {
  341. return o.cleanupArchiveReadDays
  342. }
  343. // CleanupArchiveUnreadDays returns the number of days after which marking unread items as removed.
  344. func (o *options) CleanupArchiveUnreadDays() int {
  345. return o.cleanupArchiveUnreadDays
  346. }
  347. // CleanupArchiveBatchSize returns the number of entries to archive for each interval.
  348. func (o *options) CleanupArchiveBatchSize() int {
  349. return o.cleanupArchiveBatchSize
  350. }
  351. // CleanupRemoveSessionsDays returns the number of days after which to remove sessions.
  352. func (o *options) CleanupRemoveSessionsDays() int {
  353. return o.cleanupRemoveSessionsDays
  354. }
  355. // WorkerPoolSize returns the number of background worker.
  356. func (o *options) WorkerPoolSize() int {
  357. return o.workerPoolSize
  358. }
  359. // ForceRefreshInterval returns the force refresh interval
  360. func (o *options) ForceRefreshInterval() time.Duration {
  361. return o.forceRefreshInterval
  362. }
  363. // BatchSize returns the number of feeds to send for background processing.
  364. func (o *options) BatchSize() int {
  365. return o.batchSize
  366. }
  367. // PollingFrequency returns the interval to refresh feeds in the background.
  368. func (o *options) PollingFrequency() int {
  369. return o.pollingFrequency
  370. }
  371. // PollingLimitPerHost returns the limit of concurrent requests per host.
  372. // Set to zero to disable.
  373. func (o *options) PollingLimitPerHost() int {
  374. return o.pollingLimitPerHost
  375. }
  376. // PollingParsingErrorLimit returns the limit of errors when to stop polling.
  377. func (o *options) PollingParsingErrorLimit() int {
  378. return o.pollingParsingErrorLimit
  379. }
  380. // PollingScheduler returns the scheduler used for polling feeds.
  381. func (o *options) PollingScheduler() string {
  382. return o.pollingScheduler
  383. }
  384. // SchedulerEntryFrequencyMaxInterval returns the maximum interval for the entry frequency scheduler.
  385. func (o *options) SchedulerEntryFrequencyMaxInterval() time.Duration {
  386. return o.schedulerEntryFrequencyMaxInterval
  387. }
  388. // SchedulerEntryFrequencyMinInterval returns the minimum interval for the entry frequency scheduler.
  389. func (o *options) SchedulerEntryFrequencyMinInterval() time.Duration {
  390. return o.schedulerEntryFrequencyMinInterval
  391. }
  392. // SchedulerEntryFrequencyFactor returns the factor for the entry frequency scheduler.
  393. func (o *options) SchedulerEntryFrequencyFactor() int {
  394. return o.schedulerEntryFrequencyFactor
  395. }
  396. func (o *options) SchedulerRoundRobinMinInterval() time.Duration {
  397. return o.schedulerRoundRobinMinInterval
  398. }
  399. func (o *options) SchedulerRoundRobinMaxInterval() time.Duration {
  400. return o.schedulerRoundRobinMaxInterval
  401. }
  402. // IsOAuth2UserCreationAllowed returns true if user creation is allowed for OAuth2 users.
  403. func (o *options) IsOAuth2UserCreationAllowed() bool {
  404. return o.oauth2UserCreationAllowed
  405. }
  406. // OAuth2ClientID returns the OAuth2 Client ID.
  407. func (o *options) OAuth2ClientID() string {
  408. return o.oauth2ClientID
  409. }
  410. // OAuth2ClientSecret returns the OAuth2 client secret.
  411. func (o *options) OAuth2ClientSecret() string {
  412. return o.oauth2ClientSecret
  413. }
  414. // OAuth2RedirectURL returns the OAuth2 redirect URL.
  415. func (o *options) OAuth2RedirectURL() string {
  416. return o.oauth2RedirectURL
  417. }
  418. // OIDCDiscoveryEndpoint returns the OAuth2 OIDC discovery endpoint.
  419. func (o *options) OIDCDiscoveryEndpoint() string {
  420. return o.oidcDiscoveryEndpoint
  421. }
  422. // OIDCProviderName returns the OAuth2 OIDC provider's display name
  423. func (o *options) OIDCProviderName() string {
  424. return o.oidcProviderName
  425. }
  426. // OAuth2Provider returns the name of the OAuth2 provider configured.
  427. func (o *options) OAuth2Provider() string {
  428. return o.oauth2Provider
  429. }
  430. // DisableLocalAUth returns true if the local user database should not be used to authenticate users
  431. func (o *options) DisableLocalAuth() bool {
  432. return o.disableLocalAuth
  433. }
  434. // HasHSTS returns true if HTTP Strict Transport Security is enabled.
  435. func (o *options) HasHSTS() bool {
  436. return o.hsts
  437. }
  438. // RunMigrations returns true if the environment variable RUN_MIGRATIONS is not empty.
  439. func (o *options) RunMigrations() bool {
  440. return o.runMigrations
  441. }
  442. // CreateAdmin returns true if the environment variable CREATE_ADMIN is not empty.
  443. func (o *options) CreateAdmin() bool {
  444. return o.createAdmin
  445. }
  446. // AdminUsername returns the admin username if defined.
  447. func (o *options) AdminUsername() string {
  448. return o.adminUsername
  449. }
  450. // AdminPassword returns the admin password if defined.
  451. func (o *options) AdminPassword() string {
  452. return o.adminPassword
  453. }
  454. // FetchYouTubeWatchTime returns true if the YouTube video duration
  455. // should be fetched and used as a reading time.
  456. func (o *options) FetchYouTubeWatchTime() bool {
  457. return o.fetchYouTubeWatchTime
  458. }
  459. // YouTubeApiKey returns the YouTube API key if defined.
  460. func (o *options) YouTubeApiKey() string {
  461. return o.youTubeApiKey
  462. }
  463. // YouTubeEmbedUrlOverride returns the YouTube embed URL override if defined.
  464. func (o *options) YouTubeEmbedUrlOverride() string {
  465. return o.youTubeEmbedUrlOverride
  466. }
  467. // YouTubeEmbedDomain returns the domain used for YouTube embeds.
  468. func (o *options) YouTubeEmbedDomain() string {
  469. if o.youTubeEmbedDomain != "" {
  470. return o.youTubeEmbedDomain
  471. }
  472. return "www.youtube-nocookie.com"
  473. }
  474. // FetchNebulaWatchTime returns true if the Nebula video duration
  475. // should be fetched and used as a reading time.
  476. func (o *options) FetchNebulaWatchTime() bool {
  477. return o.fetchNebulaWatchTime
  478. }
  479. // FetchOdyseeWatchTime returns true if the Odysee video duration
  480. // should be fetched and used as a reading time.
  481. func (o *options) FetchOdyseeWatchTime() bool {
  482. return o.fetchOdyseeWatchTime
  483. }
  484. // FetchBilibiliWatchTime returns true if the Bilibili video duration
  485. // should be fetched and used as a reading time.
  486. func (o *options) FetchBilibiliWatchTime() bool {
  487. return o.fetchBilibiliWatchTime
  488. }
  489. // MediaProxyMode returns "none" to never proxy, "http-only" to proxy non-HTTPS, "all" to always proxy.
  490. func (o *options) MediaProxyMode() string {
  491. return o.mediaProxyMode
  492. }
  493. // MediaProxyResourceTypes returns a slice of resource types to proxy.
  494. func (o *options) MediaProxyResourceTypes() []string {
  495. return o.mediaProxyResourceTypes
  496. }
  497. // MediaCustomProxyURL returns the custom proxy URL for medias.
  498. func (o *options) MediaCustomProxyURL() *url.URL {
  499. return o.mediaProxyCustomURL
  500. }
  501. // MediaProxyHTTPClientTimeout returns the time limit before the proxy HTTP client cancel the request.
  502. func (o *options) MediaProxyHTTPClientTimeout() time.Duration {
  503. return o.mediaProxyHTTPClientTimeout
  504. }
  505. // MediaProxyPrivateKey returns the private key used by the media proxy.
  506. func (o *options) MediaProxyPrivateKey() []byte {
  507. return o.mediaProxyPrivateKey
  508. }
  509. // HasHTTPService returns true if the HTTP service is enabled.
  510. func (o *options) HasHTTPService() bool {
  511. return o.httpService
  512. }
  513. // HasSchedulerService returns true if the scheduler service is enabled.
  514. func (o *options) HasSchedulerService() bool {
  515. return o.schedulerService
  516. }
  517. // HTTPClientTimeout returns the time limit in seconds before the HTTP client cancel the request.
  518. func (o *options) HTTPClientTimeout() time.Duration {
  519. return o.httpClientTimeout
  520. }
  521. // HTTPClientMaxBodySize returns the number of bytes allowed for the HTTP client to transfer.
  522. func (o *options) HTTPClientMaxBodySize() int64 {
  523. return o.httpClientMaxBodySize
  524. }
  525. // HTTPClientProxyURL returns the client HTTP proxy URL if configured.
  526. func (o *options) HTTPClientProxyURL() *url.URL {
  527. return o.httpClientProxyURL
  528. }
  529. // HasHTTPClientProxyURLConfigured returns true if the client HTTP proxy URL if configured.
  530. func (o *options) HasHTTPClientProxyURLConfigured() bool {
  531. return o.httpClientProxyURL != nil
  532. }
  533. // HTTPClientProxies returns the list of proxies.
  534. func (o *options) HTTPClientProxies() []string {
  535. return o.httpClientProxies
  536. }
  537. // HTTPClientProxiesString returns true if the list of rotating proxies are configured.
  538. func (o *options) HasHTTPClientProxiesConfigured() bool {
  539. return len(o.httpClientProxies) > 0
  540. }
  541. // HTTPServerTimeout returns the time limit before the HTTP server cancel the request.
  542. func (o *options) HTTPServerTimeout() time.Duration {
  543. return o.httpServerTimeout
  544. }
  545. // AuthProxyHeader returns an HTTP header name that contains username for
  546. // authentication using auth proxy.
  547. func (o *options) AuthProxyHeader() string {
  548. return o.authProxyHeader
  549. }
  550. // IsAuthProxyUserCreationAllowed returns true if user creation is allowed for
  551. // users authenticated using auth proxy.
  552. func (o *options) IsAuthProxyUserCreationAllowed() bool {
  553. return o.authProxyUserCreation
  554. }
  555. // HasMetricsCollector returns true if metrics collection is enabled.
  556. func (o *options) HasMetricsCollector() bool {
  557. return o.metricsCollector
  558. }
  559. // MetricsRefreshInterval returns the refresh interval.
  560. func (o *options) MetricsRefreshInterval() time.Duration {
  561. return o.metricsRefreshInterval
  562. }
  563. // MetricsAllowedNetworks returns the list of networks allowed to connect to the metrics endpoint.
  564. func (o *options) MetricsAllowedNetworks() []string {
  565. return o.metricsAllowedNetworks
  566. }
  567. func (o *options) MetricsUsername() string {
  568. return o.metricsUsername
  569. }
  570. func (o *options) MetricsPassword() string {
  571. return o.metricsPassword
  572. }
  573. // HTTPClientUserAgent returns the global User-Agent header for miniflux.
  574. func (o *options) HTTPClientUserAgent() string {
  575. return o.httpClientUserAgent
  576. }
  577. // HasWatchdog returns true if the systemd watchdog is enabled.
  578. func (o *options) HasWatchdog() bool {
  579. return o.watchdog
  580. }
  581. // InvidiousInstance returns the invidious instance used by miniflux
  582. func (o *options) InvidiousInstance() string {
  583. return o.invidiousInstance
  584. }
  585. // WebAuthn returns true if WebAuthn logins are supported
  586. func (o *options) WebAuthn() bool {
  587. return o.webAuthn
  588. }
  589. // FilterEntryMaxAgeDays returns the number of days after which entries should be retained.
  590. func (o *options) FilterEntryMaxAgeDays() int {
  591. return o.filterEntryMaxAgeDays
  592. }
  593. // SortedOptions returns options as a list of key value pairs, sorted by keys.
  594. func (o *options) SortedOptions(redactSecret bool) []*option {
  595. var clientProxyURLRedacted string
  596. if o.httpClientProxyURL != nil {
  597. if redactSecret {
  598. clientProxyURLRedacted = o.httpClientProxyURL.Redacted()
  599. } else {
  600. clientProxyURLRedacted = o.httpClientProxyURL.String()
  601. }
  602. }
  603. var clientProxyURLsRedacted string
  604. if len(o.httpClientProxies) > 0 {
  605. if redactSecret {
  606. var proxyURLs []string
  607. for range o.httpClientProxies {
  608. proxyURLs = append(proxyURLs, "<redacted>")
  609. }
  610. clientProxyURLsRedacted = strings.Join(proxyURLs, ",")
  611. } else {
  612. clientProxyURLsRedacted = strings.Join(o.httpClientProxies, ",")
  613. }
  614. }
  615. var mediaProxyPrivateKeyValue string
  616. if len(o.mediaProxyPrivateKey) > 0 {
  617. mediaProxyPrivateKeyValue = "<binary-data>"
  618. }
  619. var keyValues = map[string]any{
  620. "ADMIN_PASSWORD": redactSecretValue(o.adminPassword, redactSecret),
  621. "ADMIN_USERNAME": o.adminUsername,
  622. "AUTH_PROXY_HEADER": o.authProxyHeader,
  623. "AUTH_PROXY_USER_CREATION": o.authProxyUserCreation,
  624. "BASE_PATH": o.basePath,
  625. "BASE_URL": o.baseURL,
  626. "BATCH_SIZE": o.batchSize,
  627. "CERT_DOMAIN": o.certDomain,
  628. "CERT_FILE": o.certFile,
  629. "CLEANUP_ARCHIVE_BATCH_SIZE": o.cleanupArchiveBatchSize,
  630. "CLEANUP_ARCHIVE_READ_DAYS": o.cleanupArchiveReadDays,
  631. "CLEANUP_ARCHIVE_UNREAD_DAYS": o.cleanupArchiveUnreadDays,
  632. "CLEANUP_FREQUENCY_HOURS": o.cleanupFrequencyHours,
  633. "CLEANUP_REMOVE_SESSIONS_DAYS": o.cleanupRemoveSessionsDays,
  634. "CREATE_ADMIN": o.createAdmin,
  635. "DATABASE_CONNECTION_LIFETIME": o.databaseConnectionLifetime,
  636. "DATABASE_MAX_CONNS": o.databaseMaxConns,
  637. "DATABASE_MIN_CONNS": o.databaseMinConns,
  638. "DATABASE_URL": redactSecretValue(o.databaseURL, redactSecret),
  639. "DISABLE_HSTS": !o.hsts,
  640. "DISABLE_HTTP_SERVICE": !o.httpService,
  641. "DISABLE_SCHEDULER_SERVICE": !o.schedulerService,
  642. "FILTER_ENTRY_MAX_AGE_DAYS": o.filterEntryMaxAgeDays,
  643. "FETCH_YOUTUBE_WATCH_TIME": o.fetchYouTubeWatchTime,
  644. "FETCH_NEBULA_WATCH_TIME": o.fetchNebulaWatchTime,
  645. "FETCH_ODYSEE_WATCH_TIME": o.fetchOdyseeWatchTime,
  646. "FETCH_BILIBILI_WATCH_TIME": o.fetchBilibiliWatchTime,
  647. "HTTPS": o.HTTPS,
  648. "HTTP_CLIENT_MAX_BODY_SIZE": o.httpClientMaxBodySize,
  649. "HTTP_CLIENT_PROXIES": clientProxyURLsRedacted,
  650. "HTTP_CLIENT_PROXY": clientProxyURLRedacted,
  651. "HTTP_CLIENT_TIMEOUT": int(o.httpClientTimeout.Seconds()),
  652. "HTTP_CLIENT_USER_AGENT": o.httpClientUserAgent,
  653. "HTTP_SERVER_TIMEOUT": int(o.httpServerTimeout.Seconds()),
  654. "HTTP_SERVICE": o.httpService,
  655. "INVIDIOUS_INSTANCE": o.invidiousInstance,
  656. "KEY_FILE": o.certKeyFile,
  657. "LISTEN_ADDR": strings.Join(o.listenAddr, ","),
  658. "LOG_FILE": o.logFile,
  659. "LOG_DATE_TIME": o.logDateTime,
  660. "LOG_FORMAT": o.logFormat,
  661. "LOG_LEVEL": o.logLevel,
  662. "MAINTENANCE_MESSAGE": o.maintenanceMessage,
  663. "MAINTENANCE_MODE": o.maintenanceMode,
  664. "METRICS_ALLOWED_NETWORKS": strings.Join(o.metricsAllowedNetworks, ","),
  665. "METRICS_COLLECTOR": o.metricsCollector,
  666. "METRICS_PASSWORD": redactSecretValue(o.metricsPassword, redactSecret),
  667. "METRICS_REFRESH_INTERVAL": int(o.metricsRefreshInterval.Seconds()),
  668. "METRICS_USERNAME": o.metricsUsername,
  669. "OAUTH2_CLIENT_ID": o.oauth2ClientID,
  670. "OAUTH2_CLIENT_SECRET": redactSecretValue(o.oauth2ClientSecret, redactSecret),
  671. "OAUTH2_OIDC_DISCOVERY_ENDPOINT": o.oidcDiscoveryEndpoint,
  672. "OAUTH2_OIDC_PROVIDER_NAME": o.oidcProviderName,
  673. "OAUTH2_PROVIDER": o.oauth2Provider,
  674. "OAUTH2_REDIRECT_URL": o.oauth2RedirectURL,
  675. "OAUTH2_USER_CREATION": o.oauth2UserCreationAllowed,
  676. "DISABLE_LOCAL_AUTH": o.disableLocalAuth,
  677. "FORCE_REFRESH_INTERVAL": int(o.forceRefreshInterval.Seconds()),
  678. "POLLING_FREQUENCY": o.pollingFrequency,
  679. "POLLING_LIMIT_PER_HOST": o.pollingLimitPerHost,
  680. "POLLING_PARSING_ERROR_LIMIT": o.pollingParsingErrorLimit,
  681. "POLLING_SCHEDULER": o.pollingScheduler,
  682. "MEDIA_PROXY_HTTP_CLIENT_TIMEOUT": int(o.mediaProxyHTTPClientTimeout.Seconds()),
  683. "MEDIA_PROXY_RESOURCE_TYPES": o.mediaProxyResourceTypes,
  684. "MEDIA_PROXY_MODE": o.mediaProxyMode,
  685. "MEDIA_PROXY_PRIVATE_KEY": mediaProxyPrivateKeyValue,
  686. "MEDIA_PROXY_CUSTOM_URL": o.mediaProxyCustomURL,
  687. "ROOT_URL": o.rootURL,
  688. "RUN_MIGRATIONS": o.runMigrations,
  689. "SCHEDULER_ENTRY_FREQUENCY_MAX_INTERVAL": int(o.schedulerEntryFrequencyMaxInterval.Minutes()),
  690. "SCHEDULER_ENTRY_FREQUENCY_MIN_INTERVAL": int(o.schedulerEntryFrequencyMinInterval.Minutes()),
  691. "SCHEDULER_ENTRY_FREQUENCY_FACTOR": o.schedulerEntryFrequencyFactor,
  692. "SCHEDULER_ROUND_ROBIN_MIN_INTERVAL": int(o.schedulerRoundRobinMinInterval.Minutes()),
  693. "SCHEDULER_ROUND_ROBIN_MAX_INTERVAL": int(o.schedulerRoundRobinMaxInterval.Minutes()),
  694. "SCHEDULER_SERVICE": o.schedulerService,
  695. "WATCHDOG": o.watchdog,
  696. "WORKER_POOL_SIZE": o.workerPoolSize,
  697. "YOUTUBE_API_KEY": redactSecretValue(o.youTubeApiKey, redactSecret),
  698. "YOUTUBE_EMBED_URL_OVERRIDE": o.youTubeEmbedUrlOverride,
  699. "WEBAUTHN": o.webAuthn,
  700. }
  701. sortedKeys := slices.Sorted(maps.Keys(keyValues))
  702. var sortedOptions = make([]*option, 0, len(sortedKeys))
  703. for _, key := range sortedKeys {
  704. sortedOptions = append(sortedOptions, &option{Key: key, Value: keyValues[key]})
  705. }
  706. return sortedOptions
  707. }
  708. func (o *options) String() string {
  709. var builder strings.Builder
  710. for _, option := range o.SortedOptions(false) {
  711. fmt.Fprintf(&builder, "%s=%v\n", option.Key, option.Value)
  712. }
  713. return builder.String()
  714. }
  715. func redactSecretValue(value string, redactSecret bool) string {
  716. if redactSecret && value != "" {
  717. return "<secret>"
  718. }
  719. return value
  720. }