mirror of
https://github.com/navidrome/navidrome.git
synced 2026-05-03 06:51:16 +00:00
Compare commits
1 Commits
950aafd58b
...
52cdda90dc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52cdda90dc |
@ -346,7 +346,7 @@ func startPluginManager(ctx context.Context) func() error {
|
|||||||
// TODO: Implement some struct tags to map flags to viper
|
// TODO: Implement some struct tags to map flags to viper
|
||||||
func init() {
|
func init() {
|
||||||
cobra.OnInitialize(func() {
|
cobra.OnInitialize(func() {
|
||||||
conf.InitConfig(cfgFile, true)
|
conf.InitConfig(cfgFile)
|
||||||
})
|
})
|
||||||
|
|
||||||
rootCmd.PersistentFlags().StringVarP(&cfgFile, "configfile", "c", "", `config file (default "./navidrome.toml")`)
|
rootCmd.PersistentFlags().StringVarP(&cfgFile, "configfile", "c", "", `config file (default "./navidrome.toml")`)
|
||||||
|
|||||||
@ -617,7 +617,7 @@ func init() {
|
|||||||
setViperDefaults()
|
setViperDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitConfig(cfgFile string, loadEnvVars bool) {
|
func InitConfig(cfgFile string) {
|
||||||
codecRegistry := viper.NewCodecRegistry()
|
codecRegistry := viper.NewCodecRegistry()
|
||||||
_ = codecRegistry.RegisterCodec("ini", ini.Codec{
|
_ = codecRegistry.RegisterCodec("ini", ini.Codec{
|
||||||
LoadOptions: ini.LoadOptions{
|
LoadOptions: ini.LoadOptions{
|
||||||
@ -638,12 +638,10 @@ func InitConfig(cfgFile string, loadEnvVars bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_ = viper.BindEnv("port")
|
_ = viper.BindEnv("port")
|
||||||
if loadEnvVars {
|
viper.SetEnvPrefix("ND")
|
||||||
viper.SetEnvPrefix("ND")
|
replacer := strings.NewReplacer(".", "_")
|
||||||
replacer := strings.NewReplacer(".", "_")
|
viper.SetEnvKeyReplacer(replacer)
|
||||||
viper.SetEnvKeyReplacer(replacer)
|
viper.AutomaticEnv()
|
||||||
viper.AutomaticEnv()
|
|
||||||
}
|
|
||||||
|
|
||||||
err := viper.ReadInConfig()
|
err := viper.ReadInConfig()
|
||||||
if viper.ConfigFileUsed() != "" && err != nil {
|
if viper.ConfigFileUsed() != "" && err != nil {
|
||||||
|
|||||||
@ -31,7 +31,7 @@ var _ = Describe("Configuration", func() {
|
|||||||
filename := filepath.Join("testdata", "cfg."+format)
|
filename := filepath.Join("testdata", "cfg."+format)
|
||||||
|
|
||||||
// Initialize config with the test file
|
// Initialize config with the test file
|
||||||
conf.InitConfig(filename, false)
|
conf.InitConfig(filename)
|
||||||
// Load the configuration (with noConfigDump=true)
|
// Load the configuration (with noConfigDump=true)
|
||||||
conf.Load(true)
|
conf.Load(true)
|
||||||
|
|
||||||
|
|||||||
@ -113,9 +113,9 @@ func WithAdminUser(ctx context.Context, ds model.DataStore) context.Context {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
c, err := ds.User(ctx).CountAll()
|
c, err := ds.User(ctx).CountAll()
|
||||||
if c == 0 && err == nil {
|
if c == 0 && err == nil {
|
||||||
log.Debug(ctx, "No admin user yet!", err)
|
log.Debug(ctx, "Scanner: No admin user yet!", err)
|
||||||
} else {
|
} else {
|
||||||
log.Error(ctx, "No admin user found!", err)
|
log.Error(ctx, "Scanner: No admin user found!", err)
|
||||||
}
|
}
|
||||||
u = &model.User{}
|
u = &model.User{}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/navidrome/navidrome/core/metrics/insights"
|
"github.com/navidrome/navidrome/core/metrics/insights"
|
||||||
"github.com/navidrome/navidrome/log"
|
"github.com/navidrome/navidrome/log"
|
||||||
"github.com/navidrome/navidrome/model"
|
"github.com/navidrome/navidrome/model"
|
||||||
"github.com/navidrome/navidrome/model/request"
|
|
||||||
"github.com/navidrome/navidrome/plugins/schema"
|
"github.com/navidrome/navidrome/plugins/schema"
|
||||||
"github.com/navidrome/navidrome/utils/singleton"
|
"github.com/navidrome/navidrome/utils/singleton"
|
||||||
)
|
)
|
||||||
@ -65,16 +64,9 @@ func GetInstance(ds model.DataStore, pluginLoader PluginLoader) Insights {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *insightsCollector) Run(ctx context.Context) {
|
func (c *insightsCollector) Run(ctx context.Context) {
|
||||||
|
ctx = auth.WithAdminUser(ctx, c.ds)
|
||||||
for {
|
for {
|
||||||
// Refresh admin context on each iteration to handle cases where
|
c.sendInsights(ctx)
|
||||||
// admin user wasn't available on previous runs
|
|
||||||
insightsCtx := auth.WithAdminUser(ctx, c.ds)
|
|
||||||
u, _ := request.UserFrom(insightsCtx)
|
|
||||||
if !u.IsAdmin {
|
|
||||||
log.Trace(insightsCtx, "No admin user available, skipping insights collection")
|
|
||||||
} else {
|
|
||||||
c.sendInsights(insightsCtx)
|
|
||||||
}
|
|
||||||
select {
|
select {
|
||||||
case <-time.After(consts.InsightsUpdateInterval):
|
case <-time.After(consts.InsightsUpdateInterval):
|
||||||
continue
|
continue
|
||||||
|
|||||||
@ -372,18 +372,15 @@ var _ = Describe("PlaylistRepository", func() {
|
|||||||
var testPlaylistID string
|
var testPlaylistID string
|
||||||
var lib2ID int
|
var lib2ID int
|
||||||
var restrictedUserID string
|
var restrictedUserID string
|
||||||
var uniqueLibPath string
|
|
||||||
|
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
db := GetDBXBuilder()
|
db := GetDBXBuilder()
|
||||||
|
|
||||||
// Generate unique IDs for this test run
|
// Generate unique IDs for this test run
|
||||||
uniqueSuffix := time.Now().Format("20060102150405.000")
|
restrictedUserID = "restricted-user-" + time.Now().Format("20060102150405.000")
|
||||||
restrictedUserID = "restricted-user-" + uniqueSuffix
|
|
||||||
uniqueLibPath = "/music/lib2-" + uniqueSuffix
|
|
||||||
|
|
||||||
// Create a second library with unique name and path to avoid conflicts with other tests
|
// Create a second library
|
||||||
_, err := db.DB().Exec("INSERT INTO library (name, path, created_at, updated_at) VALUES (?, ?, datetime('now'), datetime('now'))", "Library 2-"+uniqueSuffix, uniqueLibPath)
|
_, err := db.DB().Exec("INSERT INTO library (name, path, created_at, updated_at) VALUES ('Library 2', '/music/lib2', datetime('now'), datetime('now'))")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = db.DB().QueryRow("SELECT last_insert_rowid()").Scan(&lib2ID)
|
err = db.DB().QueryRow("SELECT last_insert_rowid()").Scan(&lib2ID)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
@ -423,7 +420,7 @@ var _ = Describe("PlaylistRepository", func() {
|
|||||||
ArtistID: "1",
|
ArtistID: "1",
|
||||||
Album: "Test Album",
|
Album: "Test Album",
|
||||||
AlbumID: "101",
|
AlbumID: "101",
|
||||||
Path: uniqueLibPath + "/song.mp3",
|
Path: "/music/lib2/song.mp3",
|
||||||
LibraryID: lib2ID,
|
LibraryID: lib2ID,
|
||||||
Participants: model.Participants{},
|
Participants: model.Participants{},
|
||||||
Tags: model.Tags{},
|
Tags: model.Tags{},
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package persistence
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/deluan/rest"
|
"github.com/deluan/rest"
|
||||||
"github.com/navidrome/navidrome/conf/configtest"
|
"github.com/navidrome/navidrome/conf/configtest"
|
||||||
@ -46,9 +45,6 @@ var _ = Describe("Tag Library Filtering", func() {
|
|||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
DeferCleanup(configtest.SetupConfig())
|
DeferCleanup(configtest.SetupConfig())
|
||||||
|
|
||||||
// Generate unique path suffix to avoid conflicts with other tests
|
|
||||||
uniqueSuffix := time.Now().Format("20060102150405.000")
|
|
||||||
|
|
||||||
// Clean up database
|
// Clean up database
|
||||||
db := GetDBXBuilder()
|
db := GetDBXBuilder()
|
||||||
_, err := db.NewQuery("DELETE FROM library_tag").Execute()
|
_, err := db.NewQuery("DELETE FROM library_tag").Execute()
|
||||||
@ -61,12 +57,12 @@ var _ = Describe("Tag Library Filtering", func() {
|
|||||||
_, err = db.NewQuery("DELETE FROM library WHERE id > 1").Execute()
|
_, err = db.NewQuery("DELETE FROM library WHERE id > 1").Execute()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
// Create test libraries with unique names and paths to avoid conflicts with other tests
|
// Create test libraries
|
||||||
_, err = db.NewQuery("INSERT INTO library (id, name, path) VALUES ({:id}, {:name}, {:path})").
|
_, err = db.NewQuery("INSERT INTO library (id, name, path) VALUES ({:id}, {:name}, {:path})").
|
||||||
Bind(dbx.Params{"id": libraryID2, "name": "Library 2-" + uniqueSuffix, "path": "/music/lib2-" + uniqueSuffix}).Execute()
|
Bind(dbx.Params{"id": libraryID2, "name": "Library 2", "path": "/music/lib2"}).Execute()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
_, err = db.NewQuery("INSERT INTO library (id, name, path) VALUES ({:id}, {:name}, {:path})").
|
_, err = db.NewQuery("INSERT INTO library (id, name, path) VALUES ({:id}, {:name}, {:path})").
|
||||||
Bind(dbx.Params{"id": libraryID3, "name": "Library 3-" + uniqueSuffix, "path": "/music/lib3-" + uniqueSuffix}).Execute()
|
Bind(dbx.Params{"id": libraryID3, "name": "Library 3", "path": "/music/lib3"}).Execute()
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
// Give admin access to all libraries
|
// Give admin access to all libraries
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"cmp"
|
"cmp"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"encoding/pem"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
@ -72,13 +69,6 @@ func (s *Server) Run(ctx context.Context, addr string, port int, tlsCert string,
|
|||||||
// Determine if TLS is enabled
|
// Determine if TLS is enabled
|
||||||
tlsEnabled := tlsCert != "" && tlsKey != ""
|
tlsEnabled := tlsCert != "" && tlsKey != ""
|
||||||
|
|
||||||
// Validate TLS certificates before starting the server
|
|
||||||
if tlsEnabled {
|
|
||||||
if err := validateTLSCertificates(tlsCert, tlsKey); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a listener based on the address type (either Unix socket or TCP)
|
// Create a listener based on the address type (either Unix socket or TCP)
|
||||||
var listener net.Listener
|
var listener net.Listener
|
||||||
var err error
|
var err error
|
||||||
@ -99,17 +89,17 @@ func (s *Server) Run(ctx context.Context, addr string, port int, tlsCert string,
|
|||||||
// Start the server in a new goroutine and send an error signal to errC if there's an error
|
// Start the server in a new goroutine and send an error signal to errC if there's an error
|
||||||
errC := make(chan error)
|
errC := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
var err error
|
|
||||||
if tlsEnabled {
|
if tlsEnabled {
|
||||||
// Start the HTTPS server
|
// Start the HTTPS server
|
||||||
log.Info("Starting server with TLS (HTTPS) enabled", "tlsCert", tlsCert, "tlsKey", tlsKey)
|
log.Info("Starting server with TLS (HTTPS) enabled", "tlsCert", tlsCert, "tlsKey", tlsKey)
|
||||||
err = server.ServeTLS(listener, tlsCert, tlsKey)
|
if err := server.ServeTLS(listener, tlsCert, tlsKey); !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
errC <- err
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Start the HTTP server
|
// Start the HTTP server
|
||||||
err = server.Serve(listener)
|
if err := server.Serve(listener); !errors.Is(err, http.ErrServerClosed) {
|
||||||
}
|
errC <- err
|
||||||
if !errors.Is(err, http.ErrServerClosed) {
|
}
|
||||||
errC <- err
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@ -259,56 +249,3 @@ func AbsoluteURL(r *http.Request, u string, params url.Values) string {
|
|||||||
}
|
}
|
||||||
return buildUrl.String()
|
return buildUrl.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// validateTLSCertificates validates the TLS certificate and key files before starting the server.
|
|
||||||
// It provides detailed error messages for common issues like encrypted private keys.
|
|
||||||
func validateTLSCertificates(certFile, keyFile string) error {
|
|
||||||
// Read the key file to check for encryption
|
|
||||||
keyData, err := os.ReadFile(keyFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("reading TLS key file: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse PEM blocks and check for encryption
|
|
||||||
block, _ := pem.Decode(keyData)
|
|
||||||
if block == nil {
|
|
||||||
return errors.New("TLS key file does not contain a valid PEM block")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for encrypted private key indicators
|
|
||||||
if isEncryptedPEM(block, keyData) {
|
|
||||||
return errors.New("TLS private key is encrypted (password-protected). " +
|
|
||||||
"Navidrome does not support encrypted private keys. " +
|
|
||||||
"Please decrypt your key using: openssl pkey -in <encrypted-key> -out <decrypted-key>")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to load the certificate pair to validate it
|
|
||||||
_, err = tls.LoadX509KeyPair(certFile, keyFile)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("loading TLS certificate/key pair: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// isEncryptedPEM checks if a PEM block represents an encrypted private key.
|
|
||||||
func isEncryptedPEM(block *pem.Block, rawData []byte) bool {
|
|
||||||
// Check for PKCS#8 encrypted format (BEGIN ENCRYPTED PRIVATE KEY)
|
|
||||||
if block.Type == "ENCRYPTED PRIVATE KEY" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for legacy encrypted format with Proc-Type header
|
|
||||||
if block.Headers != nil {
|
|
||||||
if procType, ok := block.Headers["Proc-Type"]; ok && strings.Contains(procType, "ENCRYPTED") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also check raw data for DEK-Info header (in case pem.Decode doesn't parse headers correctly)
|
|
||||||
if bytes.Contains(rawData, []byte("DEK-Info:")) || bytes.Contains(rawData, []byte("Proc-Type: 4,ENCRYPTED")) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,20 +1,13 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"fmt"
|
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/navidrome/navidrome/conf"
|
"github.com/navidrome/navidrome/conf"
|
||||||
"github.com/navidrome/navidrome/conf/configtest"
|
|
||||||
"github.com/navidrome/navidrome/tests"
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
@ -114,146 +107,3 @@ var _ = Describe("createUnixSocketFile", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
var _ = Describe("TLS support", func() {
|
|
||||||
Describe("validateTLSCertificates", func() {
|
|
||||||
const testDataDir = "server/testdata"
|
|
||||||
|
|
||||||
When("certificate and key are valid and unencrypted", func() {
|
|
||||||
It("returns nil", func() {
|
|
||||||
certFile := filepath.Join(testDataDir, "test_cert.pem")
|
|
||||||
keyFile := filepath.Join(testDataDir, "test_key.pem")
|
|
||||||
err := validateTLSCertificates(certFile, keyFile)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
When("private key is encrypted with PKCS#8 format", func() {
|
|
||||||
It("returns an error with helpful message", func() {
|
|
||||||
certFile := filepath.Join(testDataDir, "test_cert_encrypted.pem")
|
|
||||||
keyFile := filepath.Join(testDataDir, "test_key_encrypted.pem")
|
|
||||||
err := validateTLSCertificates(certFile, keyFile)
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err.Error()).To(ContainSubstring("encrypted"))
|
|
||||||
Expect(err.Error()).To(ContainSubstring("openssl"))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
When("private key is encrypted with legacy format (Proc-Type header)", func() {
|
|
||||||
It("returns an error with helpful message", func() {
|
|
||||||
certFile := filepath.Join(testDataDir, "test_cert.pem")
|
|
||||||
keyFile := filepath.Join(testDataDir, "test_key_encrypted_legacy.pem")
|
|
||||||
err := validateTLSCertificates(certFile, keyFile)
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err.Error()).To(ContainSubstring("encrypted"))
|
|
||||||
Expect(err.Error()).To(ContainSubstring("openssl"))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
When("key file does not exist", func() {
|
|
||||||
It("returns an error", func() {
|
|
||||||
certFile := filepath.Join(testDataDir, "test_cert.pem")
|
|
||||||
keyFile := filepath.Join(testDataDir, "nonexistent.pem")
|
|
||||||
err := validateTLSCertificates(certFile, keyFile)
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err.Error()).To(ContainSubstring("reading TLS key file"))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
When("key file does not contain valid PEM", func() {
|
|
||||||
It("returns an error", func() {
|
|
||||||
// Create a temp file with invalid PEM content
|
|
||||||
tmpFile, err := os.CreateTemp("", "invalid_key*.pem")
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
DeferCleanup(func() {
|
|
||||||
_ = os.Remove(tmpFile.Name())
|
|
||||||
})
|
|
||||||
_, err = tmpFile.WriteString("not a valid PEM file")
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
_ = tmpFile.Close()
|
|
||||||
|
|
||||||
certFile := filepath.Join(testDataDir, "test_cert.pem")
|
|
||||||
err = validateTLSCertificates(certFile, tmpFile.Name())
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err.Error()).To(ContainSubstring("valid PEM block"))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
When("certificate file does not exist", func() {
|
|
||||||
It("returns an error from tls.LoadX509KeyPair", func() {
|
|
||||||
certFile := filepath.Join(testDataDir, "nonexistent_cert.pem")
|
|
||||||
keyFile := filepath.Join(testDataDir, "test_key.pem")
|
|
||||||
err := validateTLSCertificates(certFile, keyFile)
|
|
||||||
Expect(err).To(HaveOccurred())
|
|
||||||
Expect(err.Error()).To(ContainSubstring("loading TLS certificate/key pair"))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
Describe("Server TLS", func() {
|
|
||||||
const testDataDir = "server/testdata"
|
|
||||||
|
|
||||||
When("server is started with valid TLS certificates", func() {
|
|
||||||
It("accepts HTTPS connections", func() {
|
|
||||||
DeferCleanup(configtest.SetupConfig())
|
|
||||||
|
|
||||||
// Create server with mock dependencies
|
|
||||||
ds := &tests.MockDataStore{}
|
|
||||||
server := New(ds, nil, nil)
|
|
||||||
|
|
||||||
// Load the test certificate to create a trusted CA pool
|
|
||||||
certFile := filepath.Join(testDataDir, "test_cert.pem")
|
|
||||||
keyFile := filepath.Join(testDataDir, "test_key.pem")
|
|
||||||
caCert, err := os.ReadFile(certFile)
|
|
||||||
Expect(err).ToNot(HaveOccurred())
|
|
||||||
|
|
||||||
caCertPool := x509.NewCertPool()
|
|
||||||
caCertPool.AppendCertsFromPEM(caCert)
|
|
||||||
|
|
||||||
// Create an HTTPS client that trusts our test certificate
|
|
||||||
httpClient := &http.Client{
|
|
||||||
Timeout: 5 * time.Second,
|
|
||||||
Transport: &http.Transport{
|
|
||||||
TLSClientConfig: &tls.Config{
|
|
||||||
RootCAs: caCertPool,
|
|
||||||
MinVersion: tls.VersionTLS12,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the server in a goroutine
|
|
||||||
ctx, cancel := context.WithCancel(GinkgoT().Context())
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
errChan := make(chan error, 1)
|
|
||||||
go func() {
|
|
||||||
errChan <- server.Run(ctx, "127.0.0.1", 14534, certFile, keyFile)
|
|
||||||
}()
|
|
||||||
|
|
||||||
Eventually(func() error {
|
|
||||||
// Make an HTTPS request to the server
|
|
||||||
resp, err := httpClient.Get("https://127.0.0.1:14534/ping")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}, 2*time.Second, 100*time.Millisecond).Should(Succeed())
|
|
||||||
|
|
||||||
// Stop the server
|
|
||||||
cancel()
|
|
||||||
|
|
||||||
// Wait for server to stop (with timeout)
|
|
||||||
select {
|
|
||||||
case <-errChan:
|
|
||||||
// Server stopped
|
|
||||||
case <-time.After(2 * time.Second):
|
|
||||||
Fail("Server did not stop in time")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|||||||
23
server/testdata/test_cert.pem
vendored
23
server/testdata/test_cert.pem
vendored
@ -1,23 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDwzCCAqugAwIBAgIUXqdUxUOo8kmsDe71iTR+Vr7btP8wDQYJKoZIhvcNAQEL
|
|
||||||
BQAwYjELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFRlc3QxDTALBgNVBAcMBFRlc3Qx
|
|
||||||
EjAQBgNVBAoMCU5hdmlkcm9tZTENMAsGA1UECwwEVGVzdDESMBAGA1UEAwwJbG9j
|
|
||||||
YWxob3N0MCAXDTI1MTEyODE5NTkxNVoYDzIxMjUxMTA0MTk1OTE1WjBiMQswCQYD
|
|
||||||
VQQGEwJVUzENMAsGA1UECAwEVGVzdDENMAsGA1UEBwwEVGVzdDESMBAGA1UECgwJ
|
|
||||||
TmF2aWRyb21lMQ0wCwYDVQQLDARUZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QwggEi
|
|
||||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCkB/TQgl5ei5KRSHt5OJim8rKS
|
|
||||||
MzRlkK4BjSEM4D9ESbebdpEVjX48QuBYACrCvgvVp7mQGF5anl8Hm89trvd8ooVQ
|
|
||||||
x9IPQQ6gRKM+4gLrt9FHvFGGzZQS8UTQXN5oBi11E+8/Vs47HLUNXC2TRtRLCMyK
|
|
||||||
LYXQIXbhdp9anImlt+IHUxIQUchK6Zkld/gCm56X1bbzN/Zq91PQLpx2FZ0eZTjN
|
|
||||||
KaNgztLa+K/BDnTuk3iTTs9GEp6VCvqQE/6fk/UN/tkk2dLwKIFvPVR/YeAhVdz/
|
|
||||||
OHC4L3B36QN3+VQ2yDjsp1PVAPX07UnzXO3Oj7uGYnMQxwprGMEubm3nADDxAgMB
|
|
||||||
AAGjbzBtMB0GA1UdDgQWBBRAZHUVuLyzc0CfuZR9ApqMbawIqzAfBgNVHSMEGDAW
|
|
||||||
gBRAZHUVuLyzc0CfuZR9ApqMbawIqzAPBgNVHRMBAf8EBTADAQH/MBoGA1UdEQQT
|
|
||||||
MBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAmDLXcPx9LNHs
|
|
||||||
GxQIE6Q5BXbVO7c8qrWmJf5FK5VWaifNZ9U+IBi+VlB4jCLK/OkwsviN/jOnwRYx
|
|
||||||
owjq0QG0YdRT4uD9fEMrAj+EwbnrQYZQvT0yGEWA+KW5TW08wt+/qnGJDwEgbjYJ
|
|
||||||
HTdICVMhs/e8Ex48fAgO8WSsdTDekOrhuwzIfeJ1LU4ZptLsD2ePFxuzutdIuW51
|
|
||||||
/mspQGsjXqZ1qnLsavLXh/lds2g602rTpYBNZVjV9WiOvaQS8vviOxBN6f+9vgRz
|
|
||||||
a8SEbHqBG6jeyVqVZ7MjxcYxaIkxeBwMyMwgb+wwDfVXo2FZzX2TVeB7ZppI+IKv
|
|
||||||
TXYurWPYsQ==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
22
server/testdata/test_cert_encrypted.pem
vendored
22
server/testdata/test_cert_encrypted.pem
vendored
@ -1,22 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDpzCCAo+gAwIBAgIUEa7gEJYwJqYEJjTY7otQ+oUyELwwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwYjELMAkGA1UEBhMCVVMxDTALBgNVBAgMBFRlc3QxDTALBgNVBAcMBFRlc3Qx
|
|
||||||
EjAQBgNVBAoMCU5hdmlkcm9tZTENMAsGA1UECwwEVGVzdDESMBAGA1UEAwwJbG9j
|
|
||||||
YWxob3N0MCAXDTI1MTEyODE5NTI0OVoYDzIxMjUxMTA0MTk1MjQ5WjBiMQswCQYD
|
|
||||||
VQQGEwJVUzENMAsGA1UECAwEVGVzdDENMAsGA1UEBwwEVGVzdDESMBAGA1UECgwJ
|
|
||||||
TmF2aWRyb21lMQ0wCwYDVQQLDARUZXN0MRIwEAYDVQQDDAlsb2NhbGhvc3QwggEi
|
|
||||||
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBHgqJ1d9EnNxqoSZ6xXrIz/mV
|
|
||||||
Y0nWJW16/qIAvCdovSeTZhG9iqG8dUqcuu2BdD9MMHndJ2oFn3iD8EJR92dH8KBA
|
|
||||||
8xOmtZ0BEEWgXPBivywZVd1ChIflEWj6m5wwLNjb57SPpUiwaLxBQB8ByEaAAZE/
|
|
||||||
bLqvHI3vW/4s5apky17SPIqmkmqEYlRcg97tlRXsPuwoAVM9cvLMMEqtIR1CB/72
|
|
||||||
gboY2Gi2r/plLF/Rg3Dom6QljMWi57XXWJFwGYSXaZuM0gvn04e3oLu+1E+WMoq/
|
|
||||||
9rExWij2DlsmXd/RiScliFp6R4H84wQUyqrAUNytvgRO+oVnRjEA0l3oCYdRAgMB
|
|
||||||
AAGjUzBRMB0GA1UdDgQWBBQQKpB1UaKm98FnBdl8uKdRscrVTzAfBgNVHSMEGDAW
|
|
||||||
gBQQKpB1UaKm98FnBdl8uKdRscrVTzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
|
|
||||||
DQEBCwUAA4IBAQBP07l+2LmpFtcxqMGmsiNYwFuHpQCxJd4YRZHjLX7O+oJExMgR
|
|
||||||
2yP4mpMKurgKOv7unTDLwvjQRa6ZTYJCsYtvC6hbyqlGc7AfNTu6DKz8r35/2/V5
|
|
||||||
hPsG5lNb91HhvHE839mLAvpi02LoFH2Sr8BR7s6qxfNKYcP8PUOJQXltJ6yAa8YJ
|
|
||||||
syeXQQ3RIyGsJANeaC06S3UdkBM5H5BLfIHnHu3GybJjwL51va4WCdHe8QV6GI0g
|
|
||||||
RDiThDVkBSXAr136vnMdlrYCxMoxY56itJ0zbYg2ELQKU9o1w/ZJQo9uvmy9jCoZ
|
|
||||||
Hy1L5a2vUDbsdONdvRkYZRHqMpG4bdD8D3j2
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
28
server/testdata/test_key.pem
vendored
28
server/testdata/test_key.pem
vendored
@ -1,28 +0,0 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
|
||||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCkB/TQgl5ei5KR
|
|
||||||
SHt5OJim8rKSMzRlkK4BjSEM4D9ESbebdpEVjX48QuBYACrCvgvVp7mQGF5anl8H
|
|
||||||
m89trvd8ooVQx9IPQQ6gRKM+4gLrt9FHvFGGzZQS8UTQXN5oBi11E+8/Vs47HLUN
|
|
||||||
XC2TRtRLCMyKLYXQIXbhdp9anImlt+IHUxIQUchK6Zkld/gCm56X1bbzN/Zq91PQ
|
|
||||||
Lpx2FZ0eZTjNKaNgztLa+K/BDnTuk3iTTs9GEp6VCvqQE/6fk/UN/tkk2dLwKIFv
|
|
||||||
PVR/YeAhVdz/OHC4L3B36QN3+VQ2yDjsp1PVAPX07UnzXO3Oj7uGYnMQxwprGMEu
|
|
||||||
bm3nADDxAgMBAAECggEABqJFvesP2v4FEvgd+kSWM+ZL34rPmy3zQ5/MDuPA20ep
|
|
||||||
89EjQ/5hdRl1TknPcOnTu7PZVuENa9fM2xdrl7GEU9eU0bQLJE/KwiOUgJYObS8V
|
|
||||||
eTO+DlghHXUBhfXDjux1CS+htOuTUqOyFNS+CR9Lta8o6ou1xjmcP7kW78i17mxF
|
|
||||||
TuH5SZlS8W9PFLXHCInbMtqGFaT2ss09kvoPk2FDvHfxEdy6M9tKkguz02g+4bqI
|
|
||||||
aAMp2N7AOfmRpC0HvVa1ZfZo5Z8/KMoNcIm3pV9DEVM369J9EzhnMNpkGben90aT
|
|
||||||
FqO2JNsy52wmXFZUc9xe8uPdfDahALCkBGncLyLNmQKBgQDZREjocjdzOoPSlCdx
|
|
||||||
mRNe9suHz2FpUpsHCPOCotG63hFVKpah/ZvpHSsQx5rXs/mawDTmzGY9GQiBrSvg
|
|
||||||
OhfHIyT3NOhVaNcMxTqJX7rs7OG8D0MBacD9ASSeZ89MUn8q1EHZr5qxLtXl5Ikw
|
|
||||||
mHtiGRdiKGFFrG9H0zncbGhy7QKBgQDBRhQ9RAasTdmUiNQly9GVFkXto4T/9UHx
|
|
||||||
rVU44htCI2IVZUMTGlNfclfxpByDrzyA56rMzN9SAkiIp4nPpMDs5hayXaaPoojs
|
|
||||||
CPzV7r2OjemZ6CTeQ1ODImRL8L/E3jJSgWd6YYoHSQ5hjEX4yT6ft0u0tZUfdMKd
|
|
||||||
VENWIJ/hlQKBgQCo2hXjeOi5R8+tN3EUKwhP9HOnX7dv+D/9jqpZa5qdpPpJeyjI
|
|
||||||
SmYCHKYci1Q+sWOaLiiu+km20B65UVFZGSzjmd+fs+GghzMifKGKo/iNK2ggFKhZ
|
|
||||||
j8vplRrVdQ45XZ/xNDbdLEmHzEN2QE+Skd7KFYADzCgU0vdFFdbRBPuD3QKBgGIq
|
|
||||||
fQctMRJ9LCE0akSURGwr9vKflmMHKCpfdqTAu0WZgS0K1Mm0GlqlUiPKzizYaauz
|
|
||||||
f14sRNV7kWnPZsDPlqn8p9SKmpnj3RW97uWeMCtiyx6/+VHm8ljts/GaY1zT2s1r
|
|
||||||
KqrPNfNDWQmU3MljNeqbh9lOTWK/xEVy0gzB31MNAoGAQNWrZvVdAbL95XW6STUu
|
|
||||||
JmQlqJTlluuqS0Rrd/uVEQwW0Vd1dZjRQcFAFiSiCQWTbtId5gFZd6hiIQl53Xz0
|
|
||||||
5cd+9mcyA/TaoCJYbMOFYsKbZMCBhefsovJlVQXedqJrIY6BdeGlet4GTAH5Qyl0
|
|
||||||
ytEIUnvn5YmmbI7PDz80XpU=
|
|
||||||
-----END PRIVATE KEY-----
|
|
||||||
30
server/testdata/test_key_encrypted.pem
vendored
30
server/testdata/test_key_encrypted.pem
vendored
@ -1,30 +0,0 @@
|
|||||||
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
|
||||||
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
|
|
||||||
-----END ENCRYPTED PRIVATE KEY-----
|
|
||||||
30
server/testdata/test_key_encrypted_legacy.pem
vendored
30
server/testdata/test_key_encrypted_legacy.pem
vendored
@ -1,30 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
Proc-Type: 4,ENCRYPTED
|
|
||||||
DEK-Info: AES-256-CBC,3C969050EAB73F121B7F0E6B75C42525
|
|
||||||
|
|
||||||
V6pSaAsrn9CQNo4p88QshJLbg8zkQJEom81dPbYSVqQSZa9YlPtpLZ9YtuLj/Ay0
|
|
||||||
TScEKIj/gzQ32wNl6nhcSNIL9yy+X11r5gNv1kIHkecf+EbDW20VOiJsfD+6LUyW
|
|
||||||
hA96AIbPOwc76iCuvsKHPKU9MlEmjGipmk/C2RQLHCZJ3WkiDRgCM8KQ7vKhfACT
|
|
||||||
w908yj4cB1e/P0JPq8t/3F7kPJ+6SVM1vMEffHl0otQR3rAyrK8QikwJ0K9qX62d
|
|
||||||
cqchTVlEyyZBYovR8DrRRUDbsXS5j1ZmX3NQpvTSTFowr+33fMrY+4Oz8sdR4yx1
|
|
||||||
CQc0A0sHHxSEIr2xu4KzczwOYVJN8PVdU0pgvFj9KEm66N6EY5CSFIBHyO/ycOt9
|
|
||||||
U+wpkRjf3zS6ZaUU0NKdOcop4YX33i99/tZF2RNR1i7ETLYph+/LCf09286Bi3u/
|
|
||||||
UCCuWedyECPdz0c6j0s27Fdfc/HEK90OEzeWh/fc+H2gJZhqJYK9V47HPTQNNMnB
|
|
||||||
U1a6FsJlrKE3E6nfSnTLxrSx9m/XTV7HV+HkgX+q8VhN7Q2VHUqkPzE7ZOPYpZ+A
|
|
||||||
dQzsm1TmEMxym6osYqFzQScXR1NZasrV2MTQ2J16dUgCdGAM2YMUD9JaoJR+u77M
|
|
||||||
WAjYzDiRg84rLr/KbJPAwHbsfo2KpiapJGSBBEDhz4W1/LOrFhsjaqIMSy4yZDGm
|
|
||||||
1KqXGHIlqmuHI7v4fD8vuzhj7GUujRx85HSZWakE/uc6s5WrhkSeVKYJWPfpsxTv
|
|
||||||
dT3oLOGJ+nRzWxM3aFtuJghX0nIGdKxT4EAUNXz0/vLT3OP1QCZR+oELrriFzmtj
|
|
||||||
+O30bGH2SAFZEQJ/uTQg6celoNh89IzH4DJkcn67hqpX6mUiU9CrIr/eR9C/en8Q
|
|
||||||
smTbbC1C1pDUaCwR26Z+zgM90amh4yfOFKK2geO2Kj+TmwFHUvi6ZnSzMzCvty3t
|
|
||||||
+wdIrUtf55Lw51JCpLGl70mg4b/zBj5hqBkU2YvAAnz/htjfH/wrD6ZAF1TCdlRO
|
|
||||||
gyODrJjGRnLd/v0XLk0wp+RkAjBcSlRlkUvZY5BtugL7dIdwiNGGQPcOni9IVeG0
|
|
||||||
6vDUEQnDOLYDj4d/JcckTLuHdrP+SW+0RQl2HK5+/w1hScGXN4O48gccu7yR/MN8
|
|
||||||
DmpCg5rD/nq8sxJosmSt07GrN36KppYt8LCXQbSg3NG2Ad715caS2C+0Qtdm5MPD
|
|
||||||
rM1UyTXQYSJXgUN9yZS/pmzlguCywnnvsBPU6j3ljZwcoD41QJ/1OU09/W6sIMQR
|
|
||||||
IAiM35JHiLJiccFgxSE1qx5F1UZqX4P47jF0Wzi/sE/DYXg5qw2DoauqXNzqnumH
|
|
||||||
71UDGK1V6wQIV7UCZDa0WUfFzu470XpuFb8VmMOuHSQxkZESc9cz8k/ueAuO438Q
|
|
||||||
jnlkF1Ge2EEPuaK2zeaTj/lGyYA1AUfHRRgt/EMUQSBntmhlpnwVPYTVvYtHO2N5
|
|
||||||
wp7/y39KirnlTl99i3XiOJ4WF4gIU2IaSlqMo4+e/A32h2JFi9QfNyfItXe6Fm1X
|
|
||||||
d0j2XGHzwMfHEFKdWyrgtVZwc38/1d6xWYAhs02b2basV/0AQhFTaKf5Z268eBNJ
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
||||||
@ -53,7 +53,6 @@ const SharePlayer = () => {
|
|||||||
remove: false,
|
remove: false,
|
||||||
spaceBar: true,
|
spaceBar: true,
|
||||||
volumeFade: { fadeIn: 200, fadeOut: 200 },
|
volumeFade: { fadeIn: 200, fadeOut: 200 },
|
||||||
sortableOptions: { delay: 200, delayOnTouchOnly: true },
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ReactJkMusicPlayer
|
<ReactJkMusicPlayer
|
||||||
|
|||||||
@ -47,15 +47,17 @@ const stylesheet = `
|
|||||||
.react-jinke-music-player-main .music-player-panel,
|
.react-jinke-music-player-main .music-player-panel,
|
||||||
.react-jinke-music-player-mobile,
|
.react-jinke-music-player-mobile,
|
||||||
.ril__outer{
|
.ril__outer{
|
||||||
background-color: #1a1a1a;
|
background-color: #1f1f1f;
|
||||||
border: 1px solid #fff1;
|
border: 1px solid #fff1;
|
||||||
}
|
}
|
||||||
|
.ril__toolbar{
|
||||||
|
background-color: #1d1d1d
|
||||||
|
}
|
||||||
.ril__toolbarItem{
|
.ril__toolbarItem{
|
||||||
font-size: 100%;
|
font-size: 100%;
|
||||||
color: #eee
|
color: #eee
|
||||||
}
|
}
|
||||||
.audio-lists-panel,
|
.audio-lists-panel{
|
||||||
.ril__toolbar{
|
|
||||||
background-color: #1f1f1f;
|
background-color: #1f1f1f;
|
||||||
border: 1px solid #fff1;
|
border: 1px solid #fff1;
|
||||||
border-radius: 6px 6px 0 0;
|
border-radius: 6px 6px 0 0;
|
||||||
|
|||||||
@ -137,19 +137,22 @@ export default {
|
|||||||
albumName: {
|
albumName: {
|
||||||
color: '#eee',
|
color: '#eee',
|
||||||
},
|
},
|
||||||
albumPlayButton: {
|
albumSubtitle: {
|
||||||
color: '#ff4e6b',
|
|
||||||
},
|
|
||||||
albumArtistName: {
|
|
||||||
color: '#ccc',
|
color: '#ccc',
|
||||||
},
|
},
|
||||||
|
albumPlayButton: {
|
||||||
|
color: '#ff4e6b !important',
|
||||||
|
},
|
||||||
|
albumArtistName: {
|
||||||
|
color: '#ff4e6b !important',
|
||||||
|
},
|
||||||
cover: {
|
cover: {
|
||||||
borderRadius: '6px',
|
borderRadius: '10px !important',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NDLogin: {
|
NDLogin: {
|
||||||
systemNameLink: {
|
systemNameLink: {
|
||||||
color: '#ff4e6b',
|
color: '#D60017',
|
||||||
},
|
},
|
||||||
welcome: {
|
welcome: {
|
||||||
color: '#eee',
|
color: '#eee',
|
||||||
@ -158,9 +161,6 @@ export default {
|
|||||||
minWidth: 300,
|
minWidth: 300,
|
||||||
backgroundColor: '#1d1d1d',
|
backgroundColor: '#1d1d1d',
|
||||||
},
|
},
|
||||||
icon: {
|
|
||||||
filter: 'hue-rotate(115deg)',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
MuiPaper: {
|
MuiPaper: {
|
||||||
elevation1: {
|
elevation1: {
|
||||||
@ -169,9 +169,6 @@ export default {
|
|||||||
root: {
|
root: {
|
||||||
color: '#eee',
|
color: '#eee',
|
||||||
},
|
},
|
||||||
rounded: {
|
|
||||||
borderRadius: '6px',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
NDMobileArtistDetails: {
|
NDMobileArtistDetails: {
|
||||||
bgContainer: {
|
bgContainer: {
|
||||||
@ -192,30 +189,6 @@ export default {
|
|||||||
paddingBottom: '1rem',
|
paddingBottom: '1rem',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RaDeleteWithConfirmButton: {
|
|
||||||
deleteButton: {
|
|
||||||
color: 'unset',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
RaPaginationActions: {
|
|
||||||
currentPageButton: {
|
|
||||||
border: '2px solid #D60017',
|
|
||||||
background: 'transparent',
|
|
||||||
},
|
|
||||||
button: {
|
|
||||||
border: '2px solid #D60017',
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
'@global': {
|
|
||||||
'.next-page': {
|
|
||||||
border: '0 none',
|
|
||||||
},
|
|
||||||
'.previous-page': {
|
|
||||||
border: '0 none',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
player: {
|
player: {
|
||||||
theme: 'dark',
|
theme: 'dark',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user