github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/config/browser/browser.go (about)

     1  // Copyright (c) 2015-2023 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package browser
    19  
    20  import (
    21  	"fmt"
    22  	"strconv"
    23  	"sync"
    24  
    25  	"github.com/minio/minio/internal/config"
    26  	"github.com/minio/pkg/v2/env"
    27  )
    28  
    29  // Browser sub-system constants
    30  const (
    31  	// browserCSPPolicy setting name for Content-Security-Policy response header value
    32  	browserCSPPolicy = "csp_policy"
    33  	// browserHSTSSeconds setting name for Strict-Transport-Security response header, amount of seconds for 'max-age'
    34  	browserHSTSSeconds = "hsts_seconds"
    35  	// browserHSTSIncludeSubdomains setting name for Strict-Transport-Security response header 'includeSubDomains' flag (true or false)
    36  	browserHSTSIncludeSubdomains = "hsts_include_subdomains"
    37  	// browserHSTSPreload setting name for Strict-Transport-Security response header 'preload' flag (true or false)
    38  	browserHSTSPreload = "hsts_preload"
    39  	// browserReferrerPolicy setting name for Referrer-Policy response header
    40  	browserReferrerPolicy = "referrer_policy"
    41  
    42  	EnvBrowserCSPPolicy             = "MINIO_BROWSER_CONTENT_SECURITY_POLICY"
    43  	EnvBrowserHSTSSeconds           = "MINIO_BROWSER_HSTS_SECONDS"
    44  	EnvBrowserHSTSIncludeSubdomains = "MINIO_BROWSER_HSTS_INCLUDE_SUB_DOMAINS"
    45  	EnvBrowserHSTSPreload           = "MINIO_BROWSER_HSTS_PRELOAD"
    46  	EnvBrowserReferrerPolicy        = "MINIO_BROWSER_REFERRER_POLICY"
    47  )
    48  
    49  // DefaultKVS - default storage class config
    50  var (
    51  	DefaultKVS = config.KVS{
    52  		config.KV{
    53  			Key:   browserCSPPolicy,
    54  			Value: "default-src 'self' 'unsafe-eval' 'unsafe-inline';",
    55  		},
    56  		config.KV{
    57  			Key:   browserHSTSSeconds,
    58  			Value: "0",
    59  		},
    60  		config.KV{
    61  			Key:   browserHSTSIncludeSubdomains,
    62  			Value: config.EnableOff,
    63  		},
    64  		config.KV{
    65  			Key:   browserHSTSPreload,
    66  			Value: config.EnableOff,
    67  		},
    68  		config.KV{
    69  			Key:   browserReferrerPolicy,
    70  			Value: "strict-origin-when-cross-origin",
    71  		},
    72  	}
    73  )
    74  
    75  // configLock is a global lock for browser config
    76  var configLock sync.RWMutex
    77  
    78  // Config storage class configuration
    79  type Config struct {
    80  	CSPPolicy             string `json:"csp_policy"`
    81  	HSTSSeconds           int    `json:"hsts_seconds"`
    82  	HSTSIncludeSubdomains bool   `json:"hsts_include_subdomains"`
    83  	HSTSPreload           bool   `json:"hsts_preload"`
    84  	ReferrerPolicy        string `json:"referrer_policy"`
    85  }
    86  
    87  // Update Updates browser with new config
    88  func (browseCfg *Config) Update(newCfg Config) {
    89  	configLock.Lock()
    90  	defer configLock.Unlock()
    91  	browseCfg.CSPPolicy = newCfg.CSPPolicy
    92  	browseCfg.HSTSSeconds = newCfg.HSTSSeconds
    93  	browseCfg.HSTSIncludeSubdomains = newCfg.HSTSIncludeSubdomains
    94  	browseCfg.HSTSPreload = newCfg.HSTSPreload
    95  	browseCfg.ReferrerPolicy = newCfg.ReferrerPolicy
    96  }
    97  
    98  // LookupConfig - lookup api config and override with valid environment settings if any.
    99  func LookupConfig(kvs config.KVS) (cfg Config, err error) {
   100  	cspPolicy := env.Get(EnvBrowserCSPPolicy, kvs.GetWithDefault(browserCSPPolicy, DefaultKVS))
   101  	hstsSeconds, err := strconv.Atoi(env.Get(EnvBrowserHSTSSeconds, kvs.GetWithDefault(browserHSTSSeconds, DefaultKVS)))
   102  	if err != nil {
   103  		return cfg, err
   104  	}
   105  
   106  	hstsIncludeSubdomains := env.Get(EnvBrowserHSTSIncludeSubdomains, kvs.GetWithDefault(browserHSTSIncludeSubdomains, DefaultKVS)) == config.EnableOn
   107  	hstsPreload := env.Get(EnvBrowserHSTSPreload, kvs.Get(browserHSTSPreload)) == config.EnableOn
   108  
   109  	referrerPolicy := env.Get(EnvBrowserReferrerPolicy, kvs.GetWithDefault(browserReferrerPolicy, DefaultKVS))
   110  	switch referrerPolicy {
   111  	case "no-referrer", "no-referrer-when-downgrade", "origin", "origin-when-cross-origin", "same-origin", "strict-origin", "strict-origin-when-cross-origin", "unsafe-url":
   112  		cfg.ReferrerPolicy = referrerPolicy
   113  	default:
   114  		return cfg, fmt.Errorf("invalid value %v for %s", referrerPolicy, browserReferrerPolicy)
   115  	}
   116  
   117  	cfg.CSPPolicy = cspPolicy
   118  	cfg.HSTSSeconds = hstsSeconds
   119  	cfg.HSTSIncludeSubdomains = hstsIncludeSubdomains
   120  	cfg.HSTSPreload = hstsPreload
   121  
   122  	return cfg, nil
   123  }
   124  
   125  // GetCSPolicy - Get the Content security Policy
   126  func (browseCfg *Config) GetCSPolicy() string {
   127  	configLock.RLock()
   128  	defer configLock.RUnlock()
   129  	return browseCfg.CSPPolicy
   130  }
   131  
   132  // GetHSTSSeconds - Get the Content security Policy
   133  func (browseCfg *Config) GetHSTSSeconds() int {
   134  	configLock.RLock()
   135  	defer configLock.RUnlock()
   136  	return browseCfg.HSTSSeconds
   137  }
   138  
   139  // IsHSTSIncludeSubdomains - is HSTS 'includeSubdomains' directive enabled
   140  func (browseCfg *Config) IsHSTSIncludeSubdomains() string {
   141  	configLock.RLock()
   142  	defer configLock.RUnlock()
   143  	if browseCfg.HSTSSeconds > 0 && browseCfg.HSTSIncludeSubdomains {
   144  		return config.EnableOn
   145  	}
   146  	return config.EnableOff
   147  }
   148  
   149  // IsHSTSPreload - is HSTS 'preload' directive enabled
   150  func (browseCfg *Config) IsHSTSPreload() string {
   151  	configLock.RLock()
   152  	defer configLock.RUnlock()
   153  	if browseCfg.HSTSSeconds > 0 && browseCfg.HSTSPreload {
   154  		return config.EnableOn
   155  	}
   156  	return config.EnableOff
   157  }
   158  
   159  // GetReferPolicy - Get the ReferPolicy
   160  func (browseCfg *Config) GetReferPolicy() string {
   161  	configLock.RLock()
   162  	defer configLock.RUnlock()
   163  	return browseCfg.ReferrerPolicy
   164  }