this repo has no description
1package knotserver 2 3import ( 4 "bufio" 5 "context" 6 "log/slog" 7 "net/http" 8 "path/filepath" 9 "strings" 10 11 "github.com/go-chi/chi/v5" 12 "github.com/go-chi/chi/v5/middleware" 13 "tangled.sh/tangled.sh/core/knotserver/config" 14 "tangled.sh/tangled.sh/core/knotserver/db" 15 "tangled.sh/tangled.sh/core/rbac" 16) 17 18type InternalHandle struct { 19 db *db.DB 20 c *config.Config 21 e *rbac.Enforcer 22 l *slog.Logger 23} 24 25func (h *InternalHandle) PushAllowed(w http.ResponseWriter, r *http.Request) { 26 user := r.URL.Query().Get("user") 27 repo := r.URL.Query().Get("repo") 28 29 if user == "" || repo == "" { 30 w.WriteHeader(http.StatusBadRequest) 31 return 32 } 33 34 ok, err := h.e.IsPushAllowed(user, ThisServer, repo) 35 if err != nil || !ok { 36 w.WriteHeader(http.StatusForbidden) 37 return 38 } 39 40 w.WriteHeader(http.StatusNoContent) 41 return 42} 43 44func (h *InternalHandle) InternalKeys(w http.ResponseWriter, r *http.Request) { 45 keys, err := h.db.GetAllPublicKeys() 46 if err != nil { 47 writeError(w, err.Error(), http.StatusInternalServerError) 48 return 49 } 50 51 data := make([]map[string]interface{}, 0) 52 for _, key := range keys { 53 j := key.JSON() 54 data = append(data, j) 55 } 56 writeJSON(w, data) 57 return 58} 59 60func (h *InternalHandle) PostReceiveHook(w http.ResponseWriter, r *http.Request) { 61 l := h.l.With("handler", "PostReceiveHook") 62 63 gitAbsoluteDir := r.Header.Get("X-Git-Dir") 64 gitRelativeDir, err := filepath.Rel(h.c.Repo.ScanPath, gitAbsoluteDir) 65 if err != nil { 66 l.Error("failed to calculate relative git dir", "scanPath", h.c.Repo.ScanPath, "gitAbsoluteDir", gitAbsoluteDir) 67 return 68 } 69 gitUserDid := r.Header.Get("X-Git-User-Did") 70 71 var ops []db.Op 72 scanner := bufio.NewScanner(r.Body) 73 for scanner.Scan() { 74 line := scanner.Text() 75 parts := strings.SplitN(line, " ", 3) 76 if len(parts) != 3 { 77 l.Error("invalid payload", "parts", parts) 78 continue 79 } 80 81 tid := TID() 82 oldSha := parts[0] 83 newSha := parts[1] 84 ref := parts[2] 85 op := db.Op{ 86 Tid: tid, 87 Did: gitUserDid, 88 Repo: gitRelativeDir, 89 OldSha: oldSha, 90 NewSha: newSha, 91 Ref: ref, 92 } 93 ops = append(ops, op) 94 } 95 96 if err := scanner.Err(); err != nil { 97 l.Error("failed to read payload", "err", err) 98 return 99 } 100 101 for _, op := range ops { 102 err := h.db.InsertOp(op) 103 if err != nil { 104 l.Error("failed to insert op", "err", err, "op", op) 105 continue 106 } 107 } 108 109 return 110} 111 112func Internal(ctx context.Context, c *config.Config, db *db.DB, e *rbac.Enforcer, l *slog.Logger) http.Handler { 113 r := chi.NewRouter() 114 115 h := InternalHandle{ 116 db, 117 c, 118 e, 119 l, 120 } 121 122 r.Get("/push-allowed", h.PushAllowed) 123 r.Get("/keys", h.InternalKeys) 124 r.Post("/hooks/post-receive", h.PostReceiveHook) 125 r.Mount("/debug", middleware.Profiler()) 126 127 return r 128}