🎨 Format of the exist code before refactoring

This commit is contained in:
Maxim Lebedev 2022-02-16 01:07:39 +05:00
parent e494526389
commit 6a1e281ebb
Signed by: toby3d
GPG Key ID: 1F14E25B7C119FC5
15 changed files with 192 additions and 124 deletions

View File

@ -159,12 +159,12 @@ func (h *RequestHandler) Register(r *router.Router) {
middleware.LogFmt(),
}
r.GET("/authorize", chain.RequestHandler(h.handleRender))
r.GET("/authorize", chain.RequestHandler(h.handleAuthorize))
r.POST("/api/authorize", chain.RequestHandler(h.handleVerify))
r.POST("/authorize", chain.RequestHandler(h.handleExchange))
}
func (h *RequestHandler) handleRender(ctx *http.RequestCtx) {
func (h *RequestHandler) handleAuthorize(ctx *http.RequestCtx) {
ctx.SetContentType(common.MIMETextHTMLCharsetUTF8)
tags, _, _ := language.ParseAcceptLanguage(string(ctx.Request.Header.Peek(http.HeaderAcceptLanguage)))

View File

@ -35,7 +35,7 @@ type Dependencies struct {
store *sync.Map
}
func TestRender(t *testing.T) {
func TestAuthorize(t *testing.T) {
t.Parallel()
deps := NewDependencies(t)

View File

@ -1,4 +1,3 @@
//nolint: dupl
package domain
import (
@ -44,7 +43,7 @@ func ParseAction(uid string) (Action, error) {
func (a *Action) UnmarshalForm(v []byte) error {
action, err := ParseAction(string(v))
if err != nil {
return fmt.Errorf("UnmarshalForm: %w", err)
return fmt.Errorf("Action: UnmarshalForm: %w", err)
}
*a = action
@ -56,12 +55,12 @@ func (a *Action) UnmarshalForm(v []byte) error {
func (a *Action) UnmarshalJSON(v []byte) error {
src, err := strconv.Unquote(string(v))
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("Action: UnmarshalJSON: %w", err)
}
action, err := ParseAction(src)
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("Action: UnmarshalJSON: %w", err)
}
*a = action

View File

@ -107,7 +107,7 @@ func ParseClientID(src string) (*ClientID, error) {
func TestClientID(tb testing.TB) *ClientID {
tb.Helper()
clientID, err := ParseClientID("https://app.example.com/")
clientID, err := ParseClientID("https://indieauth.example.com/")
if err != nil {
tb.Fatal(err)
}
@ -119,7 +119,7 @@ func TestClientID(tb testing.TB) *ClientID {
func (cid *ClientID) UnmarshalForm(v []byte) error {
clientID, err := ParseClientID(string(v))
if err != nil {
return fmt.Errorf("UnmarshalForm: %w", err)
return fmt.Errorf("ClientID: UnmarshalForm: %w", err)
}
*cid = *clientID
@ -131,12 +131,12 @@ func (cid *ClientID) UnmarshalForm(v []byte) error {
func (cid *ClientID) UnmarshalJSON(v []byte) error {
src, err := strconv.Unquote(string(v))
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("ClientID: UnmarshalJSON: %w", err)
}
clientID, err := ParseClientID(src)
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("ClientID: UnmarshalJSON: %w", err)
}
*cid = *clientID

View File

@ -35,15 +35,13 @@ var (
}
CodeChallengeMethodMD5 = CodeChallengeMethod{
uid: "MD5",
//nolint: gosec // support old clients
hash: md5.New(),
uid: "MD5",
hash: md5.New(), //nolint: gosec // support old clients
}
CodeChallengeMethodS1 = CodeChallengeMethod{
uid: "S1",
//nolint: gosec // support old clients
hash: sha1.New(),
uid: "S1",
hash: sha1.New(), //nolint: gosec // support old clients
}
CodeChallengeMethodS256 = CodeChallengeMethod{
@ -64,7 +62,7 @@ var ErrCodeChallengeMethodUnknown error = NewError(
)
//nolint: gochecknoglobals // maps cannot be constants
var slugsMethods = map[string]CodeChallengeMethod{
var uidsMethods = map[string]CodeChallengeMethod{
CodeChallengeMethodMD5.uid: CodeChallengeMethodMD5,
CodeChallengeMethodPLAIN.uid: CodeChallengeMethodPLAIN,
CodeChallengeMethodS1.uid: CodeChallengeMethodS1,
@ -75,7 +73,7 @@ var slugsMethods = map[string]CodeChallengeMethod{
// ParseCodeChallengeMethod parse string identifier of code challenge method
// into struct enum.
func ParseCodeChallengeMethod(uid string) (CodeChallengeMethod, error) {
if method, ok := slugsMethods[strings.ToUpper(uid)]; ok {
if method, ok := uidsMethods[strings.ToUpper(uid)]; ok {
return method, nil
}
@ -86,7 +84,7 @@ func ParseCodeChallengeMethod(uid string) (CodeChallengeMethod, error) {
func (ccm *CodeChallengeMethod) UnmarshalForm(v []byte) error {
method, err := ParseCodeChallengeMethod(string(v))
if err != nil {
return fmt.Errorf("UnmarshalForm: %w", err)
return fmt.Errorf("CodeChallengeMethod: UnmarshalForm: %w", err)
}
*ccm = method
@ -98,12 +96,12 @@ func (ccm *CodeChallengeMethod) UnmarshalForm(v []byte) error {
func (ccm *CodeChallengeMethod) UnmarshalJSON(v []byte) error {
src, err := strconv.Unquote(string(v))
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("CodeChallengeMethod: UnmarshalJSON: %w", err)
}
method, err := ParseCodeChallengeMethod(src)
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("CodeChallengeMethod: UnmarshalJSON: %w", err)
}
*ccm = method
@ -111,6 +109,10 @@ func (ccm *CodeChallengeMethod) UnmarshalJSON(v []byte) error {
return nil
}
func (ccm CodeChallengeMethod) MarshalJSON() ([]byte, error) {
return []byte(strconv.Quote(ccm.uid)), nil
}
// String returns string representation of code challenge method.
func (ccm CodeChallengeMethod) String() string {
return ccm.uid

View File

@ -46,7 +46,7 @@ func ParseGrantType(uid string) (GrantType, error) {
func (gt *GrantType) UnmarshalForm(src []byte) error {
responseType, err := ParseGrantType(string(src))
if err != nil {
return fmt.Errorf("UnmarshalForm: %w", err)
return fmt.Errorf("GrantType: UnmarshalForm: %w", err)
}
*gt = responseType
@ -58,12 +58,12 @@ func (gt *GrantType) UnmarshalForm(src []byte) error {
func (gt *GrantType) UnmarshalJSON(v []byte) error {
src, err := strconv.Unquote(string(v))
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("GrantType: UnmarshalJSON: %w", err)
}
responseType, err := ParseGrantType(src)
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("GrantType: UnmarshalJSON: %w", err)
}
*gt = responseType
@ -71,6 +71,10 @@ func (gt *GrantType) UnmarshalJSON(v []byte) error {
return nil
}
func (gt GrantType) MarshalJSON() ([]byte, error) {
return []byte(strconv.Quote(gt.uid)), nil
}
// String returns string representation of grant type.
func (gt GrantType) String() string {
return gt.uid

View File

@ -115,7 +115,7 @@ func TestMe(tb testing.TB, src string) *Me {
func (m *Me) UnmarshalForm(v []byte) error {
me, err := ParseMe(string(v))
if err != nil {
return fmt.Errorf("UnmarshalForm: %w", err)
return fmt.Errorf("Me: UnmarshalForm: %w", err)
}
*m = *me
@ -127,12 +127,12 @@ func (m *Me) UnmarshalForm(v []byte) error {
func (m *Me) UnmarshalJSON(v []byte) error {
src, err := strconv.Unquote(string(v))
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("Me: UnmarshalJSON: %w", err)
}
me, err := ParseMe(src)
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("Me: UnmarshalJSON: %w", err)
}
*m = *me

View File

@ -1,5 +1,7 @@
package domain
import "testing"
//nolint: tagliatelle // https://indieauth.net/source/#indieauth-server-metadata
type Metadata struct {
// The server's issuer identifier. The issuer identifier is a URL that
@ -10,7 +12,7 @@ type Metadata struct {
// issuer URL could be https://example.com/, or for a metadata URL of
// https://example.com/wp-json/indieauth/1.0/metadata, the issuer URL
// could be https://example.com/wp-json/indieauth/1.0
Issuer *URL `json:"issuer"`
Issuer *ClientID `json:"issuer"`
// The Authorization Endpoint.
AuthorizationEndpoint *URL `json:"authorization_endpoint"`
@ -60,3 +62,48 @@ type Metadata struct {
// WARN(toby3d): experimental
Microsub *URL `json:"microsub,omitempty"`
}
// TestMetadata returns valid random generated Metadata for tests.
func TestMetadata(tb testing.TB) *Metadata {
tb.Helper()
return &Metadata{
Issuer: TestClientID(tb),
AuthorizationEndpoint: TestURL(tb, "https://indieauth.example.com/auth"),
TokenEndpoint: TestURL(tb, "https://indieauth.example.com/token"),
ScopesSupported: Scopes{
ScopeBlock,
ScopeChannels,
ScopeCreate,
ScopeDelete,
ScopeDraft,
ScopeEmail,
ScopeFollow,
ScopeMedia,
ScopeMute,
ScopeProfile,
ScopeRead,
ScopeUpdate,
},
ResponseTypesSupported: []ResponseType{
ResponseTypeCode,
ResponseTypeID,
},
GrantTypesSupported: []GrantType{
GrantTypeAuthorizationCode,
GrantTypeTicket,
},
ServiceDocumentation: TestURL(tb, "https://indieauth.net/draft/"),
CodeChallengeMethodsSupported: []CodeChallengeMethod{
CodeChallengeMethodMD5,
CodeChallengeMethodPLAIN,
CodeChallengeMethodS1,
CodeChallengeMethodS256,
CodeChallengeMethodS512,
},
AuthorizationResponseIssParameterSupported: true,
TicketEndpoint: TestURL(tb, "https://auth.example.org/ticket"),
Micropub: TestURL(tb, "https://example.com/micropub"),
Microsub: TestURL(tb, "https://example.com/microsub"),
}
}

View File

@ -1,4 +1,3 @@
//nolint: dupl
package domain
import (
@ -51,7 +50,7 @@ func ParseResponseType(uid string) (ResponseType, error) {
func (rt *ResponseType) UnmarshalForm(src []byte) error {
responseType, err := ParseResponseType(string(src))
if err != nil {
return fmt.Errorf("UnmarshalForm: %w", err)
return fmt.Errorf("ResponseType: UnmarshalForm: %w", err)
}
*rt = responseType
@ -63,12 +62,12 @@ func (rt *ResponseType) UnmarshalForm(src []byte) error {
func (rt *ResponseType) UnmarshalJSON(v []byte) error {
uid, err := strconv.Unquote(string(v))
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("ResponseType: UnmarshalJSON: %w", err)
}
responseType, err := ParseResponseType(uid)
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("ResponseType: UnmarshalJSON: %w", err)
}
*rt = responseType
@ -76,6 +75,10 @@ func (rt *ResponseType) UnmarshalJSON(v []byte) error {
return nil
}
func (rt ResponseType) MarshalJSON() ([]byte, error) {
return []byte(strconv.Quote(rt.uid)), nil
}
// String returns string representation of response type.
func (rt ResponseType) String() string {
return rt.uid

View File

@ -81,6 +81,15 @@ func ParseScope(uid string) (Scope, error) {
return ScopeUndefined, fmt.Errorf("%w: %s", ErrScopeUnknown, uid)
}
func (s Scope) MarshalJSON() ([]byte, error) {
return []byte(strconv.Quote(s.uid)), nil
}
// String returns string representation of scope.
func (s Scope) String() string {
return s.uid
}
// UnmarshalForm implements custom unmarshler for form values.
func (s *Scopes) UnmarshalForm(v []byte) error {
scopes := make(Scopes, 0)
@ -88,7 +97,7 @@ func (s *Scopes) UnmarshalForm(v []byte) error {
for _, rawScope := range strings.Fields(string(v)) {
scope, err := ParseScope(rawScope)
if err != nil {
return fmt.Errorf("UnmarshalForm: %w", err)
return fmt.Errorf("Scopes: UnmarshalForm: %w", err)
}
if scopes.Has(scope) {
@ -107,7 +116,7 @@ func (s *Scopes) UnmarshalForm(v []byte) error {
func (s *Scopes) UnmarshalJSON(v []byte) error {
src, err := strconv.Unquote(string(v))
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("Scopes: UnmarshalJSON: %w", err)
}
result := make(Scopes, 0)
@ -115,7 +124,7 @@ func (s *Scopes) UnmarshalJSON(v []byte) error {
for _, rawScope := range strings.Fields(src) {
scope, err := ParseScope(rawScope)
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("Scopes: UnmarshalJSON: %w", err)
}
if result.Has(scope) {
@ -141,11 +150,6 @@ func (s Scopes) MarshalJSON() ([]byte, error) {
return []byte(strconv.Quote(strings.Join(scopes, " "))), nil
}
// String returns string representation of scope.
func (s Scope) String() string {
return s.uid
}
// String returns string representation of scopes.
func (s Scopes) String() string {
scopes := make([]string, len(s))

View File

@ -14,7 +14,7 @@ type URL struct {
*http.URI
}
// ParseURL parse strings as URL.
// ParseURL parse string as URL.
func ParseURL(src string) (*URL, error) {
u := http.AcquireURI()
if err := u.Parse(nil, []byte(src)); err != nil {
@ -24,6 +24,16 @@ func ParseURL(src string) (*URL, error) {
return &URL{URI: u}, nil
}
// MustParseURL parse string as URL or panic.
func MustParseURL(src string) *URL {
uri, err := ParseURL(src)
if err != nil {
panic("MustParseURL: " + err.Error())
}
return uri
}
// TestURL returns URL of provided input for tests.
func TestURL(tb testing.TB, src string) *URL {
tb.Helper()
@ -40,7 +50,7 @@ func TestURL(tb testing.TB, src string) *URL {
func (u *URL) UnmarshalForm(v []byte) error {
url, err := ParseURL(string(v))
if err != nil {
return fmt.Errorf("UnmarshalForm: %w", err)
return fmt.Errorf("URL: UnmarshalForm: %w", err)
}
*u = *url
@ -52,12 +62,12 @@ func (u *URL) UnmarshalForm(v []byte) error {
func (u *URL) UnmarshalJSON(v []byte) error {
src, err := strconv.Unquote(string(v))
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("URL: UnmarshalJSON: %w", err)
}
url, err := ParseURL(src)
if err != nil {
return fmt.Errorf("UnmarshalJSON: %w", err)
return fmt.Errorf("URL: UnmarshalJSON: %w", err)
}
*u = *url
@ -65,6 +75,10 @@ func (u *URL) UnmarshalJSON(v []byte) error {
return nil
}
func (u URL) MarshalJSON() ([]byte, error) {
return []byte(strconv.Quote(u.String())), nil
}
// URL returns url.URL representation of URL.
func (u URL) URL() *url.URL {
if u.URI == nil {

View File

@ -23,39 +23,39 @@ type (
// metadata URL of
// https://example.com/wp-json/indieauth/1.0/metadata, the
// issuer URL could be https://example.com/wp-json/indieauth/1.0
Issuer string `json:"issuer"`
Issuer *domain.ClientID `json:"issuer"`
// The Authorization Endpoint.
AuthorizationEndpoint string `json:"authorization_endpoint"`
AuthorizationEndpoint *domain.URL `json:"authorization_endpoint"`
// The Token Endpoint.
TokenEndpoint string `json:"token_endpoint"`
TokenEndpoint *domain.URL `json:"token_endpoint"`
// JSON array containing scope values supported by the
// JSON array containing scope values supported by the
// IndieAuth server. Servers MAY choose not to advertise some
// supported scope values even when this parameter is used.
ScopesSupported []string `json:"scopes_supported,omitempty"`
ScopesSupported []domain.Scope `json:"scopes_supported,omitempty"`
// JSON array containing the response_type values supported.
// This differs from RFC8414 in that this parameter is OPTIONAL
// and that, if omitted, the default is code.
ResponseTypesSupported []string `json:"response_types_supported,omitempty"`
ResponseTypesSupported []domain.ResponseType `json:"response_types_supported,omitempty"`
// JSON array containing grant type values supported. If
// omitted, the default value differs from RFC8414 and is
// authorization_code.
GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
GrantTypesSupported []domain.GrantType `json:"grant_types_supported,omitempty"`
// URL of a page containing human-readable information that
// developers might need to know when using the server. This
// might be a link to the IndieAuth spec or something more
// personal to your implementation.
ServiceDocumentation string `json:"service_documentation,omitempty"`
ServiceDocumentation *domain.URL `json:"service_documentation,omitempty"`
// JSON array containing the methods supported for PKCE. This
// parameter differs from RFC8414 in that it is not optional as
// PKCE is REQUIRED.
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"`
CodeChallengeMethodsSupported []domain.CodeChallengeMethod `json:"code_challenge_methods_supported"`
// Boolean parameter indicating whether the authorization server
// provides the iss parameter. If omitted, the default value is
@ -68,52 +68,13 @@ type (
}
RequestHandler struct {
config *domain.Config
metadata *domain.Metadata
}
)
// DefaultMetadataResponse contains all supported types by default.
//nolint: gochecknoglobals // structs cannot be constants
var DefaultMetadataResponse = MetadataResponse{
AuthorizationEndpoint: "",
AuthorizationResponseIssParameterSupported: true,
CodeChallengeMethodsSupported: []string{
domain.CodeChallengeMethodMD5.String(),
domain.CodeChallengeMethodPLAIN.String(),
domain.CodeChallengeMethodS1.String(),
domain.CodeChallengeMethodS256.String(),
domain.CodeChallengeMethodS512.String(),
},
GrantTypesSupported: []string{
domain.GrantTypeAuthorizationCode.String(),
domain.GrantTypeTicket.String(),
},
Issuer: "",
ResponseTypesSupported: []string{
domain.ResponseTypeCode.String(),
domain.ResponseTypeID.String(),
},
ScopesSupported: []string{
domain.ScopeBlock.String(),
domain.ScopeChannels.String(),
domain.ScopeCreate.String(),
domain.ScopeDelete.String(),
domain.ScopeDraft.String(),
domain.ScopeEmail.String(),
domain.ScopeFollow.String(),
domain.ScopeMedia.String(),
domain.ScopeMute.String(),
domain.ScopeProfile.String(),
domain.ScopeRead.String(),
domain.ScopeUpdate.String(),
},
ServiceDocumentation: "https://indieauth.net/source/",
TokenEndpoint: "",
}
func NewRequestHandler(config *domain.Config) *RequestHandler {
func NewRequestHandler(metadata *domain.Metadata) *RequestHandler {
return &RequestHandler{
config: config,
metadata: metadata,
}
}
@ -126,12 +87,17 @@ func (h *RequestHandler) Register(r *router.Router) {
}
func (h *RequestHandler) read(ctx *http.RequestCtx) {
resp := DefaultMetadataResponse
resp.Issuer = h.config.Server.GetRootURL()
resp.AuthorizationEndpoint = resp.Issuer + "authorize"
resp.TokenEndpoint = resp.Issuer + "token"
ctx.SetStatusCode(http.StatusOK)
ctx.SetContentType(common.MIMEApplicationJSON)
_ = json.NewEncoder(ctx).Encode(&resp)
ctx.SetContentType(common.MIMEApplicationJSONCharsetUTF8)
_ = json.NewEncoder(ctx).Encode(&MetadataResponse{
Issuer: h.metadata.Issuer,
AuthorizationEndpoint: h.metadata.AuthorizationEndpoint,
TokenEndpoint: h.metadata.TokenEndpoint,
ScopesSupported: h.metadata.ScopesSupported,
ResponseTypesSupported: h.metadata.ResponseTypesSupported,
GrantTypesSupported: h.metadata.GrantTypesSupported,
ServiceDocumentation: h.metadata.ServiceDocumentation,
CodeChallengeMethodsSupported: h.metadata.CodeChallengeMethodsSupported,
AuthorizationResponseIssParameterSupported: h.metadata.AuthorizationResponseIssParameterSupported,
})
}

View File

@ -1,7 +1,6 @@
package http_test
import (
"reflect"
"testing"
"github.com/fasthttp/router"
@ -17,8 +16,8 @@ func TestMetadata(t *testing.T) {
t.Parallel()
r := router.New()
cfg := domain.TestConfig(t)
delivery.NewRequestHandler(cfg).Register(r)
metadata := domain.TestMetadata(t)
delivery.NewRequestHandler(metadata).Register(r)
client, _, cleanup := httptest.New(t, r.Handler)
t.Cleanup(cleanup)
@ -36,15 +35,7 @@ func TestMetadata(t *testing.T) {
result := new(delivery.MetadataResponse)
if err = json.Unmarshal(body, result); err != nil {
t.Fatal(err)
}
expResult := delivery.DefaultMetadataResponse
expResult.Issuer = cfg.Server.GetRootURL()
expResult.AuthorizationEndpoint = expResult.Issuer + "authorize"
expResult.TokenEndpoint = expResult.Issuer + "token"
if !reflect.DeepEqual(*result, expResult) {
t.Errorf("Unmarshal(%s) = %+v, want %+v", body, result, expResult)
e := err.(*json.SyntaxError)
t.Fatalf("%s#ERROR#%s", body[:e.Offset], body[e.Offset:])
}
}

View File

@ -39,8 +39,8 @@ type (
TokenExchangeResponse struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
Scope string `json:"scope"`
Me string `json:"me"`
Scope domain.Scopes `json:"scope"`
Me *domain.Me `json:"me"`
Profile *TokenProfileResponse `json:"profile,omitempty"`
}
@ -176,8 +176,8 @@ func (h *RequestHandler) handleExchange(ctx *http.RequestCtx) {
resp := &TokenExchangeResponse{
AccessToken: token.AccessToken,
TokenType: "Bearer",
Scope: token.Scope.String(),
Me: token.Me.String(),
Scope: token.Scope,
Me: token.Me,
Profile: nil,
}
@ -269,9 +269,9 @@ func (h *RequestHandler) handleTicket(ctx *http.RequestCtx) {
_ = encoder.Encode(TokenExchangeResponse{
AccessToken: tkn.AccessToken,
TokenType: "Bearer",
Scope: tkn.Scope.String(),
Me: tkn.Me.String(),
Profile: nil,
Scope: tkn.Scope,
Me: tkn.Me,
Profile: nil, // TODO(toby3d)
})
}

40
main.go
View File

@ -279,7 +279,45 @@ func NewApp(opts NewAppOptions) *App {
func (app *App) Register(r *router.Router) {
tickethttpdelivery.NewRequestHandler(app.tickets, app.matcher, config).Register(r)
healthhttpdelivery.NewRequestHandler().Register(r)
metadatahttpdelivery.NewRequestHandler(config).Register(r)
metadatahttpdelivery.NewRequestHandler(&domain.Metadata{
Issuer: indieAuthClient.ID,
AuthorizationEndpoint: domain.MustParseURL(indieAuthClient.ID.String() + "authorize"),
TokenEndpoint: domain.MustParseURL(indieAuthClient.ID.String() + "token"),
ScopesSupported: domain.Scopes{
domain.ScopeBlock,
domain.ScopeChannels,
domain.ScopeCreate,
domain.ScopeDelete,
domain.ScopeDraft,
domain.ScopeEmail,
domain.ScopeFollow,
domain.ScopeMedia,
domain.ScopeMute,
domain.ScopeProfile,
domain.ScopeRead,
domain.ScopeUpdate,
},
ResponseTypesSupported: []domain.ResponseType{
domain.ResponseTypeCode,
domain.ResponseTypeID,
},
GrantTypesSupported: []domain.GrantType{
domain.GrantTypeAuthorizationCode,
domain.GrantTypeTicket,
},
ServiceDocumentation: domain.MustParseURL("https://indieauth.net/source/"),
CodeChallengeMethodsSupported: []domain.CodeChallengeMethod{
domain.CodeChallengeMethodMD5,
domain.CodeChallengeMethodPLAIN,
domain.CodeChallengeMethodS1,
domain.CodeChallengeMethodS256,
domain.CodeChallengeMethodS512,
},
AuthorizationResponseIssParameterSupported: true,
TicketEndpoint: domain.MustParseURL(indieAuthClient.ID.String() + "ticket"),
Micropub: nil,
Microsub: nil,
}).Register(r)
tokenhttpdelivery.NewRequestHandler(app.tokens, app.tickets).Register(r)
clienthttpdelivery.NewRequestHandler(clienthttpdelivery.NewRequestHandlerOptions{
Client: indieAuthClient,