mirror of https://github.com/ory/kratos
213 lines
5.0 KiB
Go
213 lines
5.0 KiB
Go
// Copyright © 2023 Ory Corp
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package courier
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/ory/kratos/x/nosurfx"
|
|
"github.com/ory/kratos/x/redir"
|
|
|
|
"github.com/gofrs/uuid"
|
|
|
|
"github.com/ory/herodot"
|
|
keysetpagination "github.com/ory/x/pagination/keysetpagination_v2"
|
|
|
|
"github.com/ory/kratos/driver/config"
|
|
"github.com/ory/kratos/x"
|
|
)
|
|
|
|
const (
|
|
AdminRouteCourier = "/courier"
|
|
AdminRouteListMessages = AdminRouteCourier + "/messages"
|
|
AdminRouteGetMessage = AdminRouteCourier + "/messages/{msgID}"
|
|
)
|
|
|
|
type (
|
|
handlerDependencies interface {
|
|
x.WriterProvider
|
|
x.LoggingProvider
|
|
nosurfx.CSRFProvider
|
|
PersistenceProvider
|
|
config.Provider
|
|
}
|
|
Handler struct {
|
|
r handlerDependencies
|
|
}
|
|
HandlerProvider interface {
|
|
CourierHandler() *Handler
|
|
}
|
|
)
|
|
|
|
func NewHandler(r handlerDependencies) *Handler {
|
|
return &Handler{r: r}
|
|
}
|
|
|
|
func (h *Handler) RegisterPublicRoutes(public *x.RouterPublic) {
|
|
h.r.CSRFHandler().IgnoreGlobs(x.AdminPrefix+AdminRouteListMessages, AdminRouteListMessages)
|
|
public.GET(x.AdminPrefix+AdminRouteListMessages, redir.RedirectToAdminRoute(h.r))
|
|
public.GET(x.AdminPrefix+AdminRouteGetMessage, redir.RedirectToAdminRoute(h.r))
|
|
}
|
|
|
|
func (h *Handler) RegisterAdminRoutes(admin *x.RouterAdmin) {
|
|
admin.GET(AdminRouteListMessages, h.listCourierMessages)
|
|
admin.GET(AdminRouteGetMessage, h.getCourierMessage)
|
|
}
|
|
|
|
// Paginated Courier Message List Response
|
|
//
|
|
// swagger:response listCourierMessages
|
|
//
|
|
//nolint:deadcode,unused
|
|
//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions
|
|
type listCourierMessagesResponse struct {
|
|
keysetpagination.ResponseHeaders
|
|
|
|
// List of identities
|
|
//
|
|
// in:body
|
|
Body []Message
|
|
}
|
|
|
|
// Paginated List Courier Message Parameters
|
|
//
|
|
// swagger:parameters listCourierMessages
|
|
type ListCourierMessagesParameters struct {
|
|
keysetpagination.RequestParameters
|
|
|
|
// Status filters out messages based on status.
|
|
// If no value is provided, it doesn't take effect on filter.
|
|
//
|
|
// required: false
|
|
// in: query
|
|
Status *MessageStatus `json:"status"`
|
|
|
|
// Recipient filters out messages based on recipient.
|
|
// If no value is provided, it doesn't take effect on filter.
|
|
//
|
|
// required: false
|
|
// in: query
|
|
Recipient string `json:"recipient"`
|
|
}
|
|
|
|
// swagger:route GET /admin/courier/messages courier listCourierMessages
|
|
//
|
|
// # List Messages
|
|
//
|
|
// Lists all messages by given status and recipient.
|
|
//
|
|
// Produces:
|
|
// - application/json
|
|
//
|
|
// Security:
|
|
// oryAccessToken:
|
|
//
|
|
// Schemes: http, https
|
|
//
|
|
// Responses:
|
|
// 200: listCourierMessages
|
|
// 400: errorGeneric
|
|
// default: errorGeneric
|
|
func (h *Handler) listCourierMessages(w http.ResponseWriter, r *http.Request) {
|
|
keys := h.r.Config().SecretsPagination(r.Context())
|
|
filter, paginator, err := parseMessagesFilter(r, keys)
|
|
if err != nil {
|
|
h.r.Writer().WriteErrorCode(w, r, http.StatusBadRequest, err)
|
|
return
|
|
}
|
|
|
|
l, nextPage, err := h.r.CourierPersister().ListMessages(r.Context(), filter, paginator)
|
|
if err != nil {
|
|
h.r.Writer().WriteError(w, r, err)
|
|
return
|
|
}
|
|
|
|
if !h.r.Config().IsInsecureDevMode(r.Context()) {
|
|
for i := range l {
|
|
l[i].Body = "<redacted-unless-dev-mode>"
|
|
}
|
|
}
|
|
|
|
u := *r.URL
|
|
keysetpagination.SetLinkHeader(w, keys, &u, nextPage)
|
|
h.r.Writer().Write(w, r, l)
|
|
}
|
|
|
|
func parseMessagesFilter(r *http.Request, keys [][32]byte) (ListCourierMessagesParameters, []keysetpagination.Option, error) {
|
|
var status *MessageStatus
|
|
|
|
if r.URL.Query().Has("status") {
|
|
ms, err := ToMessageStatus(r.URL.Query().Get("status"))
|
|
if err != nil {
|
|
return ListCourierMessagesParameters{}, nil, errors.WithStack(err)
|
|
}
|
|
|
|
status = &ms
|
|
}
|
|
|
|
opts, err := keysetpagination.ParseQueryParams(keys, r.URL.Query())
|
|
if err != nil {
|
|
return ListCourierMessagesParameters{}, nil, errors.WithStack(err)
|
|
}
|
|
|
|
return ListCourierMessagesParameters{
|
|
Status: status,
|
|
Recipient: r.URL.Query().Get("recipient"),
|
|
}, opts, nil
|
|
}
|
|
|
|
// Get Courier Message Parameters
|
|
//
|
|
// swagger:parameters getCourierMessage
|
|
//
|
|
//nolint:deadcode,unused
|
|
//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions
|
|
type getCourierMessage struct {
|
|
// MessageID is the ID of the message.
|
|
//
|
|
// required: true
|
|
// in: path
|
|
MessageID string `json:"id"`
|
|
}
|
|
|
|
// swagger:route GET /admin/courier/messages/{id} courier getCourierMessage
|
|
//
|
|
// # Get a Message
|
|
//
|
|
// Gets a specific messages by the given ID.
|
|
//
|
|
// Produces:
|
|
// - application/json
|
|
//
|
|
// Security:
|
|
// oryAccessToken:
|
|
//
|
|
// Schemes: http, https
|
|
//
|
|
// Responses:
|
|
// 200: message
|
|
// 400: errorGeneric
|
|
// default: errorGeneric
|
|
func (h *Handler) getCourierMessage(w http.ResponseWriter, r *http.Request) {
|
|
msgID, err := uuid.FromString(r.PathValue("msgID"))
|
|
if err != nil {
|
|
h.r.Writer().WriteError(w, r, herodot.ErrBadRequest.WithError(err.Error()).WithDebugf("could not parse parameter {id} as UUID, got %s", r.PathValue("id")))
|
|
return
|
|
}
|
|
|
|
message, err := h.r.CourierPersister().FetchMessage(r.Context(), msgID)
|
|
if err != nil {
|
|
h.r.Writer().WriteError(w, r, err)
|
|
return
|
|
}
|
|
|
|
if !h.r.Config().IsInsecureDevMode(r.Context()) {
|
|
message.Body = "<redacted-unless-dev-mode>"
|
|
}
|
|
|
|
h.r.Writer().Write(w, r, message)
|
|
}
|