55 lines
1.2 KiB
Go
55 lines
1.2 KiB
Go
package config
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// encoding/json accepts repeated object keys. Inspect the token stream before
|
|
// typed decoding so deployment settings cannot silently override earlier values.
|
|
func uniqueJSONKeys(decoder *json.Decoder, depth int) error {
|
|
if depth > 16 {
|
|
return errors.New("configuration nesting is too deep")
|
|
}
|
|
token, err := decoder.Token()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
delimiter, compound := token.(json.Delim)
|
|
if !compound {
|
|
return nil
|
|
}
|
|
switch delimiter {
|
|
case '{':
|
|
seen := make(map[string]bool)
|
|
for decoder.More() {
|
|
keyToken, err := decoder.Token()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
key, ok := keyToken.(string)
|
|
if !ok {
|
|
return errors.New("configuration object key must be a string")
|
|
}
|
|
if seen[key] {
|
|
return fmt.Errorf("duplicate configuration field %q", key)
|
|
}
|
|
seen[key] = true
|
|
if err := uniqueJSONKeys(decoder, depth+1); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
case '[':
|
|
for decoder.More() {
|
|
if err := uniqueJSONKeys(decoder, depth+1); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
default:
|
|
return errors.New("unexpected configuration JSON delimiter")
|
|
}
|
|
_, err = decoder.Token()
|
|
return err
|
|
}
|