chore: updated utility functions

This commit is contained in:
David Allen 2025-05-01 23:25:27 -06:00
parent 040e9ac808
commit 5e3332e080
Signed by: towk
GPG key ID: 0430CDBE22619155
5 changed files with 157 additions and 4 deletions

116
internal/urlx/url.go Normal file
View file

@ -0,0 +1,116 @@
package urlx
import (
"fmt"
"net/url"
"strings"
"github.com/rs/zerolog/log"
)
func Sanitize(uri string) (string, error) {
// URL sanitanization for host argument
parsedURI, err := url.ParseRequestURI(uri)
if err != nil {
return "", fmt.Errorf("failed to parse URI: %w", err)
}
// Remove any trailing slashes
parsedURI.Path = strings.TrimSuffix(parsedURI.Path, "/")
// Collapse any doubled slashes
parsedURI.Path = strings.ReplaceAll(parsedURI.Path, "//", "/")
return parsedURI.String(), nil
}
// FormatHosts() takes a list of hosts and ports and builds full URLs in the
// form of scheme://host:port. If no scheme is provided, it will use "https" by
// default.
//
// Returns a 2D string slice where each slice contains URL host strings for each
// port. The intention is to have all of the URLs for a single host combined into
// a single slice to initiate one goroutine per host, but making request to multiple
// ports.
func FormatHosts(hosts []string, ports []int, scheme string, verbose bool) [][]string {
// format each positional arg as a complete URL
var formattedHosts [][]string
for _, host := range hosts {
uri, err := url.ParseRequestURI(host)
if err != nil {
if verbose {
log.Warn().Msgf("invalid URI parsed: %s", host)
}
continue
}
// check if scheme is set, if not set it with flag or default value ('https' if flag is not set)
if uri.Scheme == "" {
if scheme != "" {
uri.Scheme = scheme
} else {
// hardcoded assumption
uri.Scheme = "https"
}
}
// tidy up slashes and update arg with new value
uri.Path = strings.TrimSuffix(uri.Path, "/")
uri.Path = strings.ReplaceAll(uri.Path, "//", "/")
// for hosts with unspecified ports, add ports to scan from flag
if uri.Port() == "" {
var tmp []string
for _, port := range ports {
uri.Host += fmt.Sprintf(":%d", port)
tmp = append(tmp, uri.String())
}
formattedHosts = append(formattedHosts, tmp)
} else {
formattedHosts = append(formattedHosts, []string{uri.String()})
}
}
return formattedHosts
}
// FormatIPs() takes a list of IP addresses and ports and builds full URLs in the
// form of scheme://host:port. If no scheme is provided, it will use "https" by
// default.
//
// Returns a 2D string slice where each slice contains URL host strings for each
// port. The intention is to have all of the URLs for a single host combined into
// a single slice to initiate one goroutine per host, but making request to multiple
// ports.
func FormatIPs(ips []string, ports []int, scheme string, verbose bool) [][]string {
// format each positional arg as a complete URL
var formattedHosts [][]string
for _, ip := range ips {
if scheme == "" {
scheme = "https"
}
// make an entirely new object since we're expecting just IPs
uri := &url.URL{
Scheme: scheme,
Host: ip,
}
// tidy up slashes and update arg with new value
uri.Path = strings.ReplaceAll(uri.Path, "//", "/")
uri.Path = strings.TrimSuffix(uri.Path, "/")
// for hosts with unspecified ports, add ports to scan from flag
if uri.Port() == "" {
if len(ports) == 0 {
ports = append(ports, 443)
}
var tmp []string
for _, port := range ports {
uri.Host += fmt.Sprintf(":%d", port)
tmp = append(tmp, uri.String())
}
formattedHosts = append(formattedHosts, tmp)
} else {
formattedHosts = append(formattedHosts, []string{uri.String()})
}
}
return formattedHosts
}

View file

@ -13,7 +13,7 @@ func GetBMCCredentials(store secrets.SecretStore, id string) bmc.BMCCredentials
) )
if id == "" { if id == "" {
log.Error().Msg("failed to get BMC credentials: id was empty") log.Error().Msg("failed to get BMC credentials: ID was empty")
return creds return creds
} }
@ -36,11 +36,11 @@ func GetBMCCredentials(store secrets.SecretStore, id string) bmc.BMCCredentials
log.Warn().Str("id", id).Err(err).Msg("no default credentials were set, they will be blank unless overridden by CLI flags") log.Warn().Str("id", id).Err(err).Msg("no default credentials were set, they will be blank unless overridden by CLI flags")
} else { } else {
// Default credentials found, use them. // Default credentials found, use them.
log.Info().Str("id", id).Msg("default credentials found, using") log.Info().Str("id", id).Msg("using default credentials found")
creds = defaultSecret creds = defaultSecret
} }
} else { } else {
log.Info().Str("id", id).Msg("specific credentials found, using") log.Info().Str("id", id).Msg("using specific credentials found")
} }
return creds return creds

View file

@ -1,6 +1,8 @@
package util package util
import "fmt" import (
"fmt"
)
// FormatErrorList() is a wrapper function that unifies error list formatting // FormatErrorList() is a wrapper function that unifies error list formatting
// and makes printing error lists consistent. // and makes printing error lists consistent.

25
internal/util/print.go Normal file
View file

@ -0,0 +1,25 @@
package util
import (
"encoding/json"
"fmt"
"github.com/rs/zerolog/log"
"gopkg.in/yaml.v2"
)
func PrintJSON(data any) {
b, err := json.MarshalIndent(data, "", " ")
if err != nil {
log.Error().Err(err).Msgf("failed to marshal scanned results to JSON")
}
fmt.Println(string(b))
}
func PrintYAML(data any) {
b, err := yaml.Marshal(data)
if err != nil {
log.Error().Err(err).Msgf("failed to marshal scanned results to JSON")
}
fmt.Printf("%s\n", string(b))
}

10
internal/util/strings.go Normal file
View file

@ -0,0 +1,10 @@
package util
import "strings"
func TidyJSON(s string) string {
s = strings.ReplaceAll(s, "\n", "")
s = strings.ReplaceAll(s, "\t", "")
s = strings.ReplaceAll(s, " ", "")
return strings.ReplaceAll(s, "\"", "'")
}