From beb6b880fc69112cd70195e1f3e9ef4865457eb2 Mon Sep 17 00:00:00 2001 From: Quick <31828688+Quick104@users.noreply.github.com> Date: Thu, 11 Jun 2026 22:06:09 -0400 Subject: [PATCH] fix(api): move account-level Discord routes out of RequireProfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Discord DM channel's prefs, link-init, and unlink endpoints are account-level — the handlers only read the user ID — but were mounted inside the /notifications subrouter, whose RequireProfile middleware 400s any request without an X-Profile-Id header. Register them as static paths on the auth-only group instead, the same coexistence pattern the public email-link routes already use (static paths win over the mounted subrouter's wildcards; verified empirically, no middleware leak onto profile-scoped routes). Co-Authored-By: Claude Fable 5 --- internal/api/router.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/internal/api/router.go b/internal/api/router.go index 0d17c003..7068a335 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -1558,6 +1558,16 @@ func NewRouter(deps Dependencies) chi.Router { } notificationsHandler := handlers.NewNotificationsHandler(deps.Notifications, deps.EventsHub) r.With(apimw.RequireProfile).Post("/events/ws-ticket", notificationsHandler.HandleMintWSTicket) + // Discord DM channel: the linked identity and mode hang off + // the login account, not a profile, so these stay outside + // the RequireProfile subrouter below (static paths coexist + // with it, same as the public email-link routes above). + if discordNotificationsHandler != nil { + r.Get("/notifications/discord-preferences", discordNotificationsHandler.HandleGetPreferences) + r.Put("/notifications/discord-preferences", discordNotificationsHandler.HandleUpdatePreferences) + r.Delete("/notifications/discord-link", discordNotificationsHandler.HandleUnlink) + r.Post("/notifications/discord/link/init", discordNotificationsHandler.HandleLinkInit) + } r.Route("/notifications", func(r chi.Router) { r.Use(apimw.RequireProfile) r.Get("/", notificationsHandler.HandleList) @@ -1570,12 +1580,6 @@ func NewRouter(deps Dependencies) chi.Router { r.Put("/email-preferences", notificationsHandler.HandleUpdateEmailPreferences) r.Put("/email-preferences/address", notificationsHandler.HandleRequestEmailAddress) r.Delete("/email-preferences/address", notificationsHandler.HandleClearEmailAddress) - if discordNotificationsHandler != nil { - r.Get("/discord-preferences", discordNotificationsHandler.HandleGetPreferences) - r.Put("/discord-preferences", discordNotificationsHandler.HandleUpdatePreferences) - r.Delete("/discord-link", discordNotificationsHandler.HandleUnlink) - r.Post("/discord/link/init", discordNotificationsHandler.HandleLinkInit) - } r.Post("/read-all", notificationsHandler.HandleReadAll) r.Route("/webhooks", func(r chi.Router) { r.Get("/", notificationsHandler.HandleListWebhooks)