config: fix unmarshalling of secret URLs (#1663)
* config: fix unmarshalling of secret URLs * Add comment describing why we need the special case Signed-off-by: Simon Pasquier <spasquie@redhat.com>
This commit is contained in:
parent
f1d33fbcc2
commit
34f78c9146
|
@ -29,13 +29,25 @@ import (
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const secretToken = "<secret>"
|
||||||
|
|
||||||
|
var secretTokenJSON string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
b, err := json.Marshal(secretToken)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
secretTokenJSON = string(b)
|
||||||
|
}
|
||||||
|
|
||||||
// Secret is a string that must not be revealed on marshaling.
|
// Secret is a string that must not be revealed on marshaling.
|
||||||
type Secret string
|
type Secret string
|
||||||
|
|
||||||
// MarshalYAML implements the yaml.Marshaler interface.
|
// MarshalYAML implements the yaml.Marshaler interface.
|
||||||
func (s Secret) MarshalYAML() (interface{}, error) {
|
func (s Secret) MarshalYAML() (interface{}, error) {
|
||||||
if s != "" {
|
if s != "" {
|
||||||
return "<secret>", nil
|
return secretToken, nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -48,7 +60,7 @@ func (s *Secret) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
func (s Secret) MarshalJSON() ([]byte, error) {
|
func (s Secret) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal("<secret>")
|
return json.Marshal(secretToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
// URL is a custom type that represents an HTTP or HTTPS URL and allows validation at configuration load time.
|
// URL is a custom type that represents an HTTP or HTTPS URL and allows validation at configuration load time.
|
||||||
|
@ -112,23 +124,41 @@ type SecretURL URL
|
||||||
// MarshalYAML implements the yaml.Marshaler interface for SecretURL.
|
// MarshalYAML implements the yaml.Marshaler interface for SecretURL.
|
||||||
func (s SecretURL) MarshalYAML() (interface{}, error) {
|
func (s SecretURL) MarshalYAML() (interface{}, error) {
|
||||||
if s.URL != nil {
|
if s.URL != nil {
|
||||||
return "<secret>", nil
|
return secretToken, nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalYAML implements the yaml.Unmarshaler interface for SecretURL.
|
// UnmarshalYAML implements the yaml.Unmarshaler interface for SecretURL.
|
||||||
func (s *SecretURL) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
func (s *SecretURL) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
|
var str string
|
||||||
|
if err := unmarshal(&str); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// In order to deserialize a previously serialized configuration (eg from
|
||||||
|
// the Alertmanager API with amtool), `<secret>` needs to be treated
|
||||||
|
// specially, as it isn't a valid URL.
|
||||||
|
if str == secretToken {
|
||||||
|
s.URL = &url.URL{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return unmarshal((*URL)(s))
|
return unmarshal((*URL)(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface for SecretURL.
|
// MarshalJSON implements the json.Marshaler interface for SecretURL.
|
||||||
func (s SecretURL) MarshalJSON() ([]byte, error) {
|
func (s SecretURL) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal("<secret>")
|
return json.Marshal(secretToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalJSON implements the json.Marshaler interface for SecretURL.
|
// UnmarshalJSON implements the json.Marshaler interface for SecretURL.
|
||||||
func (s *SecretURL) UnmarshalJSON(data []byte) error {
|
func (s *SecretURL) UnmarshalJSON(data []byte) error {
|
||||||
|
// In order to deserialize a previously serialized configuration (eg from
|
||||||
|
// the Alertmanager API with amtool), `<secret>` needs to be treated
|
||||||
|
// specially, as it isn't a valid URL.
|
||||||
|
if string(data) == secretToken || string(data) == secretTokenJSON {
|
||||||
|
s.URL = &url.URL{}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return json.Unmarshal(data, (*URL)(s))
|
return json.Unmarshal(data, (*URL)(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -346,12 +346,24 @@ func TestMarshalSecretURL(t *testing.T) {
|
||||||
// u003c -> "<"
|
// u003c -> "<"
|
||||||
// u003e -> ">"
|
// u003e -> ">"
|
||||||
require.Equal(t, "\"\\u003csecret\\u003e\"", string(c), "SecretURL not properly elided in JSON.")
|
require.Equal(t, "\"\\u003csecret\\u003e\"", string(c), "SecretURL not properly elided in JSON.")
|
||||||
|
// Check that the marshaled data can be unmarshaled again.
|
||||||
|
out := &SecretURL{}
|
||||||
|
err = json.Unmarshal(c, out)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
c, err = yaml.Marshal(u)
|
c, err = yaml.Marshal(u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
require.Equal(t, "<secret>\n", string(c), "SecretURL not properly elided in YAML.")
|
require.Equal(t, "<secret>\n", string(c), "SecretURL not properly elided in YAML.")
|
||||||
|
// Check that the marshaled data can be unmarshaled again.
|
||||||
|
out = &SecretURL{}
|
||||||
|
err = yaml.Unmarshal(c, &out)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalSecretURL(t *testing.T) {
|
func TestUnmarshalSecretURL(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue