✨ Added UserInfo endpoint
This commit is contained in:
parent
6594a532fc
commit
9b94472bb5
|
@ -0,0 +1,95 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/fasthttp/router"
|
||||||
|
"github.com/lestrrat-go/jwx/jwa"
|
||||||
|
http "github.com/valyala/fasthttp"
|
||||||
|
|
||||||
|
"source.toby3d.me/toby3d/middleware"
|
||||||
|
"source.toby3d.me/website/indieauth/internal/common"
|
||||||
|
"source.toby3d.me/website/indieauth/internal/domain"
|
||||||
|
"source.toby3d.me/website/indieauth/internal/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
UserInformationResponse struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
URL *domain.URL `json:"url,omitempty"`
|
||||||
|
Photo *domain.URL `json:"photo,omitempty"`
|
||||||
|
Email *domain.Email `json:"email,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestHandler struct {
|
||||||
|
config *domain.Config
|
||||||
|
tokens token.UseCase
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewRequestHandler(tokens token.UseCase, config *domain.Config) *RequestHandler {
|
||||||
|
return &RequestHandler{
|
||||||
|
tokens: tokens,
|
||||||
|
config: config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHandler) Register(r *router.Router) {
|
||||||
|
chain := middleware.Chain{
|
||||||
|
middleware.JWTWithConfig(middleware.JWTConfig{
|
||||||
|
AuthScheme: "Bearer",
|
||||||
|
BeforeFunc: nil,
|
||||||
|
Claims: nil,
|
||||||
|
ContextKey: "token",
|
||||||
|
ErrorHandler: nil,
|
||||||
|
ErrorHandlerWithContext: nil,
|
||||||
|
ParseTokenFunc: nil,
|
||||||
|
SigningKey: []byte(h.config.JWT.Secret),
|
||||||
|
SigningKeys: nil,
|
||||||
|
SigningMethod: jwa.SignatureAlgorithm(h.config.JWT.Algorithm),
|
||||||
|
Skipper: middleware.DefaultSkipper,
|
||||||
|
SuccessHandler: nil,
|
||||||
|
TokenLookup: middleware.SourceHeader + ":" + http.HeaderAuthorization +
|
||||||
|
"," + middleware.SourceCookie + ":" + "__Secure-auth-token",
|
||||||
|
}),
|
||||||
|
middleware.LogFmt(),
|
||||||
|
}
|
||||||
|
|
||||||
|
r.GET("/userinfo", chain.RequestHandler(h.handleUserInformation))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RequestHandler) handleUserInformation(ctx *http.RequestCtx) {
|
||||||
|
ctx.SetContentType(common.MIMEApplicationJSONCharsetUTF8)
|
||||||
|
ctx.SetStatusCode(http.StatusOK)
|
||||||
|
|
||||||
|
encoder := json.NewEncoder(ctx)
|
||||||
|
|
||||||
|
tkn, err := h.tokens.Verify(ctx, strings.TrimPrefix(string(ctx.Request.Header.Peek(http.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)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !tkn.Scope.Has(domain.ScopeProfile) && !tkn.Scope.Has(domain.ScopeEmail) {
|
||||||
|
ctx.SetStatusCode(http.StatusForbidden)
|
||||||
|
_ = encoder.Encode(domain.NewError(
|
||||||
|
domain.ErrorCodeInsufficientScope,
|
||||||
|
"token with 'profile' and/or 'email' scopes is required to view profile data",
|
||||||
|
"https://indieauth.net/source/#user-information",
|
||||||
|
))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = encoder.Encode(&UserInformationResponse{
|
||||||
|
Name: "",
|
||||||
|
URL: &domain.URL{},
|
||||||
|
Photo: &domain.URL{},
|
||||||
|
Email: &domain.Email{},
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue