diff --git a/internal/handlers/source_detail_test.go b/internal/handlers/source_detail_test.go index 007f464..2d58837 100644 --- a/internal/handlers/source_detail_test.go +++ b/internal/handlers/source_detail_test.go @@ -275,3 +275,99 @@ func TestHandleSourceDetail_FitsWideAndNarrowWindows(t *testing.T) { `
`, ) } + +// TestHandleSourceDetail_DeletePromptsNameWhatIsLost checks that each +// delete prompt on the webhook page names the webhook, entrypoint or +// target and says what deleting it loses, that the webhook's gives its +// number of stored events (5 received, 2 removed by retention, so 3, +// the statistics pane's "Within retention" figure), and that an +// entrypoint with no description is named by its URL. The template +// writes the slashes after http: as \/, which the browser reads as /. +func TestHandleSourceDetail_DeletePromptsNameWhatIsLost(t *testing.T) { + t.Parallel() + + var ( + h *handlers.Handlers + sess *session.Session + db *database.Database + dbMgr *database.WebhookDBManager + ) + + app := newTestApp(t, &h, &sess, &db, &dbMgr) + app.RequireStart() + + t.Cleanup(app.RequireStop) + + wh := seedWebhook(t, db) + + webhookDB, err := dbMgr.GetDB(wh.ID) + require.NoError(t, err) + require.NoError(t, database.AddEventTotals( + webhookDB, database.EventTotals{Events: 5, EventsRemoved: 2}, + )) + + unnamed := seedEntrypoint(t, db, wh.ID) + require.NoError(t, db.DB().Omit(clause.Associations).Create( + &database.Entrypoint{ + WebhookID: wh.ID, + Path: "described-" + wh.ID, + Description: "Stripe", + Active: true, + }, + ).Error) + seedTarget(t, db, wh.ID, database.TargetTypeLog) + + body := renderSourceDetailPage(t, h, sess, wh.ID) + + assert.Contains(t, body, + `Delete webhook "delete-me"?\n\n`+ + `This deletes its stored events (3) and their deliveries. `+ + `Any archive files it wrote are kept.`) + assert.Contains(t, body, + `Delete entrypoint "Stripe"?\n\n`+ + `Senders using its URL get an error from now on, `+ + `and the URL cannot be restored.`) + assert.Contains(t, body, + `Delete entrypoint "http:\/\/example.com/h/`+ + unnamed.Path+`"?`) + assert.Contains(t, body, + `Delete target "t-log"?\n\n`+ + `Nothing more is delivered to it. `+ + `Its past deliveries stay in the event log.`) +} + +// TestHandleSourceDetail_DeletePromptKeepsQuotesInName checks that a +// webhook name with quotes, a backslash, a closing script tag and a +// newline reaches its delete prompt escaped for the script, which the +// browser reads back as the name typed: each quote and angle bracket +// as a \u escape, the slash as \/, the newline as \n and the backslash +// doubled. An unescaped newline would break the prompt's script, and +// the form would then submit without asking. +func TestHandleSourceDetail_DeletePromptKeepsQuotesInName(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 := &database.Webhook{ + UserID: deleteTestUserID, + Name: "Bob's \"best\" \\ hook\nline two", + } + require.NoError( + t, db.DB().Omit(clause.Associations).Create(wh).Error, + ) + + body := renderSourceDetailPage(t, h, sess, wh.ID) + + assert.Contains(t, body, + "Delete webhook "Bob\\u0027s \\u0022best\\u0022 \\\\ hook"+ + "\\u003c\\/script\\u003e\\nline two"?") +} diff --git a/internal/handlers/source_management.go b/internal/handlers/source_management.go index 01dcb50..5b6049c 100644 --- a/internal/handlers/source_management.go +++ b/internal/handlers/source_management.go @@ -612,8 +612,9 @@ func (h *Handlers) renderSourceDetail( // The host is the client's Host header, unvalidated. It is // inert only because source_detail.html renders BaseURL as - // text inside a element; putting it in an href or any - // other URL context needs it constrained first. + // text, inside a element and in an entrypoint's delete + // prompt; putting it in an href or any other URL context + // needs it constrained first. baseURL := scheme + "://" + r.Host // The template calls Webhook methods, which take pointer diff --git a/templates/source_detail.html b/templates/source_detail.html index a27c382..eeea81a 100644 --- a/templates/source_detail.html +++ b/templates/source_detail.html @@ -20,7 +20,11 @@
Full Event Log Edit -
+ +
@@ -83,7 +87,7 @@ {{if .Active}}Deactivate{{else}}Activate{{end}} -
+
@@ -249,7 +253,7 @@ {{if .Active}}Deactivate{{else}}Activate{{end}} -
+