Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Examples:
fmt.Print(err)
}

responseMap, err := requests.HandleRequests(requestsCfg)
responseMap, err := requests.HandleRequests(os.Stdout, requestsCfg)
if err != nil {
fmt.Print(err)
}
Expand Down
24 changes: 20 additions & 4 deletions devenv.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
"devenv": {
"locked": {
"dir": "src/modules",
"lastModified": 1763386227,
"lastModified": 1764449550,
"owner": "cachix",
"repo": "devenv",
"rev": "9f855598530d6ee075cc126e4f13812fd008209a",
"rev": "dfb58ac03bed07b93f629df55034bc50394d3971",
"type": "github"
},
"original": {
Expand Down Expand Up @@ -40,10 +40,10 @@
]
},
"locked": {
"lastModified": 1763319842,
"lastModified": 1763988335,
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "7275fa67fbbb75891c16d9dee7d88e58aea2d761",
"rev": "50b9238891e388c9fdc6a5c49e49c42533a1b5ce",
"type": "github"
},
"original": {
Expand Down Expand Up @@ -87,11 +87,27 @@
"type": "github"
}
},
"nixpkgsStable": {
"locked": {
"lastModified": 1764560356,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "6c8f0cca84510cc79e09ea99a299c9bc17d03cb6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.05",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"git-hooks": "git-hooks",
"nixpkgs": "nixpkgs",
"nixpkgsStable": "nixpkgsStable",
"pre-commit-hooks": [
"git-hooks"
]
Expand Down
12 changes: 10 additions & 2 deletions devenv.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
config,
inputs,
...
}: {
}: let
# TODO: align go version between nixos/nixvim and devenv
pkgsStable = import inputs.nixpkgsStable {system = pkgs.stdenv.system;};
in {
env = {
GUM_FORMAT_THEME = "tokyo-night";
CAROOT = "tests/certs";
Expand Down Expand Up @@ -49,7 +52,12 @@
};
};

# languages.go.enable = true;
# https://devenv.sh/reference/options/#languagesgoenable
# TODO: align go related versions used by vim to this before enabling
# languages.go = {
# enable = true;
# package = pkgs.go;
# };

services.nginx = {
enable = true;
Expand Down
3 changes: 3 additions & 0 deletions devenv.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
---
# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json
inputs:
nixpkgs:
url: github:cachix/devenv-nixpkgs/rolling
nixpkgsStable:
url: "github:NixOS/nixpkgs/nixos-25.05"

# If you're using non-OSS software, you can set allowUnfree to true.
# allowUnfree: true
Expand Down
11 changes: 6 additions & 5 deletions internal/certinfo/certinfo_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"crypto/x509"
"encoding/hex"
"fmt"
"io"
"net"
"os"
"strconv"
Expand Down Expand Up @@ -62,7 +63,7 @@ func (c *CertinfoConfig) PrintData() {
))
}

CertsToTables(c.CertsBundle)
CertsToTables(os.Stdout, c.CertsBundle)
}

if len(c.TLSEndpointCerts) > 0 {
Expand Down Expand Up @@ -96,7 +97,7 @@ func (c *CertinfoConfig) PrintData() {
))
}

CertsToTables(c.TLSEndpointCerts)
CertsToTables(os.Stdout, c.TLSEndpointCerts)
}

if len(c.CACertsFilePath) > 0 {
Expand All @@ -116,7 +117,7 @@ func (c *CertinfoConfig) PrintData() {
return
}

CertsToTables(rootCerts)
CertsToTables(os.Stdout, rootCerts)
}
}

Expand Down Expand Up @@ -162,7 +163,7 @@ func (c *CertinfoConfig) GetRemoteCerts() {
}
}

