feat: Hide secrets on api and channels
This commit is contained in:
@@ -14,6 +14,28 @@ const (
|
||||
ChannelTelegram = "telegram"
|
||||
)
|
||||
|
||||
// RedactedSecret is what a channel's secret config values read as over the API.
|
||||
// It is a sentinel and not merely a mask: a client may write it straight back,
|
||||
// and the value it stood for is preserved. See NotificationChannel.Redacted.
|
||||
const RedactedSecret = "••••••••"
|
||||
|
||||
// channelSecretKeys names, per channel type, the config entries that are
|
||||
// credentials rather than settings. A Slack or Discord webhook URL is on this
|
||||
// list because possession of the URL *is* the authorisation to post to that
|
||||
// channel — there is nothing else to steal.
|
||||
var channelSecretKeys = map[string][]string{
|
||||
ChannelWebhook: {"url"},
|
||||
ChannelSlack: {"url"},
|
||||
ChannelDiscord: {"url"},
|
||||
ChannelTelegram: {"token"},
|
||||
ChannelSMTP: {"password"},
|
||||
}
|
||||
|
||||
// ChannelSecretKeys reports which config keys of a channel type are secret.
|
||||
func ChannelSecretKeys(channelType string) []string {
|
||||
return channelSecretKeys[channelType]
|
||||
}
|
||||
|
||||
type NotificationChannel struct {
|
||||
ID bson.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"`
|
||||
InstanceID string `bson:"instance_id" json:"instance_id"`
|
||||
@@ -24,3 +46,25 @@ type NotificationChannel struct {
|
||||
Enabled bool `bson:"enabled" json:"enabled"`
|
||||
CreatedAt time.Time `bson:"created_at" json:"created_at"`
|
||||
}
|
||||
|
||||
// Redacted returns a copy with every secret config value replaced by
|
||||
// RedactedSecret, for handing to a client. Nothing internal uses it: the
|
||||
// dispatchers read the stored document through GetChannel/GetChannels, so the
|
||||
// redaction is a property of the API boundary and cannot break delivery.
|
||||
//
|
||||
// A set-but-secret key keeps its key, so a caller can still tell configured
|
||||
// from absent; an empty value is left empty rather than being dressed up as a
|
||||
// credential that is not there.
|
||||
func (c NotificationChannel) Redacted() NotificationChannel {
|
||||
out := c
|
||||
out.Config = make(map[string]string, len(c.Config))
|
||||
for k, v := range c.Config {
|
||||
out.Config[k] = v
|
||||
}
|
||||
for _, k := range ChannelSecretKeys(c.Type) {
|
||||
if out.Config[k] != "" {
|
||||
out.Config[k] = RedactedSecret
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user