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"
|
||||
)
|
||||
|
||||
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.
|
||||
type Secret string
|
||||
|
||||
// MarshalYAML implements the yaml.Marshaler interface.
|
||||
func (s Secret) MarshalYAML() (interface{}, error) {
|
||||
if s != "" {
|
||||
return "<secret>", nil
|
||||
return secretToken, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -48,7 +60,7 @@ func (s *Secret) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
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.
|
||||
|
@ -112,23 +124,41 @@ type SecretURL URL
|
|||
// MarshalYAML implements the yaml.Marshaler interface for SecretURL.
|
||||
func (s SecretURL) MarshalYAML() (interface{}, error) {
|
||||
if s.URL != nil {
|
||||
return "<secret>", nil
|
||||
return secretToken, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface for SecretURL.
|
||||
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))
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface for SecretURL.
|
||||
func (s SecretURL) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal("<secret>")
|
||||
return json.Marshal(secretToken)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Marshaler interface for SecretURL.
|
||||
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))
|
||||
}
|
||||
|
||||
|
|
|
@ -346,12 +346,24 @@ func TestMarshalSecretURL(t *testing.T) {
|
|||
// u003c -> "<"
|
||||
// u003e -> ">"
|
||||
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)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
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) {
|
||||
|
|
Loading…
Reference in New Issue