Jelajahi Sumber

Config Array Syntax (#8204)

* refactor util encryption library so it doesn't have to import log

* add util.SplitString to handle space and/or comma-separated config lines

* go fmt
Dan Cech 8 tahun lalu
induk
melakukan
b489e93d94

+ 6 - 1
pkg/api/pluginproxy/pluginproxy_test.go

@@ -23,9 +23,14 @@ func TestPluginProxy(t *testing.T) {
 		setting.SecretKey = "password"
 		setting.SecretKey = "password"
 
 
 		bus.AddHandler("test", func(query *m.GetPluginSettingByIdQuery) error {
 		bus.AddHandler("test", func(query *m.GetPluginSettingByIdQuery) error {
+			key, err := util.Encrypt([]byte("123"), "password")
+			if err != nil {
+				return err
+			}
+
 			query.Result = &m.PluginSetting{
 			query.Result = &m.PluginSetting{
 				SecureJsonData: map[string][]byte{
 				SecureJsonData: map[string][]byte{
-					"key": util.Encrypt([]byte("123"), "password"),
+					"key": key,
 				},
 				},
 			}
 			}
 			return nil
 			return nil

+ 13 - 2
pkg/components/securejsondata/securejsondata.go

@@ -1,6 +1,7 @@
 package securejsondata
 package securejsondata
 
 
 import (
 import (
+	"github.com/grafana/grafana/pkg/log"
 	"github.com/grafana/grafana/pkg/setting"
 	"github.com/grafana/grafana/pkg/setting"
 	"github.com/grafana/grafana/pkg/util"
 	"github.com/grafana/grafana/pkg/util"
 )
 )
@@ -10,7 +11,12 @@ type SecureJsonData map[string][]byte
 func (s SecureJsonData) Decrypt() map[string]string {
 func (s SecureJsonData) Decrypt() map[string]string {
 	decrypted := make(map[string]string)
 	decrypted := make(map[string]string)
 	for key, data := range s {
 	for key, data := range s {
-		decrypted[key] = string(util.Decrypt(data, setting.SecretKey))
+		decryptedData, err := util.Decrypt(data, setting.SecretKey)
+		if err != nil {
+			log.Fatal(4, err.Error())
+		}
+
+		decrypted[key] = string(decryptedData)
 	}
 	}
 	return decrypted
 	return decrypted
 }
 }
@@ -18,7 +24,12 @@ func (s SecureJsonData) Decrypt() map[string]string {
 func GetEncryptedJsonData(sjd map[string]string) SecureJsonData {
 func GetEncryptedJsonData(sjd map[string]string) SecureJsonData {
 	encrypted := make(SecureJsonData)
 	encrypted := make(SecureJsonData)
 	for key, data := range sjd {
 	for key, data := range sjd {
-		encrypted[key] = util.Encrypt([]byte(data), setting.SecretKey)
+		encryptedData, err := util.Encrypt([]byte(data), setting.SecretKey)
+		if err != nil {
+			log.Fatal(4, err.Error())
+		}
+
+		encrypted[key] = encryptedData
 	}
 	}
 	return encrypted
 	return encrypted
 }
 }

+ 4 - 2
pkg/log/log.go

@@ -15,6 +15,8 @@ import (
 	"github.com/go-stack/stack"
 	"github.com/go-stack/stack"
 	"github.com/inconshreveable/log15"
 	"github.com/inconshreveable/log15"
 	"github.com/inconshreveable/log15/term"
 	"github.com/inconshreveable/log15/term"
+
+	"github.com/grafana/grafana/pkg/util"
 )
 )
 
 
 var Root log15.Logger
 var Root log15.Logger
@@ -172,7 +174,7 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) {
 	Close()
 	Close()
 
 
 	defaultLevelName, _ := getLogLevelFromConfig("log", "info", cfg)
 	defaultLevelName, _ := getLogLevelFromConfig("log", "info", cfg)
-	defaultFilters := getFilters(cfg.Section("log").Key("filters").Strings(" "))
+	defaultFilters := getFilters(util.SplitString(cfg.Section("log").Key("filters").String()))
 
 
 	handlers := make([]log15.Handler, 0)
 	handlers := make([]log15.Handler, 0)
 
 
@@ -185,7 +187,7 @@ func ReadLoggingConfig(modes []string, logsPath string, cfg *ini.File) {
 
 
 		// Log level.
 		// Log level.
 		_, level := getLogLevelFromConfig("log."+mode, defaultLevelName, cfg)
 		_, level := getLogLevelFromConfig("log."+mode, defaultLevelName, cfg)
-		modeFilters := getFilters(sec.Key("filters").Strings(" "))
+		modeFilters := getFilters(util.SplitString(sec.Key("filters").String()))
 		format := getLogFormat(sec.Key("format").MustString(""))
 		format := getLogFormat(sec.Key("format").MustString(""))
 
 
 		var handler log15.Handler
 		var handler log15.Handler

+ 8 - 3
pkg/models/datasource_cache_test.go

@@ -54,10 +54,15 @@ func TestDataSourceCache(t *testing.T) {
 		})
 		})
 
 
 		ds.JsonData = json
 		ds.JsonData = json
+
+		tlsCaCert, _ := util.Encrypt([]byte(caCert), "password")
+		tlsClientCert, _ := util.Encrypt([]byte(clientCert), "password")
+		tlsClientKey, _ := util.Encrypt([]byte(clientKey), "password")
+
 		ds.SecureJsonData = map[string][]byte{
 		ds.SecureJsonData = map[string][]byte{
-			"tlsCACert":     util.Encrypt([]byte(caCert), "password"),
-			"tlsClientCert": util.Encrypt([]byte(clientCert), "password"),
-			"tlsClientKey":  util.Encrypt([]byte(clientKey), "password"),
+			"tlsCACert":     tlsCaCert,
+			"tlsClientCert": tlsClientCert,
+			"tlsClientKey":  tlsClientKey,
 		}
 		}
 		ds.Updated = t.Add(-1 * time.Minute)
 		ds.Updated = t.Add(-1 * time.Minute)
 
 

+ 6 - 1
pkg/services/sqlstore/plugin_setting.go

@@ -74,7 +74,12 @@ func UpdatePluginSetting(cmd *m.UpdatePluginSettingCmd) error {
 			return err
 			return err
 		} else {
 		} else {
 			for key, data := range cmd.SecureJsonData {
 			for key, data := range cmd.SecureJsonData {
-				pluginSetting.SecureJsonData[key] = util.Encrypt([]byte(data), setting.SecretKey)
+				encryptedData, err := util.Encrypt([]byte(data), setting.SecretKey)
+				if err != nil {
+					return err
+				}
+
+				pluginSetting.SecureJsonData[key] = encryptedData
 			}
 			}
 
 
 			// add state change event on commit success
 			// add state change event on commit success

+ 1 - 1
pkg/setting/setting.go

@@ -509,7 +509,7 @@ func NewConfigContext(args *CommandLineArgs) error {
 
 
 	//  read data source proxy white list
 	//  read data source proxy white list
 	DataProxyWhiteList = make(map[string]bool)
 	DataProxyWhiteList = make(map[string]bool)
-	for _, hostAndIp := range security.Key("data_source_proxy_whitelist").Strings(" ") {
+	for _, hostAndIp := range util.SplitString(security.Key("data_source_proxy_whitelist").String()) {
 		DataProxyWhiteList[hostAndIp] = true
 		DataProxyWhiteList[hostAndIp] = true
 	}
 	}
 
 

+ 6 - 5
pkg/social/social.go

@@ -8,6 +8,7 @@ import (
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2"
 
 
 	"github.com/grafana/grafana/pkg/setting"
 	"github.com/grafana/grafana/pkg/setting"
+	"github.com/grafana/grafana/pkg/util"
 )
 )
 
 
 type BasicUserInfo struct {
 type BasicUserInfo struct {
@@ -53,12 +54,12 @@ func NewOAuthService() {
 		info := &setting.OAuthInfo{
 		info := &setting.OAuthInfo{
 			ClientId:       sec.Key("client_id").String(),
 			ClientId:       sec.Key("client_id").String(),
 			ClientSecret:   sec.Key("client_secret").String(),
 			ClientSecret:   sec.Key("client_secret").String(),
-			Scopes:         sec.Key("scopes").Strings(" "),
+			Scopes:         util.SplitString(sec.Key("scopes").String()),
 			AuthUrl:        sec.Key("auth_url").String(),
 			AuthUrl:        sec.Key("auth_url").String(),
 			TokenUrl:       sec.Key("token_url").String(),
 			TokenUrl:       sec.Key("token_url").String(),
 			ApiUrl:         sec.Key("api_url").String(),
 			ApiUrl:         sec.Key("api_url").String(),
 			Enabled:        sec.Key("enabled").MustBool(),
 			Enabled:        sec.Key("enabled").MustBool(),
-			AllowedDomains: sec.Key("allowed_domains").Strings(" "),
+			AllowedDomains: util.SplitString(sec.Key("allowed_domains").String()),
 			HostedDomain:   sec.Key("hosted_domain").String(),
 			HostedDomain:   sec.Key("hosted_domain").String(),
 			AllowSignup:    sec.Key("allow_sign_up").MustBool(),
 			AllowSignup:    sec.Key("allow_sign_up").MustBool(),
 			Name:           sec.Key("name").MustString(name),
 			Name:           sec.Key("name").MustString(name),
@@ -92,7 +93,7 @@ func NewOAuthService() {
 				apiUrl:               info.ApiUrl,
 				apiUrl:               info.ApiUrl,
 				allowSignup:          info.AllowSignup,
 				allowSignup:          info.AllowSignup,
 				teamIds:              sec.Key("team_ids").Ints(","),
 				teamIds:              sec.Key("team_ids").Ints(","),
-				allowedOrganizations: sec.Key("allowed_organizations").Strings(" "),
+				allowedOrganizations: util.SplitString(sec.Key("allowed_organizations").String()),
 			}
 			}
 		}
 		}
 
 
@@ -115,7 +116,7 @@ func NewOAuthService() {
 				apiUrl:               info.ApiUrl,
 				apiUrl:               info.ApiUrl,
 				allowSignup:          info.AllowSignup,
 				allowSignup:          info.AllowSignup,
 				teamIds:              sec.Key("team_ids").Ints(","),
 				teamIds:              sec.Key("team_ids").Ints(","),
-				allowedOrganizations: sec.Key("allowed_organizations").Strings(" "),
+				allowedOrganizations: util.SplitString(sec.Key("allowed_organizations").String()),
 			}
 			}
 		}
 		}
 
 
@@ -135,7 +136,7 @@ func NewOAuthService() {
 				Config:               &config,
 				Config:               &config,
 				url:                  setting.GrafanaNetUrl,
 				url:                  setting.GrafanaNetUrl,
 				allowSignup:          info.AllowSignup,
 				allowSignup:          info.AllowSignup,
-				allowedOrganizations: sec.Key("allowed_organizations").Strings(" "),
+				allowedOrganizations: util.SplitString(sec.Key("allowed_organizations").String()),
 			}
 			}
 		}
 		}
 	}
 	}

