cmd: switch programs over to certlib.Fetcher.

This commit is contained in:
2025-11-18 11:08:17 -08:00
parent 8d5406256f
commit 4560868688
8 changed files with 114 additions and 25 deletions

View File

@@ -12,6 +12,7 @@ import (
"io"
"os"
"path/filepath"
"sort"
"strings"
"time"
@@ -483,11 +484,19 @@ func encodeCertsToPEM(certs []*x509.Certificate) []byte {
}
func generateManifest(files []fileEntry) []byte {
var manifest strings.Builder
for _, file := range files {
if file.name == "MANIFEST" {
// Build a sorted list of files by filename to ensure deterministic manifest ordering
sorted := make([]fileEntry, 0, len(files))
for _, f := range files {
// Defensive: skip any existing manifest entry
if f.name == "MANIFEST" {
continue
}
sorted = append(sorted, f)
}
sort.Slice(sorted, func(i, j int) bool { return sorted[i].name < sorted[j].name })
var manifest strings.Builder
for _, file := range sorted {
hash := sha256.Sum256(file.content)
manifest.WriteString(fmt.Sprintf("%x %s\n", hash, file.name))
}

View File

@@ -396,6 +396,41 @@ func ParseOneCertificateFromPEM(certsPEM []byte) ([]*x509.Certificate, []byte, e
return certs, rest, nil
}
// LoadFullCertPool returns a certificate pool with roots and intermediates
// from disk. If no roots are provided, the system root pool will be used.
func LoadFullCertPool(roots, intermediates string) (*x509.CertPool, error) {
pool := x509.NewCertPool()
if roots == "" {
pool, err := x509.SystemCertPool()
if err != nil {
return nil, fmt.Errorf("loading system cert pool: %w", err)
}
} else {
rootCerts, err := LoadCertificates(roots)
if err != nil {
return nil, fmt.Errorf("loading roots: %w", err)
}
for _, cert := range rootCerts {
pool.AddCert(cert)
}
}
if intermediates != "" {
intCerts, err := LoadCertificates(intermediates)
if err != nil {
return nil, fmt.Errorf("loading intermediates: %w", err)
}
for _, cert := range intCerts {
pool.AddCert(cert)
}
}
return pool, nil
}
// LoadPEMCertPool loads a pool of PEM certificates from file.
func LoadPEMCertPool(certsFile string) (*x509.CertPool, error) {
if certsFile == "" {

View File

@@ -26,8 +26,14 @@ func parseURL(host string) (string, int, error) {
return "", 0, fmt.Errorf("certlib/hosts: invalid host: %s", host)
}
if strings.ToLower(url.Scheme) != "https" {
switch strings.ToLower(url.Scheme) {
case "https":
// OK
case "tls":
// OK
default:
return "", 0, errors.New("certlib/hosts: only https scheme supported")
}
if url.Port() == "" {
@@ -43,28 +49,28 @@ func parseURL(host string) (string, int, error) {
}
func parseHostPort(host string) (string, int, error) {
host, sport, err := net.SplitHostPort(host)
shost, sport, err := net.SplitHostPort(host)
if err == nil {
portInt, err2 := strconv.ParseInt(sport, 10, 16)
if err2 != nil {
return "", 0, fmt.Errorf("certlib/hosts: invalid port: %s", sport)
}
return host, int(portInt), nil
return shost, int(portInt), nil
}
return host, defaultHTTPSPort, nil
}
func ParseHost(host string) (*Target, error) {
host, port, err := parseURL(host)
uhost, port, err := parseURL(host)
if err == nil {
return &Target{Host: host, Port: port}, nil
return &Target{Host: uhost, Port: port}, nil
}
host, port, err = parseHostPort(host)
shost, port, err := parseHostPort(host)
if err == nil {
return &Target{Host: host, Port: port}, nil
return &Target{Host: shost, Port: port}, nil
}
return nil, fmt.Errorf("certlib/hosts: invalid host: %s", host)

View File

@@ -0,0 +1,34 @@
package hosts_test
import (
"git.wntrmute.dev/kyle/goutils/certlib/hosts"
"testing"
)
type testCase struct {
Host string
Target hosts.Target
}
var testCases = []testCase{
{Host: "server-name", Target: hosts.Target{Host: "server-name", Port: 443}},
{Host: "server-name:8443", Target: hosts.Target{Host: "server-name", Port: 8443}},
{Host: "tls://server-name", Target: hosts.Target{Host: "server-name", Port: 443}},
{Host: "https://server-name", Target: hosts.Target{Host: "server-name", Port: 443}},
{Host: "https://server-name:8443", Target: hosts.Target{Host: "server-name", Port: 8443}},
{Host: "tls://server-name:8443", Target: hosts.Target{Host: "server-name", Port: 8443}},
{Host: "https://server-name/something/else", Target: hosts.Target{Host: "server-name", Port: 443}},
}
func TestParseHost(t *testing.T) {
for i, tc := range testCases {
target, err := hosts.ParseHost(tc.Host)
if err != nil {
t.Fatalf("test case %d: %s", i+1, err)
}
if target.Host != tc.Target.Host {
t.Fatalf("test case %d: got host '%s', want host '%s'", i+1, target.Host, tc.Target.Host)
}
}
}