func CertsToTables(certs []*x509.Certificate) {
func CertsToTables(w io.Writer, certs []*x509.Certificate) {
sl := style.CertKeyP4.Render
sv := style.CertValue.Render
svn := style.CertValueNotice.Render
Expand Down Expand Up @@ -214,7 +215,7 @@ func CertsToTables(certs []*x509.Certificate) {
t.Row(sl("SignatureAlgorithm"), sv(signatureAlgorithm))
t.Row(sl("SerialNumber"), sv(serialNumber))
t.Row(sl("Fingerprint SHA-256"), sv(fingerprintSha256))
fmt.Println(t.Render())
fmt.Fprintln(w, t.Render())
t.ClearRows()
}
}
27 changes: 26 additions & 1 deletion internal/requests/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type demoHttpServerData struct {
serverAddr string
proxyprotoEnabled bool
serverName string
tlsCipherSuites []uint16
tlsMaxVersion uint16
}

var (
Expand Down Expand Up @@ -209,7 +211,30 @@ func NewHTTPSTestServer(data demoHttpServerData) (*httptest.Server, error) {
return nil, err
}

ts.TLS = &tls.Config{Certificates: []tls.Certificate{cert}}
// Set default TLS CipherSuites to TLS 1.3 cipher suites
// https://pkg.go.dev/crypto/tls#pkg-constants
tlsCipherSuites := []uint16{
tls.TLS_AES_128_GCM_SHA256,
tls.TLS_AES_256_GCM_SHA384,
tls.TLS_CHACHA20_POLY1305_SHA256,
}

if len(data.tlsCipherSuites) > 0 {
tlsCipherSuites = data.tlsCipherSuites
}

// Set default TLS MaxVersion to 1.3
var tlsMaxVersion uint16 = tls.VersionTLS13

if data.tlsMaxVersion > 0 {
tlsMaxVersion = data.tlsMaxVersion
}

ts.TLS = &tls.Config{
Certificates: []tls.Certificate{cert},
CipherSuites: tlsCipherSuites,
MaxVersion: tlsMaxVersion,
}

ts.StartTLS()

Expand Down
5 changes: 4 additions & 1 deletion internal/requests/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,10 @@ func processHTTPRequestsByHost(r RequestConfig, caPool *x509.CertPool, isVerbose
return nil, err
}

urlList := getUrlsFromHost(host)
urlList, err := getUrlsFromHost(host)
if err != nil {
return nil, err
}

for _, reqURL := range urlList {
responseData := ResponseData{
Expand Down
70 changes: 40 additions & 30 deletions internal/requests/requests_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func (h ResponseHeader) String() string {
}

func (u URI) Parse() bool {
// URIs must start with a slash as in /uri
matched, err := regexp.Match(`^\/.*`, []byte(u))
if err != nil {
return false
Expand Down Expand Up @@ -54,14 +55,14 @@ func TLSVersionName(v uint16) string {

func cipherSuiteName(id uint16) string {
cs := tls.CipherSuiteName(id)
if cs == "" {
if strings.Contains(cs, "0x") {
return fmt.Sprintf("Unknown (0x%x)", id)
}

return cs
}

func parseResponseHeaders(headers http.Header, filter []string) string {
func filterResponseHeaders(headers http.Header, filter []string) string {
var outputStr string

var outputMap map[string][]string
Expand Down Expand Up @@ -94,49 +95,48 @@ func parseResponseHeaders(headers http.Header, filter []string) string {
return outputStr
}

func getUrlsFromHost(h Host) []string {
func getUrlsFromHost(h Host) ([]string, error) {
var list []string

if len(h.URIList) == 0 {
s := httpClientDefaultScheme + "://" + h.Name
list = append(list, s)

return list
return list, nil
}

for _, uri := range h.URIList {
if parsed := uri.Parse(); !parsed {
fmt.Printf("Invalid uri %s for host %s", uri, h.Name)

break
return nil, fmt.Errorf("invalid uri %s for host %s", uri, h.Name)
}

s := fmt.Sprintf("%s://%s%s", httpClientDefaultScheme, h.Name, uri)
list = append(list, s)
}

return list
}

func transportAddressFromRequest(r RequestConfig) (string, error) {
addr, err := transportAddressFromURLString(r.TransportOverrideURL)
if err != nil {
return emptyString, err
}

return addr, nil
return list, nil
}

func transportAddressFromURLString(transportURL string) (string, error) {
var addr string

if transportURL == emptyString {
return emptyString, errors.New("empty string provided as transportURL")
}

// Add HTTPS scheme if missing from transportURL
if match, _ := regexp.MatchString("^https://", transportURL); !match {
transportURL = "https://" + transportURL
}

overrideURL, err := url.Parse(transportURL)
if err != nil {
return "", err
}

addr = overrideURL.Host

// Add default HTTPS port if a port is missing from transportURL
if match, _ := regexp.MatchString("\\:\\d+$", addr); !match {
addr += ":443"
}
Expand Down Expand Up @@ -203,10 +203,10 @@ func proxyProtoHeaderFromRequest(r RequestConfig, serverName string) (proxyproto
return header, nil
}

func HandleRequests(cfg *RequestsMetaConfig) (map[string][]ResponseData, error) {
func HandleRequests(w io.Writer, cfg *RequestsMetaConfig) (map[string][]ResponseData, error) {
responseDataMap := make(map[string][]ResponseData)

cfg.PrintCmd(os.Stdout)
cfg.PrintCmd(w)

for _, r := range cfg.Requests {
responseDataList, err := processHTTPRequestsByHost(
Expand Down Expand Up @@ -304,11 +304,11 @@ func (rd ResponseData) PrintResponseData(isVerbose bool) {
style.StatusCodeParse(rd.Response.StatusCode)))

if rd.Request.PrintResponseCertificates {
RenderTLSData(rd.Response)
RenderTLSData(os.Stdout, rd.Response)
}

if rd.Request.PrintResponseHeaders {
headersStr := parseResponseHeaders(
headersStr := filterResponseHeaders(
rd.Response.Header,
rd.Request.ResponseHeadersFilter)

Expand All @@ -330,26 +330,36 @@ func (rd ResponseData) PrintResponseData(isVerbose bool) {
}
}

func RenderTLSData(r *http.Response) {
func RenderTLSData(w io.Writer, r *http.Response) {
respTLS := r.TLS
sl := style.CertKeyP4.Render
sv := style.CertValue.Render

fmt.Println(style.LgSprintf(style.ItemKeyP3, "TLS:"))
fmt.Fprintln(w, style.LgSprintf(style.ItemKeyP3, "TLS:"))

if respTLS == nil {
fmt.Println(style.LgSprintf(style.CertKeyP4,
"%s",
style.Error.Render("No TLS connection state available")))
fmt.Fprintln(
w,
style.LgSprintf(style.CertKeyP4,
"%s",
style.Error.Render("No TLS connection state available"),
),
)

return
}

t := table.New().Border(style.LGDefBorder)
t.Row(sl("Version"), sv(TLSVersionName(respTLS.Version)))
t.Row(sl("CipherSuite"), sv(cipherSuiteName(respTLS.CipherSuite)))
fmt.Println(t.Render())
t.Row(
sl("Version"),
sv(TLSVersionName(respTLS.Version)),
)
t.Row(
sl("CipherSuite"),
sv(cipherSuiteName(respTLS.CipherSuite)),
)
fmt.Fprintln(w, t.Render())
t.ClearRows()

certinfo.CertsToTables(respTLS.PeerCertificates)
certinfo.CertsToTables(w, respTLS.PeerCertificates)
}
Loading
Loading