Do not show secrets in plain text on the /about page

This commit is contained in:
Frédéric Guillot 2021-10-17 16:49:37 -07:00 committed by fguillot
parent 5f9d6fd81b
commit 87d58987a6
3 changed files with 20 additions and 11 deletions

View file

@ -483,9 +483,9 @@ func (o *Options) HasWatchdog() bool {
} }
// SortedOptions returns options as a list of key value pairs, sorted by keys. // SortedOptions returns options as a list of key value pairs, sorted by keys.
func (o *Options) SortedOptions() []*Option { func (o *Options) SortedOptions(redactSecret bool) []*Option {
var keyValues = map[string]interface{}{ var keyValues = map[string]interface{}{
"ADMIN_PASSWORD": o.adminPassword, "ADMIN_PASSWORD": redactSecretValue(o.adminPassword, redactSecret),
"ADMIN_USERNAME": o.adminUsername, "ADMIN_USERNAME": o.adminUsername,
"AUTH_PROXY_HEADER": o.authProxyHeader, "AUTH_PROXY_HEADER": o.authProxyHeader,
"AUTH_PROXY_USER_CREATION": o.authProxyUserCreation, "AUTH_PROXY_USER_CREATION": o.authProxyUserCreation,
@ -503,10 +503,12 @@ func (o *Options) SortedOptions() []*Option {
"DATABASE_MAX_CONNS": o.databaseMaxConns, "DATABASE_MAX_CONNS": o.databaseMaxConns,
"DATABASE_MIN_CONNS": o.databaseMinConns, "DATABASE_MIN_CONNS": o.databaseMinConns,
"DATABASE_CONNECTION_LIFETIME": o.databaseConnectionLifetime, "DATABASE_CONNECTION_LIFETIME": o.databaseConnectionLifetime,
"DATABASE_URL": o.databaseURL, "DATABASE_URL": redactSecretValue(o.databaseURL, redactSecret),
"DEBUG": o.debug, "DEBUG": o.debug,
"DISABLE_HSTS": !o.hsts,
"DISABLE_SCHEDULER_SERVICE": !o.schedulerService,
"DISABLE_HTTP_SERVICE": !o.httpService,
"FETCH_YOUTUBE_WATCH_TIME": o.fetchYouTubeWatchTime, "FETCH_YOUTUBE_WATCH_TIME": o.fetchYouTubeWatchTime,
"HSTS": o.hsts,
"HTTPS": o.HTTPS, "HTTPS": o.HTTPS,
"HTTP_CLIENT_MAX_BODY_SIZE": o.httpClientMaxBodySize, "HTTP_CLIENT_MAX_BODY_SIZE": o.httpClientMaxBodySize,
"HTTP_CLIENT_PROXY": o.httpClientProxy, "HTTP_CLIENT_PROXY": o.httpClientProxy,
@ -518,16 +520,16 @@ func (o *Options) SortedOptions() []*Option {
"LOG_DATE_TIME": o.logDateTime, "LOG_DATE_TIME": o.logDateTime,
"MAINTENANCE_MESSAGE": o.maintenanceMessage, "MAINTENANCE_MESSAGE": o.maintenanceMessage,
"MAINTENANCE_MODE": o.maintenanceMode, "MAINTENANCE_MODE": o.maintenanceMode,
"METRICS_ALLOWED_NETWORKS": o.metricsAllowedNetworks, "METRICS_ALLOWED_NETWORKS": strings.Join(o.metricsAllowedNetworks, ","),
"METRICS_COLLECTOR": o.metricsCollector, "METRICS_COLLECTOR": o.metricsCollector,
"METRICS_REFRESH_INTERVAL": o.metricsRefreshInterval, "METRICS_REFRESH_INTERVAL": o.metricsRefreshInterval,
"OAUTH2_CLIENT_ID": o.oauth2ClientID, "OAUTH2_CLIENT_ID": o.oauth2ClientID,
"OAUTH2_CLIENT_SECRET": o.oauth2ClientSecret, "OAUTH2_CLIENT_SECRET": redactSecretValue(o.oauth2ClientSecret, redactSecret),
"OAUTH2_OIDC_DISCOVERY_ENDPOINT": o.oauth2OidcDiscoveryEndpoint, "OAUTH2_OIDC_DISCOVERY_ENDPOINT": o.oauth2OidcDiscoveryEndpoint,
"OAUTH2_PROVIDER": o.oauth2Provider, "OAUTH2_PROVIDER": o.oauth2Provider,
"OAUTH2_REDIRECT_URL": o.oauth2RedirectURL, "OAUTH2_REDIRECT_URL": o.oauth2RedirectURL,
"OAUTH2_USER_CREATION": o.oauth2UserCreationAllowed, "OAUTH2_USER_CREATION": o.oauth2UserCreationAllowed,
"POCKET_CONSUMER_KEY": o.pocketConsumerKey, "POCKET_CONSUMER_KEY": redactSecretValue(o.pocketConsumerKey, redactSecret),
"POLLING_FREQUENCY": o.pollingFrequency, "POLLING_FREQUENCY": o.pollingFrequency,
"POLLING_PARSING_ERROR_LIMIT": o.pollingParsingErrorLimit, "POLLING_PARSING_ERROR_LIMIT": o.pollingParsingErrorLimit,
"POLLING_SCHEDULER": o.pollingScheduler, "POLLING_SCHEDULER": o.pollingScheduler,
@ -558,9 +560,16 @@ func (o *Options) SortedOptions() []*Option {
func (o *Options) String() string { func (o *Options) String() string {
var builder strings.Builder var builder strings.Builder
for _, option := range o.SortedOptions() { for _, option := range o.SortedOptions(false) {
fmt.Fprintf(&builder, "%s=%v\n", option.Key, option.Value) fmt.Fprintf(&builder, "%s=%v\n", option.Key, option.Value)
} }
return builder.String() return builder.String()
} }
func redactSecretValue(value string, redactSecret bool) string {
if redactSecret && value != "" {
return "******"
}
return value
}

View file

@ -215,12 +215,12 @@ func parseBaseURL(value string) (string, string, string, error) {
url, err := url_parser.Parse(value) url, err := url_parser.Parse(value)
if err != nil { if err != nil {
return "", "", "", fmt.Errorf("Invalid BASE_URL: %v", err) return "", "", "", fmt.Errorf("config: invalid BASE_URL: %w", err)
} }
scheme := strings.ToLower(url.Scheme) scheme := strings.ToLower(url.Scheme)
if scheme != "https" && scheme != "http" { if scheme != "https" && scheme != "http" {
return "", "", "", errors.New("Invalid BASE_URL: scheme must be http or https") return "", "", "", errors.New("config: invalid BASE_URL: scheme must be http or https")
} }
basePath := url.Path basePath := url.Path

View file

@ -31,7 +31,7 @@ func (h *handler) showAboutPage(w http.ResponseWriter, r *http.Request) {
view.Set("user", user) view.Set("user", user)
view.Set("countUnread", h.store.CountUnreadEntries(user.ID)) view.Set("countUnread", h.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(user.ID)) view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(user.ID))
view.Set("globalConfigOptions", config.Opts.SortedOptions()) view.Set("globalConfigOptions", config.Opts.SortedOptions(true))
view.Set("postgres_version", h.store.DatabaseVersion()) view.Set("postgres_version", h.store.DatabaseVersion())
html.OK(w, r, view.Render("about")) html.OK(w, r, view.Render("about"))