forked from tangled.org/core
this repo has no description
at knot-xrpc 5.7 kB view raw
1package knotserver 2 3import ( 4 "context" 5 "fmt" 6 "log/slog" 7 "net/http" 8 "runtime/debug" 9 10 "github.com/go-chi/chi/v5" 11 "tangled.sh/tangled.sh/core/idresolver" 12 "tangled.sh/tangled.sh/core/jetstream" 13 "tangled.sh/tangled.sh/core/knotserver/config" 14 "tangled.sh/tangled.sh/core/knotserver/db" 15 "tangled.sh/tangled.sh/core/knotserver/xrpc" 16 tlog "tangled.sh/tangled.sh/core/log" 17 "tangled.sh/tangled.sh/core/notifier" 18 "tangled.sh/tangled.sh/core/rbac" 19 "tangled.sh/tangled.sh/core/xrpc/serviceauth" 20) 21 22type Handle struct { 23 c *config.Config 24 db *db.DB 25 jc *jetstream.JetstreamClient 26 e *rbac.Enforcer 27 l *slog.Logger 28 n *notifier.Notifier 29 resolver *idresolver.Resolver 30} 31 32func Setup(ctx context.Context, c *config.Config, db *db.DB, e *rbac.Enforcer, jc *jetstream.JetstreamClient, l *slog.Logger, n *notifier.Notifier) (http.Handler, error) { 33 r := chi.NewRouter() 34 35 h := Handle{ 36 c: c, 37 db: db, 38 e: e, 39 l: l, 40 jc: jc, 41 n: n, 42 resolver: idresolver.DefaultResolver(), 43 } 44 45 err := e.AddKnot(rbac.ThisServer) 46 if err != nil { 47 return nil, fmt.Errorf("failed to setup enforcer: %w", err) 48 } 49 50 err = h.configureOwner() 51 if err != nil { 52 return nil, err 53 } 54 h.l.Info("owner set", "did", h.c.Server.Owner) 55 56 err = h.jc.StartJetstream(ctx, h.processMessages) 57 if err != nil { 58 return nil, fmt.Errorf("failed to start jetstream: %w", err) 59 } 60 61 h.jc.AddDid(h.c.Server.Owner) 62 63 // check if the knot knows about any dids 64 dids, err := h.db.GetAllDids() 65 if err != nil { 66 return nil, fmt.Errorf("failed to get all dids: %w", err) 67 } 68 for _, d := range dids { 69 jc.AddDid(d) 70 } 71 72 r.Get("/", h.Index) 73 r.Get("/capabilities", h.Capabilities) 74 r.Get("/version", h.Version) 75 r.Get("/owner", func(w http.ResponseWriter, r *http.Request) { 76 w.Write([]byte(h.c.Server.Owner)) 77 }) 78 r.Route("/{did}", func(r chi.Router) { 79 // Repo routes 80 r.Route("/{name}", func(r chi.Router) { 81 r.Route("/collaborator", func(r chi.Router) { 82 r.Use(h.VerifySignature) 83 r.Post("/add", h.AddRepoCollaborator) 84 }) 85 86 r.Route("/languages", func(r chi.Router) { 87 r.Get("/", h.RepoLanguages) 88 r.Get("/{ref}", h.RepoLanguages) 89 }) 90 91 r.Get("/", h.RepoIndex) 92 r.Get("/info/refs", h.InfoRefs) 93 r.Post("/git-upload-pack", h.UploadPack) 94 r.Post("/git-receive-pack", h.ReceivePack) 95 r.Get("/compare/{rev1}/{rev2}", h.Compare) // git diff-tree compare of two objects 96 97 r.With(h.VerifySignature).Post("/hidden-ref/{forkRef}/{remoteRef}", h.NewHiddenRef) 98 99 r.Route("/merge", func(r chi.Router) { 100 r.With(h.VerifySignature) 101 r.Post("/", h.Merge) 102 r.Post("/check", h.MergeCheck) 103 }) 104 105 r.Route("/tree/{ref}", func(r chi.Router) { 106 r.Get("/", h.RepoIndex) 107 r.Get("/*", h.RepoTree) 108 }) 109 110 r.Route("/blob/{ref}", func(r chi.Router) { 111 r.Get("/*", h.Blob) 112 }) 113 114 r.Route("/raw/{ref}", func(r chi.Router) { 115 r.Get("/*", h.BlobRaw) 116 }) 117 118 r.Get("/log/{ref}", h.Log) 119 r.Get("/archive/{file}", h.Archive) 120 r.Get("/commit/{ref}", h.Diff) 121 r.Get("/tags", h.Tags) 122 r.Route("/branches", func(r chi.Router) { 123 r.Get("/", h.Branches) 124 r.Get("/{branch}", h.Branch) 125 r.Route("/default", func(r chi.Router) { 126 r.Get("/", h.DefaultBranch) 127 r.With(h.VerifySignature).Put("/", h.SetDefaultBranch) 128 }) 129 }) 130 }) 131 }) 132 133 // xrpc apis 134 r.Mount("/xrpc", h.XrpcRouter()) 135 136 // Create a new repository. 137 r.Route("/repo", func(r chi.Router) { 138 r.Use(h.VerifySignature) 139 r.Delete("/", h.RemoveRepo) 140 r.Route("/fork", func(r chi.Router) { 141 r.Post("/", h.RepoFork) 142 r.Post("/sync/{branch}", h.RepoForkSync) 143 r.Get("/sync/{branch}", h.RepoForkAheadBehind) 144 }) 145 }) 146 147 r.Route("/member", func(r chi.Router) { 148 r.Use(h.VerifySignature) 149 r.Put("/add", h.AddMember) 150 }) 151 152 // Socket that streams git oplogs 153 r.Get("/events", h.Events) 154 155 // Health check. Used for two-way verification with appview. 156 r.With(h.VerifySignature).Get("/health", h.Health) 157 158 // All public keys on the knot. 159 r.Get("/keys", h.Keys) 160 161 return r, nil 162} 163 164func (h *Handle) XrpcRouter() http.Handler { 165 logger := tlog.New("knots") 166 167 serviceAuth := serviceauth.NewServiceAuth(h.l, h.resolver, h.c.Server.Did().String()) 168 169 xrpc := &xrpc.Xrpc{ 170 Config: h.c, 171 Db: h.db, 172 Ingester: h.jc, 173 Enforcer: h.e, 174 Logger: logger, 175 Notifier: h.n, 176 Resolver: h.resolver, 177 ServiceAuth: serviceAuth, 178 } 179 return xrpc.Router() 180} 181 182// version is set during build time. 183var version string 184 185func (h *Handle) Version(w http.ResponseWriter, r *http.Request) { 186 if version == "" { 187 info, ok := debug.ReadBuildInfo() 188 if !ok { 189 http.Error(w, "failed to read build info", http.StatusInternalServerError) 190 return 191 } 192 193 var modVer string 194 for _, mod := range info.Deps { 195 if mod.Path == "tangled.sh/tangled.sh/knotserver" { 196 version = mod.Version 197 break 198 } 199 } 200 201 if modVer == "" { 202 version = "unknown" 203 } 204 } 205 206 w.Header().Set("Content-Type", "text/plain; charset=utf-8") 207 fmt.Fprintf(w, "knotserver/%s", version) 208} 209 210func (h *Handle) configureOwner() error { 211 cfgOwner := h.c.Server.Owner 212 213 rbacDomain := "thisserver" 214 215 existing, err := h.e.GetKnotUsersByRole("server:owner", rbacDomain) 216 if err != nil { 217 return err 218 } 219 220 switch len(existing) { 221 case 0: 222 // no owner configured, continue 223 case 1: 224 // find existing owner 225 existingOwner := existing[0] 226 227 // no ownership change, this is okay 228 if existingOwner == h.c.Server.Owner { 229 break 230 } 231 232 // remove existing owner 233 err = h.e.RemoveKnotOwner(rbacDomain, existingOwner) 234 if err != nil { 235 return nil 236 } 237 default: 238 return fmt.Errorf("more than one owner in DB, try deleting %q and starting over", h.c.Server.DBPath) 239 } 240 241 return h.e.AddKnotOwner(rbacDomain, cfgOwner) 242}