mirror of https://github.com/grafana/grafana.git
				
				
				
			Merge branch 'master' into mtanda-prometheus_table
This commit is contained in:
		
						commit
						8c448d95a1
					
				|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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"), | 			"tlsCACert":     tlsCaCert, | ||||||
| 			"tlsClientCert": util.Encrypt([]byte(clientCert), "password"), | 			"tlsClientCert": tlsClientCert, | ||||||
| 			"tlsClientKey":  util.Encrypt([]byte(clientKey), "password"), | 			"tlsClientKey":  tlsClientKey, | ||||||
| 		} | 		} | ||||||
| 		ds.Updated = t.Add(-1 * time.Minute) | 		ds.Updated = t.Add(-1 * time.Minute) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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()), | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -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
 | ||||||
|  |  | ||||||
|  | @ -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") | 		encrypted, encryptErr := Encrypt([]byte("grafana"), "1234") | ||||||
| 		decrypted := Decrypt(encrypted, "1234") | 		decrypted, decryptErr := Decrypt(encrypted, "1234") | ||||||
| 
 | 
 | ||||||
|  | 		So(encryptErr, ShouldBeNil) | ||||||
|  | 		So(decryptErr, ShouldBeNil) | ||||||
| 		So(string(decrypted), ShouldEqual, "grafana") | 		So(string(decrypted), ShouldEqual, "grafana") | ||||||
| 	}) | 	}) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -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"}) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -92,7 +92,7 @@ export class VariableSrv { | ||||||
| 
 | 
 | ||||||
|   addVariable(model) { |   addVariable(model) { | ||||||
|     var variable = this.createVariableFromModel(model); |     var variable = this.createVariableFromModel(model); | ||||||
|     this.variables.push(this.createVariableFromModel(variable)); |     this.variables.push(variable); | ||||||
|     return variable; |     return variable; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue