All checks were successful
check / check (push) Successful in 2m55s
delivery_results stored status_code, response_body, error, duration and attempt_num, and no template rendered any of it, so a failure read as "target: failed" and diagnosing it meant opening the per-webhook SQLite file by hand. An expanded delivery now lists its attempts with attempt number, status code, duration, error and response body. The body is bounded in the query rather than read whole and truncated in Go (#135), and a body the engine itself cut is no longer presented as complete. The response body and error are untrusted remote content, so target credentials are removed before rendering. Two cases needed care: a secret severed by the 4096-byte cut matches nothing as a whole string, and the engine's io.LimitReader cuts at the same constant the renderer uses, so the guard keys on the body reaching the cap rather than on the stored size exceeding it. Empty secrets are filtered where the secret list is built, because an empty string passed to strings.ReplaceAll inserts the marker at every byte boundary. loadTargetMap builds the redactor half unscoped, so a soft-deleted target's historical deliveries still render redacted. Also regenerates static/css/tailwind.css, which had drifted from the templates: hover:text-red-700, text-red-500, underline and w-28 were in use but absent from the served stylesheet (#236).
116 lines
3.3 KiB
Go
116 lines
3.3 KiB
Go
package handlers
|
|
|
|
import (
|
|
"html/template"
|
|
"log/slog"
|
|
"net/http"
|
|
|
|
"sneak.berlin/go/webhooker/internal/database"
|
|
)
|
|
|
|
// SetLogForTest replaces the handler's logger, so the handlers_test
|
|
// package can assert on what a log line actually contains rather than
|
|
// on what it is meant to contain.
|
|
func (s *Handlers) SetLogForTest(log *slog.Logger) {
|
|
s.log = log
|
|
}
|
|
|
|
// MaxRenderedBodyBytesForTest exposes the event log's body cap
|
|
// to the handlers_test package.
|
|
const MaxRenderedBodyBytesForTest = maxRenderedBodyBytes
|
|
|
|
// MaxRenderedResponseBytesForTest exposes the event log's
|
|
// delivery response cap to the handlers_test package.
|
|
const MaxRenderedResponseBytesForTest = maxRenderedResponseBytes
|
|
|
|
// MaxRenderedAttemptsForTest exposes the event log's
|
|
// per-delivery attempt ceiling to the handlers_test package.
|
|
const MaxRenderedAttemptsForTest = maxRenderedAttempts
|
|
|
|
// DummyVerificationsForTest reports how many equivalent-cost
|
|
// verifications were charged for usernames that do not exist. It
|
|
// lets a test prove the anti-enumeration path ran without timing
|
|
// anything.
|
|
func (s *Handlers) DummyVerificationsForTest() uint64 {
|
|
return s.dummyVerifications.Load()
|
|
}
|
|
|
|
// TrimPartialRuneForTest exposes trimPartialRune for use in the
|
|
// handlers_test package.
|
|
func TrimPartialRuneForTest(b []byte) []byte {
|
|
return trimPartialRune(b)
|
|
}
|
|
|
|
// LoadEventLogViewsForTest exposes loadEventsWithDeliveries for
|
|
// use in the handlers_test package. Assertions on the projected
|
|
// body need the bytes as loaded: html/template rewrites invalid
|
|
// UTF-8 on the way out, so the rendered page cannot show whether
|
|
// a binary body survived the projection intact.
|
|
func (s *Handlers) LoadEventLogViewsForTest(
|
|
w http.ResponseWriter,
|
|
webhook database.Webhook,
|
|
page int,
|
|
) []EventLogView {
|
|
views, _, _ := s.loadEventsWithDeliveries(
|
|
w, webhook, nil, page,
|
|
)
|
|
|
|
return views
|
|
}
|
|
|
|
// AddTemplateForTest registers a template under a page name so that
|
|
// the handlers_test package can drive the render path with a
|
|
// template of its own.
|
|
func (s *Handlers) AddTemplateForTest(
|
|
pageTemplate string,
|
|
tmpl *template.Template,
|
|
) {
|
|
s.templates[pageTemplate] = tmpl
|
|
}
|
|
|
|
// RenderTemplateForTest exposes renderTemplate for use in the
|
|
// handlers_test package.
|
|
func (s *Handlers) RenderTemplateForTest(
|
|
w http.ResponseWriter,
|
|
r *http.Request,
|
|
pageTemplate string,
|
|
data any,
|
|
) {
|
|
s.renderTemplate(w, r, pageTemplate, data)
|
|
}
|
|
|
|
// BuildSlackTargetConfigForTest exposes
|
|
// buildSlackTargetConfig for use in the handlers_test package.
|
|
func (s *Handlers) BuildSlackTargetConfigForTest(
|
|
w http.ResponseWriter,
|
|
r *http.Request,
|
|
targetURL string,
|
|
) (string, error) {
|
|
return s.buildSlackTargetConfig(w, r, targetURL)
|
|
}
|
|
|
|
// BuildHTTPTargetConfigForTest exposes buildHTTPTargetConfig
|
|
// for use in the handlers_test package, taking the form fields
|
|
// an HTTP target's configuration is built from.
|
|
func (s *Handlers) BuildHTTPTargetConfigForTest(
|
|
w http.ResponseWriter,
|
|
r *http.Request,
|
|
targetURL, headers, timeout string,
|
|
) (string, error) {
|
|
return s.buildHTTPTargetConfig(w, r, targetFormInput{
|
|
URL: targetURL,
|
|
Headers: headers,
|
|
Timeout: timeout,
|
|
})
|
|
}
|
|
|
|
// BuildDatabaseTargetConfigForTest exposes
|
|
// buildDatabaseTargetConfig for use in the handlers_test
|
|
// package.
|
|
func (s *Handlers) BuildDatabaseTargetConfigForTest(
|
|
w http.ResponseWriter,
|
|
expiry string,
|
|
) (string, error) {
|
|
return s.buildDatabaseTargetConfig(w, expiry)
|
|
}
|