diff --git a/internal/metadata/delivery/http/metadata_http.go b/internal/metadata/delivery/http/metadata_http.go index 7ed242a..2eb07af 100644 --- a/internal/metadata/delivery/http/metadata_http.go +++ b/internal/metadata/delivery/http/metadata_http.go @@ -13,9 +13,7 @@ type Handler struct { } func NewHandler(metadata *domain.Metadata) *Handler { - return &Handler{ - metadata: metadata, - } + return &Handler{metadata: metadata} } func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -26,47 +24,6 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } w.Header().Set(common.HeaderContentType, common.MIMEApplicationJSONCharsetUTF8) - - scopes, responseTypes, grantTypes, codeChallengeMethods := make([]string, 0), make([]string, 0), - make([]string, 0), make([]string, 0) - - for i := range h.metadata.ScopesSupported { - scopes = append(scopes, h.metadata.ScopesSupported[i].String()) - } - - for i := range h.metadata.ResponseTypesSupported { - responseTypes = append(responseTypes, h.metadata.ResponseTypesSupported[i].String()) - } - - for i := range h.metadata.GrantTypesSupported { - grantTypes = append(grantTypes, h.metadata.GrantTypesSupported[i].String()) - } - - for i := range h.metadata.CodeChallengeMethodsSupported { - codeChallengeMethods = append(codeChallengeMethods, - h.metadata.CodeChallengeMethodsSupported[i].String()) - } - - _ = json.NewEncoder(w).Encode(&MetadataResponse{ - Issuer: h.metadata.Issuer.String(), - AuthorizationEndpoint: h.metadata.AuthorizationEndpoint.String(), - TokenEndpoint: h.metadata.TokenEndpoint.String(), - IntrospectionEndpoint: h.metadata.IntrospectionEndpoint.String(), - IntrospectionEndpointAuthMethodsSupported: h.metadata.IntrospectionEndpointAuthMethodsSupported, - RevocationEndpoint: h.metadata.RevocationEndpoint.String(), - // NOTE(toby3d): If a revocation endpoint is provided, this - // property should also be provided with the value ["none"], - // since the omission of this value defaults to - // client_secret_basic according to RFC8414. - RevocationEndpointAuthMethodsSupported: h.metadata.RevocationEndpointAuthMethodsSupported, - ScopesSupported: scopes, - ResponseTypesSupported: responseTypes, - GrantTypesSupported: grantTypes, - ServiceDocumentation: h.metadata.ServiceDocumentation.String(), - CodeChallengeMethodsSupported: codeChallengeMethods, - AuthorizationResponseIssParameterSupported: h.metadata.AuthorizationResponseIssParameterSupported, - UserinfoEndpoint: h.metadata.UserinfoEndpoint.String(), - }) - + _ = json.NewEncoder(w).Encode(NewMetadataResponse(*h.metadata)) w.WriteHeader(http.StatusOK) } diff --git a/internal/metadata/delivery/http/metadata_http_schema.go b/internal/metadata/delivery/http/metadata_http_schema.go index 77905a5..f0d3a60 100644 --- a/internal/metadata/delivery/http/metadata_http_schema.go +++ b/internal/metadata/delivery/http/metadata_http_schema.go @@ -1,5 +1,11 @@ package http +import ( + "fmt" + + "source.toby3d.me/toby3d/auth/internal/domain" +) + //nolint:tagliatelle // https://indieauth.net/source/#indieauth-server-metadata type MetadataResponse struct { // URL of a page containing human-readable information that @@ -48,3 +54,69 @@ type MetadataResponse struct { // provides the iss parameter. AuthorizationResponseIssParameterSupported bool `json:"authorization_response_iss_parameter_supported,omitempty"` //nolint:lll } + +//nolint:funlen // false-positive due 3-line documentation comment +func NewMetadataResponse(m domain.Metadata) *MetadataResponse { + out := &MetadataResponse{ + AuthorizationEndpoint: "", + AuthorizationResponseIssParameterSupported: false, + CodeChallengeMethodsSupported: make([]string, 0), + GrantTypesSupported: make([]string, 0), + IntrospectionEndpoint: "", + IntrospectionEndpointAuthMethodsSupported: make([]string, 0), + Issuer: "", + ResponseTypesSupported: make([]string, 0), + RevocationEndpoint: "", + RevocationEndpointAuthMethodsSupported: make([]string, 0), + ScopesSupported: make([]string, 0), + ServiceDocumentation: "", + TokenEndpoint: "", + UserinfoEndpoint: "", + } + + out.AuthorizationResponseIssParameterSupported = m.AuthorizationResponseIssParameterSupported + + for i := range m.ScopesSupported { + out.ScopesSupported = append(out.ScopesSupported, m.ScopesSupported[i].String()) + } + + for i := range m.ResponseTypesSupported { + out.ResponseTypesSupported = append(out.ResponseTypesSupported, m.ResponseTypesSupported[i].String()) + } + + for i := range m.GrantTypesSupported { + out.GrantTypesSupported = append(out.GrantTypesSupported, m.GrantTypesSupported[i].String()) + } + + for i := range m.CodeChallengeMethodsSupported { + out.CodeChallengeMethodsSupported = append(out.CodeChallengeMethodsSupported, + m.CodeChallengeMethodsSupported[i].String()) + } + + out.IntrospectionEndpointAuthMethodsSupported = append(out.IntrospectionEndpointAuthMethodsSupported, + m.IntrospectionEndpointAuthMethodsSupported...) + + // NOTE(toby3d) = If a revocation endpoint is provided, this property + // should also be provided with the value ["none"], since the omission + // of this value defaults to client_secret_basic according to RFC8414. + out.RevocationEndpointAuthMethodsSupported = append(out.RevocationEndpointAuthMethodsSupported, + m.RevocationEndpointAuthMethodsSupported...) + + for dst, src := range map[*string]fmt.Stringer{ + &out.AuthorizationEndpoint: m.AuthorizationEndpoint, + &out.IntrospectionEndpoint: m.IntrospectionEndpoint, + &out.Issuer: m.Issuer, + &out.RevocationEndpoint: m.RevocationEndpoint, + &out.ServiceDocumentation: m.ServiceDocumentation, + &out.TokenEndpoint: m.TokenEndpoint, + &out.UserinfoEndpoint: m.UserinfoEndpoint, + } { + if src == nil { + continue + } + + *dst = src.String() + } + + return out +}