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