Load TLS config files from config path before stash home (#1678)

* Load tls files from config or home directory
* Update README
* Require both ssl files if either present
This commit is contained in:
WithoutPants 2021-08-31 19:37:45 +10:00 committed by GitHub
parent 1774a3600c
commit 709d7ce1cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 84 additions and 65 deletions

View file

@ -66,7 +66,7 @@ Stash can run over HTTPS with some additional work. First you must generate a S
This command would need customizing for your environment. [This link](https://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl) might be useful. This command would need customizing for your environment. [This link](https://stackoverflow.com/questions/10175812/how-to-create-a-self-signed-certificate-with-openssl) might be useful.
Once you have a certificate and key file name them `stash.crt` and `stash.key` and place them in the `~/.stash` directory. Stash detects these and starts up using HTTPS rather than HTTP. Once you have a certificate and key file name them `stash.crt` and `stash.key` and place them in the same directory as the `config.yml` file, or the `~/.stash` directory. Stash detects these and starts up using HTTPS rather than HTTP.
# Customization # Customization

View file

@ -27,7 +27,6 @@ import (
"github.com/stashapp/stash/pkg/logger" "github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/manager" "github.com/stashapp/stash/pkg/manager"
"github.com/stashapp/stash/pkg/manager/config" "github.com/stashapp/stash/pkg/manager/config"
"github.com/stashapp/stash/pkg/manager/paths"
"github.com/stashapp/stash/pkg/models" "github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/session" "github.com/stashapp/stash/pkg/session"
"github.com/stashapp/stash/pkg/utils" "github.com/stashapp/stash/pkg/utils"
@ -286,34 +285,31 @@ func Start() {
displayAddress := displayHost + ":" + strconv.Itoa(c.GetPort()) displayAddress := displayHost + ":" + strconv.Itoa(c.GetPort())
address := c.GetHost() + ":" + strconv.Itoa(c.GetPort()) address := c.GetHost() + ":" + strconv.Itoa(c.GetPort())
if tlsConfig := makeTLSConfig(); tlsConfig != nil { tlsConfig, err := makeTLSConfig(c)
httpsServer := &http.Server{ if err != nil {
Addr: address, // assume we don't want to start with a broken TLS configuration
Handler: r, panic(fmt.Errorf("error loading TLS config: %s", err.Error()))
TLSConfig: tlsConfig, }
}
go func() { server := &http.Server{
printVersion() Addr: address,
printLatestVersion() Handler: r,
logger.Infof("stash is listening on " + address) TLSConfig: tlsConfig,
}
go func() {
printVersion()
printLatestVersion()
logger.Infof("stash is listening on " + address)
if tlsConfig != nil {
logger.Infof("stash is running at https://" + displayAddress + "/") logger.Infof("stash is running at https://" + displayAddress + "/")
logger.Error(httpsServer.ListenAndServeTLS("", "")) logger.Error(server.ListenAndServeTLS("", ""))
}() } else {
} else {
server := &http.Server{
Addr: address,
Handler: r,
}
go func() {
printVersion()
printLatestVersion()
logger.Infof("stash is listening on " + address)
logger.Infof("stash is running at http://" + displayAddress + "/") logger.Infof("stash is running at http://" + displayAddress + "/")
logger.Error(server.ListenAndServe()) logger.Error(server.ListenAndServe())
}() }
} }()
} }
func printVersion() { func printVersion() {
@ -328,27 +324,44 @@ func GetVersion() (string, string, string) {
return version, githash, buildstamp return version, githash, buildstamp
} }
func makeTLSConfig() *tls.Config { func makeTLSConfig(c *config.Instance) (*tls.Config, error) {
cert, err := ioutil.ReadFile(paths.GetSSLCert()) c.InitTLS()
if err != nil { certFile, keyFile := c.GetTLSFiles()
return nil
if certFile == "" && keyFile == "" {
// assume http configuration
return nil, nil
} }
key, err := ioutil.ReadFile(paths.GetSSLKey()) // ensure both files are present
if certFile == "" {
return nil, errors.New("SSL certificate file must be present if key file is present")
}
if keyFile == "" {
return nil, errors.New("SSL key file must be present if certificate file is present")
}
cert, err := ioutil.ReadFile(certFile)
if err != nil { if err != nil {
return nil return nil, fmt.Errorf("error reading SSL certificate file %s: %s", certFile, err.Error())
}
key, err := ioutil.ReadFile(keyFile)
if err != nil {
return nil, fmt.Errorf("error reading SSL key file %s: %s", keyFile, err.Error())
} }
certs := make([]tls.Certificate, 1) certs := make([]tls.Certificate, 1)
certs[0], err = tls.X509KeyPair(cert, key) certs[0], err = tls.X509KeyPair(cert, key)
if err != nil { if err != nil {
return nil return nil, fmt.Errorf("error parsing key pair: %s", err.Error())
} }
tlsConfig := &tls.Config{ tlsConfig := &tls.Config{
Certificates: certs, Certificates: certs,
} }
return tlsConfig return tlsConfig, nil
} }
type contextKey struct { type contextKey struct {

View file

@ -16,17 +16,6 @@ import (
"github.com/stashapp/stash/pkg/utils" "github.com/stashapp/stash/pkg/utils"
) )
func findInPaths(paths []string, baseName string) string {
for _, p := range paths {
filePath := filepath.Join(p, baseName)
if exists, _ := utils.FileExists(filePath); exists {
return filePath
}
}
return ""
}
func GetPaths(paths []string) (string, string) { func GetPaths(paths []string) (string, string) {
var ffmpegPath, ffprobePath string var ffmpegPath, ffprobePath string
@ -38,10 +27,10 @@ func GetPaths(paths []string) (string, string) {
// Check if ffmpeg exists in the config directory // Check if ffmpeg exists in the config directory
if ffmpegPath == "" { if ffmpegPath == "" {
ffmpegPath = findInPaths(paths, getFFMPEGFilename()) ffmpegPath = utils.FindInPaths(paths, getFFMPEGFilename())
} }
if ffprobePath == "" { if ffprobePath == "" {
ffprobePath = findInPaths(paths, getFFProbeFilename()) ffprobePath = utils.FindInPaths(paths, getFFProbeFilename())
} }
return ffmpegPath, ffprobePath return ffmpegPath, ffprobePath

View file

@ -157,18 +157,11 @@ func (e MissingConfigError) Error() string {
return fmt.Sprintf("missing the following mandatory settings: %s", strings.Join(e.missingFields, ", ")) return fmt.Sprintf("missing the following mandatory settings: %s", strings.Join(e.missingFields, ", "))
} }
func HasTLSConfig() bool {
ret, _ := utils.FileExists(paths.GetSSLCert())
if ret {
ret, _ = utils.FileExists(paths.GetSSLKey())
}
return ret
}
type Instance struct { type Instance struct {
cpuProfilePath string cpuProfilePath string
isNewSystem bool isNewSystem bool
certFile string
keyFile string
sync.RWMutex sync.RWMutex
//deadlock.RWMutex // for deadlock testing/issues //deadlock.RWMutex // for deadlock testing/issues
} }
@ -192,6 +185,26 @@ func (i *Instance) SetConfigFile(fn string) {
viper.SetConfigFile(fn) viper.SetConfigFile(fn)
} }
func (i *Instance) InitTLS() {
configDirectory := i.GetConfigPath()
tlsPaths := []string{
configDirectory,
paths.GetStashHomeDirectory(),
}
i.certFile = utils.FindInPaths(tlsPaths, "stash.crt")
i.keyFile = utils.FindInPaths(tlsPaths, "stash.key")
}
func (i *Instance) GetTLSFiles() (certFile, keyFile string) {
return i.certFile, i.keyFile
}
func (i *Instance) HasTLSConfig() bool {
certFile, keyFile := i.GetTLSFiles()
return certFile != "" && keyFile != ""
}
// GetCPUProfilePath returns the path to the CPU profile file to output // GetCPUProfilePath returns the path to the CPU profile file to output
// profiling info to. This is set only via a commandline flag. Returns an // profiling info to. This is set only via a commandline flag. Returns an
// empty string if not set. // empty string if not set.

View file

@ -29,11 +29,3 @@ func GetStashHomeDirectory() string {
func GetDefaultDatabaseFilePath() string { func GetDefaultDatabaseFilePath() string {
return filepath.Join(GetStashHomeDirectory(), "stash-go.sqlite") return filepath.Join(GetStashHomeDirectory(), "stash-go.sqlite")
} }
func GetSSLKey() string {
return filepath.Join(GetStashHomeDirectory(), "stash.key")
}
func GetSSLCert() string {
return filepath.Join(GetStashHomeDirectory(), "stash.crt")
}

View file

@ -133,7 +133,7 @@ func (c Cache) makeServerConnection(ctx context.Context) common.StashServerConne
Dir: c.config.GetConfigPath(), Dir: c.config.GetConfigPath(),
} }
if config.HasTLSConfig() { if c.config.HasTLSConfig() {
serverConnection.Scheme = "https" serverConnection.Scheme = "https"
} }

View file

@ -346,3 +346,14 @@ func IsFsPathCaseSensitive(path string) (bool, error) {
} }
return false, fmt.Errorf("can not determine case sensitivity of path %s", path) return false, fmt.Errorf("can not determine case sensitivity of path %s", path)
} }
func FindInPaths(paths []string, baseName string) string {
for _, p := range paths {
filePath := filepath.Join(p, baseName)
if exists, _ := FileExists(filePath); exists {
return filePath
}
}
return ""
}

View file

@ -12,6 +12,7 @@
* Added not equals/greater than/less than modifiers for resolution criteria. ([#1568](https://github.com/stashapp/stash/pull/1568)) * Added not equals/greater than/less than modifiers for resolution criteria. ([#1568](https://github.com/stashapp/stash/pull/1568))
### 🎨 Improvements ### 🎨 Improvements
* Added support for loading TLS/SSL configuration files from the configuration directory. ([#1678](https://github.com/stashapp/stash/pull/1678))
* Added total scenes duration to Stats page. ([#1626](https://github.com/stashapp/stash/pull/1626)) * Added total scenes duration to Stats page. ([#1626](https://github.com/stashapp/stash/pull/1626))
* Move Play Selected Scenes, and Add/Remove Gallery Image buttons to button toolbar. ([#1673](https://github.com/stashapp/stash/pull/1673)) * Move Play Selected Scenes, and Add/Remove Gallery Image buttons to button toolbar. ([#1673](https://github.com/stashapp/stash/pull/1673))
* Added image and gallery counts to tag list view. ([#1672](https://github.com/stashapp/stash/pull/1672)) * Added image and gallery counts to tag list view. ([#1672](https://github.com/stashapp/stash/pull/1672))