package webfinger
import (
"encoding/json"
"net/http"
"alin.ovh/x/log"
"github.com/benpate/digit"
ihttp "alin.ovh/homestead/shared/http"
)
type ResourceProvider interface {
GetResource() string
GetIdentityResource() digit.Resource
}
type Service struct {
log *log.Logger
providers []ResourceProvider
corsOrigin string
}
type Option func(*Service)
var (
ErrMissingResourceParameter = ihttp.NewError(
"Missing resource parameter",
http.StatusBadRequest,
)
ErrFailedToEncodeResponse = ihttp.NewError(
"Failed to encode webfinger response",
http.StatusInternalServerError,
)
ErrNotFound = ihttp.NewError("Resource not found", http.StatusNotFound)
)
func WithCORSOrigin(origin string) Option {
return func(s *Service) {
s.corsOrigin = origin
}
}
func New(logger *log.Logger, providers []ResourceProvider, opts ...Option) *Service {
service := &Service{
log: logger,
providers: providers,
corsOrigin: "*", // Default to allow all origins
}
for _, opt := range opts {
opt(service)
}
return service
}
func (s *Service) RegisterHandlers(mux *ihttp.ServeMux) {
mux.HandleFunc("/.well-known/webfinger", s.HandleFunc)
}
func (s *Service) HandleFunc(w http.ResponseWriter, r *http.Request) ihttp.Error {
resource := r.URL.Query().Get("resource")
if resource == "" {
return ErrMissingResourceParameter
}
for _, provider := range s.providers {
if resource == provider.GetResource() {
w.Header().Add("Content-Type", "application/jrd+json")
if s.corsOrigin != "" {
w.Header().Add("Access-Control-Allow-Origin", s.corsOrigin)
}
if err := json.NewEncoder(w).Encode(provider.GetIdentityResource()); err != nil {
return ErrFailedToEncodeResponse.WithCause(err)
}
return nil
}
}
return ErrNotFound
}
domain/identity/webfinger/service.go (view raw)