// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package external

import (
	"github.com/hashicorp/go-uuid"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"github.com/hashicorp/consul/acl"
	"github.com/hashicorp/consul/acl/resolver"
)

// We tag logs with a unique identifier to ease debugging. In the future this
// should probably be a real Open Telemetry trace ID.
func TraceID() string {
	id, err := uuid.GenerateUUID()
	if err != nil {
		return ""
	}
	return id
}

type ACLResolver interface {
	ResolveTokenAndDefaultMeta(string, *acl.EnterpriseMeta, *acl.AuthorizerContext) (resolver.Result, error)
}

// RequireAnyValidACLToken checks that the caller provided a valid ACL token
// without requiring any specific permissions. This is useful for endpoints
// that are used by all/most consumers of our API, such as those called by the
// consul-server-connection-manager library when establishing a new connection.
//
// Note: no token is required if ACLs are disabled.
func RequireAnyValidACLToken(resolver ACLResolver, token string) error {
	authz, err := resolver.ResolveTokenAndDefaultMeta(token, nil, nil)
	if err != nil {
		return status.Error(codes.Unauthenticated, err.Error())
	}

	if id := authz.ACLIdentity; id != nil && id.ID() == acl.AnonymousTokenID {
		return status.Error(codes.Unauthenticated, "An ACL token must be provided (via the `x-consul-token` metadata field) to call this endpoint")
	}

	return nil
}

func RequireNotNil(v interface{}, name string) {
	if v == nil {
		panic(name + " is required")
	}
}