🗃️ Added metadata repository implementations
This commit is contained in:
parent
2e791a74f6
commit
a2420359fa
|
@ -0,0 +1,17 @@
|
|||
package metadata
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"source.toby3d.me/website/indieauth/internal/domain"
|
||||
)
|
||||
|
||||
type Repository interface {
|
||||
Get(ctx context.Context, me *domain.Me) (*domain.Metadata, error)
|
||||
}
|
||||
|
||||
var ErrNotExist error = domain.NewError(
|
||||
domain.ErrorCodeInvalidClient,
|
||||
"not found 'indieauth-metadata' endpoint on provided me URL",
|
||||
"https://indieauth.net/source/#discovery-0",
|
||||
)
|
|
@ -0,0 +1,90 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
http "github.com/valyala/fasthttp"
|
||||
|
||||
"source.toby3d.me/website/indieauth/internal/domain"
|
||||
"source.toby3d.me/website/indieauth/internal/metadata"
|
||||
"source.toby3d.me/website/indieauth/internal/util"
|
||||
)
|
||||
|
||||
type (
|
||||
//nolint: tagliatelle,lll
|
||||
Metadata struct {
|
||||
Issuer *domain.ClientID `json:"issuer"`
|
||||
AuthorizationEndpoint *domain.URL `json:"authorization_endpoint"`
|
||||
IntrospectionEndpoint *domain.URL `json:"introspection_endpoint"`
|
||||
RevocationEndpoint *domain.URL `json:"revocation_endpoint,omitempty"`
|
||||
ServiceDocumentation *domain.URL `json:"service_documentation,omitempty"`
|
||||
TokenEndpoint *domain.URL `json:"token_endpoint"`
|
||||
UserinfoEndpoint *domain.URL `json:"userinfo_endpoint,omitempty"`
|
||||
CodeChallengeMethodsSupported []domain.CodeChallengeMethod `json:"code_challenge_methods_supported"`
|
||||
GrantTypesSupported []domain.GrantType `json:"grant_types_supported,omitempty"`
|
||||
ResponseTypesSupported []domain.ResponseType `json:"response_types_supported,omitempty"`
|
||||
ScopesSupported []domain.Scope `json:"scopes_supported,omitempty"`
|
||||
IntrospectionEndpointAuthMethodsSupported []string `json:"introspection_endpoint_auth_methods_supported,omitempty"`
|
||||
RevocationEndpointAuthMethodsSupported []string `json:"revocation_endpoint_auth_methods_supported,omitempty"`
|
||||
AuthorizationResponseIssParameterSupported bool `json:"authorization_response_iss_parameter_supported,omitempty"`
|
||||
}
|
||||
|
||||
httpMetadataRepository struct {
|
||||
client *http.Client
|
||||
}
|
||||
)
|
||||
|
||||
const DefaultMaxRedirectsCount int = 10
|
||||
|
||||
func NewHTTPMetadataRepository(client *http.Client) metadata.Repository {
|
||||
return &httpMetadataRepository{
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func (repo *httpMetadataRepository) Get(ctx context.Context, me *domain.Me) (*domain.Metadata, error) {
|
||||
req := http.AcquireRequest()
|
||||
defer http.ReleaseRequest(req)
|
||||
req.SetRequestURI(me.String())
|
||||
req.Header.SetMethod(http.MethodGet)
|
||||
|
||||
resp := http.AcquireResponse()
|
||||
defer http.ReleaseResponse(resp)
|
||||
|
||||
if err := repo.client.DoRedirects(req, resp, DefaultMaxRedirectsCount); err != nil {
|
||||
return nil, fmt.Errorf("failed to make a request to the client: %w", err)
|
||||
}
|
||||
|
||||
endpoints := util.ExtractEndpoints(resp, "indieauth-metadata")
|
||||
if len(endpoints) == 0 {
|
||||
return nil, metadata.ErrNotExist
|
||||
}
|
||||
|
||||
_, body, err := repo.client.Get(nil, endpoints[len(endpoints)-1].String())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch metadata endpoint configuration: %w", err)
|
||||
}
|
||||
|
||||
data := new(Metadata)
|
||||
if err = json.Unmarshal(body, data); err != nil {
|
||||
return nil, fmt.Errorf("cannot unmarshal metadata configuration: %w", err)
|
||||
}
|
||||
|
||||
return &domain.Metadata{
|
||||
AuthorizationEndpoint: data.AuthorizationEndpoint,
|
||||
AuthorizationResponseIssParameterSupported: data.AuthorizationResponseIssParameterSupported,
|
||||
CodeChallengeMethodsSupported: data.CodeChallengeMethodsSupported,
|
||||
GrantTypesSupported: data.GrantTypesSupported,
|
||||
Issuer: data.Issuer,
|
||||
ResponseTypesSupported: data.ResponseTypesSupported,
|
||||
ScopesSupported: data.ScopesSupported,
|
||||
ServiceDocumentation: data.ServiceDocumentation,
|
||||
TokenEndpoint: data.TokenEndpoint,
|
||||
// TODO(toby3d): support extensions?
|
||||
// Micropub: data.Micropub,
|
||||
// Microsub: data.Microsub,
|
||||
// TicketEndpoint: data.TicketEndpoint,
|
||||
}, nil
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package memory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"sync"
|
||||
|
||||
"source.toby3d.me/website/indieauth/internal/domain"
|
||||
"source.toby3d.me/website/indieauth/internal/metadata"
|
||||
)
|
||||
|
||||
type memoryMetadataRepository struct {
|
||||
store *sync.Map
|
||||
}
|
||||
|
||||
const DefaultPathPrefix = "metadata"
|
||||
|
||||
func NewMemoryMetadataRepository(store *sync.Map) metadata.Repository {
|
||||
return &memoryMetadataRepository{
|
||||
store: store,
|
||||
}
|
||||
}
|
||||
|
||||
func (repo *memoryMetadataRepository) Get(ctx context.Context, me *domain.Me) (*domain.Metadata, error) {
|
||||
src, ok := repo.store.Load(path.Join(DefaultPathPrefix, me.String()))
|
||||
if !ok {
|
||||
return nil, metadata.ErrNotExist
|
||||
}
|
||||
|
||||
result, ok := src.(*domain.Metadata)
|
||||
if !ok {
|
||||
return nil, metadata.ErrNotExist
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
Loading…
Reference in New Issue