~ knotless Search/
↑↓ move↵ open⇧↵ all results
0
0
main
74 lines · 2.1 KB Raw History
package servetls

import (
	"crypto/tls"
	"errors"
	"log/slog"
	"path/filepath"
	"strings"

	"github.com/johnandersen777/socialweb-computer-kcp/api/v1alpha1"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/kit/hostport"
	"github.com/johnandersen777/socialweb-computer-kcp/internal/kit/tlsreload"
)

func KeyFileFor(certFile string) string {
	switch {
	case certFile == "":
		return ""
	case strings.HasSuffix(certFile, ".crt"):
		return strings.TrimSuffix(certFile, ".crt") + ".key"
	case strings.HasSuffix(certFile, ".pem"):
		return strings.TrimSuffix(certFile, ".pem") + ".key"
	default:
		return certFile + ".key"
	}
}

func KeyFilesFor(certFile string) []string {
	candidates := []string{KeyFileFor(certFile)}
	if before, ok := strings.CutSuffix(certFile, ".pem"); ok {
		candidates = append(candidates, before+"-key.pem")
	}
	return append(candidates, certFile)
}

func RefPath(ref string, storage *v1alpha1.ComponentStorage) string {
	ref = strings.TrimSpace(ref)
	if ref == "" {
		return ""
	}
	if filepath.IsAbs(ref) || storage == nil || storage.CertsDir == "" {
		return ref
	}
	return filepath.Join(storage.CertsDir, ref)
}

func CertificateFiles(certRef string, storage *v1alpha1.ComponentStorage, hostnames []string) (string, string) {
	certFile := RefPath(certRef, storage)
	if certFile == "" && storage != nil && storage.CertsDir != "" && len(hostnames) > 0 {
		name := hostport.HostnameOnly(hostnames[0])
		if name != "" && name != "*" {
			certFile = filepath.Join(storage.CertsDir, name+".crt")
		}
	}
	return certFile, KeyFileFor(certFile)
}

func Config(certFile string, fallback *tls.Config, log *slog.Logger) (*tls.Config, error) {
	if certFile != "" {
		reloader, err := tlsreload.New(certFile, KeyFilesFor(certFile), log)
		if err != nil {
			return nil, err
		}
		return reloader.TLSConfig(&tls.Config{MinVersion: tls.VersionTLS12, NextProtos: []string{"http/1.1"}}), nil
	}
	if fallback != nil {
		tlsConfig := fallback.Clone()
		if len(tlsConfig.NextProtos) == 0 {
			tlsConfig.NextProtos = []string{"http/1.1"}
		}
		return tlsConfig, nil
	}
	return nil, errors.New("a TLS certificate is required")
}