~sircmpwn/core-go

5f76a1f40df81b73fbc63c3622cb436058434112 — Drew DeVault 2 years ago 1371ba4 webhooks
Enforce complexity limit on webhook payload
2 files changed, 17 insertions(+), 8 deletions(-)

M server/server.go
M webhooks/context.go
M server/server.go => server/server.go +7 -7
@@ 56,6 56,8 @@ type Server struct {
	service string
	queues  []*work.Queue
	email   *work.Queue

	MaxComplexity int
}

// Creates a new common server context for a SourceHut GraphQL daemon.


@@ 81,22 83,19 @@ func (server *Server) WithSchema(
	schema graphql.ExecutableSchema, scopes []string) *Server {
	server.Schema = schema

	var (
		complexity int
		err        error
	)
	var err error
	if limit, ok := server.conf.Get(
		server.service+"::api", "max-complexity"); ok {
		complexity, err = strconv.Atoi(limit)
		server.MaxComplexity, err = strconv.Atoi(limit)
		if err != nil {
			panic(err)
		}
	} else {
		complexity = 250
		server.MaxComplexity = 250
	}

	srv := handler.GraphQL(schema,
		handler.ComplexityLimit(complexity),
		handler.ComplexityLimit(server.MaxComplexity),
		handler.RecoverFunc(EmailRecover),
		handler.UploadMaxSize(1073741824)) // 1 GiB (TODO: configurable?)



@@ 234,6 233,7 @@ func (server *Server) WithQueues(queues ...*work.Queue) *Server {
	ctx = database.Context(ctx, server.db)
	ctx = redis.Context(ctx, server.redis)
	ctx = email.Context(ctx, server.email)
	ctx = context.WithValue(ctx, serverCtxKey, server)

	server.queues = append(server.queues, queues...)
	for _, queue := range queues {

M webhooks/context.go => webhooks/context.go +10 -1
@@ 7,6 7,7 @@ import (
	"errors"
	"fmt"

	"github.com/99designs/gqlgen/complexity"
	"github.com/99designs/gqlgen/graphql"
	"github.com/99designs/gqlgen/graphql/executor"
	"github.com/google/uuid"


@@ 64,7 65,6 @@ func (webhook *WebhookContext) Exec(ctx context.Context,
		return nil, err
	}

	// TODO: Set complexity limit
	exec := executor.New(schema)
	params := graphql.RawParams{
		Query: sub.Query,


@@ 80,6 80,15 @@ func (webhook *WebhookContext) Exec(ctx context.Context,
	}
	rc.RecoverFunc = server.EmailRecover

	op := rc.Doc.Operations.ForName(rc.OperationName)
	complexity := complexity.Calculate(schema, op, rc.Variables)
	srv := server.ForContext(ctx)
	if complexity > srv.MaxComplexity {
		// TODO: This doesn't bubble up to the user well
		return nil, fmt.Errorf("operation has complexity %d, which exceeds the maximum of %d",
			complexity, srv.MaxComplexity)
	}

	var resp graphql.ResponseHandler
	ctx = graphql.WithOperationContext(ctx, rc)
	resp, ctx = exec.DispatchOperation(ctx, rc)