aboutsummaryrefslogtreecommitdiff
path: root/internal/liturgy/fetch_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/liturgy/fetch_test.go')
-rw-r--r--internal/liturgy/fetch_test.go28
1 files changed, 28 insertions, 0 deletions
diff --git a/internal/liturgy/fetch_test.go b/internal/liturgy/fetch_test.go
index ae8a68c..1cebb86 100644
--- a/internal/liturgy/fetch_test.go
+++ b/internal/liturgy/fetch_test.go
@@ -4,6 +4,7 @@ import (
"net/http"
"net/http/httptest"
"os"
+ "path/filepath"
"testing"
)
@@ -30,3 +31,30 @@ func TestLoadCaches(t *testing.T) {
t.Error("cache returned different section count")
}
}
+
+// TestLoadRejectsInvalidDate is the liturgy-layer defense-in-depth check for
+// the ?date= path-traversal finding: Load must reject a non-YYYY-MM-DD date
+// before it ever builds a filesystem path from it, so every caller (web,
+// cli, tui) is protected even if a future caller forgets to validate.
+//
+// The planted "passwd.json" sits one level *above* cacheDir() -- reachable
+// only via a "../" date -- so if Load ever built jsonPath from the raw date
+// unchecked, loadJSONCache would read it back and return its section instead
+// of an error.
+func TestLoadRejectsInvalidDate(t *testing.T) {
+ dir := t.TempDir()
+ t.Setenv("XDG_CACHE_HOME", dir)
+
+ evilPath := filepath.Join(dir, "passwd.json")
+ if err := os.WriteFile(evilPath, []byte(`[{"Heading":"SHOULD-NEVER-BE-READ"}]`), 0o644); err != nil {
+ t.Fatal(err)
+ }
+
+ secs, err := Load(Options{Date: "../passwd"})
+ if err == nil {
+ t.Fatalf("Load(Date=%q) = (%v, nil), want a non-nil error", "../passwd", secs)
+ }
+ if secs != nil {
+ t.Errorf("Load(Date=%q) sections = %v, want nil", "../passwd", secs)
+ }
+}