+ 9 - 10
pkg/util/encryption.go

@@ -5,26 +5,25 @@ import (
 	"crypto/cipher"
 	"crypto/cipher"
 	"crypto/rand"
 	"crypto/rand"
 	"crypto/sha256"
 	"crypto/sha256"
+	"errors"
 	"io"
 	"io"
-
-	"github.com/grafana/grafana/pkg/log"
 )
 )
 
 
 const saltLength = 8
 const saltLength = 8
 
 
-func Decrypt(payload []byte, secret string) []byte {
+func Decrypt(payload []byte, secret string) ([]byte, error) {
 	salt := payload[:saltLength]
 	salt := payload[:saltLength]
 	key := encryptionKeyToBytes(secret, string(salt))
 	key := encryptionKeyToBytes(secret, string(salt))
 
 
 	block, err := aes.NewCipher(key)
 	block, err := aes.NewCipher(key)
 	if err != nil {
 	if err != nil {
-		log.Fatal(4, err.Error())
+		return nil, err
 	}
 	}
 
 
 	// The IV needs to be unique, but not secure. Therefore it's common to
 	// The IV needs to be unique, but not secure. Therefore it's common to
 	// include it at the beginning of the ciphertext.
 	// include it at the beginning of the ciphertext.
 	if len(payload) < aes.BlockSize {
 	if len(payload) < aes.BlockSize {
-		log.Fatal(4, "payload too short")
+		return nil, errors.New("payload too short")
 	}
 	}
 	iv := payload[saltLength : saltLength+aes.BlockSize]
 	iv := payload[saltLength : saltLength+aes.BlockSize]
 	payload = payload[saltLength+aes.BlockSize:]
 	payload = payload[saltLength+aes.BlockSize:]
@@ -33,16 +32,16 @@ func Decrypt(payload []byte, secret string) []byte {
 
 
 	// XORKeyStream can work in-place if the two arguments are the same.
 	// XORKeyStream can work in-place if the two arguments are the same.
 	stream.XORKeyStream(payload, payload)
 	stream.XORKeyStream(payload, payload)
-	return payload
+	return payload, nil
 }
 }
 
 
-func Encrypt(payload []byte, secret string) []byte {
+func Encrypt(payload []byte, secret string) ([]byte, error) {
 	salt := GetRandomString(saltLength)
 	salt := GetRandomString(saltLength)
 
 
 	key := encryptionKeyToBytes(secret, salt)
 	key := encryptionKeyToBytes(secret, salt)
 	block, err := aes.NewCipher(key)
 	block, err := aes.NewCipher(key)
 	if err != nil {
 	if err != nil {
-		log.Fatal(4, err.Error())
+		return nil, err
 	}
 	}
 
 
 	// The IV needs to be unique, but not secure. Therefore it's common to
 	// The IV needs to be unique, but not secure. Therefore it's common to
@@ -51,13 +50,13 @@ func Encrypt(payload []byte, secret string) []byte {
 	copy(ciphertext[:saltLength], []byte(salt))
 	copy(ciphertext[:saltLength], []byte(salt))
 	iv := ciphertext[saltLength : saltLength+aes.BlockSize]
 	iv := ciphertext[saltLength : saltLength+aes.BlockSize]
 	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
 	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
-		log.Fatal(4, err.Error())
+		return nil, err
 	}
 	}
 
 
 	stream := cipher.NewCFBEncrypter(block, iv)
 	stream := cipher.NewCFBEncrypter(block, iv)
 	stream.XORKeyStream(ciphertext[saltLength+aes.BlockSize:], payload)
 	stream.XORKeyStream(ciphertext[saltLength+aes.BlockSize:], payload)
 
 
-	return ciphertext
+	return ciphertext, nil
 }
 }
 
 
 // Key needs to be 32bytes
 // Key needs to be 32bytes

