all repos — homestead @ 7a7c44a6caec3fd3b5eb655f332450e86b8c4774

Code for my website

domain/identity/webfinger/service.go (view raw)

package webfinger

import (
	"encoding/json"
	"net/http"

	ihttp "alin.ovh/homestead/shared/http"
	"alin.ovh/x/log"

	"github.com/benpate/digit"
)

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
}