diff --git a/internal/handlers/source_detail_test.go b/internal/handlers/source_detail_test.go index 007f464..7a08b4f 100644 --- a/internal/handlers/source_detail_test.go +++ b/internal/handlers/source_detail_test.go @@ -275,3 +275,94 @@ 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, 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: 3}, + )) + + 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 and a backslash reaches its delete prompt +// escaped for the script, each quote as a \u escape and the backslash +// doubled, which the browser reads back as the name typed. +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`, + } + 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"?") +} 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}} -
+