Compare commits
1 Commits
issue-102-
...
issue-115-
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c0ea2b44f |
@@ -106,6 +106,12 @@ func slackConfigFields(configJSON string) []ConfigField {
|
|||||||
// and its retry settings. Header values are not shown — they
|
// and its retry settings. Header values are not shown — they
|
||||||
// routinely carry authorization tokens — only how many are
|
// routinely carry authorization tokens — only how many are
|
||||||
// configured.
|
// configured.
|
||||||
|
//
|
||||||
|
// The destination is masked to scheme and host by the same
|
||||||
|
// rule the Slack target uses. An HTTP target's destination is
|
||||||
|
// commonly a Slack, Discord or Teams incoming-webhook endpoint
|
||||||
|
// whose path segments are the credential, and the field takes
|
||||||
|
// an arbitrary URL, so no segment can be assumed non-secret.
|
||||||
func httpConfigFields(t *database.Target) []ConfigField {
|
func httpConfigFields(t *database.Target) []ConfigField {
|
||||||
cfg, err := parseHTTPConfig(t.Config)
|
cfg, err := parseHTTPConfig(t.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -114,7 +120,7 @@ func httpConfigFields(t *database.Target) []ConfigField {
|
|||||||
|
|
||||||
fields := []ConfigField{{
|
fields := []ConfigField{{
|
||||||
Label: "Destination URL",
|
Label: "Destination URL",
|
||||||
Value: cfg.URL,
|
Value: MaskURL(cfg.URL),
|
||||||
}}
|
}}
|
||||||
|
|
||||||
if cfg.Timeout > 0 {
|
if cfg.Timeout > 0 {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const (
|
|||||||
|
|
||||||
viewExampleOrigin = "https://example.com"
|
viewExampleOrigin = "https://example.com"
|
||||||
viewExampleHook = viewExampleOrigin + "/hook"
|
viewExampleHook = viewExampleOrigin + "/hook"
|
||||||
|
viewMaskedOrigin = viewExampleOrigin + "/..."
|
||||||
viewUnavailable = "(unavailable)"
|
viewUnavailable = "(unavailable)"
|
||||||
viewExpiryNever = "never"
|
viewExpiryNever = "never"
|
||||||
)
|
)
|
||||||
@@ -162,7 +163,7 @@ func TestNewTargetViews_HTTP(t *testing.T) {
|
|||||||
assert.Equal(
|
assert.Equal(
|
||||||
t,
|
t,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"Destination URL": viewExampleHook,
|
"Destination URL": viewMaskedOrigin,
|
||||||
"Timeout": "30s",
|
"Timeout": "30s",
|
||||||
"Headers": "1 configured",
|
"Headers": "1 configured",
|
||||||
"Max Retries": "5",
|
"Max Retries": "5",
|
||||||
@@ -188,13 +189,41 @@ func TestNewTargetViews_HTTPFireAndForget(t *testing.T) {
|
|||||||
assert.Equal(
|
assert.Equal(
|
||||||
t,
|
t,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"Destination URL": viewExampleHook,
|
"Destination URL": viewMaskedOrigin,
|
||||||
"Max Retries": "0 (fire-and-forget)",
|
"Max Retries": "0 (fire-and-forget)",
|
||||||
},
|
},
|
||||||
fieldMap(view.Config),
|
fieldMap(view.Config),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestNewTargetViews_HTTPMasksDestinationURL proves the rule
|
||||||
|
// holds for the http target too: an http destination is
|
||||||
|
// routinely an incoming-webhook endpoint whose path segments
|
||||||
|
// are the credential, so none of them is shown.
|
||||||
|
func TestNewTargetViews_HTTPMasksDestinationURL(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
view := viewFor(t, database.Target{
|
||||||
|
Type: database.TargetTypeHTTP,
|
||||||
|
Config: `{"url":"` + slackWebhookURL + `"}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
fields := fieldMap(view.Config)
|
||||||
|
|
||||||
|
assert.Equal(
|
||||||
|
t,
|
||||||
|
"https://hooks.slack.com/...",
|
||||||
|
fields["Destination URL"],
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, v := range fields {
|
||||||
|
assert.NotContains(t, v, slackSecretPath)
|
||||||
|
assert.NotContains(t, v, "T00000000")
|
||||||
|
assert.NotContains(t, v, "B00000000")
|
||||||
|
assert.NotContains(t, v, "XXXXXXXXXXXXXXXXXXXXXXXX")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewTargetViews_Database(t *testing.T) {
|
func TestNewTargetViews_Database(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,47 @@ func TestHandleSourceDetail_MasksSlackWebhookURL(t *testing.T) {
|
|||||||
assert.Contains(t, body, "https://hooks.slack.com/...")
|
assert.Contains(t, body, "https://hooks.slack.com/...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestHandleSourceDetail_MasksHTTPDestinationURL is the
|
||||||
|
// regression test for the same leak reached through the http
|
||||||
|
// target: its destination is routinely an incoming-webhook
|
||||||
|
// endpoint whose path segments are the credential, so the
|
||||||
|
// rendered page must not contain them.
|
||||||
|
func TestHandleSourceDetail_MasksHTTPDestinationURL(
|
||||||
|
t *testing.T,
|
||||||
|
) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var (
|
||||||
|
h *handlers.Handlers
|
||||||
|
sess *session.Session
|
||||||
|
db *database.Database
|
||||||
|
)
|
||||||
|
|
||||||
|
app := newTestApp(t, &h, &sess, &db)
|
||||||
|
app.RequireStart()
|
||||||
|
|
||||||
|
t.Cleanup(app.RequireStop)
|
||||||
|
|
||||||
|
wh := seedWebhook(t, db)
|
||||||
|
seedConfiguredTarget(
|
||||||
|
t, db, wh.ID,
|
||||||
|
database.TargetTypeHTTP,
|
||||||
|
`{"url":"`+slackWebhookURL+`"}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
body := renderSourceDetailPage(t, h, sess, wh.ID)
|
||||||
|
|
||||||
|
assert.NotContains(t, body, slackSecretPath)
|
||||||
|
assert.NotContains(t, body, "T00000000")
|
||||||
|
assert.NotContains(t, body, "B00000000")
|
||||||
|
assert.NotContains(
|
||||||
|
t, body, "XXXXXXXXXXXXXXXXXXXXXXXX",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Contains(t, body, "Destination URL")
|
||||||
|
assert.Contains(t, body, "https://hooks.slack.com/...")
|
||||||
|
}
|
||||||
|
|
||||||
// TestHandleSourceDetail_RendersNamedTargetFields proves the
|
// TestHandleSourceDetail_RendersNamedTargetFields proves the
|
||||||
// other target types render labelled fields rather than the
|
// other target types render labelled fields rather than the
|
||||||
// stored blob.
|
// stored blob.
|
||||||
@@ -172,7 +213,7 @@ func TestHandleSourceDetail_RendersNamedTargetFields(
|
|||||||
body := renderSourceDetailPage(t, h, sess, wh.ID)
|
body := renderSourceDetailPage(t, h, sess, wh.ID)
|
||||||
|
|
||||||
assert.Contains(t, body, "Destination URL")
|
assert.Contains(t, body, "Destination URL")
|
||||||
assert.Contains(t, body, "https://example.com/hook")
|
assert.Contains(t, body, "https://example.com/...")
|
||||||
assert.Contains(t, body, "Timeout")
|
assert.Contains(t, body, "Timeout")
|
||||||
assert.Contains(t, body, "1 configured")
|
assert.Contains(t, body, "1 configured")
|
||||||
assert.NotContains(t, body, "sekrit")
|
assert.NotContains(t, body, "sekrit")
|
||||||
|
|||||||
Reference in New Issue
Block a user