repos / pico

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

commit
f650e5e
parent
74f0af0
author
Eric Bower
date
2024-03-13 16:22:57 +0000 UTC
feat(pgs): impersonation working
10 files changed,  +78, -58
M feeds/api.go
+2, -2
 1@@ -64,12 +64,12 @@ func StartApiServer() {
 2 
 3 	mainRoutes := createMainRoutes(staticRoutes)
 4 
 5-	httpCtx := &shared.HttpCtx{
 6+	apiConfig := &shared.ApiConfig{
 7 		Cfg:     cfg,
 8 		Dbpool:  db,
 9 		Storage: st,
10 	}
11-	handler := shared.CreateServe(mainRoutes, []shared.Route{}, httpCtx)
12+	handler := shared.CreateServe(mainRoutes, []shared.Route{}, apiConfig)
13 	router := http.HandlerFunc(handler)
14 
15 	portStr := fmt.Sprintf(":%s", cfg.Port)
M imgs/api.go
+2, -2
 1@@ -322,12 +322,12 @@ func StartApiServer() {
 2 	mainRoutes := createMainRoutes(staticRoutes)
 3 	subdomainRoutes := createSubdomainRoutes(staticRoutes)
 4 
 5-	httpCtx := &shared.HttpCtx{
 6+	apiConfig := &shared.ApiConfig{
 7 		Cfg:     cfg,
 8 		Dbpool:  db,
 9 		Storage: st,
10 	}
11-	handler := shared.CreateServe(mainRoutes, subdomainRoutes, httpCtx)
12+	handler := shared.CreateServe(mainRoutes, subdomainRoutes, apiConfig)
13 	router := http.HandlerFunc(handler)
14 
15 	portStr := fmt.Sprintf(":%s", cfg.Port)
M pastes/api.go
+2, -2
 1@@ -379,12 +379,12 @@ func StartApiServer() {
 2 	mainRoutes := createMainRoutes(staticRoutes)
 3 	subdomainRoutes := createSubdomainRoutes(staticRoutes)
 4 
 5-	httpCtx := &shared.HttpCtx{
 6+	apiConfig := &shared.ApiConfig{
 7 		Cfg:     cfg,
 8 		Dbpool:  db,
 9 		Storage: st,
10 	}
11-	handler := shared.CreateServe(mainRoutes, subdomainRoutes, httpCtx)
12+	handler := shared.CreateServe(mainRoutes, subdomainRoutes, apiConfig)
13 	router := http.HandlerFunc(handler)
14 
15 	portStr := fmt.Sprintf(":%s", cfg.Port)
M pgs/api.go
+2, -2
 1@@ -441,12 +441,12 @@ func StartApiServer() {
 2 		return
 3 	}
 4 
 5-	httpCtx := &shared.HttpCtx{
 6+	apiConfig := &shared.ApiConfig{
 7 		Cfg:     cfg,
 8 		Dbpool:  db,
 9 		Storage: st,
10 	}
11-	handler := shared.CreateServe(mainRoutes, createSubdomainRoutes(publicPerm), httpCtx)
12+	handler := shared.CreateServe(mainRoutes, createSubdomainRoutes(publicPerm), apiConfig)
13 	router := http.HandlerFunc(handler)
14 
15 	portStr := fmt.Sprintf(":%s", cfg.Port)
M pgs/ssh.go
+2, -2
 1@@ -86,7 +86,7 @@ func StartSshServer() {
 2 		st,
 3 	)
 4 
 5-	httpCtx := &shared.HttpCtx{
 6+	apiConfig := &shared.ApiConfig{
 7 		Cfg:     cfg,
 8 		Dbpool:  dbh,
 9 		Storage: st,
10@@ -94,7 +94,7 @@ func StartSshServer() {
11 
12 	webTunnel := &ptun.WebTunnelHandler{
13 		Logger:      logger,
14-		HttpHandler: createHttpHandler(httpCtx),
15+		HttpHandler: createHttpHandler(apiConfig),
16 	}
17 
18 	s, err := wish.NewServer(
M pgs/tunnel.go
+8, -6
 1@@ -19,17 +19,17 @@ type CtxHttpBridge = func(ssh.Context) http.Handler
 2 
 3 func getInfoFromUser(user string) (string, string) {
 4 	if strings.Contains(user, "__") {
 5-		results := strings.SplitN(user, "__", 1)
 6+		results := strings.SplitN(user, "__", 2)
 7 		return results[0], results[1]
 8 	}
 9 
10 	return "", user
11 }
12 
13-func createHttpHandler(httpCtx *shared.HttpCtx) CtxHttpBridge {
14+func createHttpHandler(apiConfig *shared.ApiConfig) CtxHttpBridge {
15 	return func(ctx ssh.Context) http.Handler {
16-		dbh := httpCtx.Dbpool
17-		logger := httpCtx.Cfg.Logger
18+		dbh := apiConfig.Dbpool
19+		logger := apiConfig.Cfg.Logger
20 		asUser, subdomain := getInfoFromUser(ctx.User())
21 		log := logger.With(
22 			"subdomain", subdomain,
23@@ -88,6 +88,8 @@ func createHttpHandler(httpCtx *shared.HttpCtx) CtxHttpBridge {
24 			requester, _ = dbh.FindUserForName(asUser)
25 		}
26 
27+		shared.SetUserCtx(ctx, requester)
28+
29 		if !HasProjectAccess(project, owner, requester, pubkey) {
30 			log.Error("no access")
31 			return http.HandlerFunc(shared.UnauthorizedHandler)
32@@ -108,13 +110,13 @@ func createHttpHandler(httpCtx *shared.HttpCtx) CtxHttpBridge {
33 		}
34 
35 		if subdomain == "pico-ui" || subdomain == "erock-ui" {
36-			rts := ui.CreateRoutes(httpCtx, ctx)
37+			rts := ui.CreateRoutes(apiConfig, ctx)
38 			routes = append(routes, rts...)
39 		}
40 
41 		subdomainRoutes := createSubdomainRoutes(allowPerm)
42 		routes = append(routes, subdomainRoutes...)
43-		finctx := httpCtx.CreateCtx(ctx, subdomain)
44+		finctx := apiConfig.CreateCtx(ctx, subdomain)
45 		httpHandler := shared.CreateServeBasic(routes, finctx)
46 		httpRouter := http.HandlerFunc(httpHandler)
47 		return httpRouter
M prose/api.go
+2, -2
 1@@ -920,12 +920,12 @@ func StartApiServer() {
 2 	mainRoutes := createMainRoutes(staticRoutes)
 3 	subdomainRoutes := createSubdomainRoutes(staticRoutes)
 4 
 5-	httpCtx := &shared.HttpCtx{
 6+	apiConfig := &shared.ApiConfig{
 7 		Cfg:     cfg,
 8 		Dbpool:  db,
 9 		Storage: st,
10 	}
11-	handler := shared.CreateServe(mainRoutes, subdomainRoutes, httpCtx)
12+	handler := shared.CreateServe(mainRoutes, subdomainRoutes, apiConfig)
13 	router := http.HandlerFunc(handler)
14 
15 	portStr := fmt.Sprintf(":%s", cfg.Port)
M shared/router.go
+5, -5
 1@@ -55,13 +55,13 @@ func CreatePProfRoutes(routes []Route) []Route {
 2 }
 3 
 4 type ServeFn func(http.ResponseWriter, *http.Request)
 5-type HttpCtx struct {
 6+type ApiConfig struct {
 7 	Cfg     *ConfigSite
 8 	Dbpool  db.DB
 9 	Storage storage.StorageServe
10 }
11 
12-func (hc *HttpCtx) CreateCtx(prevCtx context.Context, subdomain string) context.Context {
13+func (hc *ApiConfig) CreateCtx(prevCtx context.Context, subdomain string) context.Context {
14 	loggerCtx := context.WithValue(prevCtx, ctxLoggerKey{}, hc.Cfg.Logger)
15 	subdomainCtx := context.WithValue(loggerCtx, ctxSubdomainKey{}, subdomain)
16 	dbCtx := context.WithValue(subdomainCtx, ctxDBKey{}, hc.Dbpool)
17@@ -129,10 +129,10 @@ func findRouteConfig(r *http.Request, routes []Route, subdomainRoutes []Route, c
18 	return curRoutes, subdomain
19 }
20 
21-func CreateServe(routes []Route, subdomainRoutes []Route, httpCtx *HttpCtx) ServeFn {
22+func CreateServe(routes []Route, subdomainRoutes []Route, apiConfig *ApiConfig) ServeFn {
23 	return func(w http.ResponseWriter, r *http.Request) {
24-		curRoutes, subdomain := findRouteConfig(r, routes, subdomainRoutes, httpCtx.Cfg)
25-		ctx := httpCtx.CreateCtx(r.Context(), subdomain)
26+		curRoutes, subdomain := findRouteConfig(r, routes, subdomainRoutes, apiConfig.Cfg)
27+		ctx := apiConfig.CreateCtx(r.Context(), subdomain)
28 		router := CreateServeBasic(curRoutes, ctx)
29 		router(w, r)
30 	}
M shared/tunnel.go
+15, -0
 1@@ -4,9 +4,11 @@ import (
 2 	"fmt"
 3 
 4 	"github.com/charmbracelet/ssh"
 5+	"github.com/picosh/pico/db"
 6 )
 7 
 8 type ctxPublicKey struct{}
 9+type ctxUserKey struct{}
10 
11 func GetPublicKeyCtx(ctx ssh.Context) (ssh.PublicKey, error) {
12 	pk, ok := ctx.Value(ctxPublicKey{}).(ssh.PublicKey)
13@@ -15,6 +17,19 @@ func GetPublicKeyCtx(ctx ssh.Context) (ssh.PublicKey, error) {
14 	}
15 	return pk, nil
16 }
17+
18 func SetPublicKeyCtx(ctx ssh.Context, pk ssh.PublicKey) {
19 	ctx.SetValue(ctxPublicKey{}, pk)
20 }
21+
22+func GetUserCtx(ctx ssh.Context) (*db.User, error) {
23+	pk, ok := ctx.Value(ctxUserKey{}).(*db.User)
24+	if !ok {
25+		return nil, fmt.Errorf("user not set on `ssh.Context()` for connection")
26+	}
27+	return pk, nil
28+}
29+
30+func SetUserCtx(ctx ssh.Context, user *db.User) {
31+	ctx.SetValue(ctxUserKey{}, user)
32+}
M ui/api.go
+38, -35
  1@@ -24,8 +24,8 @@ func ensureUser(w http.ResponseWriter, user *db.User) bool {
  2 	return true
  3 }
  4 
  5-func registerUser(httpCtx *shared.HttpCtx, ctx ssh.Context, pubkey ssh.PublicKey, pubkeyStr string) http.HandlerFunc {
  6-	logger := httpCtx.Cfg.Logger
  7+func registerUser(apiConfig *shared.ApiConfig, ctx ssh.Context, pubkey ssh.PublicKey, pubkeyStr string) http.HandlerFunc {
  8+	logger := apiConfig.Cfg.Logger
  9 	return func(w http.ResponseWriter, r *http.Request) {
 10 		w.Header().Set("Content-Type", "application/json")
 11 		dbpool := shared.GetDB(r)
 12@@ -53,8 +53,8 @@ type featuresPayload struct {
 13 	Features []*db.FeatureFlag `json:"features"`
 14 }
 15 
 16-func getFeatures(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.HandlerFunc {
 17-	logger := httpCtx.Cfg.Logger
 18+func getFeatures(apiConfig *shared.ApiConfig, ctx ssh.Context, user *db.User) http.HandlerFunc {
 19+	logger := apiConfig.Cfg.Logger
 20 	return func(w http.ResponseWriter, r *http.Request) {
 21 		w.Header().Set("Content-Type", "application/json")
 22 		if !ensureUser(w, user) {
 23@@ -82,8 +82,8 @@ type tokenSecretPayload struct {
 24 	Secret string `json:"secret"`
 25 }
 26 
 27-func findOrCreateRssToken(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.HandlerFunc {
 28-	logger := httpCtx.Cfg.Logger
 29+func findOrCreateRssToken(apiConfig *shared.ApiConfig, ctx ssh.Context, user *db.User) http.HandlerFunc {
 30+	logger := apiConfig.Cfg.Logger
 31 	return func(w http.ResponseWriter, r *http.Request) {
 32 		w.Header().Set("Content-Type", "application/json")
 33 		if !ensureUser(w, user) {
 34@@ -112,7 +112,7 @@ type pubkeysPayload struct {
 35 	Pubkeys []*db.PublicKey `json:"pubkeys"`
 36 }
 37 
 38-func getPublicKeys(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.HandlerFunc {
 39+func getPublicKeys(httpCtx *shared.ApiConfig, ctx ssh.Context, user *db.User) http.HandlerFunc {
 40 	logger := httpCtx.Cfg.Logger
 41 	return func(w http.ResponseWriter, r *http.Request) {
 42 		w.Header().Set("Content-Type", "application/json")
 43@@ -148,7 +148,7 @@ type createPubkeyPayload struct {
 44 	Name   string `json:"name"`
 45 }
 46 
 47-func createPubkey(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.HandlerFunc {
 48+func createPubkey(httpCtx *shared.ApiConfig, ctx ssh.Context, user *db.User) http.HandlerFunc {
 49 	logger := httpCtx.Cfg.Logger
 50 	return func(w http.ResponseWriter, r *http.Request) {
 51 		w.Header().Set("Content-Type", "application/json")
 52@@ -173,7 +173,7 @@ func createPubkey(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.
 53 	}
 54 }
 55 
 56-func deletePubkey(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.HandlerFunc {
 57+func deletePubkey(httpCtx *shared.ApiConfig, ctx ssh.Context, user *db.User) http.HandlerFunc {
 58 	logger := httpCtx.Cfg.Logger
 59 	return func(w http.ResponseWriter, r *http.Request) {
 60 		w.Header().Set("Content-Type", "application/json")
 61@@ -197,7 +197,7 @@ type tokensPayload struct {
 62 	Tokens []*db.Token `json:"tokens"`
 63 }
 64 
 65-func getTokens(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.HandlerFunc {
 66+func getTokens(httpCtx *shared.ApiConfig, ctx ssh.Context, user *db.User) http.HandlerFunc {
 67 	logger := httpCtx.Cfg.Logger
 68 	return func(w http.ResponseWriter, r *http.Request) {
 69 		w.Header().Set("Content-Type", "application/json")
 70@@ -232,7 +232,7 @@ type createTokenResponsePayload struct {
 71 	Token  *db.Token `json:"token"`
 72 }
 73 
 74-func createToken(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.HandlerFunc {
 75+func createToken(httpCtx *shared.ApiConfig, ctx ssh.Context, user *db.User) http.HandlerFunc {
 76 	logger := httpCtx.Cfg.Logger
 77 	return func(w http.ResponseWriter, r *http.Request) {
 78 		w.Header().Set("Content-Type", "application/json")
 79@@ -271,7 +271,7 @@ func createToken(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.H
 80 	}
 81 }
 82 
 83-func deleteToken(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.HandlerFunc {
 84+func deleteToken(httpCtx *shared.ApiConfig, ctx ssh.Context, user *db.User) http.HandlerFunc {
 85 	logger := httpCtx.Cfg.Logger
 86 	return func(w http.ResponseWriter, r *http.Request) {
 87 		w.Header().Set("Content-Type", "application/json")
 88@@ -295,7 +295,7 @@ type projectsPayload struct {
 89 	Projects []*db.Project `json:"projects"`
 90 }
 91 
 92-func getProjects(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.HandlerFunc {
 93+func getProjects(httpCtx *shared.ApiConfig, ctx ssh.Context, user *db.User) http.HandlerFunc {
 94 	logger := httpCtx.Cfg.Logger
 95 	return func(w http.ResponseWriter, r *http.Request) {
 96 		w.Header().Set("Content-Type", "application/json")
 97@@ -325,7 +325,7 @@ type postsPayload struct {
 98 	Posts []*db.Post `json:"posts"`
 99 }
100 
101-func getPosts(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User, space string) http.HandlerFunc {
102+func getPosts(httpCtx *shared.ApiConfig, ctx ssh.Context, user *db.User, space string) http.HandlerFunc {
103 	logger := httpCtx.Cfg.Logger
104 	return func(w http.ResponseWriter, r *http.Request) {
105 		w.Header().Set("Content-Type", "application/json")
106@@ -362,9 +362,9 @@ type ProjectObject struct {
107 	ModTime time.Time `json:"mod_time"`
108 }
109 
110-func getProjectObjects(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User) http.HandlerFunc {
111-	logger := httpCtx.Cfg.Logger
112-	storage := httpCtx.Storage
113+func getProjectObjects(apiConfig *shared.ApiConfig, ctx ssh.Context, user *db.User) http.HandlerFunc {
114+	logger := apiConfig.Cfg.Logger
115+	storage := apiConfig.Storage
116 	return func(w http.ResponseWriter, r *http.Request) {
117 		w.Header().Set("Content-Type", "application/json")
118 		if !ensureUser(w, user) {
119@@ -403,9 +403,8 @@ func getProjectObjects(httpCtx *shared.HttpCtx, ctx ssh.Context, user *db.User)
120 	}
121 }
122 
123-func CreateRoutes(httpCtx *shared.HttpCtx, ctx ssh.Context) []shared.Route {
124-	logger := httpCtx.Cfg.Logger
125-	dbpool := httpCtx.Dbpool
126+func CreateRoutes(apiConfig *shared.ApiConfig, ctx ssh.Context) []shared.Route {
127+	logger := apiConfig.Cfg.Logger
128 	pubkey, err := shared.GetPublicKeyCtx(ctx)
129 	if err != nil {
130 		logger.Error("could not get pubkey from ctx", "err", err.Error())
131@@ -418,22 +417,26 @@ func CreateRoutes(httpCtx *shared.HttpCtx, ctx ssh.Context) []shared.Route {
132 		return []shared.Route{}
133 	}
134 
135-	user, _ := dbpool.FindUserForKey("", pubkeyStr)
136+	user, err := shared.GetUserCtx(ctx)
137+	if err != nil {
138+		logger.Error("could not convert key to text", "err", err.Error())
139+		return []shared.Route{}
140+	}
141 
142 	return []shared.Route{
143-		shared.NewCorsRoute("POST", "/api/users", registerUser(httpCtx, ctx, pubkey, pubkeyStr)),
144-		shared.NewCorsRoute("GET", "/api/features", getFeatures(httpCtx, ctx, user)),
145-		shared.NewCorsRoute("PUT", "/api/rss-token", findOrCreateRssToken(httpCtx, ctx, user)),
146-		shared.NewCorsRoute("GET", "/api/pubkeys", getPublicKeys(httpCtx, ctx, user)),
147-		shared.NewCorsRoute("POST", "/api/pubkeys", createPubkey(httpCtx, ctx, user)),
148-		shared.NewCorsRoute("DELETE", "/api/pubkeys/(.+)", deletePubkey(httpCtx, ctx, user)),
149-		shared.NewCorsRoute("GET", "/api/tokens", getTokens(httpCtx, ctx, user)),
150-		shared.NewCorsRoute("POST", "/api/tokens", createToken(httpCtx, ctx, user)),
151-		shared.NewCorsRoute("DELETE", "/api/tokens/(.+)", deleteToken(httpCtx, ctx, user)),
152-		shared.NewCorsRoute("GET", "/api/projects", getProjects(httpCtx, ctx, user)),
153-		shared.NewCorsRoute("GET", "/api/projects/(.+)", getProjectObjects(httpCtx, ctx, user)),
154-		shared.NewCorsRoute("GET", "/api/posts/prose", getPosts(httpCtx, ctx, user, "prose")),
155-		shared.NewCorsRoute("GET", "/api/posts/pastes", getPosts(httpCtx, ctx, user, "pastes")),
156-		shared.NewCorsRoute("GET", "/api/posts/feeds", getPosts(httpCtx, ctx, user, "feeds")),
157+		shared.NewCorsRoute("POST", "/api/users", registerUser(apiConfig, ctx, pubkey, pubkeyStr)),
158+		shared.NewCorsRoute("GET", "/api/features", getFeatures(apiConfig, ctx, user)),
159+		shared.NewCorsRoute("PUT", "/api/rss-token", findOrCreateRssToken(apiConfig, ctx, user)),
160+		shared.NewCorsRoute("GET", "/api/pubkeys", getPublicKeys(apiConfig, ctx, user)),
161+		shared.NewCorsRoute("POST", "/api/pubkeys", createPubkey(apiConfig, ctx, user)),
162+		shared.NewCorsRoute("DELETE", "/api/pubkeys/(.+)", deletePubkey(apiConfig, ctx, user)),
163+		shared.NewCorsRoute("GET", "/api/tokens", getTokens(apiConfig, ctx, user)),
164+		shared.NewCorsRoute("POST", "/api/tokens", createToken(apiConfig, ctx, user)),
165+		shared.NewCorsRoute("DELETE", "/api/tokens/(.+)", deleteToken(apiConfig, ctx, user)),
166+		shared.NewCorsRoute("GET", "/api/projects", getProjects(apiConfig, ctx, user)),
167+		shared.NewCorsRoute("GET", "/api/projects/(.+)", getProjectObjects(apiConfig, ctx, user)),
168+		shared.NewCorsRoute("GET", "/api/posts/prose", getPosts(apiConfig, ctx, user, "prose")),
169+		shared.NewCorsRoute("GET", "/api/posts/pastes", getPosts(apiConfig, ctx, user, "pastes")),
170+		shared.NewCorsRoute("GET", "/api/posts/feeds", getPosts(apiConfig, ctx, user, "feeds")),
171 	}
172 }