86 lines
2.1 KiB
Go
86 lines
2.1 KiB
Go
package http
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/goccy/go-json"
|
|
"github.com/lestrrat-go/jwx/v2/jwa"
|
|
|
|
"source.toby3d.me/toby3d/auth/internal/common"
|
|
"source.toby3d.me/toby3d/auth/internal/domain"
|
|
"source.toby3d.me/toby3d/auth/internal/middleware"
|
|
"source.toby3d.me/toby3d/auth/internal/token"
|
|
)
|
|
|
|
type Handler struct {
|
|
config *domain.Config
|
|
tokens token.UseCase
|
|
}
|
|
|
|
func NewHandler(tokens token.UseCase, config *domain.Config) *Handler {
|
|
return &Handler{
|
|
tokens: tokens,
|
|
config: config,
|
|
}
|
|
}
|
|
|
|
func (h *Handler) Handler() http.Handler {
|
|
chain := middleware.Chain{
|
|
//nolint:exhaustivestruct
|
|
middleware.JWTWithConfig(middleware.JWTConfig{
|
|
AuthScheme: "Bearer",
|
|
ContextKey: "token",
|
|
SigningKey: []byte(h.config.JWT.Secret),
|
|
SigningMethod: jwa.SignatureAlgorithm(h.config.JWT.Algorithm),
|
|
Skipper: middleware.DefaultSkipper,
|
|
TokenLookup: "header:" + common.HeaderAuthorization + ":Bearer ",
|
|
}),
|
|
}
|
|
|
|
return chain.Handler(h.handleFunc)
|
|
}
|
|
|
|
func (h *Handler) handleFunc(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != "" && r.Method != http.MethodGet {
|
|
http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
|
|
|
|
return
|
|
}
|
|
|
|
w.Header().Set(common.HeaderContentType, common.MIMEApplicationJSONCharsetUTF8)
|
|
|
|
encoder := json.NewEncoder(w)
|
|
|
|
tkn, userInfo, err := h.tokens.Verify(r.Context(),
|
|
strings.TrimPrefix(r.Header.Get(common.HeaderAuthorization), "Bearer "))
|
|
if err != nil || tkn == nil {
|
|
// WARN(toby3d): If the token is not valid, the endpoint still
|
|
// MUST return a 200 Response.
|
|
_ = encoder.Encode(err) //nolint:errchkjson
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
return
|
|
}
|
|
|
|
if !tkn.Scope.Has(domain.ScopeProfile) {
|
|
//nolint:errchkjson
|
|
_ = encoder.Encode(domain.NewError(
|
|
domain.ErrorCodeInsufficientScope,
|
|
"token with 'profile' scope is required to view profile data",
|
|
"https://indieauth.net/source/#user-information",
|
|
))
|
|
|
|
w.WriteHeader(http.StatusForbidden)
|
|
|
|
return
|
|
}
|
|
|
|
//nolint:errchkjson
|
|
_ = encoder.Encode(NewUserInformationResponse(userInfo,
|
|
userInfo.HasEmail() && tkn.Scope.Has(domain.ScopeEmail)))
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
}
|