repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

commit
ea9df3f
parent
45f05e7
author
Eric Bower
date
2025-04-23 23:52:14 -0400 EDT
fix(pgs): private site access

We were not correctly overriding the default WebRouter which meant it
was always rejecting non-public ACLs for sites.
3 files changed,  +41, -32
M pkg/apps/pgs/tunnel.go
+4, -4
 1@@ -19,12 +19,12 @@ type TunnelWebRouter struct {
 2 
 3 func (web *TunnelWebRouter) InitRouter() {
 4 	router := http.NewServeMux()
 5-	router.HandleFunc("GET /{fname...}", web.AssetRequest)
 6-	router.HandleFunc("GET /{$}", web.AssetRequest)
 7+	router.HandleFunc("GET /{fname...}", web.AssetRequest(tunnelPerm))
 8+	router.HandleFunc("GET /{$}", web.AssetRequest(tunnelPerm))
 9 	web.UserRouter = router
10 }
11 
12-func (web *TunnelWebRouter) Perm(proj *db.Project) bool {
13+func tunnelPerm(proj *db.Project) bool {
14 	return true
15 }
16 
17@@ -128,7 +128,7 @@ func createHttpHandler(cfg *PgsConfig) CtxHttpBridge {
18 
19 		routes := NewWebRouter(cfg)
20 		tunnelRouter := TunnelWebRouter{routes, subdomain}
21-		tunnelRouter.initRouters()
22+		tunnelRouter.InitRouter()
23 		return &tunnelRouter
24 	}
25 }
M pkg/apps/pgs/web.go
+33, -28
 1@@ -143,8 +143,8 @@ func (web *WebRouter) initRouters() {
 2 
 3 	// subdomain or custom domains
 4 	userRouter := http.NewServeMux()
 5-	userRouter.HandleFunc("GET /{fname...}", web.AssetRequest)
 6-	userRouter.HandleFunc("GET /{$}", web.AssetRequest)
 7+	userRouter.HandleFunc("GET /{fname...}", web.AssetRequest(WebPerm))
 8+	userRouter.HandleFunc("GET /{$}", web.AssetRequest(WebPerm))
 9 	web.UserRouter = userRouter
10 }
11 
12@@ -397,42 +397,46 @@ func (web *WebRouter) createRssHandler(by string) http.HandlerFunc {
13 	}
14 }
15 
16-func (web *WebRouter) Perm(proj *db.Project) bool {
17+func WebPerm(proj *db.Project) bool {
18 	return proj.Acl.Type == "public" || proj.Acl.Type == ""
19 }
20 
21 var imgRegex = regexp.MustCompile("(.+.(?:jpg|jpeg|png|gif|webp|svg))(/.+)")
22 
23-func (web *WebRouter) AssetRequest(w http.ResponseWriter, r *http.Request) {
24-	fname := r.PathValue("fname")
25-	if imgRegex.MatchString(fname) {
26-		web.ImageRequest(w, r)
27-		return
28+func (web *WebRouter) AssetRequest(perm func(proj *db.Project) bool) http.HandlerFunc {
29+	return func(w http.ResponseWriter, r *http.Request) {
30+		fname := r.PathValue("fname")
31+		if imgRegex.MatchString(fname) {
32+			web.ImageRequest(perm)(w, r)
33+			return
34+		}
35+		web.ServeAsset(fname, nil, false, perm, w, r)
36 	}
37-	web.ServeAsset(fname, nil, false, web.Perm, w, r)
38 }
39 
40-func (web *WebRouter) ImageRequest(w http.ResponseWriter, r *http.Request) {
41-	rawname := r.PathValue("fname")
42-	matches := imgRegex.FindStringSubmatch(rawname)
43-	fname := rawname
44-	imgOpts := ""
45-	if len(matches) >= 2 {
46-		fname = matches[1]
47-	}
48-	if len(matches) >= 3 {
49-		imgOpts = matches[2]
50-	}
51+func (web *WebRouter) ImageRequest(perm func(proj *db.Project) bool) http.HandlerFunc {
52+	return func(w http.ResponseWriter, r *http.Request) {
53+		rawname := r.PathValue("fname")
54+		matches := imgRegex.FindStringSubmatch(rawname)
55+		fname := rawname
56+		imgOpts := ""
57+		if len(matches) >= 2 {
58+			fname = matches[1]
59+		}
60+		if len(matches) >= 3 {
61+			imgOpts = matches[2]
62+		}
63 
64-	opts, err := storage.UriToImgProcessOpts(imgOpts)
65-	if err != nil {
66-		errMsg := fmt.Sprintf("error processing img options: %s", err.Error())
67-		web.Cfg.Logger.Error("error processing img options", "err", errMsg)
68-		http.Error(w, errMsg, http.StatusUnprocessableEntity)
69-		return
70-	}
71+		opts, err := storage.UriToImgProcessOpts(imgOpts)
72+		if err != nil {
73+			errMsg := fmt.Sprintf("error processing img options: %s", err.Error())
74+			web.Cfg.Logger.Error("error processing img options", "err", errMsg)
75+			http.Error(w, errMsg, http.StatusUnprocessableEntity)
76+			return
77+		}
78 
79-	web.ServeAsset(fname, opts, false, web.Perm, w, r)
80+		web.ServeAsset(fname, opts, false, perm, w, r)
81+	}
82 }
83 
84 func (web *WebRouter) ServeAsset(fname string, opts *storage.ImgProcessOpts, fromImgs bool, hasPerm HasPerm, w http.ResponseWriter, r *http.Request) {
85@@ -502,6 +506,7 @@ func (web *WebRouter) ServeAsset(fname string, opts *storage.ImgProcessOpts, fro
86 		projectID = project.ID
87 		projectDir = project.ProjectDir
88 		if !hasPerm(project) {
89+			logger.Error("You do not have access to this site")
90 			http.Error(w, "You do not have access to this site", http.StatusUnauthorized)
91 			return
92 		}
M pkg/tunkit/ptun.go
+4, -0
 1@@ -1,6 +1,7 @@
 2 package tunkit
 3 
 4 import (
 5+	"context"
 6 	"errors"
 7 	"io"
 8 	"log/slog"
 9@@ -51,9 +52,12 @@ func LocalForwardHandler(handler Tunnel) pssh.SSHServerChannelMiddleware {
10 			return err
11 		}
12 
13+		origCtx, cancel := context.WithCancel(context.Background())
14 		ctx := &pssh.SSHServerConnSession{
15 			Channel:       ch,
16 			SSHServerConn: sc,
17+			Ctx:           origCtx,
18+			CancelFunc:    cancel,
19 		}
20 
21 		go ssh.DiscardRequests(reqs)