peridot/vendor/github.com/authzed/grpcutil/dial_opts.go
Mustafa Gezen ad0f7a5305
Major upgrades
Upgrade to Go 1.20.5, Hydra v2 SDK, rules-go v0.44.2 (with proper resolves), protobuf v25.3 and mass upgrade of Go dependencies.
2024-03-17 08:06:08 +01:00

150 lines
4.4 KiB
Go

// Package grpcutil implements various utilities to simplify common gRPC APIs.
package grpcutil
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io/fs"
"os"
"github.com/certifi/gocertifi"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
type verification int
const (
// SkipVerifyCA is a constant that improves the readability of functions
// with the insecureSkipVerify parameter.
SkipVerifyCA verification = iota
// VerifyCA is a constant that improves the readability of functions
// with the insecureSkipVerify parameter.
VerifyCA
)
func (v verification) asInsecureSkipVerify() bool {
switch v {
case SkipVerifyCA:
return true
case VerifyCA:
return false
default:
panic("unknown verification")
}
}
// WithSystemCerts returns a grpc.DialOption that uses the system-provided
// certificate authority chain to verify the connection.
//
// If one cannot be found, this falls back to using a vendored version of
// Mozilla's collection of root certificate authorities.
func WithSystemCerts(v verification) (grpc.DialOption, error) {
certPool, err := x509.SystemCertPool()
if err != nil {
// Fall back to Mozilla collection of root CAs.
certPool, err = gocertifi.CACerts()
if err != nil {
// This library promises that this should never occur.
return nil, fmt.Errorf("gocertifi returned an error: %w", err)
}
}
return grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
RootCAs: certPool,
InsecureSkipVerify: v.asInsecureSkipVerify(), // nolint
})), nil
}
func forEachFileContents(dirPath string, fn func(contents []byte)) error {
dirFS := os.DirFS(dirPath)
return fs.WalkDir(dirFS, ".", func(path string, d fs.DirEntry, err error) error {
if !d.IsDir() {
contents, err := fs.ReadFile(dirFS, d.Name())
if err != nil {
return err
}
fn(contents)
}
return nil
})
}
// WithCustomCerts returns a grpc.DialOption for requiring TLS that is
// authenticated using a certificate authority chain provided as a path on disk.
//
// If the path is a directory, all files are loaded.
func WithCustomCerts(v verification, certPaths ...string) (grpc.DialOption, error) {
var caFiles [][]byte
for _, certPath := range certPaths {
fi, err := os.Stat(certPath)
if err != nil {
return nil, fmt.Errorf("failed to find certificate: %w", err)
}
if fi.IsDir() {
if err = forEachFileContents(certPath, func(contents []byte) {
caFiles = append(caFiles, contents)
}); err != nil {
return nil, err
}
} else {
contents, err := os.ReadFile(certPath)
if err != nil {
return nil, err
}
caFiles = append(caFiles, contents)
}
}
return WithCustomCertBytes(v, caFiles...)
}
// WithCustomCertBytes returns a grpc.DialOption for requiring TLS that is
// authenticated using a certificate authority chain provided in bytes.
func WithCustomCertBytes(v verification, certsContents ...[]byte) (grpc.DialOption, error) {
certPool := x509.NewCertPool()
for _, certContents := range certsContents {
if ok := certPool.AppendCertsFromPEM(certContents); !ok {
return nil, errors.New("failed to append certs from CA PEM")
}
}
return grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{
RootCAs: certPool,
InsecureSkipVerify: v.asInsecureSkipVerify(), // nolint:gosec
})), nil
}
type secureMetadataCreds map[string]string
func (c secureMetadataCreds) RequireTransportSecurity() bool { return true }
func (c secureMetadataCreds) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {
return c, nil
}
// WithBearerToken returns a grpc.DialOption that adds a standard HTTP Bearer
// token to all requests sent from a client.
func WithBearerToken(token string) grpc.DialOption {
return grpc.WithPerRPCCredentials(secureMetadataCreds{"authorization": "Bearer " + token})
}
type insecureMetadataCreds map[string]string
func (c insecureMetadataCreds) RequireTransportSecurity() bool { return false }
func (c insecureMetadataCreds) GetRequestMetadata(_ context.Context, _ ...string) (map[string]string, error) {
return c, nil
}
// WithInsecureBearerToken returns a grpc.DialOption that adds a standard HTTP
// Bearer token to all requests sent from an insecure client.
//
// Must be used in conjunction with `insecure.NewCredentials()`.
func WithInsecureBearerToken(token string) grpc.DialOption {
return grpc.WithPerRPCCredentials(insecureMetadataCreds{"authorization": "Bearer " + token})
}