Compare commits

...

8 Commits

Author SHA1 Message Date
45d011e114 Update CHANGELOG for v1.16.1. 2025-11-20 19:11:05 -08:00
31fa136b49 msg: rename functions for ergonomics. 2025-11-20 19:10:15 -08:00
d511aeb52d Update CHANGELOG for v1.16.0. 2025-11-20 18:22:00 -08:00
eac59fd5a6 msg: add new package for CLI output. 2025-11-20 18:21:01 -08:00
bd5ec3f425 cmd/kgz: linter fixes 2025-11-20 18:20:28 -08:00
b81709cfdd lib/fetch: documentation 2025-11-20 18:20:28 -08:00
8518cc6e56 lib: add DummyWriteCloser. 2025-11-20 18:20:28 -08:00
0bdd30f506 make the linter happy 2025-11-19 23:23:18 -08:00
8 changed files with 195 additions and 41 deletions

View File

@@ -1,5 +1,19 @@
CHANGELOG CHANGELOG
v1.16.1 - 2025-11-21
Changed:
- msg: rename functions for ergonomics.
v1.16.0 - 2025-11-20
Added:
- msg: package for command line outputs.
Changed:
- lib: add DummyWriteCloser
- Miscellaneous linter fixes and documentation updates.
v1.15.8 - 2025-11-20 v1.15.8 - 2025-11-20
Changed: Changed:

View File

@@ -84,6 +84,7 @@ Contents:
lib/ Commonly-useful functions for writing Go programs. lib/ Commonly-useful functions for writing Go programs.
log/ A syslog library. log/ A syslog library.
logging/ A logging library. logging/ A logging library.
msg/ Output library for command line programs.
mwc/ MultiwriteCloser implementation. mwc/ MultiwriteCloser implementation.
sbuf/ A byte buffer that can be wiped. sbuf/ A byte buffer that can be wiped.
seekbuf/ A read-seekable byte buffer. seekbuf/ A read-seekable byte buffer.

View File

@@ -179,6 +179,8 @@ func (ka KeyAlgo) String() string {
return "Ed25519" return "Ed25519"
case x509.DSA: case x509.DSA:
return "DSA" return "DSA"
case x509.UnknownPublicKeyAlgorithm:
fallthrough // make linter happy
default: default:
return "unknown" return "unknown"
} }

View File

@@ -101,7 +101,7 @@ func buildExtraForPath(st unix.Stat_t, path string, setUID, setGID int) []byte {
gid = uint32(setGID & 0xFFFFFFFF) //#nosec G115 - masked gid = uint32(setGID & 0xFFFFFFFF) //#nosec G115 - masked
} }
} }
mode := uint32(st.Mode & 0o7777) mode := st.Mode & 0o7777
// Use portable helper to gather ctime // Use portable helper to gather ctime
var cts int64 var cts int64

6
go.sum
View File

@@ -29,19 +29,15 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU=
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=

View File

