2024-08-11 03:51:22 +02:00
|
|
|
package val_impls
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"errors"
|
|
|
|
|
"git.devminer.xyz/devminer/unitel"
|
|
|
|
|
"github.com/go-logr/logr"
|
|
|
|
|
"github.com/gofiber/fiber/v2"
|
2024-08-28 00:25:25 +02:00
|
|
|
"github.com/versia-pub/versia-go/internal/repository"
|
|
|
|
|
"github.com/versia-pub/versia-go/internal/utils"
|
|
|
|
|
"github.com/versia-pub/versia-go/internal/validators"
|
|
|
|
|
versiacrypto "github.com/versia-pub/versia-go/pkg/versia/crypto"
|
|
|
|
|
versiautils "github.com/versia-pub/versia-go/pkg/versia/utils"
|
2024-08-11 03:51:22 +02:00
|
|
|
"net/http"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
2024-09-22 01:09:05 +02:00
|
|
|
ErrInvalidSignature = errors.New("invalid signature")
|
|
|
|
|
ErrInvalidOriginHeader = errors.New("invalid origin header")
|
2024-08-11 03:51:22 +02:00
|
|
|
|
|
|
|
|
_ validators.RequestValidator = (*RequestValidatorImpl)(nil)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type RequestValidatorImpl struct {
|
|
|
|
|
repositories repository.Manager
|
|
|
|
|
|
|
|
|
|
telemetry *unitel.Telemetry
|
|
|
|
|
log logr.Logger
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewRequestValidator(repositories repository.Manager, telemetry *unitel.Telemetry, log logr.Logger) *RequestValidatorImpl {
|
|
|
|
|
return &RequestValidatorImpl{
|
|
|
|
|
repositories: repositories,
|
|
|
|
|
|
|
|
|
|
telemetry: telemetry,
|
|
|
|
|
log: log,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (i RequestValidatorImpl) Validate(ctx context.Context, r *http.Request) error {
|
2024-08-20 22:43:26 +02:00
|
|
|
s := i.telemetry.StartSpan(ctx, "function", "val_impls/RequestValidatorImpl.Validate")
|
2024-08-11 03:51:22 +02:00
|
|
|
defer s.End()
|
|
|
|
|
ctx = s.Context()
|
|
|
|
|
|
2024-09-22 01:09:05 +02:00
|
|
|
origin := r.Header.Get("Origin")
|
|
|
|
|
if origin != "" {
|
|
|
|
|
return ErrInvalidOriginHeader
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l := i.log.WithValues("url", r.URL.Path)
|
|
|
|
|
|
2024-08-11 03:51:22 +02:00
|
|
|
r = r.WithContext(ctx)
|
|
|
|
|
|
2024-08-22 23:03:38 +02:00
|
|
|
fedHeaders, err := versiacrypto.ExtractFederationHeaders(r.Header)
|
2024-08-11 03:51:22 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-22 01:09:05 +02:00
|
|
|
var key *versiacrypto.SPKIPublicKey
|
|
|
|
|
var signerURI *versiautils.URL
|
|
|
|
|
if fedHeaders.SignedBy == nil {
|
|
|
|
|
metadata, err := i.repositories.InstanceMetadata().Resolve(ctx, origin)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
signerURI = metadata.URI
|
|
|
|
|
} else {
|
|
|
|
|
user, err := i.repositories.Users().Resolve(ctx, versiautils.URLFromStd(fedHeaders.SignedBy))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
signerURI = user.URI
|
2024-08-11 03:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-22 01:09:05 +02:00
|
|
|
l = l.WithValues("signer", signerURI)
|
|
|
|
|
|
2024-08-20 22:43:26 +02:00
|
|
|
body, err := utils.CopyBody(r)
|
2024-08-11 03:51:22 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-22 01:09:05 +02:00
|
|
|
if !(versiacrypto.Verifier{PublicKey: key}).Verify(r.Method, r.URL, body, fedHeaders) {
|
|
|
|
|
l.WithCallDepth(1).Info("signature verification failed")
|
2024-08-11 03:51:22 +02:00
|
|
|
s.CaptureError(ErrInvalidSignature)
|
|
|
|
|
|
|
|
|
|
return ErrInvalidSignature
|
|
|
|
|
} else {
|
2024-09-22 01:09:05 +02:00
|
|
|
l.V(2).Info("signature verification succeeded")
|
2024-08-11 03:51:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (i RequestValidatorImpl) ValidateFiberCtx(ctx context.Context, c *fiber.Ctx) error {
|
2024-08-20 22:43:26 +02:00
|
|
|
s := i.telemetry.StartSpan(ctx, "function", "val_impls/RequestValidatorImpl.ValidateFiberCtx")
|
2024-08-11 03:51:22 +02:00
|
|
|
defer s.End()
|
|
|
|
|
ctx = s.Context()
|
|
|
|
|
|
2024-08-20 22:43:26 +02:00
|
|
|
r, err := utils.ConvertToStdRequest(c)
|
2024-08-11 03:51:22 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return i.Validate(ctx, r)
|
|
|
|
|
}
|