+ 4 - 2
pkg/util/encryption_test.go

@@ -18,9 +18,11 @@ func TestEncryption(t *testing.T) {
 	})
 	})
 
 
 	Convey("When decrypting basic payload", t, func() {
 	Convey("When decrypting basic payload", t, func() {
-		encrypted := Encrypt([]byte("grafana"), "1234")
-		decrypted := Decrypt(encrypted, "1234")
+		encrypted, encryptErr := Encrypt([]byte("grafana"), "1234")
+		decrypted, decryptErr := Decrypt(encrypted, "1234")
 
 
+		So(encryptErr, ShouldBeNil)
+		So(decryptErr, ShouldBeNil)
 		So(string(decrypted), ShouldEqual, "grafana")
 		So(string(decrypted), ShouldEqual, "grafana")
 	})
 	})
 
 

+ 12 - 0
pkg/util/strings.go

@@ -1,5 +1,9 @@
 package util
 package util
 
 
+import (
+	"regexp"
+)
+
 func StringsFallback2(val1 string, val2 string) string {
 func StringsFallback2(val1 string, val2 string) string {
 	return stringsFallback(val1, val2)
 	return stringsFallback(val1, val2)
 }
 }
@@ -16,3 +20,11 @@ func stringsFallback(vals ...string) string {
 	}
 	}
 	return ""
 	return ""
 }
 }
+
+func SplitString(str string) []string {
+	if len(str) == 0 {
+		return []string{}
+	}
+
+	return regexp.MustCompile("[, ]+").Split(str, -1)
+}

+ 11 - 0
pkg/util/strings_test.go

@@ -13,3 +13,14 @@ func TestStringsUtil(t *testing.T) {
 		So(StringsFallback3("", "", "3"), ShouldEqual, "3")
 		So(StringsFallback3("", "", "3"), ShouldEqual, "3")
 	})
 	})
 }
 }
+
+func TestSplitString(t *testing.T) {
+	Convey("Splits strings correctly", t, func() {
+		So(SplitString(""), ShouldResemble, []string{})
+		So(SplitString("test"), ShouldResemble, []string{"test"})
+		So(SplitString("test1 test2 test3"), ShouldResemble, []string{"test1", "test2", "test3"})
+		So(SplitString("test1,test2,test3"), ShouldResemble, []string{"test1", "test2", "test3"})
+		So(SplitString("test1, test2, test3"), ShouldResemble, []string{"test1", "test2", "test3"})
+		So(SplitString("test1 , test2 test3"), ShouldResemble, []string{"test1", "test2", "test3"})
+	})
+}