summaryrefslogtreecommitdiff
path: root/app/cli.go
diff options
context:
space:
mode:
authorChristian Cleberg <[email protected]>2026-07-15 02:24:58 -0500
committerChristian Cleberg <[email protected]>2026-07-15 02:24:58 -0500
commit7eb5e5e2230b6fb5b1bed6f0eaa03279aa61555b (patch)
tree85e30ad9bf89809e3f2179123239d52bda81f63c /app/cli.go
parent40d405f318a109aad5e7de7ad71fedcc04bb0e86 (diff)
downloadskunky-art-7eb5e5e2230b6fb5b1bed6f0eaa03279aa61555b.tar.gz
skunky-art-7eb5e5e2230b6fb5b1bed6f0eaa03279aa61555b.tar.bz2
skunky-art-7eb5e5e2230b6fb5b1bed6f0eaa03279aa61555b.zip
fix: harden HTTP transport, server timeouts and panic paths
Correctness and security findings surfaced by golangci-lint, plus two latent panics found alongside them. - router: http.ListenAndServe has no timeouts at all (gosec G114), so a slow client could hold a connection and its handler open indefinitely. Replace it with an explicit http.Server carrying read/write/idle timeouts. - httpclient: InstallDAThrottle asserted http.DefaultTransport was a *http.Transport and would panic outright if anything had already wrapped it -- which is precisely what that function does. Check the assertion and fall back to a fresh transport. Expose ProxiedTransport so a configured download-proxy can inherit the same throttle and timeouts instead of silently bypassing them. - cache: the Sys() assertion to *syscall.Stat_t is only valid on unix and would panic elsewhere; skip rotation instead. Indexing Headers["Content-Type"][0] panics when the header is absent; use Headers.Get. Cache files are written 0600 rather than 0700, as they are never executed. - cli, api: check error returns, and exit rather than nil-dereference a file handle that failed to open. SHA-1 and math/rand keep //nolint:gosec with reasons: they are cache-key hashes and random-artwork picks, not security primitives.
Diffstat (limited to 'app/cli.go')
-rwxr-xr-xapp/cli.go33
1 files changed, 23 insertions, 10 deletions
diff --git a/app/cli.go b/app/cli.go
index 042aabd..f9d3c12 100755
--- a/app/cli.go
+++ b/app/cli.go
@@ -9,6 +9,9 @@ import (
"time"
)
+// ExecuteCommandLineArguments parses argv, applying the flags that override
+// config and running one-shot commands such as --help and --add-instance. Some
+// of those commands exit the process rather than return.
func ExecuteCommandLineArguments() {
var helpmsg = `SkunkyArt v{{.Version}} [{{.Description}}]
Usage:
@@ -31,8 +34,12 @@ Copyright lost+skunk, X11. https://github.com/zerolabsco/skunky-art/releases/tag
case "-h", "--help":
var buf bytes.Buffer
t := template.New("help")
- t.Parse(helpmsg)
- t.Execute(&buf, &Release)
+ tryWithExitStatus(func() error {
+ if _, err := t.Parse(helpmsg); err != nil {
+ return err
+ }
+ return t.Execute(&buf, &Release)
+ }(), 1)
exit(buf.String(), 0)
case "-a", "--add-instance":
addInstance()
@@ -79,13 +86,19 @@ func addInstance() {
var settingsVar struct {
Instances []settings `json:"instances"`
}
- instancesJson, err := os.OpenFile("instances.json", os.O_CREATE|os.O_WRONLY, 0644)
- try(err)
- defer instancesJson.Close()
+ // 0644: both files are committed to the repository and are meant to be
+ // world-readable, so gosec's 0600 default does not apply.
+ instancesJSON, err := os.OpenFile("instances.json", os.O_CREATE|os.O_WRONLY, 0644) //nolint:gosec // G302
+ if err != nil {
+ exit(err.Error(), 1)
+ }
+ defer func() { try(instancesJSON.Close()) }()
- instancesFile, err := os.OpenFile("INSTANCES.md", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
- try(err)
- defer instancesFile.Close()
+ instancesFile, err := os.OpenFile("INSTANCES.md", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) //nolint:gosec // G302
+ if err != nil {
+ exit(err.Error(), 1)
+ }
+ defer func() { try(instancesFile.Close()) }()
for {
if string(instances) == "" {
@@ -113,7 +126,7 @@ func addInstance() {
j, err := json.MarshalIndent(&settingsVar, "", " ")
try(err)
- instancesJson.Write(j)
+ try(func() error { _, err := instancesJSON.Write(j); return err }())
settingsVar := &settingsVar.Instances[len(settingsVar.Instances)-1]
var mdstr bytes.Buffer
@@ -157,7 +170,7 @@ func addInstance() {
mdstr.WriteString(settingsVar.Country)
mdstr.WriteString("|")
- instancesFile.Write(mdstr.Bytes())
+ try(func() error { _, err := instancesFile.Write(mdstr.Bytes()); return err }())
break
}
time.Sleep(500 * time.Millisecond)