repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

commit
74f0af0
parent
6cec7bd
author
Eric Bower
date
2024-03-13 03:29:02 +0000 UTC
feat(pgs): impersonate any user
1 files changed,  +23, -2
M pgs/tunnel.go
+23, -2
 1@@ -3,6 +3,7 @@ package pgs
 2 import (
 3 	"encoding/json"
 4 	"net/http"
 5+	"strings"
 6 
 7 	"github.com/charmbracelet/ssh"
 8 	"github.com/picosh/pico/db"
 9@@ -16,13 +17,23 @@ func allowPerm(proj *db.Project) bool {
10 
11 type CtxHttpBridge = func(ssh.Context) http.Handler
12 
13+func getInfoFromUser(user string) (string, string) {
14+	if strings.Contains(user, "__") {
15+		results := strings.SplitN(user, "__", 1)
16+		return results[0], results[1]
17+	}
18+
19+	return "", user
20+}
21+
22 func createHttpHandler(httpCtx *shared.HttpCtx) CtxHttpBridge {
23 	return func(ctx ssh.Context) http.Handler {
24-		subdomain := ctx.User()
25 		dbh := httpCtx.Dbpool
26 		logger := httpCtx.Cfg.Logger
27+		asUser, subdomain := getInfoFromUser(ctx.User())
28 		log := logger.With(
29 			"subdomain", subdomain,
30+			"impersonating", asUser,
31 		)
32 
33 		pubkey, err := shared.GetPublicKeyCtx(ctx)
34@@ -62,11 +73,21 @@ func createHttpHandler(httpCtx *shared.HttpCtx) CtxHttpBridge {
35 
36 		requester, _ := dbh.FindUserForKey("", pubkeyStr)
37 		if requester != nil {
38-			log = logger.With(
39+			log = log.With(
40 				"requester", requester.Name,
41 			)
42 		}
43 
44+		// impersonation logic
45+		if asUser != "" {
46+			isAdmin := dbh.HasFeatureForUser(requester.ID, "admin")
47+			if !isAdmin {
48+				log.Error("impersonation attempt failed")
49+				return http.HandlerFunc(shared.UnauthorizedHandler)
50+			}
51+			requester, _ = dbh.FindUserForName(asUser)
52+		}
53+
54 		if !HasProjectAccess(project, owner, requester, pubkey) {
55 			log.Error("no access")
56 			return http.HandlerFunc(shared.UnauthorizedHandler)