summaryrefslogtreecommitdiff
path: root/internal/web/server.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/web/server.go')
-rw-r--r--internal/web/server.go25
1 files changed, 18 insertions, 7 deletions
diff --git a/internal/web/server.go b/internal/web/server.go
index 5886f0f..3fe1e4e 100644
--- a/internal/web/server.go
+++ b/internal/web/server.go
@@ -14,6 +14,7 @@ import (
"net"
"net/http"
"os/exec"
+ "regexp"
"runtime"
"strings"
"time"
@@ -57,6 +58,13 @@ func today() string {
return time.Now().Format("2006-01-02")
}
+// dateRe validates a ?date= query param before it is ever handed to
+// readings.Load/liturgy.Load, which build a filesystem cache path by string
+// concatenation from it -- an unvalidated date is a path-traversal vector.
+// Compiled once at package scope (not per request), the same shape as
+// internal/cli's dateRe. See resolveQuery.
+var dateRe = regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`)
+
// shiftDate adds days to date (YYYY-MM-DD); an unparsable date is returned
// unchanged, mirroring internal/tui's shiftDate.
func shiftDate(date string, days int) string {
@@ -119,7 +127,7 @@ func requestDisplay(cfg config.Config, r *http.Request) string {
// can't drift.
func resolveQuery(cfg config.Config, r *http.Request) (date, lectionary string, all bool, versions []string, display string) {
date = r.URL.Query().Get("date")
- if date == "" {
+ if date == "" || !dateRe.MatchString(date) {
date = today()
}
lectionary = requestLectionary(cfg, r)
@@ -328,17 +336,20 @@ func themeCSSHandler(cfg config.Config) http.HandlerFunc {
// defaultWebPort is the port chooseListener prefers when cfg.WebPort is 0.
const defaultWebPort = 1099
-// chooseListener binds the port to serve on. port==0 means "prefer
-// defaultWebPort (1099), else let the OS pick a free port"; a non-zero port
-// is bound exactly (and its bind error surfaced if the port is in use).
+// chooseListener binds the port to serve on, on loopback only (127.0.0.1) --
+// lectio-web is documented as a personal tool and Run prints an
+// http://localhost/... URL, so it must not be reachable from the LAN. port==0
+// means "prefer defaultWebPort (1099), else let the OS pick a free port"; a
+// non-zero port is bound exactly (and its bind error surfaced if the port is
+// in use).
func chooseListener(port int) (net.Listener, error) {
if port != 0 {
- return net.Listen("tcp", fmt.Sprintf(":%d", port))
+ return net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
}
- if ln, err := net.Listen("tcp", fmt.Sprintf(":%d", defaultWebPort)); err == nil {
+ if ln, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", defaultWebPort)); err == nil {
return ln, nil
}
- return net.Listen("tcp", ":0") // 1099 taken -> any free port
+ return net.Listen("tcp", "127.0.0.1:0") // 1099 taken -> any free port
}
// Run starts lectio-web: listens on cfg.WebPort via chooseListener (0