@@ -22,43 +22,50 @@ import (
// Fetcher is an interface for fetching certificates from a remote source. It // Fetcher is an interface for fetching certificates from a remote source. It
// currently supports fetching from a server or a file. // currently supports fetching from a server or a file.
type Fetcher interface { type Fetcher interface {
// Get retrieves the leaf certificate from the source.
Get() (*x509.Certificate, error) Get() (*x509.Certificate, error)
// GetChain retrieves the entire chain from the Fetcher.
GetChain() ([]*x509.Certificate, error) GetChain() ([]*x509.Certificate, error)
// String returns a string representation of the Fetcher.
String() string String() string
} }
func NewFetcher(spec string, tcfg *tls.Config) (Fetcher, error) {
if fileutil.FileDoesExist(spec) || spec == "-" {
return NewFileFetcher(spec), nil
}
fetcher, err := ParseServer(spec, tcfg)
if err != nil {
return nil, err
}
fetcher.config = tcfg
return fetcher, nil
}
// ServerFetcher retrieves certificates from a TLS connection.
type ServerFetcher struct { type ServerFetcher struct {
host string host string
port int port int
insecure bool config *tls.Config
roots *x509.CertPool
}
// WithRoots sets the roots for the ServerFetcher.
func WithRoots(roots *x509.CertPool) func(*ServerFetcher) {
return func(sf *ServerFetcher) {
sf.roots = roots
}
}
// WithSkipVerify sets the insecure flag for the ServerFetcher.
func WithSkipVerify() func(*ServerFetcher) {
return func(sf *ServerFetcher) {
sf.insecure = true
}
} }
// ParseServer parses a server string into a ServerFetcher. It can be a URL or a // ParseServer parses a server string into a ServerFetcher. It can be a URL or a
// a host:port pair. // a host:port pair.
func ParseServer(host string) (*ServerFetcher, error) { func ParseServer(host string, cfg *tls.Config) (*ServerFetcher, error) {
target, err := hosts.ParseHost(host) target, err := hosts.ParseHost(host)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse server: %w", err) return nil, fmt.Errorf("failed to parse server: %w", err)
} }
return &ServerFetcher{ return &ServerFetcher{
host: target.Host, host: target.Host,
port: target.Port, port: target.Port,
config: cfg,
}, nil }, nil
} }
@@ -68,10 +75,7 @@ func (sf *ServerFetcher) String() string {
func (sf *ServerFetcher) GetChain() ([]*x509.Certificate, error) { func (sf *ServerFetcher) GetChain() ([]*x509.Certificate, error) {
opts := dialer.Opts{ opts := dialer.Opts{
TLSConfig: &tls.Config{ TLSConfig: sf.config,
InsecureSkipVerify: sf.insecure, // #nosec G402 - no shit sherlock
RootCAs: sf.roots,
},
} }
conn, err := dialer.DialTLS(context.Background(), net.JoinHostPort(sf.host, lib.Itoa(sf.port, -1)), opts) conn, err := dialer.DialTLS(context.Background(), net.JoinHostPort(sf.host, lib.Itoa(sf.port, -1)), opts)
@@ -93,6 +97,7 @@ func (sf *ServerFetcher) Get() (*x509.Certificate, error) {
return certs[0], nil return certs[0], nil
} }
// FileFetcher retrieves certificates from files on disk.
type FileFetcher struct { type FileFetcher struct {
path string path string
} }
@@ -139,20 +144,11 @@ func (ff *FileFetcher) Get() (*x509.Certificate, error) {
// configuration will be used to control verification behavior (e.g., // configuration will be used to control verification behavior (e.g.,
// InsecureSkipVerify, RootCAs). // InsecureSkipVerify, RootCAs).
func GetCertificateChain(spec string, cfg *tls.Config) ([]*x509.Certificate, error) { func GetCertificateChain(spec string, cfg *tls.Config) ([]*x509.Certificate, error) {
if fileutil.FileDoesExist(spec) { fetcher, err := NewFetcher(spec, cfg)
return NewFileFetcher(spec).GetChain()
}
fetcher, err := ParseServer(spec)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if cfg != nil {
fetcher.insecure = cfg.InsecureSkipVerify
fetcher.roots = cfg.RootCAs
}
return fetcher.GetChain() return fetcher.GetChain()
} }

View File

@@ -5,6 +5,7 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"io"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
@@ -329,3 +330,20 @@ func HexEncode(b []byte, mode HexEncodeMode) string {
panic("invalid hex encode mode") panic("invalid hex encode mode")
} }
} }
// DummyWriteCloser wraps an io.Writer in a struct with a no-op Close.
type DummyWriteCloser struct {
w io.Writer
}
func WithCloser(w io.Writer) io.WriteCloser {
return &DummyWriteCloser{w: w}
}
func (dwc *DummyWriteCloser) Write(p []byte) (int, error) {
return dwc.w.Write(p)
}
func (dwc *DummyWriteCloser) Close() error {
return nil
}

127
msg/msg.go Normal file
View File

@@ -0,0 +1,127 @@
// Package msg is a tool for handling commandline output based on
// flags for quiet, verbose, and debug modes. The default is to
// have all modes disabled.
//
// The Qprint messages will only output messages if quiet mode is
// disabled
// The Vprint messages will only output messages if verbose mode
// is enabled.
// The Dprint messages will only output messages if debug mode
// is enabled.
package msg
import (
"fmt"
"io"
"git.wntrmute.dev/kyle/goutils/lib"
"git.wntrmute.dev/kyle/goutils/dbg"
)
var (
enableQuiet bool
enableVerbose bool
debug *dbg.DebugPrinter
w io.Writer
)
func SetQuiet(q bool) {
enableQuiet = q
}
func SetVerbose(v bool) {
enableVerbose = v
}
func SetDebug(d bool) {
debug.Enabled = d
}
func Set(q, v, d bool) {
SetQuiet(q)
SetVerbose(v)
SetDebug(d)
}
func Qprint(a ...any) {
if enableQuiet {
return
}
fmt.Fprint(w, a...)
}
func Qprintf(format string, a ...any) {
if enableQuiet {
return
}
fmt.Fprintf(w, format, a...)
}
func Qprintln(a ...any) {
if enableQuiet {
return
}
fmt.Fprintln(w, a...)
}
func Dprint(a ...any) {
debug.Print(a...)
}
func Dprintf(format string, a ...any) {
debug.Printf(format, a...)
}
func Dprintln(a ...any) {
debug.Println(a...)
}
func StackTrace() {
debug.StackTrace()
}
func Vprint(a ...any) {
if !enableVerbose {
return
}
fmt.Fprint(w, a...)
}
func Vprintf(format string, a ...any) {
if !enableVerbose {
return
}
fmt.Fprintf(w, format, a...)
}
func Vprintln(a ...any) {
if !enableVerbose {
return
}
fmt.Fprintln(w, a...)
}
func Print(a ...any) {
fmt.Fprint(w, a...)
}
func Printf(format string, a ...any) {
fmt.Fprintf(w, format, a...)
}
func Println(a ...any) {
fmt.Fprintln(w, a...)
}
// SetWriter changes the output for messages.
func SetWriter(dst io.Writer) {
w = dst
debug = dbg.To(lib.WithCloser(w))
}