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